Enhance testing of overriding exception specs for inaccessible base exceptions.

llvm-svn: 76317
This commit is contained in:
Sebastian Redl 2009-07-18 14:32:15 +00:00
parent 0ef680bcbd
commit e644e19671
4 changed files with 61 additions and 37 deletions

View File

@ -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,

View File

@ -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<CXXMethodDecl>(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;
}

View File

@ -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;

View File

@ -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}}
};