diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index f17b77baaa7b..82a8a087d9f2 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1989,17 +1989,21 @@ public: //===--------------------------------------------------------------------===// // C++ Access Control // - + bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, NamedDecl *PrevMemberDecl, AccessSpecifier LexicalAS); - - bool CheckBaseClassAccess(QualType Derived, QualType Base, + + const CXXBaseSpecifier *FindInaccessibleBase(QualType Derived, QualType Base, + BasePaths &Paths, + bool NoPrivileges = false); + + bool CheckBaseClassAccess(QualType Derived, QualType Base, unsigned InaccessibleBaseID, BasePaths& Paths, SourceLocation AccessLoc, DeclarationName Name); - - + + enum AbstractDiagSelID { AbstractNone = -1, AbstractReturnType, diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index bae69ac6dc74..31d8a3f5ab07 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -43,36 +43,34 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, return false; } -/// CheckBaseClassAccess - Check that a derived class can access its base class -/// and report an error if it can't. [class.access.base] -bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, - unsigned InaccessibleBaseID, - BasePaths& Paths, SourceLocation AccessLoc, - DeclarationName Name) { +/// Find a class on the derivation path between Derived and Base that is +/// inaccessible. If @p NoPrivileges is true, special access rights (members +/// and friends) are not considered. +const CXXBaseSpecifier *Sema::FindInaccessibleBase( + QualType Derived, QualType Base, BasePaths &Paths, bool NoPrivileges) +{ Base = Context.getCanonicalType(Base).getUnqualifiedType(); assert(!Paths.isAmbiguous(Base) && "Can't check base class access if set of paths is ambiguous"); assert(Paths.isRecordingPaths() && "Can't check base class access without recorded paths"); - - if (!getLangOptions().AccessControl) - return false; - - const CXXBaseSpecifier *InacessibleBase = 0; - const CXXRecordDecl* CurrentClassDecl = 0; + + const CXXBaseSpecifier *InaccessibleBase = 0; + + const CXXRecordDecl *CurrentClassDecl = 0; if (CXXMethodDecl *MD = dyn_cast_or_null(getCurFunctionDecl())) CurrentClassDecl = MD->getParent(); - for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); + for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); Path != PathsEnd; ++Path) { - + bool FoundInaccessibleBase = false; - - for (BasePath::const_iterator Element = Path->begin(), + + for (BasePath::const_iterator Element = Path->begin(), ElementEnd = Path->end(); Element != ElementEnd; ++Element) { const CXXBaseSpecifier *Base = Element->Base; - + switch (Base->getAccessSpecifier()) { default: assert(0 && "invalid access specifier"); @@ -81,44 +79,59 @@ bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, break; case AS_private: // FIXME: Check if the current function/class is a friend. - if (CurrentClassDecl != Element->Class) + if (NoPrivileges || CurrentClassDecl != Element->Class) FoundInaccessibleBase = true; break; - case AS_protected: + case AS_protected: // FIXME: Implement break; } - + if (FoundInaccessibleBase) { - InacessibleBase = Base; + InaccessibleBase = Base; break; } } - + if (!FoundInaccessibleBase) { // We found a path to the base, our work here is done. - InacessibleBase = 0; - break; + return 0; } } - if (InacessibleBase) { + assert(InaccessibleBase && "no path found, but no inaccessible base"); + return InaccessibleBase; +} + +/// CheckBaseClassAccess - Check that a derived class can access its base class +/// and report an error if it can't. [class.access.base] +bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + BasePaths &Paths, SourceLocation AccessLoc, + DeclarationName Name) { + + if (!getLangOptions().AccessControl) + return false; + const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase( + Derived, Base, Paths); + + if (InaccessibleBase) { Diag(AccessLoc, InaccessibleBaseID) << Derived << Base << Name; - AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten(); - + AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten(); + // If there's no written access specifier, then the inheritance specifier // is implicitly private. if (AS == AS_none) - Diag(InacessibleBase->getSourceRange().getBegin(), + Diag(InaccessibleBase->getSourceRange().getBegin(), diag::note_inheritance_implicitly_private_here); else - Diag(InacessibleBase->getSourceRange().getBegin(), + Diag(InaccessibleBase->getSourceRange().getBegin(), diag::note_inheritance_specifier_here) << AS; return true; } - + return false; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 8195aba967a2..036ccc87392d 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1294,7 +1294,7 @@ bool Sema::CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID, bool SubIsClass = CanonicalSubT->isRecordType(); CanonicalSubT.setCVRQualifiers(0); - BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); bool Contained = false; @@ -1332,7 +1332,8 @@ bool Sema::CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID, if (Paths.isAmbiguous(CanonicalSuperT)) continue; - // FIXME: Check base access. Don't forget to enable path recording. + if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true)) + continue; Contained = true; break; diff --git a/clang/test/SemaCXX/exception-spec.cpp b/clang/test/SemaCXX/exception-spec.cpp index dd12f3032fb1..443cee98e86a 100644 --- a/clang/test/SemaCXX/exception-spec.cpp +++ b/clang/test/SemaCXX/exception-spec.cpp @@ -78,6 +78,10 @@ struct D : B1, B2 { }; +struct P : private A +{ +}; + struct Base { virtual void f1() throw(); @@ -94,6 +98,7 @@ struct Base virtual void g2() throw(int); // expected-note {{overridden virtual function is here}} virtual void g3() throw(A); // expected-note {{overridden virtual function is here}} virtual void g4() throw(B1); // expected-note {{overridden virtual function is here}} + virtual void g5() throw(A); // expected-note {{overridden virtual function is here}} }; struct Derived : Base { @@ -111,4 +116,5 @@ struct Derived : Base virtual void g2(); // expected-error {{exception specification of overriding function is more lax}} virtual void g3() throw(D); // expected-error {{exception specification of overriding function is more lax}} virtual void g4() throw(A); // expected-error {{exception specification of overriding function is more lax}} + virtual void g5() throw(P); // expected-error {{exception specification of overriding function is more lax}} };