[cfe-commits] r95775 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ lib/Sema/ test/CXX/class.access/ test/CXX/class.access/class.access.base/ test/CXX/class/class.local/ test/CXX/conv/conv.mem/ test/SemaCXX/
John McCall
rjmccall at apple.com
Wed Feb 10 01:31:13 PST 2010
Author: rjmccall
Date: Wed Feb 10 03:31:12 2010
New Revision: 95775
URL: http://llvm.org/viewvc/llvm-project?rev=95775&view=rev
Log:
Improve access control diagnostics. Perform access control on member-pointer
conversions. Fix an access-control bug where privileges were not considered
at intermediate points along the inheritance path. Prepare for friends.
Modified:
cfe/trunk/include/clang/AST/CXXInheritance.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/Lookup.h
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaAccess.cpp
cfe/trunk/lib/Sema/SemaCXXCast.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp
cfe/trunk/test/CXX/class.access/p4.cpp
cfe/trunk/test/CXX/class.access/p6.cpp
cfe/trunk/test/CXX/class/class.local/p2.cpp
cfe/trunk/test/CXX/conv/conv.mem/p4.cpp
cfe/trunk/test/SemaCXX/access-base-class.cpp
cfe/trunk/test/SemaCXX/access-control-check.cpp
cfe/trunk/test/SemaCXX/conditional-expr.cpp
cfe/trunk/test/SemaCXX/static-cast.cpp
cfe/trunk/test/SemaCXX/virtual-override.cpp
Modified: cfe/trunk/include/clang/AST/CXXInheritance.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CXXInheritance.h?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/CXXInheritance.h (original)
+++ cfe/trunk/include/clang/AST/CXXInheritance.h Wed Feb 10 03:31:12 2010
@@ -161,7 +161,8 @@
void ComputeDeclsFound();
public:
- typedef std::list<CXXBasePath>::const_iterator paths_iterator;
+ typedef std::list<CXXBasePath>::iterator paths_iterator;
+ typedef std::list<CXXBasePath>::const_iterator const_paths_iterator;
typedef NamedDecl **decl_iterator;
/// BasePaths - Construct a new BasePaths structure to record the
@@ -175,8 +176,10 @@
~CXXBasePaths() { delete [] DeclsFound; }
- paths_iterator begin() const { return Paths.begin(); }
- paths_iterator end() const { return Paths.end(); }
+ paths_iterator begin() { return Paths.begin(); }
+ paths_iterator end() { return Paths.end(); }
+ const_paths_iterator begin() const { return Paths.begin(); }
+ const_paths_iterator end() const { return Paths.end(); }
CXXBasePath& front() { return Paths.front(); }
const CXXBasePath& front() const { return Paths.front(); }
@@ -206,7 +209,7 @@
const RecordType* getDetectedVirtual() const {
return DetectedVirtual;
}
-
+
/// \brief Retrieve the type from which this base-paths search
/// began
CXXRecordDecl *getOrigin() const { return Origin; }
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Feb 10 03:31:12 2010
@@ -417,17 +417,20 @@
// C++ access checking
def err_class_redeclared_with_different_access : Error<
"%0 redeclared with '%1' access">;
+def err_access_private : Error<"%0 is a private member of %1">;
+def err_access_ctor_private : Error<"calling a private constructor of %0">;
+// Say something about the context for these?
+def err_access_protected : Error<"%0 is a protected member of %1">;
+def err_access_ctor_protected : Error<"calling a protected constructor of %0">;
def note_previous_access_declaration : Note<
"previously declared '%1' here">;
def err_access_outside_class : Error<
"access to %select{private|protected}0 member outside any class context">;
-def note_access_natural : Note<"declared %select{private|protected}0 here">;
+def note_access_natural : Note<
+ "%select{|implicitly }1declared %select{private|protected}0 here">;
def note_access_constrained_by_path : Note<
- "access to decl constrained by %select{private|protected}0 inheritance">;
-def err_access_protected : Error<
- "access to protected member of %0 from %1, which is not a subclass">;
-def err_access_private : Error<
- "access to private member of %0 from %1">;
+ "constrained by %select{|implicitly }1%select{private|protected}0"
+ " inheritance here">;
// C++ name lookup
def err_incomplete_nested_name_spec : Error<
@@ -509,9 +512,8 @@
"overridden virtual function is here">;
def err_covariant_return_inaccessible_base : Error<
- "return type of virtual function %2 is not covariant with the return type "
- "of the function it overrides "
- "(conversion from %0 to inaccessible base class %1)">, NoSFINAE;
+ "invalid covariant return for virtual function: %1 is a "
+ "%select{private|protected}2 base class of %0">, NoSFINAE;
def err_covariant_return_ambiguous_derived_to_base_conv : Error<
"return type of virtual function %3 is not covariant with the return type of "
"the function it overrides (ambiguous conversion from derived class "
@@ -1958,7 +1960,9 @@
def err_static_downcast_via_virtual : Error<
"cannot cast %0 to %1 via virtual base %2">;
def err_downcast_from_inaccessible_base : Error<
- "cannot cast %1 to %0 due to inaccessible conversion path">;
+ "cannot cast %select{private|protected}2 base class %1 to %0">;
+def err_upcast_to_inaccessible_base : Error<
+ "cannot cast %0 to its %select{private|protected}2 base class %1">;
def err_bad_dynamic_cast_not_ref_or_ptr : Error<
"%0 is not a reference or pointer">;
def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">;
Modified: cfe/trunk/lib/Sema/Lookup.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Lookup.h?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Lookup.h (original)
+++ cfe/trunk/lib/Sema/Lookup.h Wed Feb 10 03:31:12 2010
@@ -503,7 +503,7 @@
if (isAmbiguous())
SemaRef.DiagnoseAmbiguousLookup(*this);
else if (isClassLookup() && SemaRef.getLangOptions().AccessControl)
- SemaRef.CheckAccess(*this);
+ SemaRef.CheckLookupAccess(*this);
}
void setAmbiguous(AmbiguityKind AK) {
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Feb 10 03:31:12 2010
@@ -96,6 +96,7 @@
class ObjCPropertyDecl;
class ObjCContainerDecl;
class FunctionProtoType;
+ class CXXBasePath;
class CXXBasePaths;
class CXXTemporary;
class LookupResult;
@@ -275,6 +276,77 @@
/// \brief All the tentative definitions encountered in the TU.
std::vector<VarDecl *> TentativeDefinitions;
+ /// An enum describing the kind of diagnostics to use when checking
+ /// access.
+ enum AccessDiagnosticsKind {
+ /// Suppress diagnostics.
+ ADK_quiet,
+
+ /// Use the normal diagnostics.
+ ADK_normal,
+
+ /// Use the diagnostics appropriate for checking a covariant
+ /// return type.
+ ADK_covariance
+ };
+
+ class AccessedEntity {
+ public:
+ enum Kind {
+ /// A member declaration found through lookup. The target is the
+ /// member.
+ Member,
+
+ /// A base-to-derived conversion. The target is the base class.
+ BaseToDerivedConversion,
+
+ /// A derived-to-base conversion. The target is the base class.
+ DerivedToBaseConversion
+ };
+
+ bool isMemberAccess() const { return K == Member; }
+
+ static AccessedEntity makeMember(CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ NamedDecl *Target) {
+ AccessedEntity E;
+ E.K = Member;
+ E.Access = Access;
+ E.Target = Target;
+ E.NamingClass = NamingClass;
+ return E;
+ }
+
+ static AccessedEntity makeBaseClass(bool BaseToDerived,
+ CXXRecordDecl *BaseClass,
+ CXXRecordDecl *DerivedClass,
+ AccessSpecifier Access) {
+ AccessedEntity E;
+ E.K = BaseToDerived ? BaseToDerivedConversion : DerivedToBaseConversion;
+ E.Access = Access;
+ E.Target = BaseClass;
+ E.NamingClass = DerivedClass;
+ return E;
+ }
+
+ Kind getKind() const { return Kind(K); }
+ AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
+
+ // These apply to member decls...
+ NamedDecl *getTargetDecl() const { return Target; }
+ CXXRecordDecl *getNamingClass() const { return NamingClass; }
+
+ // ...and these apply to hierarchy conversions.
+ CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
+ CXXRecordDecl *getDerivedClass() const { return NamingClass; }
+
+ private:
+ unsigned K : 2;
+ unsigned Access : 2;
+ NamedDecl *Target;
+ CXXRecordDecl *NamingClass;
+ };
+
struct DelayedDiagnostic {
enum DDKind { Deprecation, Access };
@@ -288,11 +360,7 @@
struct { NamedDecl *Decl; } DeprecationData;
/// Access control.
- struct {
- NamedDecl *Decl;
- AccessSpecifier Access;
- CXXRecordDecl *NamingClass;
- } AccessData;
+ AccessedEntity AccessData;
};
static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
@@ -306,16 +374,12 @@
}
static DelayedDiagnostic makeAccess(SourceLocation Loc,
- NamedDecl *Decl,
- AccessSpecifier AS,
- CXXRecordDecl *NamingClass) {
+ const AccessedEntity &Entity) {
DelayedDiagnostic DD;
DD.Kind = Access;
DD.Triggered = false;
DD.Loc = Loc;
- DD.AccessData.Decl = Decl;
- DD.AccessData.Access = AS;
- DD.AccessData.NamingClass = NamingClass;
+ DD.AccessData = Entity;
return DD;
}
@@ -2385,7 +2449,7 @@
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess = false);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
+ AccessDiagnosticsKind ADK,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name);
@@ -2412,38 +2476,43 @@
// C++ Access Control
//
+ enum AccessResult {
+ AR_accessible,
+ AR_inaccessible,
+ AR_dependent,
+ AR_delayed
+ };
+
bool SetMemberAccessSpecifier(NamedDecl *MemberDecl,
NamedDecl *PrevMemberDecl,
AccessSpecifier LexicalAS);
- const CXXBaseSpecifier *FindInaccessibleBase(QualType Derived, QualType Base,
- CXXBasePaths &Paths,
- bool NoPrivileges = false);
-
- bool CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
- NamedDecl *D,
- AccessSpecifier Access);
- bool CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
- NamedDecl *D,
- AccessSpecifier Access);
- bool CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D,
- AccessSpecifier Access);
- bool CheckDestructorAccess(SourceLocation Loc, const RecordType *Record);
- bool CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr,
- NamedDecl *D, AccessSpecifier Access);
- bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access);
- void CheckAccess(const LookupResult &R);
+ AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckConstructorAccess(SourceLocation Loc,
+ CXXConstructorDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckDestructorAccess(SourceLocation Loc,
+ const RecordType *Record);
+ AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
+ Expr *ObjectExpr,
+ NamedDecl *D,
+ AccessSpecifier Access);
+ AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
+ bool IsBaseToDerived,
+ QualType Base, QualType Derived,
+ const CXXBasePath &Path,
+ bool ForceCheck = false,
+ bool ForceUnprivileged = false,
+ AccessDiagnosticsKind ADK = ADK_normal);
+
+ void CheckLookupAccess(const LookupResult &R);
void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx);
- bool CheckEffectiveAccess(DeclContext *EffectiveContext,
- const LookupResult &R, NamedDecl *D,
- AccessSpecifier Access);
-
- bool CheckBaseClassAccess(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
- CXXBasePaths& Paths, SourceLocation AccessLoc,
- DeclarationName Name);
-
enum AbstractDiagSelID {
AbstractNone = -1,
Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Wed Feb 10 03:31:12 2010
@@ -49,326 +49,500 @@
return false;
}
-/// 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, CXXBasePaths &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");
-
-
- const CXXBaseSpecifier *InaccessibleBase = 0;
-
- const CXXRecordDecl *CurrentClassDecl = 0;
- if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
- CurrentClassDecl = MD->getParent();
-
- for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
- Path != PathsEnd; ++Path) {
-
- bool FoundInaccessibleBase = false;
-
- for (CXXBasePath::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/class is a friend.
- if (NoPrivileges || CurrentClassDecl != Element->Class)
- FoundInaccessibleBase = true;
- break;
- case AS_protected:
- // FIXME: Implement
- break;
- }
+namespace {
+struct EffectiveContext {
+ EffectiveContext() : Record(0), Function(0) {}
+
+ explicit EffectiveContext(DeclContext *DC) {
+ if (isa<FunctionDecl>(DC)) {
+ Function = cast<FunctionDecl>(DC);
+ DC = Function->getDeclContext();
+ } else
+ Function = 0;
+
+ if (isa<CXXRecordDecl>(DC))
+ Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ else
+ Record = 0;
+ }
+
+ bool isClass(const CXXRecordDecl *R) const {
+ return R->getCanonicalDecl() == Record;
+ }
+
+ CXXRecordDecl *Record;
+ FunctionDecl *Function;
+};
+}
+
+static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+ while (DeclaringClass->isAnonymousStructOrUnion())
+ DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
+ return DeclaringClass;
+}
+
+static Sema::AccessResult GetFriendKind(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Class) {
+ if (EC.isClass(Class))
+ return Sema::AR_accessible;
+
+ // FIXME: implement
+ return Sema::AR_inaccessible;
+}
- if (FoundInaccessibleBase) {
- InaccessibleBase = Base;
- break;
+/// Finds the best path from the naming class to the declaring class,
+/// taking friend declarations into account.
+///
+/// \return null if friendship is dependent
+static CXXBasePath *FindBestPath(Sema &S,
+ const EffectiveContext &EC,
+ CXXRecordDecl *Derived,
+ CXXRecordDecl *Base,
+ CXXBasePaths &Paths) {
+ // Derive the paths to the desired base.
+ bool isDerived = Derived->isDerivedFrom(Base, Paths);
+ assert(isDerived && "derived class not actually derived from base");
+ (void) isDerived;
+
+ CXXBasePath *BestPath = 0;
+
+ // Derive the friend-modified access along each path.
+ for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
+ PI != PE; ++PI) {
+
+ // Walk through the path backwards.
+ AccessSpecifier PathAccess = AS_public;
+ CXXBasePath::iterator I = PI->end(), E = PI->begin();
+ while (I != E) {
+ --I;
+
+ AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
+ if (BaseAccess != AS_public) {
+ switch (GetFriendKind(S, EC, I->Class)) {
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_accessible: BaseAccess = AS_public; break;
+ case Sema::AR_dependent: return 0;
+ case Sema::AR_delayed:
+ llvm_unreachable("friend resolution is never delayed"); break;
+ }
}
+
+ PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
}
- if (!FoundInaccessibleBase) {
- // We found a path to the base, our work here is done.
- return 0;
+ // Note that we modify the path's Access field to the
+ // friend-modified access.
+ if (BestPath == 0 || PathAccess < BestPath->Access) {
+ BestPath = &*PI;
+ BestPath->Access = PathAccess;
}
}
- assert(InaccessibleBase && "no path found, but no inaccessible base");
- return InaccessibleBase;
+ return BestPath;
}
-/// 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,
- CXXBasePaths &Paths, SourceLocation AccessLoc,
- DeclarationName Name) {
+/// Diagnose the path which caused the given declaration or base class
+/// to become inaccessible.
+static void DiagnoseAccessPath(Sema &S,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ CXXRecordDecl *DeclaringClass,
+ NamedDecl *D, AccessSpecifier Access) {
+ // Easy case: the decl's natural access determined its path access.
+ // We have to check against AS_private here in case Access is AS_none,
+ // indicating a non-public member of a private base class.
+ //
+ // DependentFriend should be impossible here.
+ if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
+ switch (GetFriendKind(S, EC, DeclaringClass)) {
+ case Sema::AR_inaccessible: {
+ S.Diag(D->getLocation(), diag::note_access_natural)
+ << (unsigned) (Access == AS_protected)
+ << /*FIXME: not implicitly*/ 0;
+ return;
+ }
- if (!getLangOptions().AccessControl)
- return false;
- const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase(
- Derived, Base, Paths);
-
- if (InaccessibleBase) {
- Diag(AccessLoc, InaccessibleBaseID)
- << Derived << Base << Name;
-
- AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
-
- // If there's no written access specifier, then the inheritance specifier
- // is implicitly private.
- if (AS == AS_none)
- Diag(InaccessibleBase->getSourceRange().getBegin(),
- diag::note_inheritance_implicitly_private_here);
- else
- Diag(InaccessibleBase->getSourceRange().getBegin(),
- diag::note_inheritance_specifier_here) << AS;
+ case Sema::AR_accessible: break;
- return true;
+ case Sema::AR_dependent:
+ case Sema::AR_delayed:
+ llvm_unreachable("dependent/delayed not allowed");
+ return;
+ }
}
- return false;
+ CXXBasePaths Paths;
+ CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths);
+
+ CXXBasePath::iterator I = Path.end(), E = Path.begin();
+ while (I != E) {
+ --I;
+
+ const CXXBaseSpecifier *BS = I->Base;
+ AccessSpecifier BaseAccess = BS->getAccessSpecifier();
+
+ // If this is public inheritance, or the derived class is a friend,
+ // skip this step.
+ if (BaseAccess == AS_public)
+ continue;
+
+ switch (GetFriendKind(S, EC, I->Class)) {
+ case Sema::AR_accessible: continue;
+ case Sema::AR_inaccessible: break;
+
+ case Sema::AR_dependent:
+ case Sema::AR_delayed:
+ llvm_unreachable("dependent friendship, should not be diagnosing");
+ }
+
+ // Check whether this base specifier is the tighest point
+ // constraining access. We have to check against AS_private for
+ // the same reasons as above.
+ if (BaseAccess == AS_private || BaseAccess >= Access) {
+
+ // We're constrained by inheritance, but we want to say
+ // "declared private here" if we're diagnosing a hierarchy
+ // conversion and this is the final step.
+ unsigned diagnostic;
+ if (D) diagnostic = diag::note_access_constrained_by_path;
+ else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
+ else diagnostic = diag::note_access_constrained_by_path;
+
+ S.Diag(BS->getSourceRange().getBegin(), diagnostic)
+ << BS->getSourceRange()
+ << (BaseAccess == AS_protected)
+ << (BS->getAccessSpecifierAsWritten() == AS_none);
+ return;
+ }
+ }
+
+ llvm_unreachable("access not apparently constrained by path");
}
-/// Diagnose the path which caused the given declaration to become
-/// inaccessible.
-static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D,
- AccessSpecifier Access) {
- // Easy case: the decl's natural access determined its path access.
- if (Access == D->getAccess() || D->getAccess() == AS_private) {
- S.Diag(D->getLocation(), diag::note_access_natural)
- << (unsigned) (Access == AS_protected);
- return;
+/// Diagnose an inaccessible class member.
+static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity) {
+ NamedDecl *D = Entity.getTargetDecl();
+ CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+
+ if (isa<CXXConstructorDecl>(D)) {
+ unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected
+ : diag::err_access_ctor_private);
+ S.Diag(Loc, DiagID)
+ << S.Context.getTypeDeclType(DeclaringClass);
+ } else {
+ unsigned DiagID = (Access == AS_protected ? diag::err_access_protected
+ : diag::err_access_private);
+ S.Diag(Loc, DiagID)
+ << D->getDeclName()
+ << S.Context.getTypeDeclType(DeclaringClass);
}
+ DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
+}
- // TODO: flesh this out
- S.Diag(D->getLocation(), diag::note_access_constrained_by_path)
- << (unsigned) (Access == AS_protected);
+/// Diagnose an inaccessible hierarchy conversion.
+static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ if (ADK == Sema::ADK_covariance) {
+ S.Diag(Loc, diag::err_covariant_return_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) {
+ S.Diag(Loc, diag::err_downcast_from_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ } else {
+ S.Diag(Loc, diag::err_upcast_to_inaccessible_base)
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass())
+ << (Access == AS_protected);
+ }
+ DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
+ Entity.getBaseClass(), 0, Access);
}
-/// Checks access to the given declaration in the current context.
-///
-/// \param R the means via which the access was made; must have a naming
-/// class set
-/// \param D the declaration accessed
-/// \param Access the best access along any inheritance path from the
-/// naming class to the declaration. AS_none means the path is impossible
-bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D,
- AccessSpecifier Access) {
- assert(R.getNamingClass() && "performing access check without naming class");
+static void DiagnoseBadAccess(Sema &S,
+ SourceLocation Loc,
+ const EffectiveContext &EC,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ if (Entity.isMemberAccess())
+ DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
+ else
+ DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK);
+}
- // If the access path is public, it's accessible everywhere.
- if (Access == AS_public)
- return false;
- // If we're currently parsing a top-level declaration, delay
- // diagnostics. This is the only case where parsing a declaration
- // can actually change our effective context for the purposes of
- // access control.
- if (CurContext->isFileContext() && ParsingDeclDepth) {
- DelayedDiagnostics.push_back(
- DelayedDiagnostic::makeAccess(R.getNameLoc(), D, Access,
- R.getNamingClass()));
- return false;
- }
-
- return CheckEffectiveAccess(CurContext, R, D, Access);
-}
-
-/// Checks access from the given effective context.
-bool Sema::CheckEffectiveAccess(DeclContext *EffectiveContext,
- const LookupResult &R,
- NamedDecl *D, AccessSpecifier Access) {
- DeclContext *DC = EffectiveContext;
- while (isa<CXXRecordDecl>(DC) &&
- cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
- DC = DC->getParent();
-
- CXXRecordDecl *CurRecord;
- if (isa<CXXRecordDecl>(DC))
- CurRecord = cast<CXXRecordDecl>(DC);
- else if (isa<CXXMethodDecl>(DC))
- CurRecord = cast<CXXMethodDecl>(DC)->getParent();
- else {
- Diag(R.getNameLoc(), diag::err_access_outside_class)
- << (Access == AS_protected);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
+/// Try to elevate access using friend declarations. This is
+/// potentially quite expensive.
+static void TryElevateAccess(Sema &S,
+ const EffectiveContext &EC,
+ const Sema::AccessedEntity &Entity,
+ AccessSpecifier &Access) {
+ CXXRecordDecl *DeclaringClass;
+ if (Entity.isMemberAccess()) {
+ DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
+ } else {
+ DeclaringClass = Entity.getBaseClass();
+ }
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
+
+ // Adjust the declaration of the referred entity.
+ AccessSpecifier DeclAccess = AS_none;
+ if (Entity.isMemberAccess()) {
+ NamedDecl *Target = Entity.getTargetDecl();
+
+ DeclAccess = Target->getAccess();
+ if (DeclAccess != AS_public) {
+ switch (GetFriendKind(S, EC, DeclaringClass)) {
+ case Sema::AR_accessible: DeclAccess = AS_public; break;
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
+ case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
+ }
+ }
+
+ if (DeclaringClass == NamingClass) {
+ Access = DeclAccess;
+ return;
+ }
+ }
+
+ assert(DeclaringClass != NamingClass);
+
+ // Append the declaration's access if applicable.
+ CXXBasePaths Paths;
+ CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
+ DeclaringClass, Paths);
+ if (!Path) {
+ // FIXME: delay dependent friendship
+ return;
}
- CXXRecordDecl *NamingClass = R.getNamingClass();
+ // Grab the access along the best path.
+ AccessSpecifier NewAccess = Path->Access;
+ if (Entity.isMemberAccess())
+ NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess);
+
+ assert(NewAccess <= Access && "access along best path worse than direct?");
+ Access = NewAccess;
+}
+
+/// Checks access to an entity from the given effective context.
+static Sema::AccessResult CheckEffectiveAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ Sema::AccessedEntity const &Entity,
+ Sema::AccessDiagnosticsKind ADK) {
+ AccessSpecifier Access = Entity.getAccess();
+ assert(Access != AS_public);
+
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
while (NamingClass->isAnonymousStructOrUnion())
// This should be guaranteed by the fact that the decl has
// non-public access. If not, we should make it guaranteed!
NamingClass = cast<CXXRecordDecl>(NamingClass);
+ if (!EC.Record) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+
+ if (ADK != Sema::ADK_quiet)
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ return Sema::AR_inaccessible;
+ }
+
// White-list accesses from within the declaring class.
- if (Access != AS_none &&
- CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl())
- return false;
+ if (Access != AS_none && EC.isClass(NamingClass))
+ return Sema::AR_accessible;
+
+ // If the access is worse than 'protected', try to promote to it using
+ // friend declarations.
+ bool TriedElevation = false;
+ if (Access != AS_protected) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+ TriedElevation = true;
+ }
// Protected access.
if (Access == AS_protected) {
// FIXME: implement [class.protected]p1
- if (CurRecord->isDerivedFrom(NamingClass))
- return false;
+ if (EC.Record->isDerivedFrom(NamingClass))
+ return Sema::AR_accessible;
- // FIXME: dependent classes
+ // FIXME: delay dependent classes
}
- // FIXME: friends
-
- // Okay, it's a bad access, reject it.
+ // We're about to reject; one last chance to promote access.
+ if (!TriedElevation) {
+ TryElevateAccess(S, EC, Entity, Access);
+ if (Access == AS_public) return Sema::AR_accessible;
+ }
+
+ // Okay, that's it, reject it.
+ if (ADK != Sema::ADK_quiet)
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ return Sema::AR_inaccessible;
+}
-
- CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
+ const Sema::AccessedEntity &Entity,
+ Sema::AccessDiagnosticsKind ADK
+ = Sema::ADK_normal) {
+ // If the access path is public, it's accessible everywhere.
+ if (Entity.getAccess() == AS_public)
+ return Sema::AR_accessible;
- if (Access == AS_protected) {
- Diag(R.getNameLoc(), diag::err_access_protected)
- << Context.getTypeDeclType(DeclaringClass)
- << Context.getTypeDeclType(CurRecord);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
+ // If we're currently parsing a top-level declaration, delay
+ // diagnostics. This is the only case where parsing a declaration
+ // can actually change our effective context for the purposes of
+ // access control.
+ if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
+ assert(ADK == Sema::ADK_normal && "delaying abnormal access check");
+ S.DelayedDiagnostics.push_back(
+ Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
+ return Sema::AR_delayed;
}
- assert(Access == AS_private || Access == AS_none);
- Diag(R.getNameLoc(), diag::err_access_private)
- << Context.getTypeDeclType(DeclaringClass)
- << Context.getTypeDeclType(CurRecord);
- DiagnoseAccessPath(*this, R, D, Access);
- return true;
+ return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
+ Loc, Entity, ADK);
}
void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
- NamedDecl *D = DD.AccessData.Decl;
-
- // Fake up a lookup result.
- LookupResult R(*this, D->getDeclName(), DD.Loc, LookupOrdinaryName);
- R.suppressDiagnostics();
- R.setNamingClass(DD.AccessData.NamingClass);
-
// Pretend we did this from the context of the newly-parsed
// declaration.
- DeclContext *EffectiveContext = Ctx->getDeclContext();
+ EffectiveContext EC(Ctx->getDeclContext());
- if (CheckEffectiveAccess(EffectiveContext, R, D, DD.AccessData.Access))
+ if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
DD.Triggered = true;
}
-bool Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
- NamedDecl *D, AccessSpecifier Access) {
+Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access) {
if (!getLangOptions().AccessControl || !E->getNamingClass())
- return false;
-
- // Fake up a lookup result.
- LookupResult R(*this, E->getName(), E->getNameLoc(), LookupOrdinaryName);
- R.suppressDiagnostics();
-
- R.setNamingClass(E->getNamingClass());
- R.addDecl(D, Access);
+ return AR_accessible;
- // FIXME: protected check (triggers for member-address expressions)
-
- return CheckAccess(R, D, Access);
+ return CheckAccess(*this, E->getNameLoc(),
+ AccessedEntity::makeMember(E->getNamingClass(), Access, D));
}
/// Perform access-control checking on a previously-unresolved member
/// access which has now been resolved to a member.
-bool Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
- NamedDecl *D, AccessSpecifier Access) {
+Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+ NamedDecl *D,
+ AccessSpecifier Access) {
if (!getLangOptions().AccessControl)
- return false;
-
- // Fake up a lookup result.
- LookupResult R(*this, E->getMemberName(), E->getMemberLoc(),
- LookupOrdinaryName);
- R.suppressDiagnostics();
-
- R.setNamingClass(E->getNamingClass());
- R.addDecl(D, Access);
+ return AR_accessible;
- if (CheckAccess(R, D, Access))
- return true;
-
- // FIXME: protected check
-
- return false;
+ return CheckAccess(*this, E->getMemberLoc(),
+ AccessedEntity::makeMember(E->getNamingClass(), Access, D));
}
-bool Sema::CheckDestructorAccess(SourceLocation Loc, const RecordType *RT) {
+Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
+ const RecordType *RT) {
if (!getLangOptions().AccessControl)
- return false;
+ return AR_accessible;
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
AccessSpecifier Access = Dtor->getAccess();
if (Access == AS_public)
- return false;
+ return AR_accessible;
- LookupResult R(*this, Dtor->getDeclName(), Loc, LookupOrdinaryName);
- R.suppressDiagnostics();
-
- R.setNamingClass(NamingClass);
- return CheckAccess(R, Dtor, Access);
-
- // FIXME: protected check
+ return CheckAccess(*this, Loc,
+ AccessedEntity::makeMember(NamingClass, Access, Dtor));
}
/// Checks access to a constructor.
-bool Sema::CheckConstructorAccess(SourceLocation UseLoc,
+Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
AccessSpecifier Access) {
if (!getLangOptions().AccessControl)
- return false;
-
- CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Constructor->getParent());
+ return AR_accessible;
- LookupResult R(*this, Constructor->getDeclName(), UseLoc, LookupOrdinaryName);
- R.suppressDiagnostics();
-
- R.setNamingClass(NamingClass);
- return CheckAccess(R, Constructor, Access);
+ CXXRecordDecl *NamingClass = Constructor->getParent();
+ return CheckAccess(*this, UseLoc,
+ AccessedEntity::makeMember(NamingClass, Access, Constructor));
}
/// Checks access to an overloaded member operator, including
/// conversion operators.
-bool Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
- Expr *ObjectExpr,
- NamedDecl *MemberOperator,
- AccessSpecifier Access) {
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+ Expr *ObjectExpr,
+ NamedDecl *MemberOperator,
+ AccessSpecifier Access) {
if (!getLangOptions().AccessControl)
- return false;
+ return AR_accessible;
const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
assert(RT && "found member operator but object expr not of record type");
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
- LookupResult R(*this, DeclarationName(), OpLoc, LookupOrdinaryName);
- R.suppressDiagnostics();
-
- R.setNamingClass(NamingClass);
- if (CheckAccess(R, MemberOperator, Access))
- return true;
-
- // FIXME: protected check
+ return CheckAccess(*this, OpLoc,
+ AccessedEntity::makeMember(NamingClass, Access, MemberOperator));
+}
- return false;
+/// Checks access for a hierarchy conversion.
+///
+/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
+/// or a derived-to-base conversion (false)
+/// \param ForceCheck true if this check should be performed even if access
+/// control is disabled; some things rely on this for semantics
+/// \param ForceUnprivileged true if this check should proceed as if the
+/// context had no special privileges
+/// \param ADK controls the kind of diagnostics that are used
+Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
+ bool IsBaseToDerived,
+ QualType Base,
+ QualType Derived,
+ const CXXBasePath &Path,
+ bool ForceCheck,
+ bool ForceUnprivileged,
+ AccessDiagnosticsKind ADK) {
+ if (!ForceCheck && !getLangOptions().AccessControl)
+ return AR_accessible;
+
+ if (Path.Access == AS_public)
+ return AR_accessible;
+
+ // TODO: preserve the information about which types exactly were used.
+ CXXRecordDecl *BaseD, *DerivedD;
+ BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
+ DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
+ AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived,
+ BaseD, DerivedD,
+ Path.Access);
+
+ if (ForceUnprivileged)
+ return CheckEffectiveAccess(*this, EffectiveContext(),
+ AccessLoc, Entity, ADK);
+ return CheckAccess(*this, AccessLoc, Entity, ADK);
}
/// Checks access to all the declarations in the given result set.
-void Sema::CheckAccess(const LookupResult &R) {
+void Sema::CheckLookupAccess(const LookupResult &R) {
+ assert(getLangOptions().AccessControl
+ && "performing access check without access control");
+ assert(R.getNamingClass() && "performing access check without naming class");
+
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- CheckAccess(R, *I, I.getAccess());
+ if (I.getAccess() != AS_public)
+ CheckAccess(*this, R.getNameLoc(),
+ AccessedEntity::makeMember(R.getNamingClass(),
+ I.getAccess(), *I));
}
Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Wed Feb 10 03:31:12 2010
@@ -778,9 +778,10 @@
return TC_Failed;
}
- if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
- diag::err_downcast_from_inaccessible_base, Paths,
- OpRange.getBegin(), DeclarationName())) {
+ if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
+ /*IsBaseToDerived*/ true,
+ SrcType, DestType,
+ Paths.front())) {
msg = 0;
return TC_Failed;
}
@@ -844,9 +845,10 @@
return TC_Failed;
}
- if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
- diag::err_downcast_from_inaccessible_base, Paths,
- OpRange.getBegin(), DeclarationName())) {
+ if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
+ /*IsBaseToDerived*/ false,
+ DestType, SrcType,
+ Paths.front())) {
msg = 0;
return TC_Failed;
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Feb 10 03:31:12 2010
@@ -713,7 +713,7 @@
/// if there is an error.
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- unsigned InaccessibleBaseID,
+ AccessDiagnosticsKind ADK,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name) {
@@ -729,11 +729,20 @@
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (InaccessibleBaseID == 0)
+ if (ADK == ADK_quiet)
return false;
+
// Check that the base class can be accessed.
- return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
- Name);
+ switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false,
+ Base, Derived, Paths.front(),
+ /*force*/ false,
+ /*unprivileged*/ false,
+ ADK)) {
+ case AR_accessible: return false;
+ case AR_inaccessible: return true;
+ case AR_dependent: return false;
+ case AR_delayed: return false;
+ }
}
// We know that the derived-to-base conversion is ambiguous, and
@@ -764,8 +773,7 @@
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess) {
return CheckDerivedToBaseConversion(Derived, Base,
- IgnoreAccess ? 0 :
- diag::err_conv_to_inaccessible_base,
+ IgnoreAccess ? ADK_quiet : ADK_normal,
diag::err_ambiguous_derived_to_base_conv,
Loc, Range, DeclarationName());
}
@@ -5626,8 +5634,7 @@
}
// Check if we the conversion from derived to base is valid.
- if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
- diag::err_covariant_return_inaccessible_base,
+ if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance,
diag::err_covariant_return_ambiguous_derived_to_base_conv,
// FIXME: Should this point to the return type?
New->getLocation(), SourceRange(), New->getDeclName())) {
Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Wed Feb 10 03:31:12 2010
@@ -232,8 +232,22 @@
if (Paths.isAmbiguous(CanonicalSuperT))
continue;
- if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true))
- continue;
+ // Do this check from a context without privileges.
+ switch (CheckBaseClassAccess(SourceLocation(), false,
+ CanonicalSuperT, CanonicalSubT,
+ Paths.front(),
+ /*ForceCheck*/ true,
+ /*ForceUnprivileged*/ true,
+ ADK_quiet)) {
+ case AR_accessible: break;
+ case AR_inaccessible: continue;
+ case AR_dependent:
+ llvm_unreachable("access check dependent for unprivileged context");
+ break;
+ case AR_delayed:
+ llvm_unreachable("access check delayed in non-declaration");
+ break;
+ }
Contained = true;
break;
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Feb 10 03:31:12 2010
@@ -404,7 +404,7 @@
}
void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
- CXXBasePaths::paths_iterator I, E;
+ CXXBasePaths::const_paths_iterator I, E;
DeclContext::lookup_iterator DI, DE;
for (I = P.begin(), E = P.end(); I != E; ++I)
for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI)
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Feb 10 03:31:12 2010
@@ -1355,14 +1355,13 @@
/// CheckMemberPointerConversion - Check the member pointer conversion from the
/// expression From to the type ToType. This routine checks for ambiguous or
-/// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions
+/// virtual or inaccessible base-to-derived member pointer conversions
/// for which IsMemberPointerConversion has already returned true. It returns
/// true and produces a diagnostic if there was an error, or returns false
/// otherwise.
bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
bool IgnoreBaseAccess) {
- (void)IgnoreBaseAccess;
QualType FromType = From->getType();
const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
if (!FromPtrType) {
@@ -1385,7 +1384,7 @@
assert(FromClass->isRecordType() && "Pointer into non-class.");
assert(ToClass->isRecordType() && "Pointer into non-class.");
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/ true,
/*DetectVirtual=*/true);
bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
assert(DerivationOkay &&
@@ -1394,13 +1393,6 @@
if (Paths.isAmbiguous(Context.getCanonicalType(FromClass).
getUnqualifiedType())) {
- // Derivation is ambiguous. Redo the check to find the exact paths.
- Paths.clear();
- Paths.setRecordingPaths(true);
- bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths);
- assert(StillOkay && "Derivation changed due to quantum fluctuation.");
- (void)StillOkay;
-
std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv)
<< 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange();
@@ -1414,6 +1406,10 @@
return true;
}
+ if (!IgnoreBaseAccess)
+ CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true,
+ FromClass, ToClass, Paths.front());
+
// Must be a base to derived member conversion.
Kind = CastExpr::CK_BaseToDerivedMemberPointer;
return false;
Modified: cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp Wed Feb 10 03:31:12 2010
@@ -54,13 +54,13 @@
// of the base class are accessible as protected members of the
// derived class.
namespace test1 {
- class Base { // expected-note 6 {{constrained by protected inheritance}}
- public: int pub; static int spub; // expected-note 2 {{constrained by protected inheritance}}
+ class Base {
+ public: int pub; static int spub;
protected: int prot; static int sprot; // expected-note 4 {{declared protected here}}
private: int priv; static int spriv; // expected-note 8 {{declared private here}}
};
- class Test : protected Base {
+ class Test : protected Base { // expected-note 6 {{declared protected here}} expected-note 8 {{constrained by protected inheritance here}}
void test() {
pub++;
spub++;
@@ -79,19 +79,19 @@
};
void test(Test *t) {
- t->pub++; // expected-error {{protected member}}
+ t->pub++; // expected-error {{protected member}} expected-error {{protected base class}}
t->spub++; // expected-error {{protected member}}
- t->prot++; // expected-error {{protected member}}
+ t->prot++; // expected-error {{protected member}} expected-error {{protected base class}}
t->sprot++; // expected-error {{protected member}}
- t->priv++; // expected-error {{private member}}
+ t->priv++; // expected-error {{private member}} expected-error {{protected base class}}
t->spriv++; // expected-error {{private member}}
// Two possible errors here: one for Base, one for the member
- t->Base::pub++; // expected-error {{protected member}}
+ t->Base::pub++; // expected-error {{protected member}} expected-error {{protected base class}}
t->Base::spub++; // expected-error {{protected member}}
- t->Base::prot++; // expected-error 2 {{protected member}}
+ t->Base::prot++; // expected-error 2 {{protected member}} expected-error {{protected base class}}
t->Base::sprot++; // expected-error 2 {{protected member}}
- t->Base::priv++; // expected-error {{protected member}} expected-error {{private member}}
+ t->Base::priv++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{protected base class}}
t->Base::spriv++; // expected-error {{protected member}} expected-error {{private member}}
}
}
@@ -102,21 +102,20 @@
// the base class are accessible as private members of the derived
// class.
namespace test2 {
- class Base { //expected-note 6 {{constrained by private inheritance}}
+ class Base {
public:
- int pub; // expected-note {{constrained by private inheritance}}
- static int spub; // expected-note {{constrained by private inheritance}}
+ int pub;
+ static int spub;
protected:
- int prot; // expected-note {{constrained by private inheritance}} \
- // expected-note {{declared protected here}}
- static int sprot; // expected-note {{constrained by private inheritance}} \
- // expected-note {{declared protected here}}
+ int prot; // expected-note {{declared protected here}}
+ static int sprot; // expected-note {{declared protected here}}
private:
int priv; // expected-note 4 {{declared private here}}
static int spriv; // expected-note 4 {{declared private here}}
};
- class Test : private Base { // expected-note 6 {{'private' inheritance specifier here}}
+ class Test : private Base { // expected-note 6 {{declared private here}} \
+ // expected-note 10 {{constrained by private inheritance here}}
void test() {
pub++;
spub++;
@@ -135,18 +134,18 @@
};
void test(Test *t) {
- t->pub++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->pub++; // expected-error {{private member}} expected-error {{private base class}}
t->spub++; // expected-error {{private member}}
- t->prot++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->prot++; // expected-error {{private member}} expected-error {{private base class}}
t->sprot++; // expected-error {{private member}}
- t->priv++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->priv++; // expected-error {{private member}} expected-error {{private base class}}
t->spriv++; // expected-error {{private member}}
- t->Base::pub++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->Base::pub++; // expected-error {{private member}} expected-error {{private base class}}
t->Base::spub++; // expected-error {{private member}}
- t->Base::prot++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{inaccessible base class}}
+ t->Base::prot++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{private base class}}
t->Base::sprot++; // expected-error {{protected member}} expected-error {{private member}}
- t->Base::priv++; // expected-error 2 {{private member}} expected-error {{inaccessible base class}}
+ t->Base::priv++; // expected-error 2 {{private member}} expected-error {{private base class}}
t->Base::spriv++; // expected-error 2 {{private member}}
}
}
Modified: cfe/trunk/test/CXX/class.access/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p4.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/p4.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p4.cpp Wed Feb 10 03:31:12 2010
@@ -23,12 +23,12 @@
void test(A *op) {
op->foo(PublicInst);
- op->foo(ProtectedInst); // expected-error {{access to protected member outside any class}}
- op->foo(PrivateInst); // expected-error {{access to private member outside any class}}
+ op->foo(ProtectedInst); // expected-error {{'foo' is a protected member}}
+ op->foo(PrivateInst); // expected-error {{'foo' is a private member}}
void (A::*a)(Public&) = &A::foo;
- void (A::*b)(Protected&) = &A::foo; // expected-error {{access to protected member outside any class}}
- void (A::*c)(Private&) = &A::foo; // expected-error {{access to private member outside any class}}
+ void (A::*b)(Protected&) = &A::foo; // expected-error {{'foo' is a protected member}}
+ void (A::*c)(Private&) = &A::foo; // expected-error {{'foo' is a private member}}
}
}
@@ -62,15 +62,15 @@
void test(A &a, Public &pub, Protected &prot, Private &priv) {
a + pub;
- a + prot; // expected-error {{access to protected member}}
- a + priv; // expected-error {{access to private member}}
+ a + prot; // expected-error {{'operator+' is a protected member}}
+ a + priv; // expected-error {{'operator+' is a private member}}
a[pub];
- a[prot]; // expected-error {{access to protected member}}
- a[priv]; // expected-error {{access to private member}}
+ a[prot]; // expected-error {{'operator[]' is a protected member}}
+ a[priv]; // expected-error {{'operator[]' is a private member}}
a(pub);
- a(prot); // expected-error {{access to protected member}}
- a(priv); // expected-error {{access to private member}}
- -a; // expected-error {{access to private member}}
+ a(prot); // expected-error {{'operator()' is a protected member}}
+ a(priv); // expected-error {{'operator()' is a private member}}
+ -a; // expected-error {{'operator-' is a private member}}
const A &ca = a;
ca + pub;
@@ -79,8 +79,8 @@
-ca;
// These are all surrogate calls
ca(pub);
- ca(prot); // expected-error {{access to protected member}}
- ca(priv); // expected-error {{access to private member}}
+ ca(prot); // expected-error {{'operator void (*)(class Protected &)' is a protected member}}
+ ca(priv); // expected-error {{'operator void (*)(class Private &)' is a private member}}
}
}
@@ -93,7 +93,7 @@
static A foo;
};
- A a; // expected-error {{access to private member}}
+ A a; // expected-error {{calling a private constructor}}
A A::foo; // okay
}
@@ -105,10 +105,10 @@
static A foo;
};
- A a; // expected-error {{access to private member}}
+ A a; // expected-error {{'~A' is a private member}}
A A::foo;
- void foo(A param) { // expected-error {{access to private member}}
- A local; // expected-error {{access to private member}}
+ void foo(A param) { // expected-error {{'~A' is a private member}}
+ A local; // expected-error {{'~A' is a private member}}
}
}
Modified: cfe/trunk/test/CXX/class.access/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p6.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/p6.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p6.cpp Wed Feb 10 03:31:12 2010
@@ -23,7 +23,7 @@
type foo();
};
- A::type foo() { } // expected-error {{access to private member}}
+ A::type foo() { } // expected-error {{'type' is a private member}}
A::type A::foo() { }
}
@@ -45,10 +45,10 @@
void test() {
A a;
Public pub = a;
- Protected prot = a; // expected-error {{access to protected member}}
- Private priv = a; // expected-error {{access to private member}}
+ Protected prot = a; // expected-error {{'operator Protected' is a protected member}}
+ Private priv = a; // expected-error {{'operator Private' is a private member}}
A apub = pub;
- A aprot = prot; // expected-error {{access to protected member}}
- A apriv = priv; // expected-error {{access to private member}}
+ A aprot = prot; // expected-error {{protected constructor}}
+ A apriv = priv; // expected-error {{private constructor}}
}
}
Modified: cfe/trunk/test/CXX/class/class.local/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.local/p2.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.local/p2.cpp (original)
+++ cfe/trunk/test/CXX/class/class.local/p2.cpp Wed Feb 10 03:31:12 2010
@@ -3,9 +3,9 @@
struct A { };
void f() {
- struct B : private A {}; // expected-note{{'private' inheritance specifier here}}
+ struct B : private A {}; // expected-note{{declared private here}}
B b;
- A *a = &b; // expected-error{{conversion from 'struct B' to inaccessible base class 'struct A'}}
+ A *a = &b; // expected-error{{cannot cast 'struct B' to its private base class 'struct A'}}
}
Modified: cfe/trunk/test/CXX/conv/conv.mem/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/conv/conv.mem/p4.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/CXX/conv/conv.mem/p4.cpp (original)
+++ cfe/trunk/test/CXX/conv/conv.mem/p4.cpp Wed Feb 10 03:31:12 2010
@@ -15,12 +15,12 @@
}
}
-// FIXME: can't be inaccessible.
+// Can't be inaccessible.
namespace test1 {
- struct Derived : private Base {};
+ struct Derived : private Base {}; // expected-note 2 {{declared private here}}
void test() {
- int (Derived::*d) = data_ptr; // error
- int (Derived::*m)() = method_ptr; // error
+ int (Derived::*d) = data_ptr; // expected-error {{cannot cast private base class 'struct Base' to 'struct test1::Derived'}}
+ int (Derived::*m)() = method_ptr; // expected-error {{cannot cast private base class 'struct Base' to 'struct test1::Derived'}}
}
};
Modified: cfe/trunk/test/SemaCXX/access-base-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/access-base-class.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/access-base-class.cpp (original)
+++ cfe/trunk/test/SemaCXX/access-base-class.cpp Wed Feb 10 03:31:12 2010
@@ -2,10 +2,10 @@
namespace T1 {
class A { };
-class B : private A { }; // expected-note {{'private' inheritance specifier here}}
+class B : private A { }; // expected-note {{declared private here}}
void f(B* b) {
- A *a = b; // expected-error{{conversion from 'class T1::B' to inaccessible base class 'class T1::A'}}
+ A *a = b; // expected-error{{cannot cast 'class T1::B' to its private base class 'class T1::A'}}
}
}
@@ -13,10 +13,10 @@
namespace T2 {
class A { };
-class B : A { }; // expected-note {{inheritance is implicitly 'private'}}
+class B : A { }; // expected-note {{implicitly declared private here}}
void f(B* b) {
- A *a = b; // expected-error {{conversion from 'class T2::B' to inaccessible base class 'class T2::A'}}
+ A *a = b; // expected-error {{cannot cast 'class T2::B' to its private base class 'class T2::A'}}
}
}
@@ -63,13 +63,13 @@
class A {};
- class B : private A { // expected-note {{'private' inheritance specifier here}}
+ class B : private A { // expected-note {{declared private here}}
void f(C* c);
};
class C : public B {
void f(C *c) {
- A* a = c; // expected-error {{conversion from 'class T6::C' to inaccessible base class 'class T6::A'}}
+ A* a = c; // expected-error {{cannot cast 'class T6::C' to its private base class 'class T6::A'}}
}
};
@@ -77,3 +77,14 @@
A *a = c;
}
}
+
+namespace T7 {
+ class A {};
+ class B : public A {};
+ class C : private B {
+ void f(C *c) {
+ A* a = c; // okay
+ }
+ };
+}
+
Modified: cfe/trunk/test/SemaCXX/access-control-check.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/access-control-check.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/access-control-check.cpp (original)
+++ cfe/trunk/test/SemaCXX/access-control-check.cpp Wed Feb 10 03:31:12 2010
@@ -11,5 +11,5 @@
class N : M,P {
N() {}
- int PR() { return iP + PPR(); } // expected-error 2 {{access to private member of 'class P'}}
+ int PR() { return iP + PPR(); } // expected-error 2 {{private member of 'class P'}}
};
Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Wed Feb 10 03:31:12 2010
@@ -25,7 +25,7 @@
void fn2();
};
struct Convertible { operator Base&(); };
-struct Priv : private Base {}; // expected-note 4 {{'private' inheritance specifier here}}
+struct Priv : private Base {}; // expected-note 4 {{declared private here}}
struct Mid : Base {};
struct Fin : Mid, Derived {};
typedef void (Derived::*DFnPtr)();
@@ -111,12 +111,12 @@
Priv priv;
Fin fin;
- (void)(i1 ? Base() : Priv()); // expected-error{{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
- (void)(i1 ? Priv() : Base()); // expected-error{{error: conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
+ (void)(i1 ? Base() : Priv()); // expected-error{{private base class}}
+ (void)(i1 ? Priv() : Base()); // expected-error{{private base class}}
(void)(i1 ? Base() : Fin()); // expected-error{{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
(void)(i1 ? Fin() : Base()); // expected-error{{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
- (void)(i1 ? base : priv); // expected-error {{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
- (void)(i1 ? priv : base); // expected-error {{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
+ (void)(i1 ? base : priv); // expected-error {{private base class}}
+ (void)(i1 ? priv : base); // expected-error {{private base class}}
(void)(i1 ? base : fin); // expected-error {{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
(void)(i1 ? fin : base); // expected-error {{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
Modified: cfe/trunk/test/SemaCXX/static-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-cast.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/static-cast.cpp (original)
+++ cfe/trunk/test/SemaCXX/static-cast.cpp Wed Feb 10 03:31:12 2010
@@ -4,7 +4,7 @@
struct C1 : public virtual B {}; // Single virtual base.
struct C2 : public virtual B {};
struct D : public C1, public C2 {}; // Diamond
-struct E : private A {}; // Single private base. expected-note 3 {{'private' inheritance specifier here}}
+struct E : private A {}; // Single private base. expected-note 3 {{declared private here}}
struct F : public C1 {}; // Single path to B with virtual.
struct G1 : public B {};
struct G2 : public B {};
@@ -56,7 +56,7 @@
// Bad code below
(void)static_cast<void*>((const int*)0); // expected-error {{static_cast from 'int const *' to 'void *' is not allowed}}
- (void)static_cast<A*>((E*)0); // expected-error {{inaccessible base class 'struct A'}}
+ (void)static_cast<A*>((E*)0); // expected-error {{private base class 'struct A'}}
(void)static_cast<A*>((H*)0); // expected-error {{ambiguous conversion}}
(void)static_cast<int>((int*)0); // expected-error {{static_cast from 'int *' to 'int' is not allowed}}
(void)static_cast<A**>((B**)0); // expected-error {{static_cast from 'struct B **' to 'struct A **' is not allowed}}
@@ -86,8 +86,8 @@
(void)static_cast<D&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct D &' via virtual base 'struct B'}}
(void)static_cast<B*>((const A*)0); // expected-error {{static_cast from 'struct A const *' to 'struct B *' casts away constness}}
(void)static_cast<B&>(*((const A*)0)); // expected-error {{static_cast from 'struct A const' to 'struct B &' casts away constness}}
- (void)static_cast<E*>((A*)0); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
- (void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
+ (void)static_cast<E*>((A*)0); // expected-error {{cannot cast private base class 'struct A' to 'struct E'}}
+ (void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast private base class 'struct A' to 'struct E'}}
(void)static_cast<H*>((A*)0); // expected-error {{ambiguous cast from base 'struct A' to derived 'struct H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
(void)static_cast<H&>(*((A*)0)); // expected-error {{ambiguous cast from base 'struct A' to derived 'struct H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
(void)static_cast<E*>((B*)0); // expected-error {{static_cast from 'struct B *' to 'struct E *' is not allowed}}
Modified: cfe/trunk/test/SemaCXX/virtual-override.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/virtual-override.cpp?rev=95775&r1=95774&r2=95775&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/virtual-override.cpp (original)
+++ cfe/trunk/test/SemaCXX/virtual-override.cpp Wed Feb 10 03:31:12 2010
@@ -29,14 +29,14 @@
namespace T3 {
struct a { };
-struct b : private a { }; // expected-note{{'private' inheritance specifier here}}
+struct b : private a { }; // expected-note{{declared private here}}
class A {
virtual a* f(); // expected-note{{overridden virtual function is here}}
};
class B : A {
- virtual b* f(); // expected-error{{return type of virtual function 'f' is not covariant with the return type of the function it overrides (conversion from 'struct T3::b' to inaccessible base class 'struct T3::a')}}
+ virtual b* f(); // expected-error{{invalid covariant return for virtual function: 'struct T3::a' is a private base class of 'struct T3::b'}}
};
}
More information about the cfe-commits
mailing list