PR6037
Warn on inaccessible direct base
llvm-svn: 226423
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 57ace2b..5fb10f6 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1545,6 +1545,31 @@
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 @@
// 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 @@
// 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 @@
// 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();
- // Delete the remaining (good) base class specifiers, since their
- // data has been copied into the CXXRecordDecl.
- for (unsigned idx = 0; idx < NumGoodBases; ++idx)
+ 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 base class specifier, since its data has been copied
+ // into the CXXRecordDecl.
Context.Deallocate(Bases[idx]);
+ }
return Invalid;
}