|  | //===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file provides Sema routines for C++ access control semantics. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/Sema/SemaInternal.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/AST/CXXInheritance.h" | 
|  | #include "clang/AST/DeclCXX.h" | 
|  | #include "clang/AST/DeclFriend.h" | 
|  | #include "clang/AST/DeclObjC.h" | 
|  | #include "clang/AST/DependentDiagnostic.h" | 
|  | #include "clang/AST/ExprCXX.h" | 
|  | #include "clang/Sema/DelayedDiagnostic.h" | 
|  | #include "clang/Sema/Initialization.h" | 
|  | #include "clang/Sema/Lookup.h" | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace sema; | 
|  |  | 
|  | /// A copy of Sema's enum without AR_delayed. | 
|  | enum AccessResult { | 
|  | AR_accessible, | 
|  | AR_inaccessible, | 
|  | AR_dependent | 
|  | }; | 
|  |  | 
|  | /// SetMemberAccessSpecifier - Set the access specifier of a member. | 
|  | /// Returns true on error (when the previous member decl access specifier | 
|  | /// is different from the new member decl access specifier). | 
|  | bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, | 
|  | NamedDecl *PrevMemberDecl, | 
|  | AccessSpecifier LexicalAS) { | 
|  | if (!PrevMemberDecl) { | 
|  | // Use the lexical access specifier. | 
|  | MemberDecl->setAccess(LexicalAS); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // C++ [class.access.spec]p3: When a member is redeclared its access | 
|  | // specifier must be same as its initial declaration. | 
|  | if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { | 
|  | Diag(MemberDecl->getLocation(), | 
|  | diag::err_class_redeclared_with_different_access) | 
|  | << MemberDecl << LexicalAS; | 
|  | Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) | 
|  | << PrevMemberDecl << PrevMemberDecl->getAccess(); | 
|  |  | 
|  | MemberDecl->setAccess(LexicalAS); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | MemberDecl->setAccess(PrevMemberDecl->getAccess()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | struct EffectiveContext { | 
|  | EffectiveContext() : Inner(0), Dependent(false) {} | 
|  |  | 
|  | explicit EffectiveContext(DeclContext *DC) | 
|  | : Inner(DC), | 
|  | Dependent(DC->isDependentContext()) { | 
|  |  | 
|  | // C++11 [class.access.nest]p1: | 
|  | //   A nested class is a member and as such has the same access | 
|  | //   rights as any other member. | 
|  | // C++11 [class.access]p2: | 
|  | //   A member of a class can also access all the names to which | 
|  | //   the class has access.  A local class of a member function | 
|  | //   may access the same names that the member function itself | 
|  | //   may access. | 
|  | // This almost implies that the privileges of nesting are transitive. | 
|  | // Technically it says nothing about the local classes of non-member | 
|  | // functions (which can gain privileges through friendship), but we | 
|  | // take that as an oversight. | 
|  | while (true) { | 
|  | // We want to add canonical declarations to the EC lists for | 
|  | // simplicity of checking, but we need to walk up through the | 
|  | // actual current DC chain.  Otherwise, something like a local | 
|  | // extern or friend which happens to be the canonical | 
|  | // declaration will really mess us up. | 
|  |  | 
|  | if (isa<CXXRecordDecl>(DC)) { | 
|  | CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); | 
|  | Records.push_back(Record->getCanonicalDecl()); | 
|  | DC = Record->getDeclContext(); | 
|  | } else if (isa<FunctionDecl>(DC)) { | 
|  | FunctionDecl *Function = cast<FunctionDecl>(DC); | 
|  | Functions.push_back(Function->getCanonicalDecl()); | 
|  | if (Function->getFriendObjectKind()) | 
|  | DC = Function->getLexicalDeclContext(); | 
|  | else | 
|  | DC = Function->getDeclContext(); | 
|  | } else if (DC->isFileContext()) { | 
|  | break; | 
|  | } else { | 
|  | DC = DC->getParent(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool isDependent() const { return Dependent; } | 
|  |  | 
|  | bool includesClass(const CXXRecordDecl *R) const { | 
|  | R = R->getCanonicalDecl(); | 
|  | return std::find(Records.begin(), Records.end(), R) | 
|  | != Records.end(); | 
|  | } | 
|  |  | 
|  | /// Retrieves the innermost "useful" context.  Can be null if we're | 
|  | /// doing access-control without privileges. | 
|  | DeclContext *getInnerContext() const { | 
|  | return Inner; | 
|  | } | 
|  |  | 
|  | typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; | 
|  |  | 
|  | DeclContext *Inner; | 
|  | SmallVector<FunctionDecl*, 4> Functions; | 
|  | SmallVector<CXXRecordDecl*, 4> Records; | 
|  | bool Dependent; | 
|  | }; | 
|  |  | 
|  | /// Like sema::AccessedEntity, but kindly lets us scribble all over | 
|  | /// it. | 
|  | struct AccessTarget : public AccessedEntity { | 
|  | AccessTarget(const AccessedEntity &Entity) | 
|  | : AccessedEntity(Entity) { | 
|  | initialize(); | 
|  | } | 
|  |  | 
|  | AccessTarget(ASTContext &Context, | 
|  | MemberNonce _, | 
|  | CXXRecordDecl *NamingClass, | 
|  | DeclAccessPair FoundDecl, | 
|  | QualType BaseObjectType) | 
|  | : AccessedEntity(Context.getDiagAllocator(), Member, NamingClass, | 
|  | FoundDecl, BaseObjectType) { | 
|  | initialize(); | 
|  | } | 
|  |  | 
|  | AccessTarget(ASTContext &Context, | 
|  | BaseNonce _, | 
|  | CXXRecordDecl *BaseClass, | 
|  | CXXRecordDecl *DerivedClass, | 
|  | AccessSpecifier Access) | 
|  | : AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass, | 
|  | Access) { | 
|  | initialize(); | 
|  | } | 
|  |  | 
|  | bool isInstanceMember() const { | 
|  | return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember()); | 
|  | } | 
|  |  | 
|  | bool hasInstanceContext() const { | 
|  | return HasInstanceContext; | 
|  | } | 
|  |  | 
|  | class SavedInstanceContext { | 
|  | public: | 
|  | ~SavedInstanceContext() { | 
|  | Target.HasInstanceContext = Has; | 
|  | } | 
|  |  | 
|  | private: | 
|  | friend struct AccessTarget; | 
|  | explicit SavedInstanceContext(AccessTarget &Target) | 
|  | : Target(Target), Has(Target.HasInstanceContext) {} | 
|  | AccessTarget &Target; | 
|  | bool Has; | 
|  | }; | 
|  |  | 
|  | SavedInstanceContext saveInstanceContext() { | 
|  | return SavedInstanceContext(*this); | 
|  | } | 
|  |  | 
|  | void suppressInstanceContext() { | 
|  | HasInstanceContext = false; | 
|  | } | 
|  |  | 
|  | const CXXRecordDecl *resolveInstanceContext(Sema &S) const { | 
|  | assert(HasInstanceContext); | 
|  | if (CalculatedInstanceContext) | 
|  | return InstanceContext; | 
|  |  | 
|  | CalculatedInstanceContext = true; | 
|  | DeclContext *IC = S.computeDeclContext(getBaseObjectType()); | 
|  | InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0); | 
|  | return InstanceContext; | 
|  | } | 
|  |  | 
|  | const CXXRecordDecl *getDeclaringClass() const { | 
|  | return DeclaringClass; | 
|  | } | 
|  |  | 
|  | /// The "effective" naming class is the canonical non-anonymous | 
|  | /// class containing the actual naming class. | 
|  | const CXXRecordDecl *getEffectiveNamingClass() const { | 
|  | const CXXRecordDecl *namingClass = getNamingClass(); | 
|  | while (namingClass->isAnonymousStructOrUnion()) | 
|  | namingClass = cast<CXXRecordDecl>(namingClass->getParent()); | 
|  | return namingClass->getCanonicalDecl(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | void initialize() { | 
|  | HasInstanceContext = (isMemberAccess() && | 
|  | !getBaseObjectType().isNull() && | 
|  | getTargetDecl()->isCXXInstanceMember()); | 
|  | CalculatedInstanceContext = false; | 
|  | InstanceContext = 0; | 
|  |  | 
|  | if (isMemberAccess()) | 
|  | DeclaringClass = FindDeclaringClass(getTargetDecl()); | 
|  | else | 
|  | DeclaringClass = getBaseClass(); | 
|  | DeclaringClass = DeclaringClass->getCanonicalDecl(); | 
|  | } | 
|  |  | 
|  | bool HasInstanceContext : 1; | 
|  | mutable bool CalculatedInstanceContext : 1; | 
|  | mutable const CXXRecordDecl *InstanceContext; | 
|  | const CXXRecordDecl *DeclaringClass; | 
|  | }; | 
|  |  | 
|  | } | 
|  |  | 
|  | /// Checks whether one class might instantiate to the other. | 
|  | static bool MightInstantiateTo(const CXXRecordDecl *From, | 
|  | const CXXRecordDecl *To) { | 
|  | // Declaration names are always preserved by instantiation. | 
|  | if (From->getDeclName() != To->getDeclName()) | 
|  | return false; | 
|  |  | 
|  | const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext(); | 
|  | const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext(); | 
|  | if (FromDC == ToDC) return true; | 
|  | if (FromDC->isFileContext() || ToDC->isFileContext()) return false; | 
|  |  | 
|  | // Be conservative. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// Checks whether one class is derived from another, inclusively. | 
|  | /// Properly indicates when it couldn't be determined due to | 
|  | /// dependence. | 
|  | /// | 
|  | /// This should probably be donated to AST or at least Sema. | 
|  | static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, | 
|  | const CXXRecordDecl *Target) { | 
|  | assert(Derived->getCanonicalDecl() == Derived); | 
|  | assert(Target->getCanonicalDecl() == Target); | 
|  |  | 
|  | if (Derived == Target) return AR_accessible; | 
|  |  | 
|  | bool CheckDependent = Derived->isDependentContext(); | 
|  | if (CheckDependent && MightInstantiateTo(Derived, Target)) | 
|  | return AR_dependent; | 
|  |  | 
|  | AccessResult OnFailure = AR_inaccessible; | 
|  | SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack | 
|  |  | 
|  | while (true) { | 
|  | if (Derived->isDependentContext() && !Derived->hasDefinition()) | 
|  | return AR_dependent; | 
|  |  | 
|  | for (CXXRecordDecl::base_class_const_iterator | 
|  | I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) { | 
|  |  | 
|  | const CXXRecordDecl *RD; | 
|  |  | 
|  | QualType T = I->getType(); | 
|  | if (const RecordType *RT = T->getAs<RecordType>()) { | 
|  | RD = cast<CXXRecordDecl>(RT->getDecl()); | 
|  | } else if (const InjectedClassNameType *IT | 
|  | = T->getAs<InjectedClassNameType>()) { | 
|  | RD = IT->getDecl(); | 
|  | } else { | 
|  | assert(T->isDependentType() && "non-dependent base wasn't a record?"); | 
|  | OnFailure = AR_dependent; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | RD = RD->getCanonicalDecl(); | 
|  | if (RD == Target) return AR_accessible; | 
|  | if (CheckDependent && MightInstantiateTo(RD, Target)) | 
|  | OnFailure = AR_dependent; | 
|  |  | 
|  | Queue.push_back(RD); | 
|  | } | 
|  |  | 
|  | if (Queue.empty()) break; | 
|  |  | 
|  | Derived = Queue.pop_back_val(); | 
|  | } | 
|  |  | 
|  | return OnFailure; | 
|  | } | 
|  |  | 
|  |  | 
|  | static bool MightInstantiateTo(Sema &S, DeclContext *Context, | 
|  | DeclContext *Friend) { | 
|  | if (Friend == Context) | 
|  | return true; | 
|  |  | 
|  | assert(!Friend->isDependentContext() && | 
|  | "can't handle friends with dependent contexts here"); | 
|  |  | 
|  | if (!Context->isDependentContext()) | 
|  | return false; | 
|  |  | 
|  | if (Friend->isFileContext()) | 
|  | return false; | 
|  |  | 
|  | // TODO: this is very conservative | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Asks whether the type in 'context' can ever instantiate to the type | 
|  | // in 'friend'. | 
|  | static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) { | 
|  | if (Friend == Context) | 
|  | return true; | 
|  |  | 
|  | if (!Friend->isDependentType() && !Context->isDependentType()) | 
|  | return false; | 
|  |  | 
|  | // TODO: this is very conservative. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool MightInstantiateTo(Sema &S, | 
|  | FunctionDecl *Context, | 
|  | FunctionDecl *Friend) { | 
|  | if (Context->getDeclName() != Friend->getDeclName()) | 
|  | return false; | 
|  |  | 
|  | if (!MightInstantiateTo(S, | 
|  | Context->getDeclContext(), | 
|  | Friend->getDeclContext())) | 
|  | return false; | 
|  |  | 
|  | CanQual<FunctionProtoType> FriendTy | 
|  | = S.Context.getCanonicalType(Friend->getType()) | 
|  | ->getAs<FunctionProtoType>(); | 
|  | CanQual<FunctionProtoType> ContextTy | 
|  | = S.Context.getCanonicalType(Context->getType()) | 
|  | ->getAs<FunctionProtoType>(); | 
|  |  | 
|  | // There isn't any way that I know of to add qualifiers | 
|  | // during instantiation. | 
|  | if (FriendTy.getQualifiers() != ContextTy.getQualifiers()) | 
|  | return false; | 
|  |  | 
|  | if (FriendTy->getNumArgs() != ContextTy->getNumArgs()) | 
|  | return false; | 
|  |  | 
|  | if (!MightInstantiateTo(S, | 
|  | ContextTy->getResultType(), | 
|  | FriendTy->getResultType())) | 
|  | return false; | 
|  |  | 
|  | for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I) | 
|  | if (!MightInstantiateTo(S, | 
|  | ContextTy->getArgType(I), | 
|  | FriendTy->getArgType(I))) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool MightInstantiateTo(Sema &S, | 
|  | FunctionTemplateDecl *Context, | 
|  | FunctionTemplateDecl *Friend) { | 
|  | return MightInstantiateTo(S, | 
|  | Context->getTemplatedDecl(), | 
|  | Friend->getTemplatedDecl()); | 
|  | } | 
|  |  | 
|  | static AccessResult MatchesFriend(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | const CXXRecordDecl *Friend) { | 
|  | if (EC.includesClass(Friend)) | 
|  | return AR_accessible; | 
|  |  | 
|  | if (EC.isDependent()) { | 
|  | CanQualType FriendTy | 
|  | = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend)); | 
|  |  | 
|  | for (EffectiveContext::record_iterator | 
|  | I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { | 
|  | CanQualType ContextTy | 
|  | = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); | 
|  | if (MightInstantiateTo(S, ContextTy, FriendTy)) | 
|  | return AR_dependent; | 
|  | } | 
|  | } | 
|  |  | 
|  | return AR_inaccessible; | 
|  | } | 
|  |  | 
|  | static AccessResult MatchesFriend(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | CanQualType Friend) { | 
|  | if (const RecordType *RT = Friend->getAs<RecordType>()) | 
|  | return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); | 
|  |  | 
|  | // TODO: we can do better than this | 
|  | if (Friend->isDependentType()) | 
|  | return AR_dependent; | 
|  |  | 
|  | return AR_inaccessible; | 
|  | } | 
|  |  | 
|  | /// Determines whether the given friend class template matches | 
|  | /// anything in the effective context. | 
|  | static AccessResult MatchesFriend(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | ClassTemplateDecl *Friend) { | 
|  | AccessResult OnFailure = AR_inaccessible; | 
|  |  | 
|  | // Check whether the friend is the template of a class in the | 
|  | // context chain. | 
|  | for (SmallVectorImpl<CXXRecordDecl*>::const_iterator | 
|  | I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { | 
|  | CXXRecordDecl *Record = *I; | 
|  |  | 
|  | // Figure out whether the current class has a template: | 
|  | ClassTemplateDecl *CTD; | 
|  |  | 
|  | // A specialization of the template... | 
|  | if (isa<ClassTemplateSpecializationDecl>(Record)) { | 
|  | CTD = cast<ClassTemplateSpecializationDecl>(Record) | 
|  | ->getSpecializedTemplate(); | 
|  |  | 
|  | // ... or the template pattern itself. | 
|  | } else { | 
|  | CTD = Record->getDescribedClassTemplate(); | 
|  | if (!CTD) continue; | 
|  | } | 
|  |  | 
|  | // It's a match. | 
|  | if (Friend == CTD->getCanonicalDecl()) | 
|  | return AR_accessible; | 
|  |  | 
|  | // If the context isn't dependent, it can't be a dependent match. | 
|  | if (!EC.isDependent()) | 
|  | continue; | 
|  |  | 
|  | // If the template names don't match, it can't be a dependent | 
|  | // match. | 
|  | if (CTD->getDeclName() != Friend->getDeclName()) | 
|  | continue; | 
|  |  | 
|  | // If the class's context can't instantiate to the friend's | 
|  | // context, it can't be a dependent match. | 
|  | if (!MightInstantiateTo(S, CTD->getDeclContext(), | 
|  | Friend->getDeclContext())) | 
|  | continue; | 
|  |  | 
|  | // Otherwise, it's a dependent match. | 
|  | OnFailure = AR_dependent; | 
|  | } | 
|  |  | 
|  | return OnFailure; | 
|  | } | 
|  |  | 
|  | /// Determines whether the given friend function matches anything in | 
|  | /// the effective context. | 
|  | static AccessResult MatchesFriend(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | FunctionDecl *Friend) { | 
|  | AccessResult OnFailure = AR_inaccessible; | 
|  |  | 
|  | for (SmallVectorImpl<FunctionDecl*>::const_iterator | 
|  | I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { | 
|  | if (Friend == *I) | 
|  | return AR_accessible; | 
|  |  | 
|  | if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) | 
|  | OnFailure = AR_dependent; | 
|  | } | 
|  |  | 
|  | return OnFailure; | 
|  | } | 
|  |  | 
|  | /// Determines whether the given friend function template matches | 
|  | /// anything in the effective context. | 
|  | static AccessResult MatchesFriend(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | FunctionTemplateDecl *Friend) { | 
|  | if (EC.Functions.empty()) return AR_inaccessible; | 
|  |  | 
|  | AccessResult OnFailure = AR_inaccessible; | 
|  |  | 
|  | for (SmallVectorImpl<FunctionDecl*>::const_iterator | 
|  | I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { | 
|  |  | 
|  | FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); | 
|  | if (!FTD) | 
|  | FTD = (*I)->getDescribedFunctionTemplate(); | 
|  | if (!FTD) | 
|  | continue; | 
|  |  | 
|  | FTD = FTD->getCanonicalDecl(); | 
|  |  | 
|  | if (Friend == FTD) | 
|  | return AR_accessible; | 
|  |  | 
|  | if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) | 
|  | OnFailure = AR_dependent; | 
|  | } | 
|  |  | 
|  | return OnFailure; | 
|  | } | 
|  |  | 
|  | /// Determines whether the given friend declaration matches anything | 
|  | /// in the effective context. | 
|  | static AccessResult MatchesFriend(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | FriendDecl *FriendD) { | 
|  | // Whitelist accesses if there's an invalid or unsupported friend | 
|  | // declaration. | 
|  | if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend()) | 
|  | return AR_accessible; | 
|  |  | 
|  | if (TypeSourceInfo *T = FriendD->getFriendType()) | 
|  | return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); | 
|  |  | 
|  | NamedDecl *Friend | 
|  | = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl()); | 
|  |  | 
|  | // FIXME: declarations with dependent or templated scope. | 
|  |  | 
|  | if (isa<ClassTemplateDecl>(Friend)) | 
|  | return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend)); | 
|  |  | 
|  | if (isa<FunctionTemplateDecl>(Friend)) | 
|  | return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend)); | 
|  |  | 
|  | if (isa<CXXRecordDecl>(Friend)) | 
|  | return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend)); | 
|  |  | 
|  | assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind"); | 
|  | return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); | 
|  | } | 
|  |  | 
|  | static AccessResult GetFriendKind(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | const CXXRecordDecl *Class) { | 
|  | AccessResult OnFailure = AR_inaccessible; | 
|  |  | 
|  | // Okay, check friends. | 
|  | for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), | 
|  | E = Class->friend_end(); I != E; ++I) { | 
|  | FriendDecl *Friend = *I; | 
|  |  | 
|  | switch (MatchesFriend(S, EC, Friend)) { | 
|  | case AR_accessible: | 
|  | return AR_accessible; | 
|  |  | 
|  | case AR_inaccessible: | 
|  | continue; | 
|  |  | 
|  | case AR_dependent: | 
|  | OnFailure = AR_dependent; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // That's it, give up. | 
|  | return OnFailure; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | /// A helper class for checking for a friend which will grant access | 
|  | /// to a protected instance member. | 
|  | struct ProtectedFriendContext { | 
|  | Sema &S; | 
|  | const EffectiveContext &EC; | 
|  | const CXXRecordDecl *NamingClass; | 
|  | bool CheckDependent; | 
|  | bool EverDependent; | 
|  |  | 
|  | /// The path down to the current base class. | 
|  | SmallVector<const CXXRecordDecl*, 20> CurPath; | 
|  |  | 
|  | ProtectedFriendContext(Sema &S, const EffectiveContext &EC, | 
|  | const CXXRecordDecl *InstanceContext, | 
|  | const CXXRecordDecl *NamingClass) | 
|  | : S(S), EC(EC), NamingClass(NamingClass), | 
|  | CheckDependent(InstanceContext->isDependentContext() || | 
|  | NamingClass->isDependentContext()), | 
|  | EverDependent(false) {} | 
|  |  | 
|  | /// Check classes in the current path for friendship, starting at | 
|  | /// the given index. | 
|  | bool checkFriendshipAlongPath(unsigned I) { | 
|  | assert(I < CurPath.size()); | 
|  | for (unsigned E = CurPath.size(); I != E; ++I) { | 
|  | switch (GetFriendKind(S, EC, CurPath[I])) { | 
|  | case AR_accessible:   return true; | 
|  | case AR_inaccessible: continue; | 
|  | case AR_dependent:    EverDependent = true; continue; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Perform a search starting at the given class. | 
|  | /// | 
|  | /// PrivateDepth is the index of the last (least derived) class | 
|  | /// along the current path such that a notional public member of | 
|  | /// the final class in the path would have access in that class. | 
|  | bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) { | 
|  | // If we ever reach the naming class, check the current path for | 
|  | // friendship.  We can also stop recursing because we obviously | 
|  | // won't find the naming class there again. | 
|  | if (Cur == NamingClass) | 
|  | return checkFriendshipAlongPath(PrivateDepth); | 
|  |  | 
|  | if (CheckDependent && MightInstantiateTo(Cur, NamingClass)) | 
|  | EverDependent = true; | 
|  |  | 
|  | // Recurse into the base classes. | 
|  | for (CXXRecordDecl::base_class_const_iterator | 
|  | I = Cur->bases_begin(), E = Cur->bases_end(); I != E; ++I) { | 
|  |  | 
|  | // If this is private inheritance, then a public member of the | 
|  | // base will not have any access in classes derived from Cur. | 
|  | unsigned BasePrivateDepth = PrivateDepth; | 
|  | if (I->getAccessSpecifier() == AS_private) | 
|  | BasePrivateDepth = CurPath.size() - 1; | 
|  |  | 
|  | const CXXRecordDecl *RD; | 
|  |  | 
|  | QualType T = I->getType(); | 
|  | if (const RecordType *RT = T->getAs<RecordType>()) { | 
|  | RD = cast<CXXRecordDecl>(RT->getDecl()); | 
|  | } else if (const InjectedClassNameType *IT | 
|  | = T->getAs<InjectedClassNameType>()) { | 
|  | RD = IT->getDecl(); | 
|  | } else { | 
|  | assert(T->isDependentType() && "non-dependent base wasn't a record?"); | 
|  | EverDependent = true; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Recurse.  We don't need to clean up if this returns true. | 
|  | CurPath.push_back(RD); | 
|  | if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth)) | 
|  | return true; | 
|  | CurPath.pop_back(); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool findFriendship(const CXXRecordDecl *Cur) { | 
|  | assert(CurPath.empty()); | 
|  | CurPath.push_back(Cur); | 
|  | return findFriendship(Cur, 0); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | /// Search for a class P that EC is a friend of, under the constraint | 
|  | ///   InstanceContext <= P | 
|  | /// if InstanceContext exists, or else | 
|  | ///   NamingClass <= P | 
|  | /// and with the additional restriction that a protected member of | 
|  | /// NamingClass would have some natural access in P, which implicitly | 
|  | /// imposes the constraint that P <= NamingClass. | 
|  | /// | 
|  | /// This isn't quite the condition laid out in the standard. | 
|  | /// Instead of saying that a notional protected member of NamingClass | 
|  | /// would have to have some natural access in P, it says the actual | 
|  | /// target has to have some natural access in P, which opens up the | 
|  | /// possibility that the target (which is not necessarily a member | 
|  | /// of NamingClass) might be more accessible along some path not | 
|  | /// passing through it.  That's really a bad idea, though, because it | 
|  | /// introduces two problems: | 
|  | ///   - Most importantly, it breaks encapsulation because you can | 
|  | ///     access a forbidden base class's members by directly subclassing | 
|  | ///     it elsewhere. | 
|  | ///   - It also makes access substantially harder to compute because it | 
|  | ///     breaks the hill-climbing algorithm: knowing that the target is | 
|  | ///     accessible in some base class would no longer let you change | 
|  | ///     the question solely to whether the base class is accessible, | 
|  | ///     because the original target might have been more accessible | 
|  | ///     because of crazy subclassing. | 
|  | /// So we don't implement that. | 
|  | static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC, | 
|  | const CXXRecordDecl *InstanceContext, | 
|  | const CXXRecordDecl *NamingClass) { | 
|  | assert(InstanceContext == 0 || | 
|  | InstanceContext->getCanonicalDecl() == InstanceContext); | 
|  | assert(NamingClass->getCanonicalDecl() == NamingClass); | 
|  |  | 
|  | // If we don't have an instance context, our constraints give us | 
|  | // that NamingClass <= P <= NamingClass, i.e. P == NamingClass. | 
|  | // This is just the usual friendship check. | 
|  | if (!InstanceContext) return GetFriendKind(S, EC, NamingClass); | 
|  |  | 
|  | ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass); | 
|  | if (PRC.findFriendship(InstanceContext)) return AR_accessible; | 
|  | if (PRC.EverDependent) return AR_dependent; | 
|  | return AR_inaccessible; | 
|  | } | 
|  |  | 
|  | static AccessResult HasAccess(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | const CXXRecordDecl *NamingClass, | 
|  | AccessSpecifier Access, | 
|  | const AccessTarget &Target) { | 
|  | assert(NamingClass->getCanonicalDecl() == NamingClass && | 
|  | "declaration should be canonicalized before being passed here"); | 
|  |  | 
|  | if (Access == AS_public) return AR_accessible; | 
|  | assert(Access == AS_private || Access == AS_protected); | 
|  |  | 
|  | AccessResult OnFailure = AR_inaccessible; | 
|  |  | 
|  | for (EffectiveContext::record_iterator | 
|  | I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { | 
|  | // All the declarations in EC have been canonicalized, so pointer | 
|  | // equality from this point on will work fine. | 
|  | const CXXRecordDecl *ECRecord = *I; | 
|  |  | 
|  | // [B2] and [M2] | 
|  | if (Access == AS_private) { | 
|  | if (ECRecord == NamingClass) | 
|  | return AR_accessible; | 
|  |  | 
|  | if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass)) | 
|  | OnFailure = AR_dependent; | 
|  |  | 
|  | // [B3] and [M3] | 
|  | } else { | 
|  | assert(Access == AS_protected); | 
|  | switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { | 
|  | case AR_accessible: break; | 
|  | case AR_inaccessible: continue; | 
|  | case AR_dependent: OnFailure = AR_dependent; continue; | 
|  | } | 
|  |  | 
|  | // C++ [class.protected]p1: | 
|  | //   An additional access check beyond those described earlier in | 
|  | //   [class.access] is applied when a non-static data member or | 
|  | //   non-static member function is a protected member of its naming | 
|  | //   class.  As described earlier, access to a protected member is | 
|  | //   granted because the reference occurs in a friend or member of | 
|  | //   some class C.  If the access is to form a pointer to member, | 
|  | //   the nested-name-specifier shall name C or a class derived from | 
|  | //   C. All other accesses involve a (possibly implicit) object | 
|  | //   expression. In this case, the class of the object expression | 
|  | //   shall be C or a class derived from C. | 
|  | // | 
|  | // We interpret this as a restriction on [M3]. | 
|  |  | 
|  | // In this part of the code, 'C' is just our context class ECRecord. | 
|  |  | 
|  | // These rules are different if we don't have an instance context. | 
|  | if (!Target.hasInstanceContext()) { | 
|  | // If it's not an instance member, these restrictions don't apply. | 
|  | if (!Target.isInstanceMember()) return AR_accessible; | 
|  |  | 
|  | // If it's an instance member, use the pointer-to-member rule | 
|  | // that the naming class has to be derived from the effective | 
|  | // context. | 
|  |  | 
|  | // Emulate a MSVC bug where the creation of pointer-to-member | 
|  | // to protected member of base class is allowed but only from | 
|  | // static member functions. | 
|  | if (S.getLangOpts().MicrosoftMode && !EC.Functions.empty()) | 
|  | if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front())) | 
|  | if (MD->isStatic()) return AR_accessible; | 
|  |  | 
|  | // Despite the standard's confident wording, there is a case | 
|  | // where you can have an instance member that's neither in a | 
|  | // pointer-to-member expression nor in a member access:  when | 
|  | // it names a field in an unevaluated context that can't be an | 
|  | // implicit member.  Pending clarification, we just apply the | 
|  | // same naming-class restriction here. | 
|  | //   FIXME: we're probably not correctly adding the | 
|  | //   protected-member restriction when we retroactively convert | 
|  | //   an expression to being evaluated. | 
|  |  | 
|  | // We know that ECRecord derives from NamingClass.  The | 
|  | // restriction says to check whether NamingClass derives from | 
|  | // ECRecord, but that's not really necessary: two distinct | 
|  | // classes can't be recursively derived from each other.  So | 
|  | // along this path, we just need to check whether the classes | 
|  | // are equal. | 
|  | if (NamingClass == ECRecord) return AR_accessible; | 
|  |  | 
|  | // Otherwise, this context class tells us nothing;  on to the next. | 
|  | continue; | 
|  | } | 
|  |  | 
|  | assert(Target.isInstanceMember()); | 
|  |  | 
|  | const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); | 
|  | if (!InstanceContext) { | 
|  | OnFailure = AR_dependent; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { | 
|  | case AR_accessible: return AR_accessible; | 
|  | case AR_inaccessible: continue; | 
|  | case AR_dependent: OnFailure = AR_dependent; continue; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // [M3] and [B3] say that, if the target is protected in N, we grant | 
|  | // access if the access occurs in a friend or member of some class P | 
|  | // that's a subclass of N and where the target has some natural | 
|  | // access in P.  The 'member' aspect is easy to handle because P | 
|  | // would necessarily be one of the effective-context records, and we | 
|  | // address that above.  The 'friend' aspect is completely ridiculous | 
|  | // to implement because there are no restrictions at all on P | 
|  | // *unless* the [class.protected] restriction applies.  If it does, | 
|  | // however, we should ignore whether the naming class is a friend, | 
|  | // and instead rely on whether any potential P is a friend. | 
|  | if (Access == AS_protected && Target.isInstanceMember()) { | 
|  | // Compute the instance context if possible. | 
|  | const CXXRecordDecl *InstanceContext = 0; | 
|  | if (Target.hasInstanceContext()) { | 
|  | InstanceContext = Target.resolveInstanceContext(S); | 
|  | if (!InstanceContext) return AR_dependent; | 
|  | } | 
|  |  | 
|  | switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) { | 
|  | case AR_accessible: return AR_accessible; | 
|  | case AR_inaccessible: return OnFailure; | 
|  | case AR_dependent: return AR_dependent; | 
|  | } | 
|  | llvm_unreachable("impossible friendship kind"); | 
|  | } | 
|  |  | 
|  | switch (GetFriendKind(S, EC, NamingClass)) { | 
|  | case AR_accessible: return AR_accessible; | 
|  | case AR_inaccessible: return OnFailure; | 
|  | case AR_dependent: return AR_dependent; | 
|  | } | 
|  |  | 
|  | // Silence bogus warnings | 
|  | llvm_unreachable("impossible friendship kind"); | 
|  | } | 
|  |  | 
|  | /// Finds the best path from the naming class to the declaring class, | 
|  | /// taking friend declarations into account. | 
|  | /// | 
|  | /// C++0x [class.access.base]p5: | 
|  | ///   A member m is accessible at the point R when named in class N if | 
|  | ///   [M1] m as a member of N is public, or | 
|  | ///   [M2] m as a member of N is private, and R occurs in a member or | 
|  | ///        friend of class N, or | 
|  | ///   [M3] m as a member of N is protected, and R occurs in a member or | 
|  | ///        friend of class N, or in a member or friend of a class P | 
|  | ///        derived from N, where m as a member of P is public, private, | 
|  | ///        or protected, or | 
|  | ///   [M4] there exists a base class B of N that is accessible at R, and | 
|  | ///        m is accessible at R when named in class B. | 
|  | /// | 
|  | /// C++0x [class.access.base]p4: | 
|  | ///   A base class B of N is accessible at R, if | 
|  | ///   [B1] an invented public member of B would be a public member of N, or | 
|  | ///   [B2] R occurs in a member or friend of class N, and an invented public | 
|  | ///        member of B would be a private or protected member of N, or | 
|  | ///   [B3] R occurs in a member or friend of a class P derived from N, and an | 
|  | ///        invented public member of B would be a private or protected member | 
|  | ///        of P, or | 
|  | ///   [B4] there exists a class S such that B is a base class of S accessible | 
|  | ///        at R and S is a base class of N accessible at R. | 
|  | /// | 
|  | /// Along a single inheritance path we can restate both of these | 
|  | /// iteratively: | 
|  | /// | 
|  | /// First, we note that M1-4 are equivalent to B1-4 if the member is | 
|  | /// treated as a notional base of its declaring class with inheritance | 
|  | /// access equivalent to the member's access.  Therefore we need only | 
|  | /// ask whether a class B is accessible from a class N in context R. | 
|  | /// | 
|  | /// Let B_1 .. B_n be the inheritance path in question (i.e. where | 
|  | /// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of | 
|  | /// B_i).  For i in 1..n, we will calculate ACAB(i), the access to the | 
|  | /// closest accessible base in the path: | 
|  | ///   Access(a, b) = (* access on the base specifier from a to b *) | 
|  | ///   Merge(a, forbidden) = forbidden | 
|  | ///   Merge(a, private) = forbidden | 
|  | ///   Merge(a, b) = min(a,b) | 
|  | ///   Accessible(c, forbidden) = false | 
|  | ///   Accessible(c, private) = (R is c) || IsFriend(c, R) | 
|  | ///   Accessible(c, protected) = (R derived from c) || IsFriend(c, R) | 
|  | ///   Accessible(c, public) = true | 
|  | ///   ACAB(n) = public | 
|  | ///   ACAB(i) = | 
|  | ///     let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in | 
|  | ///     if Accessible(B_i, AccessToBase) then public else AccessToBase | 
|  | /// | 
|  | /// B is an accessible base of N at R iff ACAB(1) = public. | 
|  | /// | 
|  | /// \param FinalAccess the access of the "final step", or AS_public if | 
|  | ///   there is no final step. | 
|  | /// \return null if friendship is dependent | 
|  | static CXXBasePath *FindBestPath(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | AccessTarget &Target, | 
|  | AccessSpecifier FinalAccess, | 
|  | CXXBasePaths &Paths) { | 
|  | // Derive the paths to the desired base. | 
|  | const CXXRecordDecl *Derived = Target.getNamingClass(); | 
|  | const CXXRecordDecl *Base = Target.getDeclaringClass(); | 
|  |  | 
|  | // FIXME: fail correctly when there are dependent paths. | 
|  | bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base), | 
|  | Paths); | 
|  | assert(isDerived && "derived class not actually derived from base"); | 
|  | (void) isDerived; | 
|  |  | 
|  | CXXBasePath *BestPath = 0; | 
|  |  | 
|  | assert(FinalAccess != AS_none && "forbidden access after declaring class"); | 
|  |  | 
|  | bool AnyDependent = false; | 
|  |  | 
|  | // Derive the friend-modified access along each path. | 
|  | for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); | 
|  | PI != PE; ++PI) { | 
|  | AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext(); | 
|  |  | 
|  | // Walk through the path backwards. | 
|  | AccessSpecifier PathAccess = FinalAccess; | 
|  | CXXBasePath::iterator I = PI->end(), E = PI->begin(); | 
|  | while (I != E) { | 
|  | --I; | 
|  |  | 
|  | assert(PathAccess != AS_none); | 
|  |  | 
|  | // If the declaration is a private member of a base class, there | 
|  | // is no level of friendship in derived classes that can make it | 
|  | // accessible. | 
|  | if (PathAccess == AS_private) { | 
|  | PathAccess = AS_none; | 
|  | break; | 
|  | } | 
|  |  | 
|  | const CXXRecordDecl *NC = I->Class->getCanonicalDecl(); | 
|  |  | 
|  | AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); | 
|  | PathAccess = std::max(PathAccess, BaseAccess); | 
|  |  | 
|  | switch (HasAccess(S, EC, NC, PathAccess, Target)) { | 
|  | case AR_inaccessible: break; | 
|  | case AR_accessible: | 
|  | PathAccess = AS_public; | 
|  |  | 
|  | // Future tests are not against members and so do not have | 
|  | // instance context. | 
|  | Target.suppressInstanceContext(); | 
|  | break; | 
|  | case AR_dependent: | 
|  | AnyDependent = true; | 
|  | goto Next; | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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; | 
|  |  | 
|  | // Short-circuit if we found a public path. | 
|  | if (BestPath->Access == AS_public) | 
|  | return BestPath; | 
|  | } | 
|  |  | 
|  | Next: ; | 
|  | } | 
|  |  | 
|  | assert((!BestPath || BestPath->Access != AS_public) && | 
|  | "fell out of loop with public path"); | 
|  |  | 
|  | // We didn't find a public path, but at least one path was subject | 
|  | // to dependent friendship, so delay the check. | 
|  | if (AnyDependent) | 
|  | return 0; | 
|  |  | 
|  | return BestPath; | 
|  | } | 
|  |  | 
|  | /// Given that an entity has protected natural access, check whether | 
|  | /// access might be denied because of the protected member access | 
|  | /// restriction. | 
|  | /// | 
|  | /// \return true if a note was emitted | 
|  | static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC, | 
|  | AccessTarget &Target) { | 
|  | // Only applies to instance accesses. | 
|  | if (!Target.isInstanceMember()) | 
|  | return false; | 
|  |  | 
|  | assert(Target.isMemberAccess()); | 
|  |  | 
|  | const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass(); | 
|  |  | 
|  | for (EffectiveContext::record_iterator | 
|  | I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { | 
|  | const CXXRecordDecl *ECRecord = *I; | 
|  | switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { | 
|  | case AR_accessible: break; | 
|  | case AR_inaccessible: continue; | 
|  | case AR_dependent: continue; | 
|  | } | 
|  |  | 
|  | // The effective context is a subclass of the declaring class. | 
|  | // Check whether the [class.protected] restriction is limiting | 
|  | // access. | 
|  |  | 
|  | // To get this exactly right, this might need to be checked more | 
|  | // holistically;  it's not necessarily the case that gaining | 
|  | // access here would grant us access overall. | 
|  |  | 
|  | NamedDecl *D = Target.getTargetDecl(); | 
|  |  | 
|  | // If we don't have an instance context, [class.protected] says the | 
|  | // naming class has to equal the context class. | 
|  | if (!Target.hasInstanceContext()) { | 
|  | // If it does, the restriction doesn't apply. | 
|  | if (NamingClass == ECRecord) continue; | 
|  |  | 
|  | // TODO: it would be great to have a fixit here, since this is | 
|  | // such an obvious error. | 
|  | S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject) | 
|  | << S.Context.getTypeDeclType(ECRecord); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); | 
|  | assert(InstanceContext && "diagnosing dependent access"); | 
|  |  | 
|  | switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { | 
|  | case AR_accessible: continue; | 
|  | case AR_dependent: continue; | 
|  | case AR_inaccessible: | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Okay, the restriction seems to be what's limiting us. | 
|  |  | 
|  | // Use a special diagnostic for constructors and destructors. | 
|  | if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) || | 
|  | (isa<FunctionTemplateDecl>(D) && | 
|  | isa<CXXConstructorDecl>( | 
|  | cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) { | 
|  | S.Diag(D->getLocation(), diag::note_access_protected_restricted_ctordtor) | 
|  | << isa<CXXDestructorDecl>(D); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Otherwise, use the generic diagnostic. | 
|  | S.Diag(D->getLocation(), diag::note_access_protected_restricted_object) | 
|  | << S.Context.getTypeDeclType(ECRecord); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// We are unable to access a given declaration due to its direct | 
|  | /// access control;  diagnose that. | 
|  | static void diagnoseBadDirectAccess(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | AccessTarget &entity) { | 
|  | assert(entity.isMemberAccess()); | 
|  | NamedDecl *D = entity.getTargetDecl(); | 
|  |  | 
|  | if (D->getAccess() == AS_protected && | 
|  | TryDiagnoseProtectedAccess(S, EC, entity)) | 
|  | return; | 
|  |  | 
|  | // Find an original declaration. | 
|  | while (D->isOutOfLine()) { | 
|  | NamedDecl *PrevDecl = 0; | 
|  | if (VarDecl *VD = dyn_cast<VarDecl>(D)) | 
|  | PrevDecl = VD->getPreviousDecl(); | 
|  | else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) | 
|  | PrevDecl = FD->getPreviousDecl(); | 
|  | else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D)) | 
|  | PrevDecl = TND->getPreviousDecl(); | 
|  | else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { | 
|  | if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName()) | 
|  | break; | 
|  | PrevDecl = TD->getPreviousDecl(); | 
|  | } | 
|  | if (!PrevDecl) break; | 
|  | D = PrevDecl; | 
|  | } | 
|  |  | 
|  | CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); | 
|  | Decl *ImmediateChild; | 
|  | if (D->getDeclContext() == DeclaringClass) | 
|  | ImmediateChild = D; | 
|  | else { | 
|  | DeclContext *DC = D->getDeclContext(); | 
|  | while (DC->getParent() != DeclaringClass) | 
|  | DC = DC->getParent(); | 
|  | ImmediateChild = cast<Decl>(DC); | 
|  | } | 
|  |  | 
|  | // Check whether there's an AccessSpecDecl preceding this in the | 
|  | // chain of the DeclContext. | 
|  | bool isImplicit = true; | 
|  | for (CXXRecordDecl::decl_iterator | 
|  | I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end(); | 
|  | I != E; ++I) { | 
|  | if (*I == ImmediateChild) break; | 
|  | if (isa<AccessSpecDecl>(*I)) { | 
|  | isImplicit = false; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | S.Diag(D->getLocation(), diag::note_access_natural) | 
|  | << (unsigned) (D->getAccess() == AS_protected) | 
|  | << isImplicit; | 
|  | } | 
|  |  | 
|  | /// Diagnose the path which caused the given declaration or base class | 
|  | /// to become inaccessible. | 
|  | static void DiagnoseAccessPath(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | AccessTarget &entity) { | 
|  | // Save the instance context to preserve invariants. | 
|  | AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext(); | 
|  |  | 
|  | // This basically repeats the main algorithm but keeps some more | 
|  | // information. | 
|  |  | 
|  | // The natural access so far. | 
|  | AccessSpecifier accessSoFar = AS_public; | 
|  |  | 
|  | // Check whether we have special rights to the declaring class. | 
|  | if (entity.isMemberAccess()) { | 
|  | NamedDecl *D = entity.getTargetDecl(); | 
|  | accessSoFar = D->getAccess(); | 
|  | const CXXRecordDecl *declaringClass = entity.getDeclaringClass(); | 
|  |  | 
|  | switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) { | 
|  | // If the declaration is accessible when named in its declaring | 
|  | // class, then we must be constrained by the path. | 
|  | case AR_accessible: | 
|  | accessSoFar = AS_public; | 
|  | entity.suppressInstanceContext(); | 
|  | break; | 
|  |  | 
|  | case AR_inaccessible: | 
|  | if (accessSoFar == AS_private || | 
|  | declaringClass == entity.getEffectiveNamingClass()) | 
|  | return diagnoseBadDirectAccess(S, EC, entity); | 
|  | break; | 
|  |  | 
|  | case AR_dependent: | 
|  | llvm_unreachable("cannot diagnose dependent access"); | 
|  | } | 
|  | } | 
|  |  | 
|  | CXXBasePaths paths; | 
|  | CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths); | 
|  | assert(path.Access != AS_public); | 
|  |  | 
|  | CXXBasePath::iterator i = path.end(), e = path.begin(); | 
|  | CXXBasePath::iterator constrainingBase = i; | 
|  | while (i != e) { | 
|  | --i; | 
|  |  | 
|  | assert(accessSoFar != AS_none && accessSoFar != AS_private); | 
|  |  | 
|  | // Is the entity accessible when named in the deriving class, as | 
|  | // modified by the base specifier? | 
|  | const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl(); | 
|  | const CXXBaseSpecifier *base = i->Base; | 
|  |  | 
|  | // If the access to this base is worse than the access we have to | 
|  | // the declaration, remember it. | 
|  | AccessSpecifier baseAccess = base->getAccessSpecifier(); | 
|  | if (baseAccess > accessSoFar) { | 
|  | constrainingBase = i; | 
|  | accessSoFar = baseAccess; | 
|  | } | 
|  |  | 
|  | switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) { | 
|  | case AR_inaccessible: break; | 
|  | case AR_accessible: | 
|  | accessSoFar = AS_public; | 
|  | entity.suppressInstanceContext(); | 
|  | constrainingBase = 0; | 
|  | break; | 
|  | case AR_dependent: | 
|  | llvm_unreachable("cannot diagnose dependent access"); | 
|  | } | 
|  |  | 
|  | // If this was private inheritance, but we don't have access to | 
|  | // the deriving class, we're done. | 
|  | if (accessSoFar == AS_private) { | 
|  | assert(baseAccess == AS_private); | 
|  | assert(constrainingBase == i); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // If we don't have a constraining base, the access failure must be | 
|  | // due to the original declaration. | 
|  | if (constrainingBase == path.end()) | 
|  | return diagnoseBadDirectAccess(S, EC, entity); | 
|  |  | 
|  | // 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 (entity.isMemberAccess() || | 
|  | constrainingBase + 1 != path.end()) { | 
|  | diagnostic = diag::note_access_constrained_by_path; | 
|  | } else { | 
|  | diagnostic = diag::note_access_natural; | 
|  | } | 
|  |  | 
|  | const CXXBaseSpecifier *base = constrainingBase->Base; | 
|  |  | 
|  | S.Diag(base->getSourceRange().getBegin(), diagnostic) | 
|  | << base->getSourceRange() | 
|  | << (base->getAccessSpecifier() == AS_protected) | 
|  | << (base->getAccessSpecifierAsWritten() == AS_none); | 
|  |  | 
|  | if (entity.isMemberAccess()) | 
|  | S.Diag(entity.getTargetDecl()->getLocation(), diag::note_field_decl); | 
|  | } | 
|  |  | 
|  | static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, | 
|  | const EffectiveContext &EC, | 
|  | AccessTarget &Entity) { | 
|  | const CXXRecordDecl *NamingClass = Entity.getNamingClass(); | 
|  | const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); | 
|  | NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); | 
|  |  | 
|  | S.Diag(Loc, Entity.getDiag()) | 
|  | << (Entity.getAccess() == AS_protected) | 
|  | << (D ? D->getDeclName() : DeclarationName()) | 
|  | << S.Context.getTypeDeclType(NamingClass) | 
|  | << S.Context.getTypeDeclType(DeclaringClass); | 
|  | DiagnoseAccessPath(S, EC, Entity); | 
|  | } | 
|  |  | 
|  | /// MSVC has a bug where if during an using declaration name lookup, | 
|  | /// the declaration found is unaccessible (private) and that declaration | 
|  | /// was bring into scope via another using declaration whose target | 
|  | /// declaration is accessible (public) then no error is generated. | 
|  | /// Example: | 
|  | ///   class A { | 
|  | ///   public: | 
|  | ///     int f(); | 
|  | ///   }; | 
|  | ///   class B : public A { | 
|  | ///   private: | 
|  | ///     using A::f; | 
|  | ///   }; | 
|  | ///   class C : public B { | 
|  | ///   private: | 
|  | ///     using B::f; | 
|  | ///   }; | 
|  | /// | 
|  | /// Here, B::f is private so this should fail in Standard C++, but | 
|  | /// because B::f refers to A::f which is public MSVC accepts it. | 
|  | static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S, | 
|  | SourceLocation AccessLoc, | 
|  | AccessTarget &Entity) { | 
|  | if (UsingShadowDecl *Shadow = | 
|  | dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) { | 
|  | const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl(); | 
|  | if (Entity.getTargetDecl()->getAccess() == AS_private && | 
|  | (OrigDecl->getAccess() == AS_public || | 
|  | OrigDecl->getAccess() == AS_protected)) { | 
|  | S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible) | 
|  | << Shadow->getUsingDecl()->getQualifiedNameAsString() | 
|  | << OrigDecl->getQualifiedNameAsString(); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// 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. | 
|  | const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass(); | 
|  |  | 
|  | 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: | 
|  | // Target is accessible at EC when named in its declaring class. | 
|  | // We can now hill-climb and simply check whether the declaring | 
|  | // class is accessible as a base of the naming class.  This is | 
|  | // equivalent to checking the access of a notional public | 
|  | // member with no instance context. | 
|  | FinalAccess = AS_public; | 
|  | Entity.suppressInstanceContext(); | 
|  | break; | 
|  | case AR_inaccessible: break; | 
|  | case AR_dependent: return AR_dependent; // see above | 
|  | } | 
|  |  | 
|  | if (DeclaringClass == NamingClass) | 
|  | return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible); | 
|  | } 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; | 
|  | } | 
|  |  | 
|  | static void DelayDependentAccess(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | SourceLocation Loc, | 
|  | const AccessTarget &Entity) { | 
|  | assert(EC.isDependent() && "delaying non-dependent access"); | 
|  | DeclContext *DC = EC.getInnerContext(); | 
|  | assert(DC->isDependentContext() && "delaying non-dependent access"); | 
|  | DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access, | 
|  | Loc, | 
|  | Entity.isMemberAccess(), | 
|  | Entity.getAccess(), | 
|  | Entity.getTargetDecl(), | 
|  | Entity.getNamingClass(), | 
|  | Entity.getBaseObjectType(), | 
|  | Entity.getDiag()); | 
|  | } | 
|  |  | 
|  | /// Checks access to an entity from the given effective context. | 
|  | static AccessResult CheckEffectiveAccess(Sema &S, | 
|  | const EffectiveContext &EC, | 
|  | SourceLocation Loc, | 
|  | AccessTarget &Entity) { | 
|  | assert(Entity.getAccess() != AS_public && "called for public access!"); | 
|  |  | 
|  | if (S.getLangOpts().MicrosoftMode && | 
|  | IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) | 
|  | return AR_accessible; | 
|  |  | 
|  | switch (IsAccessible(S, EC, Entity)) { | 
|  | case AR_dependent: | 
|  | DelayDependentAccess(S, EC, Loc, Entity); | 
|  | return AR_dependent; | 
|  |  | 
|  | case AR_inaccessible: | 
|  | if (!Entity.isQuiet()) | 
|  | DiagnoseBadAccess(S, Loc, EC, Entity); | 
|  | return AR_inaccessible; | 
|  |  | 
|  | case AR_accessible: | 
|  | return AR_accessible; | 
|  | } | 
|  |  | 
|  | // silence unnecessary warning | 
|  | llvm_unreachable("invalid access result"); | 
|  | } | 
|  |  | 
|  | static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, | 
|  | AccessTarget &Entity) { | 
|  | // 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 declaration, we may need to delay | 
|  | // access control checking, because our effective context might be | 
|  | // different based on what the declaration comes out as. | 
|  | // | 
|  | // For example, we might be parsing a declaration with a scope | 
|  | // specifier, like this: | 
|  | //   A::private_type A::foo() { ... } | 
|  | // | 
|  | // Or we might be parsing something that will turn out to be a friend: | 
|  | //   void foo(A::private_type); | 
|  | //   void B::foo(A::private_type); | 
|  | if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { | 
|  | S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity)); | 
|  | return Sema::AR_delayed; | 
|  | } | 
|  |  | 
|  | EffectiveContext EC(S.CurContext); | 
|  | switch (CheckEffectiveAccess(S, EC, Loc, Entity)) { | 
|  | case AR_accessible: return Sema::AR_accessible; | 
|  | case AR_inaccessible: return Sema::AR_inaccessible; | 
|  | case AR_dependent: return Sema::AR_dependent; | 
|  | } | 
|  | llvm_unreachable("falling off end"); | 
|  | } | 
|  |  | 
|  | void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) { | 
|  | // Access control for names used in the declarations of functions | 
|  | // and function templates should normally be evaluated in the context | 
|  | // of the declaration, just in case it's a friend of something. | 
|  | // However, this does not apply to local extern declarations. | 
|  |  | 
|  | DeclContext *DC = D->getDeclContext(); | 
|  | if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) { | 
|  | if (D->getLexicalDeclContext()->isFunctionOrMethod()) | 
|  | DC = D->getLexicalDeclContext(); | 
|  | else | 
|  | DC = FN; | 
|  | } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) { | 
|  | DC = cast<DeclContext>(TD->getTemplatedDecl()); | 
|  | } | 
|  |  | 
|  | EffectiveContext EC(DC); | 
|  |  | 
|  | AccessTarget Target(DD.getAccessData()); | 
|  |  | 
|  | if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible) | 
|  | DD.Triggered = true; | 
|  | } | 
|  |  | 
|  | void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, | 
|  | const MultiLevelTemplateArgumentList &TemplateArgs) { | 
|  | SourceLocation Loc = DD.getAccessLoc(); | 
|  | AccessSpecifier Access = DD.getAccess(); | 
|  |  | 
|  | Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(), | 
|  | TemplateArgs); | 
|  | if (!NamingD) return; | 
|  | Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(), | 
|  | TemplateArgs); | 
|  | if (!TargetD) return; | 
|  |  | 
|  | if (DD.isAccessToMember()) { | 
|  | CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD); | 
|  | NamedDecl *TargetDecl = cast<NamedDecl>(TargetD); | 
|  | QualType BaseObjectType = DD.getAccessBaseObjectType(); | 
|  | if (!BaseObjectType.isNull()) { | 
|  | BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc, | 
|  | DeclarationName()); | 
|  | if (BaseObjectType.isNull()) return; | 
|  | } | 
|  |  | 
|  | AccessTarget Entity(Context, | 
|  | AccessTarget::Member, | 
|  | NamingClass, | 
|  | DeclAccessPair::make(TargetDecl, Access), | 
|  | BaseObjectType); | 
|  | Entity.setDiag(DD.getDiagnostic()); | 
|  | CheckAccess(*this, Loc, Entity); | 
|  | } else { | 
|  | AccessTarget Entity(Context, | 
|  | AccessTarget::Base, | 
|  | cast<CXXRecordDecl>(TargetD), | 
|  | cast<CXXRecordDecl>(NamingD), | 
|  | Access); | 
|  | Entity.setDiag(DD.getDiagnostic()); | 
|  | CheckAccess(*this, Loc, Entity); | 
|  | } | 
|  | } | 
|  |  | 
|  | Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, | 
|  | DeclAccessPair Found) { | 
|  | if (!getLangOpts().AccessControl || | 
|  | !E->getNamingClass() || | 
|  | Found.getAccess() == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), | 
|  | Found, QualType()); | 
|  | Entity.setDiag(diag::err_access) << E->getSourceRange(); | 
|  |  | 
|  | return CheckAccess(*this, E->getNameLoc(), Entity); | 
|  | } | 
|  |  | 
|  | /// Perform access-control checking on a previously-unresolved member | 
|  | /// access which has now been resolved to a member. | 
|  | Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, | 
|  | DeclAccessPair Found) { | 
|  | if (!getLangOpts().AccessControl || | 
|  | Found.getAccess() == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | QualType BaseType = E->getBaseType(); | 
|  | if (E->isArrow()) | 
|  | BaseType = BaseType->getAs<PointerType>()->getPointeeType(); | 
|  |  | 
|  | AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), | 
|  | Found, BaseType); | 
|  | Entity.setDiag(diag::err_access) << E->getSourceRange(); | 
|  |  | 
|  | return CheckAccess(*this, E->getMemberLoc(), Entity); | 
|  | } | 
|  |  | 
|  | /// Is the given special member function accessible for the purposes of | 
|  | /// deciding whether to define a special member function as deleted? | 
|  | bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, | 
|  | AccessSpecifier access, | 
|  | QualType objectType) { | 
|  | // Fast path. | 
|  | if (access == AS_public || !getLangOpts().AccessControl) return true; | 
|  |  | 
|  | AccessTarget entity(Context, AccessTarget::Member, decl->getParent(), | 
|  | DeclAccessPair::make(decl, access), objectType); | 
|  |  | 
|  | // Suppress diagnostics. | 
|  | entity.setDiag(PDiag()); | 
|  |  | 
|  | switch (CheckAccess(*this, SourceLocation(), entity)) { | 
|  | case AR_accessible: return true; | 
|  | case AR_inaccessible: return false; | 
|  | case AR_dependent: llvm_unreachable("dependent for =delete computation"); | 
|  | case AR_delayed: llvm_unreachable("cannot delay =delete computation"); | 
|  | } | 
|  | llvm_unreachable("bad access result"); | 
|  | } | 
|  |  | 
|  | Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, | 
|  | CXXDestructorDecl *Dtor, | 
|  | const PartialDiagnostic &PDiag, | 
|  | QualType ObjectTy) { | 
|  | if (!getLangOpts().AccessControl) | 
|  | return AR_accessible; | 
|  |  | 
|  | // There's never a path involved when checking implicit destructor access. | 
|  | AccessSpecifier Access = Dtor->getAccess(); | 
|  | if (Access == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | CXXRecordDecl *NamingClass = Dtor->getParent(); | 
|  | if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass); | 
|  |  | 
|  | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, | 
|  | DeclAccessPair::make(Dtor, Access), | 
|  | ObjectTy); | 
|  | Entity.setDiag(PDiag); // TODO: avoid copy | 
|  |  | 
|  | return CheckAccess(*this, Loc, Entity); | 
|  | } | 
|  |  | 
|  | /// Checks access to a constructor. | 
|  | Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, | 
|  | CXXConstructorDecl *Constructor, | 
|  | const InitializedEntity &Entity, | 
|  | AccessSpecifier Access, | 
|  | bool IsCopyBindingRefToTemp) { | 
|  | if (!getLangOpts().AccessControl || Access == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | PartialDiagnostic PD(PDiag()); | 
|  | switch (Entity.getKind()) { | 
|  | default: | 
|  | PD = PDiag(IsCopyBindingRefToTemp | 
|  | ? diag::ext_rvalue_to_reference_access_ctor | 
|  | : diag::err_access_ctor); | 
|  |  | 
|  | break; | 
|  |  | 
|  | case InitializedEntity::EK_Base: | 
|  | PD = PDiag(diag::err_access_base_ctor); | 
|  | PD << Entity.isInheritedVirtualBase() | 
|  | << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor); | 
|  | break; | 
|  |  | 
|  | case InitializedEntity::EK_Member: { | 
|  | const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); | 
|  | PD = PDiag(diag::err_access_field_ctor); | 
|  | PD << Field->getType() << getSpecialMember(Constructor); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case InitializedEntity::EK_LambdaCapture: { | 
|  | const VarDecl *Var = Entity.getCapturedVar(); | 
|  | PD = PDiag(diag::err_access_lambda_capture); | 
|  | PD << Var->getName() << Entity.getType() << getSpecialMember(Constructor); | 
|  | break; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD); | 
|  | } | 
|  |  | 
|  | /// Checks access to a constructor. | 
|  | Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, | 
|  | CXXConstructorDecl *Constructor, | 
|  | const InitializedEntity &Entity, | 
|  | AccessSpecifier Access, | 
|  | const PartialDiagnostic &PD) { | 
|  | if (!getLangOpts().AccessControl || | 
|  | Access == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | CXXRecordDecl *NamingClass = Constructor->getParent(); | 
|  |  | 
|  | // Initializing a base sub-object is an instance method call on an | 
|  | // object of the derived class.  Otherwise, we have an instance method | 
|  | // call on an object of the constructed type. | 
|  | CXXRecordDecl *ObjectClass; | 
|  | if (Entity.getKind() == InitializedEntity::EK_Base) { | 
|  | ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent(); | 
|  | } else { | 
|  | ObjectClass = NamingClass; | 
|  | } | 
|  |  | 
|  | AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, | 
|  | DeclAccessPair::make(Constructor, Access), | 
|  | Context.getTypeDeclType(ObjectClass)); | 
|  | AccessEntity.setDiag(PD); | 
|  |  | 
|  | return CheckAccess(*this, UseLoc, AccessEntity); | 
|  | } | 
|  |  | 
|  | /// Checks access to an overloaded operator new or delete. | 
|  | Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, | 
|  | SourceRange PlacementRange, | 
|  | CXXRecordDecl *NamingClass, | 
|  | DeclAccessPair Found, | 
|  | bool Diagnose) { | 
|  | if (!getLangOpts().AccessControl || | 
|  | !NamingClass || | 
|  | Found.getAccess() == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, | 
|  | QualType()); | 
|  | if (Diagnose) | 
|  | Entity.setDiag(diag::err_access) | 
|  | << PlacementRange; | 
|  |  | 
|  | return CheckAccess(*this, OpLoc, Entity); | 
|  | } | 
|  |  | 
|  | /// \brief Checks access to a member. | 
|  | Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc, | 
|  | CXXRecordDecl *NamingClass, | 
|  | DeclAccessPair Found) { | 
|  | if (!getLangOpts().AccessControl || | 
|  | !NamingClass || | 
|  | Found.getAccess() == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, | 
|  | Found, QualType()); | 
|  |  | 
|  | return CheckAccess(*this, UseLoc, Entity); | 
|  | } | 
|  |  | 
|  | /// Checks access to an overloaded member operator, including | 
|  | /// conversion operators. | 
|  | Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, | 
|  | Expr *ObjectExpr, | 
|  | Expr *ArgExpr, | 
|  | DeclAccessPair Found) { | 
|  | if (!getLangOpts().AccessControl || | 
|  | Found.getAccess() == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>(); | 
|  | CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); | 
|  |  | 
|  | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, | 
|  | ObjectExpr->getType()); | 
|  | Entity.setDiag(diag::err_access) | 
|  | << ObjectExpr->getSourceRange() | 
|  | << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); | 
|  |  | 
|  | return CheckAccess(*this, OpLoc, Entity); | 
|  | } | 
|  |  | 
|  | /// Checks access to the target of a friend declaration. | 
|  | Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) { | 
|  | assert(isa<CXXMethodDecl>(target) || | 
|  | (isa<FunctionTemplateDecl>(target) && | 
|  | isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(target) | 
|  | ->getTemplatedDecl()))); | 
|  |  | 
|  | // Friendship lookup is a redeclaration lookup, so there's never an | 
|  | // inheritance path modifying access. | 
|  | AccessSpecifier access = target->getAccess(); | 
|  |  | 
|  | if (!getLangOpts().AccessControl || access == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(target); | 
|  | if (!method) | 
|  | method = cast<CXXMethodDecl>( | 
|  | cast<FunctionTemplateDecl>(target)->getTemplatedDecl()); | 
|  | assert(method->getQualifier()); | 
|  |  | 
|  | AccessTarget entity(Context, AccessTarget::Member, | 
|  | cast<CXXRecordDecl>(target->getDeclContext()), | 
|  | DeclAccessPair::make(target, access), | 
|  | /*no instance context*/ QualType()); | 
|  | entity.setDiag(diag::err_access_friend_function) | 
|  | << method->getQualifierLoc().getSourceRange(); | 
|  |  | 
|  | // We need to bypass delayed-diagnostics because we might be called | 
|  | // while the ParsingDeclarator is active. | 
|  | EffectiveContext EC(CurContext); | 
|  | switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) { | 
|  | case AR_accessible: return Sema::AR_accessible; | 
|  | case AR_inaccessible: return Sema::AR_inaccessible; | 
|  | case AR_dependent: return Sema::AR_dependent; | 
|  | } | 
|  | llvm_unreachable("falling off end"); | 
|  | } | 
|  |  | 
|  | Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, | 
|  | DeclAccessPair Found) { | 
|  | if (!getLangOpts().AccessControl || | 
|  | Found.getAccess() == AS_none || | 
|  | Found.getAccess() == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression; | 
|  | CXXRecordDecl *NamingClass = Ovl->getNamingClass(); | 
|  |  | 
|  | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, | 
|  | /*no instance context*/ QualType()); | 
|  | Entity.setDiag(diag::err_access) | 
|  | << Ovl->getSourceRange(); | 
|  |  | 
|  | return CheckAccess(*this, Ovl->getNameLoc(), Entity); | 
|  | } | 
|  |  | 
|  | /// Checks access for a hierarchy conversion. | 
|  | /// | 
|  | /// \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 | 
|  | Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, | 
|  | QualType Base, | 
|  | QualType Derived, | 
|  | const CXXBasePath &Path, | 
|  | unsigned DiagID, | 
|  | bool ForceCheck, | 
|  | bool ForceUnprivileged) { | 
|  | if (!ForceCheck && !getLangOpts().AccessControl) | 
|  | return AR_accessible; | 
|  |  | 
|  | if (Path.Access == AS_public) | 
|  | return AR_accessible; | 
|  |  | 
|  | CXXRecordDecl *BaseD, *DerivedD; | 
|  | BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); | 
|  | DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); | 
|  |  | 
|  | AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD, | 
|  | Path.Access); | 
|  | if (DiagID) | 
|  | Entity.setDiag(DiagID) << Derived << Base; | 
|  |  | 
|  | if (ForceUnprivileged) { | 
|  | switch (CheckEffectiveAccess(*this, EffectiveContext(), | 
|  | AccessLoc, Entity)) { | 
|  | case ::AR_accessible: return Sema::AR_accessible; | 
|  | case ::AR_inaccessible: return Sema::AR_inaccessible; | 
|  | case ::AR_dependent: return Sema::AR_dependent; | 
|  | } | 
|  | llvm_unreachable("unexpected result from CheckEffectiveAccess"); | 
|  | } | 
|  | return CheckAccess(*this, AccessLoc, Entity); | 
|  | } | 
|  |  | 
|  | /// Checks access to all the declarations in the given result set. | 
|  | void Sema::CheckLookupAccess(const LookupResult &R) { | 
|  | assert(getLangOpts().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) { | 
|  | if (I.getAccess() != AS_public) { | 
|  | AccessTarget Entity(Context, AccessedEntity::Member, | 
|  | R.getNamingClass(), I.getPair(), | 
|  | R.getBaseObjectType()); | 
|  | Entity.setDiag(diag::err_access); | 
|  | CheckAccess(*this, R.getNameLoc(), Entity); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Checks access to Decl from the given class. The check will take access | 
|  | /// specifiers into account, but no member access expressions and such. | 
|  | /// | 
|  | /// \param Decl the declaration to check if it can be accessed | 
|  | /// \param Ctx the class/context from which to start the search | 
|  | /// \return true if the Decl is accessible from the Class, false otherwise. | 
|  | bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) { | 
|  | if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) { | 
|  | if (!Decl->isCXXClassMember()) | 
|  | return true; | 
|  |  | 
|  | QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal(); | 
|  | AccessTarget Entity(Context, AccessedEntity::Member, Class, | 
|  | DeclAccessPair::make(Decl, Decl->getAccess()), | 
|  | qType); | 
|  | if (Entity.getAccess() == AS_public) | 
|  | return true; | 
|  |  | 
|  | EffectiveContext EC(CurContext); | 
|  | return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; | 
|  | } | 
|  |  | 
|  | if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) { | 
|  | // @public and @package ivars are always accessible. | 
|  | if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public || | 
|  | Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package) | 
|  | return true; | 
|  |  | 
|  | // If we are inside a class or category implementation, determine the | 
|  | // interface we're in. | 
|  | ObjCInterfaceDecl *ClassOfMethodDecl = 0; | 
|  | if (ObjCMethodDecl *MD = getCurMethodDecl()) | 
|  | ClassOfMethodDecl =  MD->getClassInterface(); | 
|  | else if (FunctionDecl *FD = getCurFunctionDecl()) { | 
|  | if (ObjCImplDecl *Impl | 
|  | = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) { | 
|  | if (ObjCImplementationDecl *IMPD | 
|  | = dyn_cast<ObjCImplementationDecl>(Impl)) | 
|  | ClassOfMethodDecl = IMPD->getClassInterface(); | 
|  | else if (ObjCCategoryImplDecl* CatImplClass | 
|  | = dyn_cast<ObjCCategoryImplDecl>(Impl)) | 
|  | ClassOfMethodDecl = CatImplClass->getClassInterface(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // If we're not in an interface, this ivar is inaccessible. | 
|  | if (!ClassOfMethodDecl) | 
|  | return false; | 
|  |  | 
|  | // If we're inside the same interface that owns the ivar, we're fine. | 
|  | if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface())) | 
|  | return true; | 
|  |  | 
|  | // If the ivar is private, it's inaccessible. | 
|  | if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private) | 
|  | return false; | 
|  |  | 
|  | return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } |