static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { DeclContext *DC = D->getDeclContext(); // This can only happen at top: enum decls only "publish" their // immediate members. if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); while (DeclaringClass->isAnonymousStructOrUnion()) DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); return DeclaringClass; }
/// Determines whether the accessed entity is accessible. Public members /// have been weeded out by this point. static AccessResult IsAccessible(Sema &S, const EffectiveContext &EC, AccessTarget &Entity) { // Determine the actual naming class. CXXRecordDecl *NamingClass = Entity.getNamingClass(); while (NamingClass->isAnonymousStructOrUnion()) NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); NamingClass = NamingClass->getCanonicalDecl(); AccessSpecifier UnprivilegedAccess = Entity.getAccess(); assert(UnprivilegedAccess != AS_public && "public access not weeded out"); // Before we try to recalculate access paths, try to white-list // accesses which just trade in on the final step, i.e. accesses // which don't require [M4] or [B4]. These are by far the most // common forms of privileged access. if (UnprivilegedAccess != AS_none) { switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) { case AR_dependent: // This is actually an interesting policy decision. We don't // *have* to delay immediately here: we can do the full access // calculation in the hope that friendship on some intermediate // class will make the declaration accessible non-dependently. // But that's not cheap, and odds are very good (note: assertion // made without data) that the friend declaration will determine // access. return AR_dependent; case AR_accessible: return AR_accessible; case AR_inaccessible: break; } } AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext(); // We lower member accesses to base accesses by pretending that the // member is a base class of its declaring class. AccessSpecifier FinalAccess; if (Entity.isMemberAccess()) { // Determine if the declaration is accessible from EC when named // in its declaring class. NamedDecl *Target = Entity.getTargetDecl(); const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); FinalAccess = Target->getAccess(); switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) { case AR_accessible: FinalAccess = AS_public; break; case AR_inaccessible: break; case AR_dependent: return AR_dependent; // see above } if (DeclaringClass == NamingClass) return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible); Entity.suppressInstanceContext(); } else { FinalAccess = AS_public; } assert(Entity.getDeclaringClass() != NamingClass); // Append the declaration's access if applicable. CXXBasePaths Paths; CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); if (!Path) return AR_dependent; assert(Path->Access <= UnprivilegedAccess && "access along best path worse than direct?"); if (Path->Access == AS_public) return AR_accessible; return AR_inaccessible; }