forked from OSchip/llvm-project
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:
parent
0b08ba44a1
commit
733d77f1b4
|
@ -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<
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue