diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.h | 10 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 75 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 4 |
3 files changed, 72 insertions, 17 deletions
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 |