diff options
| author | Nathan Sidwell <nathan@acm.org> | 2015-01-19 01:44:02 +0000 |
|---|---|---|
| committer | Nathan Sidwell <nathan@acm.org> | 2015-01-19 01:44:02 +0000 |
| commit | 44b21749b9d60e7212bee632dd11e4df1b19dfd6 (patch) | |
| tree | 184ed42804c98fdfb0d2e4454e3a5afa2d2deba3 /clang/lib | |
| parent | a3306ca6266488874e4f9f6725a9a5782ef55ec7 (diff) | |
| download | bcm5719-llvm-44b21749b9d60e7212bee632dd11e4df1b19dfd6.tar.gz bcm5719-llvm-44b21749b9d60e7212bee632dd11e4df1b19dfd6.zip | |
PR6037
Warn on inaccessible direct base
llvm-svn: 226423
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 61 |
1 files changed, 58 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 57ace2b802b..5fb10f6da4a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1545,6 +1545,31 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, return true; } +/// Use small set to collect indirect bases. As this is only used +/// locally, there's no need to abstract the small size parameter. +typedef llvm::SmallPtrSet<QualType, 4> IndirectBaseSet; + +/// \brief Recursively add the bases of Type. Don't add Type itself. +static void +NoteIndirectBases(ASTContext &Context, IndirectBaseSet &Set, + const QualType &Type) +{ + // Even though the incoming type is a base, it might not be + // a class -- it could be a template parm, for instance. + if (auto Rec = Type->getAs<RecordType>()) { + auto Decl = Rec->getAsCXXRecordDecl(); + + // Iterate over its bases. + for (const auto &BaseSpec : Decl->bases()) { + QualType Base = Context.getCanonicalType(BaseSpec.getType()) + .getUnqualifiedType(); + if (Set.insert(Base).second) + // If we've not already seen it, recurse. + NoteIndirectBases(Context, Set, Base); + } + } +} + /// \brief Performs the actual work of attaching the given base class /// specifiers to a C++ class. bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, @@ -1558,6 +1583,10 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, // class. std::map<QualType, CXXBaseSpecifier*, QualTypeOrdering> KnownBaseTypes; + // Used to track indirect bases so we can see if a direct base is + // ambiguous. + IndirectBaseSet IndirectBaseTypes; + // Copy non-redundant base specifiers into permanent storage. unsigned NumGoodBases = 0; bool Invalid = false; @@ -1585,6 +1614,11 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, // Okay, add this new base class. KnownBase = Bases[idx]; Bases[NumGoodBases++] = Bases[idx]; + + // Note this base's direct & indirect bases, if there could be ambiguity. + if (NumBases > 1) + NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType); + if (const RecordType *Record = NewBaseType->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); if (Class->isInterface() && @@ -1605,11 +1639,32 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, // Attach the remaining base class specifiers to the derived class. Class->setBases(Bases, NumGoodBases); + + for (unsigned idx = 0; idx < NumGoodBases; ++idx) { + // Check whether this direct base is inaccessible due to ambiguity. + QualType BaseType = Bases[idx]->getType(); + CanQualType CanonicalBase = Context.getCanonicalType(BaseType) + .getUnqualifiedType(); + + if (IndirectBaseTypes.count(CanonicalBase)) { + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/true); + bool found + = Class->isDerivedFrom(CanonicalBase->getAsCXXRecordDecl(), Paths); + assert(found); + + if (Paths.isAmbiguous(CanonicalBase)) + Diag(Bases[idx]->getLocStart (), diag::warn_inaccessible_base_class) + << BaseType << getAmbiguousPathsDisplayString(Paths) + << Bases[idx]->getSourceRange(); + else + assert(Bases[idx]->isVirtual()); + } - // Delete the remaining (good) base class specifiers, since their - // data has been copied into the CXXRecordDecl. - for (unsigned idx = 0; idx < NumGoodBases; ++idx) + // Delete the base class specifier, since its data has been copied + // into the CXXRecordDecl. Context.Deallocate(Bases[idx]); + } return Invalid; } |

