diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-10-22 17:49:05 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-10-22 17:49:05 +0000 |
commit | f8268ae3196002bbab6adb830302e79b0f368f13 (patch) | |
tree | 755160cb56f57dd7d7dafccc13858533037e619b /lib | |
parent | ed2cb285522513d33b001900acf211cc5ee2175b (diff) |
Add representation of base classes in the AST, and verify that we
don't have duplicated direct base classes.
Seriliazation of base class specifiers is not yet implemented.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57991 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/DeclCXX.cpp | 14 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 24 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 10 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 75 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 4 |
5 files changed, 103 insertions, 24 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 9fd7ff974e..86db8532c8 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -26,6 +26,14 @@ CXXFieldDecl *CXXFieldDecl::Create(ASTContext &C, CXXRecordDecl *RD, return new (Mem) CXXFieldDecl(RD, L, Id, T, BW); } +CXXBaseSpecifier *CXXBaseSpecifier::Create(ASTContext &C, SourceRange R, bool V, + bool BC, AccessSpecifier A, QualType T) +{ + void *Mem = C.getAllocator().Allocate<CXXBaseSpecifier>(); + CXXBaseSpecifier* BS = new (Mem) CXXBaseSpecifier(R, V, BC, A, T); + return BS; +} + CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, CXXRecordDecl* PrevDecl) { @@ -35,6 +43,12 @@ CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, return R; } +CXXRecordDecl::~CXXRecordDecl() { + for (unsigned i = 0; i < NumBases; ++i) + delete Bases[i]; + delete [] Bases; +} + CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index abd432ce9f..21c7d6f0fe 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -256,12 +256,19 @@ void Parser::ParseBaseClause(DeclTy *ClassDecl) assert(Tok.is(tok::colon) && "Not a base clause"); ConsumeToken(); + // Build up an array of parsed base specifiers. + llvm::SmallVector<BaseTy *, 8> BaseInfo; + while (true) { // Parse a base-specifier. - if (ParseBaseSpecifier(ClassDecl)) { + BaseResult Result = ParseBaseSpecifier(ClassDecl); + if (Result.isInvalid) { // Skip the rest of this base specifier, up until the comma or // opening brace. - SkipUntil(tok::comma, tok::l_brace); + SkipUntil(tok::comma, tok::l_brace, true, true); + } else { + // Add this to our array of base specifiers. + BaseInfo.push_back(Result.Val); } // If the next token is a comma, consume it and keep reading @@ -271,6 +278,9 @@ void Parser::ParseBaseClause(DeclTy *ClassDecl) // Consume the comma. ConsumeToken(); } + + // Attach the base specifiers + Actions.ActOnBaseSpecifiers(ClassDecl, &BaseInfo[0], BaseInfo.size()); } /// ParseBaseSpecifier - Parse a C++ base-specifier. A base-specifier is @@ -284,7 +294,7 @@ void Parser::ParseBaseClause(DeclTy *ClassDecl) /// class-name /// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt] /// class-name -bool Parser::ParseBaseSpecifier(DeclTy *ClassDecl) +Parser::BaseResult Parser::ParseBaseSpecifier(DeclTy *ClassDecl) { bool IsVirtual = false; SourceLocation StartLoc = Tok.getLocation(); @@ -306,7 +316,8 @@ bool Parser::ParseBaseSpecifier(DeclTy *ClassDecl) SourceLocation VirtualLoc = ConsumeToken(); if (IsVirtual) { // Complain about duplicate 'virtual' - Diag(VirtualLoc, diag::err_dup_virtual); + Diag(VirtualLoc, diag::err_dup_virtual, + SourceRange(VirtualLoc, VirtualLoc)); } IsVirtual = true; @@ -339,9 +350,8 @@ bool Parser::ParseBaseSpecifier(DeclTy *ClassDecl) // Notify semantic analysis that we have parsed a complete // base-specifier. - Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, BaseType, - BaseLoc); - return false; + return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, BaseType, + BaseLoc); } /// getAccessSpecifierIfPresent - Determine whether the next token is diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b176bc9ceb..48b32e8ce1 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -753,10 +753,14 @@ public: // C++ Classes // /// ActOnBaseSpecifier - Parsed a base specifier - virtual void ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange, - bool Virtual, AccessSpecifier Access, - TypeTy *basetype, SourceLocation BaseLoc); + virtual BaseResult ActOnBaseSpecifier(DeclTy *classdecl, + SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + TypeTy *basetype, SourceLocation BaseLoc); + virtual void ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases, + unsigned NumBases); + virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl, SourceLocation LBrace); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index fef205cb11..7c4444fab6 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -20,6 +20,8 @@ #include "clang/Parse/DeclSpec.h" #include "llvm/Support/Compiler.h" #include <algorithm> // for std::equal +#include <functional> +#include <map> using namespace clang; @@ -260,23 +262,24 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { /// example: /// class foo : public bar, virtual private baz { /// 'public bar' and 'virtual private baz' are each base-specifiers. -void Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange, - bool Virtual, AccessSpecifier Access, - TypeTy *basetype, SourceLocation BaseLoc) { +Sema::BaseResult +Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + TypeTy *basetype, SourceLocation BaseLoc) { RecordDecl *Decl = (RecordDecl*)classdecl; QualType BaseType = Context.getTypeDeclType((TypeDecl*)basetype); // Base specifiers must be record types. if (!BaseType->isRecordType()) { Diag(BaseLoc, diag::err_base_must_be_class, SpecifierRange); - return; + return true; } // C++ [class.union]p1: // A union shall not be used as a base class. if (BaseType->isUnionType()) { Diag(BaseLoc, diag::err_union_as_base_class, SpecifierRange); - return; + return true; } // C++ [class.union]p1: @@ -284,8 +287,7 @@ void Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange, if (Decl->isUnion()) { Diag(Decl->getLocation(), diag::err_base_clause_on_union, SpecifierRange); - Decl->setInvalidDecl(); - return; + return true; } // C++ [class.derived]p2: @@ -293,14 +295,63 @@ void Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange, // defined class. if (BaseType->isIncompleteType()) { Diag(BaseLoc, diag::err_incomplete_base_class, SpecifierRange); - return; + return true; + } + + // Create the base specifier. + CXXBaseSpecifier *BS = CXXBaseSpecifier::Create(Context, SpecifierRange, + Virtual, + BaseType->isClassType(), + Access, BaseType); + return BS; +} + +/// QualTypeOrder - Function object that provides a total ordering on +/// QualType values. +struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> { + bool operator()(QualType T1, QualType T2) { + return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr()); } +}; + +/// ActOnBaseSpecifiers - Attach the given base specifiers to the +/// class, after checking whether there are any duplicate base +/// classes. +void Sema::ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases, + unsigned NumBases) { + if (NumBases == 0) + return; - // FIXME: C++ [class.mi]p3: - // A class shall not be specified as a direct base class of a - // derived class more than once. + // Used to keep track of which base types we have already seen, so + // that we can properly diagnose redundant direct base types. Note + // that the key is always the canonical type. + std::map<QualType, CXXBaseSpecifier*, QualTypeOrdering> KnownBaseTypes; + + // Copy non-redundant base specifiers into permanent storage. + CXXBaseSpecifier **InBaseSpecs = (CXXBaseSpecifier **)Bases; + CXXBaseSpecifier **StoredBaseSpecs = new CXXBaseSpecifier* [NumBases]; + unsigned outIdx = 0; + for (unsigned inIdx = 0; inIdx < NumBases; ++inIdx) { + QualType NewBaseType + = Context.getCanonicalType(InBaseSpecs[inIdx]->getType()); + if (KnownBaseTypes[NewBaseType]) { + // C++ [class.mi]p3: + // A class shall not be specified as a direct base class of a + // derived class more than once. + Diag(InBaseSpecs[inIdx]->getSourceRange().getBegin(), + diag::err_duplicate_base_class, + KnownBaseTypes[NewBaseType]->getType().getAsString(), + InBaseSpecs[inIdx]->getSourceRange()); + } else { + // Okay, add this new base class. + KnownBaseTypes[NewBaseType] = InBaseSpecs[inIdx]; + StoredBaseSpecs[outIdx++] = InBaseSpecs[inIdx]; + } + } - // FIXME: Attach base class to the record. + // Attach the remaining base class specifiers to the derived class. + CXXRecordDecl *Decl = (CXXRecordDecl*)ClassDecl; + Decl->setBases(StoredBaseSpecs, outIdx); } //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index cafdf8794a..19bc13a146 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -664,7 +664,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) // Within each iteration of the loop, we check the qualifiers to // determine if this still looks like a qualification // conversion. Then, if all is well, we unwrap one more level of - // pointers (FIXME: or pointers-to-members) and do it all again + // pointers or pointers-to-members and do it all again // until there are no more pointers or pointers-to-members left to // unwrap. UnwrappedAnyPointer = true; @@ -839,7 +839,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, // Within each iteration of the loop, we check the qualifiers to // determine if this still looks like a qualification // conversion. Then, if all is well, we unwrap one more level of - // pointers (FIXME: or pointers-to-members) and do it all again + // pointers or pointers-to-members and do it all again // until there are no more pointers or pointers-to-members left // to unwrap. This essentially mimics what // IsQualificationConversion does, but here we're checking for a |