Implement checking for base class access. Right now it's overly conservative but that will change. (Also, protected isn't implemented right now).

llvm-svn: 67827
This commit is contained in:
Anders Carlsson 2009-03-27 06:03:27 +00:00
parent 0b08ba44a1
commit 733d77f1b4
3 changed files with 123 additions and 0 deletions

View File

@ -1297,6 +1297,13 @@ def err_memptr_conv_via_virtual : Error<
"conversion from pointer to member of class %0 to pointer to member "
"of class %1 via virtual base %2 is not allowed">;
// C++ access control
def err_conv_to_inaccessible_base : Error<
"conversion from %0 to inaccessible base class %1">;
def note_inheritance_specifier_here : Note<
"'%0' inheritance specifier here">;
def note_inheritance_implicitly_private_here : Note<
"inheritance is implicitly 'private'">;
// C++ member name lookup
def err_ambiguous_member_multiple_subobjects : Error<

View File

@ -11,7 +11,9 @@
//
//===----------------------------------------------------------------------===//
#include "SemaInherit.h"
#include "Sema.h"
#include "clang/AST/ASTContext.h"
using namespace clang;
/// SetMemberAccessSpecifier - Set the access specifier of a member.
@ -45,5 +47,68 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
/// and report an error if it can't. [class.access.base]
bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
BasePaths& Paths, SourceLocation AccessLoc) {
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");
const CXXBaseSpecifier *InacessibleBase = 0;
for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
Path != PathsEnd; ++Path) {
bool FoundInaccessibleBase = false;
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");
case AS_public:
// Nothing to do.
break;
case AS_private:
// FIXME: Check if the current function is a member or friend.
FoundInaccessibleBase = true;
break;
case AS_protected:
// FIXME: Implement
break;
}
if (FoundInaccessibleBase) {
InacessibleBase = Base;
break;
}
}
if (!FoundInaccessibleBase) {
// We found a path to the base, our work here is done.
InacessibleBase = 0;
break;
}
}
if (InacessibleBase) {
Diag(AccessLoc, diag::err_conv_to_inaccessible_base)
<< Derived << Base;
AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten();
// If there's no written access specifier, then the inheritance specifier
// is implicitly private.
if (AS == AS_none)
Diag(InacessibleBase->getSourceRange().getBegin(),
diag::note_inheritance_implicitly_private_here);
else
Diag(InacessibleBase->getSourceRange().getBegin(),
diag::note_inheritance_specifier_here) << AS;
return true;
}
return false;
}

View File

@ -0,0 +1,51 @@
// RUN: clang-cc -fsyntax-only -verify %s
namespace T1 {
class A { };
class B : private A { }; // expected-note {{'private' inheritance specifier here}}
void f(B* b) {
A *a = b; // expected-error{{conversion from 'class T1::B' to inaccessible base class 'class T1::A'}} \
expected-error{{incompatible type initializing 'class T1::B *', expected 'class T1::A *'}}
}
}
namespace T2 {
class A { };
class B : A { }; // expected-note {{inheritance is implicitly 'private'}}
void f(B* b) {
A *a = b; // expected-error {{conversion from 'class T2::B' to inaccessible base class 'class T2::A'}} \
expected-error {{incompatible type initializing 'class T2::B *', expected 'class T2::A *'}}
}
}
namespace T3 {
class A { };
class B : public A { };
void f(B* b) {
A *a = b;
}
}
namespace T4 {
class A {};
class B : private virtual A {};
class C : public virtual A {};
class D : public B, public C {};
void f(D *d) {
// This takes the D->C->B->A path.
A *a = d;
}
}