diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-02-16 09:31:36 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-02-16 09:31:36 +0000 |
commit | fd035e6496665b1f1197868e21cb0a4594e8db6e (patch) | |
tree | 53010172e19c77ea447bcd89e117cda052ab52e0 /lib/Sema/SemaAccess.cpp | |
parent | 2fce988e86bc01829142e4362d4eff1af0925147 (diff) | |
download | FreeBSD-src-fd035e6496665b1f1197868e21cb0a4594e8db6e.zip FreeBSD-src-fd035e6496665b1f1197868e21cb0a4594e8db6e.tar.gz |
Update clang to r96341.
Diffstat (limited to 'lib/Sema/SemaAccess.cpp')
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 592 |
1 files changed, 451 insertions, 141 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 51f9e30..eca8bb4 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -16,6 +16,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" + using namespace clang; /// SetMemberAccessSpecifier - Set the access specifier of a member. @@ -47,192 +49,500 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, 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); + case Sema::AR_accessible: break; - if (InaccessibleBase) { - Diag(AccessLoc, InaccessibleBaseID) - << Derived << Base << Name; + case Sema::AR_dependent: + case Sema::AR_delayed: + llvm_unreachable("dependent/delayed not allowed"); + return; + } + } - AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten(); + CXXBasePaths Paths; + CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths); - // 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; + CXXBasePath::iterator I = Path.end(), E = Path.begin(); + while (I != E) { + --I; - return true; + 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; + } } - return false; + 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; - // Otherwise, derive the current class context. - DeclContext *DC = CurContext; - 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); - CXXRecordDecl *NamingClass = R.getNamingClass(); + // 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; + } + + // 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 + // 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; +} - // Okay, it's a bad access, reject it. +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 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; + } - - CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext()); + return CheckEffectiveAccess(S, EffectiveContext(S.CurContext), + Loc, Entity, ADK); +} - if (Access == AS_protected) { - Diag(R.getNameLoc(), diag::err_access_protected) - << Context.getTypeDeclType(DeclaringClass) - << Context.getTypeDeclType(CurRecord); - DiagnoseAccessPath(*this, R, D, Access); - return true; - } +void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { + // Pretend we did this from the context of the newly-parsed + // declaration. + EffectiveContext EC(Ctx->getDeclContext()); + + if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal)) + DD.Triggered = true; +} + +Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, + NamedDecl *D, + AccessSpecifier Access) { + if (!getLangOptions().AccessControl || !E->getNamingClass()) + return AR_accessible; - 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 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. +Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, + NamedDecl *D, + AccessSpecifier Access) { + if (!getLangOptions().AccessControl) + return AR_accessible; + + return CheckAccess(*this, E->getMemberLoc(), + AccessedEntity::makeMember(E->getNamingClass(), Access, D)); +} + +Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, + const RecordType *RT) { + if (!getLangOptions().AccessControl) + return AR_accessible; + + CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); + CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context); + + AccessSpecifier Access = Dtor->getAccess(); + if (Access == AS_public) + return AR_accessible; + + return CheckAccess(*this, Loc, + AccessedEntity::makeMember(NamingClass, Access, Dtor)); +} + +/// Checks access to a constructor. +Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, + CXXConstructorDecl *Constructor, + AccessSpecifier Access) { + if (!getLangOptions().AccessControl) + return AR_accessible; + + CXXRecordDecl *NamingClass = Constructor->getParent(); + return CheckAccess(*this, UseLoc, + AccessedEntity::makeMember(NamingClass, Access, Constructor)); +} + +/// Checks access to an overloaded member operator, including +/// conversion operators. +Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, + Expr *ObjectExpr, + NamedDecl *MemberOperator, + AccessSpecifier Access) { + if (!getLangOptions().AccessControl) + 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()); + + return CheckAccess(*this, OpLoc, + AccessedEntity::makeMember(NamingClass, Access, MemberOperator)); +} + +/// 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)); } |