17330f729Sjoerg //===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file provides Sema routines for C++ access control semantics.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "clang/Basic/Specifiers.h"
147330f729Sjoerg #include "clang/Sema/SemaInternal.h"
157330f729Sjoerg #include "clang/AST/ASTContext.h"
167330f729Sjoerg #include "clang/AST/CXXInheritance.h"
177330f729Sjoerg #include "clang/AST/DeclCXX.h"
187330f729Sjoerg #include "clang/AST/DeclFriend.h"
197330f729Sjoerg #include "clang/AST/DeclObjC.h"
207330f729Sjoerg #include "clang/AST/DependentDiagnostic.h"
217330f729Sjoerg #include "clang/AST/ExprCXX.h"
227330f729Sjoerg #include "clang/Sema/DelayedDiagnostic.h"
237330f729Sjoerg #include "clang/Sema/Initialization.h"
247330f729Sjoerg #include "clang/Sema/Lookup.h"
257330f729Sjoerg
267330f729Sjoerg using namespace clang;
277330f729Sjoerg using namespace sema;
287330f729Sjoerg
297330f729Sjoerg /// A copy of Sema's enum without AR_delayed.
307330f729Sjoerg enum AccessResult {
317330f729Sjoerg AR_accessible,
327330f729Sjoerg AR_inaccessible,
337330f729Sjoerg AR_dependent
347330f729Sjoerg };
357330f729Sjoerg
367330f729Sjoerg /// SetMemberAccessSpecifier - Set the access specifier of a member.
377330f729Sjoerg /// Returns true on error (when the previous member decl access specifier
387330f729Sjoerg /// is different from the new member decl access specifier).
SetMemberAccessSpecifier(NamedDecl * MemberDecl,NamedDecl * PrevMemberDecl,AccessSpecifier LexicalAS)397330f729Sjoerg bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
407330f729Sjoerg NamedDecl *PrevMemberDecl,
417330f729Sjoerg AccessSpecifier LexicalAS) {
427330f729Sjoerg if (!PrevMemberDecl) {
437330f729Sjoerg // Use the lexical access specifier.
447330f729Sjoerg MemberDecl->setAccess(LexicalAS);
457330f729Sjoerg return false;
467330f729Sjoerg }
477330f729Sjoerg
487330f729Sjoerg // C++ [class.access.spec]p3: When a member is redeclared its access
497330f729Sjoerg // specifier must be same as its initial declaration.
507330f729Sjoerg if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
517330f729Sjoerg Diag(MemberDecl->getLocation(),
527330f729Sjoerg diag::err_class_redeclared_with_different_access)
537330f729Sjoerg << MemberDecl << LexicalAS;
547330f729Sjoerg Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
557330f729Sjoerg << PrevMemberDecl << PrevMemberDecl->getAccess();
567330f729Sjoerg
577330f729Sjoerg MemberDecl->setAccess(LexicalAS);
587330f729Sjoerg return true;
597330f729Sjoerg }
607330f729Sjoerg
617330f729Sjoerg MemberDecl->setAccess(PrevMemberDecl->getAccess());
627330f729Sjoerg return false;
637330f729Sjoerg }
647330f729Sjoerg
FindDeclaringClass(NamedDecl * D)657330f729Sjoerg static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
667330f729Sjoerg DeclContext *DC = D->getDeclContext();
677330f729Sjoerg
687330f729Sjoerg // This can only happen at top: enum decls only "publish" their
697330f729Sjoerg // immediate members.
707330f729Sjoerg if (isa<EnumDecl>(DC))
717330f729Sjoerg DC = cast<EnumDecl>(DC)->getDeclContext();
727330f729Sjoerg
737330f729Sjoerg CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
747330f729Sjoerg while (DeclaringClass->isAnonymousStructOrUnion())
757330f729Sjoerg DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
767330f729Sjoerg return DeclaringClass;
777330f729Sjoerg }
787330f729Sjoerg
797330f729Sjoerg namespace {
807330f729Sjoerg struct EffectiveContext {
EffectiveContext__anon05ec4eb20111::EffectiveContext817330f729Sjoerg EffectiveContext() : Inner(nullptr), Dependent(false) {}
827330f729Sjoerg
EffectiveContext__anon05ec4eb20111::EffectiveContext837330f729Sjoerg explicit EffectiveContext(DeclContext *DC)
847330f729Sjoerg : Inner(DC),
857330f729Sjoerg Dependent(DC->isDependentContext()) {
867330f729Sjoerg
87*e038c9c4Sjoerg // An implicit deduction guide is semantically in the context enclosing the
88*e038c9c4Sjoerg // class template, but for access purposes behaves like the constructor
89*e038c9c4Sjoerg // from which it was produced.
90*e038c9c4Sjoerg if (auto *DGD = dyn_cast<CXXDeductionGuideDecl>(DC)) {
91*e038c9c4Sjoerg if (DGD->isImplicit()) {
92*e038c9c4Sjoerg DC = DGD->getCorrespondingConstructor();
93*e038c9c4Sjoerg if (!DC) {
94*e038c9c4Sjoerg // The copy deduction candidate doesn't have a corresponding
95*e038c9c4Sjoerg // constructor.
96*e038c9c4Sjoerg DC = cast<DeclContext>(DGD->getDeducedTemplate()->getTemplatedDecl());
97*e038c9c4Sjoerg }
98*e038c9c4Sjoerg }
99*e038c9c4Sjoerg }
100*e038c9c4Sjoerg
1017330f729Sjoerg // C++11 [class.access.nest]p1:
1027330f729Sjoerg // A nested class is a member and as such has the same access
1037330f729Sjoerg // rights as any other member.
1047330f729Sjoerg // C++11 [class.access]p2:
1057330f729Sjoerg // A member of a class can also access all the names to which
1067330f729Sjoerg // the class has access. A local class of a member function
1077330f729Sjoerg // may access the same names that the member function itself
1087330f729Sjoerg // may access.
1097330f729Sjoerg // This almost implies that the privileges of nesting are transitive.
1107330f729Sjoerg // Technically it says nothing about the local classes of non-member
1117330f729Sjoerg // functions (which can gain privileges through friendship), but we
1127330f729Sjoerg // take that as an oversight.
1137330f729Sjoerg while (true) {
1147330f729Sjoerg // We want to add canonical declarations to the EC lists for
1157330f729Sjoerg // simplicity of checking, but we need to walk up through the
1167330f729Sjoerg // actual current DC chain. Otherwise, something like a local
1177330f729Sjoerg // extern or friend which happens to be the canonical
1187330f729Sjoerg // declaration will really mess us up.
1197330f729Sjoerg
1207330f729Sjoerg if (isa<CXXRecordDecl>(DC)) {
1217330f729Sjoerg CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
1227330f729Sjoerg Records.push_back(Record->getCanonicalDecl());
1237330f729Sjoerg DC = Record->getDeclContext();
1247330f729Sjoerg } else if (isa<FunctionDecl>(DC)) {
1257330f729Sjoerg FunctionDecl *Function = cast<FunctionDecl>(DC);
1267330f729Sjoerg Functions.push_back(Function->getCanonicalDecl());
1277330f729Sjoerg if (Function->getFriendObjectKind())
1287330f729Sjoerg DC = Function->getLexicalDeclContext();
1297330f729Sjoerg else
1307330f729Sjoerg DC = Function->getDeclContext();
1317330f729Sjoerg } else if (DC->isFileContext()) {
1327330f729Sjoerg break;
1337330f729Sjoerg } else {
1347330f729Sjoerg DC = DC->getParent();
1357330f729Sjoerg }
1367330f729Sjoerg }
1377330f729Sjoerg }
1387330f729Sjoerg
isDependent__anon05ec4eb20111::EffectiveContext1397330f729Sjoerg bool isDependent() const { return Dependent; }
1407330f729Sjoerg
includesClass__anon05ec4eb20111::EffectiveContext1417330f729Sjoerg bool includesClass(const CXXRecordDecl *R) const {
1427330f729Sjoerg R = R->getCanonicalDecl();
1437330f729Sjoerg return llvm::find(Records, R) != Records.end();
1447330f729Sjoerg }
1457330f729Sjoerg
1467330f729Sjoerg /// Retrieves the innermost "useful" context. Can be null if we're
1477330f729Sjoerg /// doing access-control without privileges.
getInnerContext__anon05ec4eb20111::EffectiveContext1487330f729Sjoerg DeclContext *getInnerContext() const {
1497330f729Sjoerg return Inner;
1507330f729Sjoerg }
1517330f729Sjoerg
1527330f729Sjoerg typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
1537330f729Sjoerg
1547330f729Sjoerg DeclContext *Inner;
1557330f729Sjoerg SmallVector<FunctionDecl*, 4> Functions;
1567330f729Sjoerg SmallVector<CXXRecordDecl*, 4> Records;
1577330f729Sjoerg bool Dependent;
1587330f729Sjoerg };
1597330f729Sjoerg
1607330f729Sjoerg /// Like sema::AccessedEntity, but kindly lets us scribble all over
1617330f729Sjoerg /// it.
1627330f729Sjoerg struct AccessTarget : public AccessedEntity {
AccessTarget__anon05ec4eb20111::AccessTarget1637330f729Sjoerg AccessTarget(const AccessedEntity &Entity)
1647330f729Sjoerg : AccessedEntity(Entity) {
1657330f729Sjoerg initialize();
1667330f729Sjoerg }
1677330f729Sjoerg
AccessTarget__anon05ec4eb20111::AccessTarget1687330f729Sjoerg AccessTarget(ASTContext &Context,
1697330f729Sjoerg MemberNonce _,
1707330f729Sjoerg CXXRecordDecl *NamingClass,
1717330f729Sjoerg DeclAccessPair FoundDecl,
1727330f729Sjoerg QualType BaseObjectType)
1737330f729Sjoerg : AccessedEntity(Context.getDiagAllocator(), Member, NamingClass,
1747330f729Sjoerg FoundDecl, BaseObjectType) {
1757330f729Sjoerg initialize();
1767330f729Sjoerg }
1777330f729Sjoerg
AccessTarget__anon05ec4eb20111::AccessTarget1787330f729Sjoerg AccessTarget(ASTContext &Context,
1797330f729Sjoerg BaseNonce _,
1807330f729Sjoerg CXXRecordDecl *BaseClass,
1817330f729Sjoerg CXXRecordDecl *DerivedClass,
1827330f729Sjoerg AccessSpecifier Access)
1837330f729Sjoerg : AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass,
1847330f729Sjoerg Access) {
1857330f729Sjoerg initialize();
1867330f729Sjoerg }
1877330f729Sjoerg
isInstanceMember__anon05ec4eb20111::AccessTarget1887330f729Sjoerg bool isInstanceMember() const {
1897330f729Sjoerg return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember());
1907330f729Sjoerg }
1917330f729Sjoerg
hasInstanceContext__anon05ec4eb20111::AccessTarget1927330f729Sjoerg bool hasInstanceContext() const {
1937330f729Sjoerg return HasInstanceContext;
1947330f729Sjoerg }
1957330f729Sjoerg
1967330f729Sjoerg class SavedInstanceContext {
1977330f729Sjoerg public:
SavedInstanceContext(SavedInstanceContext && S)1987330f729Sjoerg SavedInstanceContext(SavedInstanceContext &&S)
1997330f729Sjoerg : Target(S.Target), Has(S.Has) {
2007330f729Sjoerg S.Target = nullptr;
2017330f729Sjoerg }
~SavedInstanceContext()2027330f729Sjoerg ~SavedInstanceContext() {
2037330f729Sjoerg if (Target)
2047330f729Sjoerg Target->HasInstanceContext = Has;
2057330f729Sjoerg }
2067330f729Sjoerg
2077330f729Sjoerg private:
2087330f729Sjoerg friend struct AccessTarget;
SavedInstanceContext(AccessTarget & Target)2097330f729Sjoerg explicit SavedInstanceContext(AccessTarget &Target)
2107330f729Sjoerg : Target(&Target), Has(Target.HasInstanceContext) {}
2117330f729Sjoerg AccessTarget *Target;
2127330f729Sjoerg bool Has;
2137330f729Sjoerg };
2147330f729Sjoerg
saveInstanceContext__anon05ec4eb20111::AccessTarget2157330f729Sjoerg SavedInstanceContext saveInstanceContext() {
2167330f729Sjoerg return SavedInstanceContext(*this);
2177330f729Sjoerg }
2187330f729Sjoerg
suppressInstanceContext__anon05ec4eb20111::AccessTarget2197330f729Sjoerg void suppressInstanceContext() {
2207330f729Sjoerg HasInstanceContext = false;
2217330f729Sjoerg }
2227330f729Sjoerg
resolveInstanceContext__anon05ec4eb20111::AccessTarget2237330f729Sjoerg const CXXRecordDecl *resolveInstanceContext(Sema &S) const {
2247330f729Sjoerg assert(HasInstanceContext);
2257330f729Sjoerg if (CalculatedInstanceContext)
2267330f729Sjoerg return InstanceContext;
2277330f729Sjoerg
2287330f729Sjoerg CalculatedInstanceContext = true;
2297330f729Sjoerg DeclContext *IC = S.computeDeclContext(getBaseObjectType());
2307330f729Sjoerg InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl()
2317330f729Sjoerg : nullptr);
2327330f729Sjoerg return InstanceContext;
2337330f729Sjoerg }
2347330f729Sjoerg
getDeclaringClass__anon05ec4eb20111::AccessTarget2357330f729Sjoerg const CXXRecordDecl *getDeclaringClass() const {
2367330f729Sjoerg return DeclaringClass;
2377330f729Sjoerg }
2387330f729Sjoerg
2397330f729Sjoerg /// The "effective" naming class is the canonical non-anonymous
2407330f729Sjoerg /// class containing the actual naming class.
getEffectiveNamingClass__anon05ec4eb20111::AccessTarget2417330f729Sjoerg const CXXRecordDecl *getEffectiveNamingClass() const {
2427330f729Sjoerg const CXXRecordDecl *namingClass = getNamingClass();
2437330f729Sjoerg while (namingClass->isAnonymousStructOrUnion())
2447330f729Sjoerg namingClass = cast<CXXRecordDecl>(namingClass->getParent());
2457330f729Sjoerg return namingClass->getCanonicalDecl();
2467330f729Sjoerg }
2477330f729Sjoerg
2487330f729Sjoerg private:
initialize__anon05ec4eb20111::AccessTarget2497330f729Sjoerg void initialize() {
2507330f729Sjoerg HasInstanceContext = (isMemberAccess() &&
2517330f729Sjoerg !getBaseObjectType().isNull() &&
2527330f729Sjoerg getTargetDecl()->isCXXInstanceMember());
2537330f729Sjoerg CalculatedInstanceContext = false;
2547330f729Sjoerg InstanceContext = nullptr;
2557330f729Sjoerg
2567330f729Sjoerg if (isMemberAccess())
2577330f729Sjoerg DeclaringClass = FindDeclaringClass(getTargetDecl());
2587330f729Sjoerg else
2597330f729Sjoerg DeclaringClass = getBaseClass();
2607330f729Sjoerg DeclaringClass = DeclaringClass->getCanonicalDecl();
2617330f729Sjoerg }
2627330f729Sjoerg
2637330f729Sjoerg bool HasInstanceContext : 1;
2647330f729Sjoerg mutable bool CalculatedInstanceContext : 1;
2657330f729Sjoerg mutable const CXXRecordDecl *InstanceContext;
2667330f729Sjoerg const CXXRecordDecl *DeclaringClass;
2677330f729Sjoerg };
2687330f729Sjoerg
2697330f729Sjoerg }
2707330f729Sjoerg
2717330f729Sjoerg /// Checks whether one class might instantiate to the other.
MightInstantiateTo(const CXXRecordDecl * From,const CXXRecordDecl * To)2727330f729Sjoerg static bool MightInstantiateTo(const CXXRecordDecl *From,
2737330f729Sjoerg const CXXRecordDecl *To) {
2747330f729Sjoerg // Declaration names are always preserved by instantiation.
2757330f729Sjoerg if (From->getDeclName() != To->getDeclName())
2767330f729Sjoerg return false;
2777330f729Sjoerg
2787330f729Sjoerg const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();
2797330f729Sjoerg const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();
2807330f729Sjoerg if (FromDC == ToDC) return true;
2817330f729Sjoerg if (FromDC->isFileContext() || ToDC->isFileContext()) return false;
2827330f729Sjoerg
2837330f729Sjoerg // Be conservative.
2847330f729Sjoerg return true;
2857330f729Sjoerg }
2867330f729Sjoerg
2877330f729Sjoerg /// Checks whether one class is derived from another, inclusively.
2887330f729Sjoerg /// Properly indicates when it couldn't be determined due to
2897330f729Sjoerg /// dependence.
2907330f729Sjoerg ///
2917330f729Sjoerg /// This should probably be donated to AST or at least Sema.
IsDerivedFromInclusive(const CXXRecordDecl * Derived,const CXXRecordDecl * Target)2927330f729Sjoerg static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
2937330f729Sjoerg const CXXRecordDecl *Target) {
2947330f729Sjoerg assert(Derived->getCanonicalDecl() == Derived);
2957330f729Sjoerg assert(Target->getCanonicalDecl() == Target);
2967330f729Sjoerg
2977330f729Sjoerg if (Derived == Target) return AR_accessible;
2987330f729Sjoerg
2997330f729Sjoerg bool CheckDependent = Derived->isDependentContext();
3007330f729Sjoerg if (CheckDependent && MightInstantiateTo(Derived, Target))
3017330f729Sjoerg return AR_dependent;
3027330f729Sjoerg
3037330f729Sjoerg AccessResult OnFailure = AR_inaccessible;
3047330f729Sjoerg SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
3057330f729Sjoerg
3067330f729Sjoerg while (true) {
3077330f729Sjoerg if (Derived->isDependentContext() && !Derived->hasDefinition() &&
3087330f729Sjoerg !Derived->isLambda())
3097330f729Sjoerg return AR_dependent;
3107330f729Sjoerg
3117330f729Sjoerg for (const auto &I : Derived->bases()) {
3127330f729Sjoerg const CXXRecordDecl *RD;
3137330f729Sjoerg
3147330f729Sjoerg QualType T = I.getType();
3157330f729Sjoerg if (const RecordType *RT = T->getAs<RecordType>()) {
3167330f729Sjoerg RD = cast<CXXRecordDecl>(RT->getDecl());
3177330f729Sjoerg } else if (const InjectedClassNameType *IT
3187330f729Sjoerg = T->getAs<InjectedClassNameType>()) {
3197330f729Sjoerg RD = IT->getDecl();
3207330f729Sjoerg } else {
3217330f729Sjoerg assert(T->isDependentType() && "non-dependent base wasn't a record?");
3227330f729Sjoerg OnFailure = AR_dependent;
3237330f729Sjoerg continue;
3247330f729Sjoerg }
3257330f729Sjoerg
3267330f729Sjoerg RD = RD->getCanonicalDecl();
3277330f729Sjoerg if (RD == Target) return AR_accessible;
3287330f729Sjoerg if (CheckDependent && MightInstantiateTo(RD, Target))
3297330f729Sjoerg OnFailure = AR_dependent;
3307330f729Sjoerg
3317330f729Sjoerg Queue.push_back(RD);
3327330f729Sjoerg }
3337330f729Sjoerg
3347330f729Sjoerg if (Queue.empty()) break;
3357330f729Sjoerg
3367330f729Sjoerg Derived = Queue.pop_back_val();
3377330f729Sjoerg }
3387330f729Sjoerg
3397330f729Sjoerg return OnFailure;
3407330f729Sjoerg }
3417330f729Sjoerg
3427330f729Sjoerg
MightInstantiateTo(Sema & S,DeclContext * Context,DeclContext * Friend)3437330f729Sjoerg static bool MightInstantiateTo(Sema &S, DeclContext *Context,
3447330f729Sjoerg DeclContext *Friend) {
3457330f729Sjoerg if (Friend == Context)
3467330f729Sjoerg return true;
3477330f729Sjoerg
3487330f729Sjoerg assert(!Friend->isDependentContext() &&
3497330f729Sjoerg "can't handle friends with dependent contexts here");
3507330f729Sjoerg
3517330f729Sjoerg if (!Context->isDependentContext())
3527330f729Sjoerg return false;
3537330f729Sjoerg
3547330f729Sjoerg if (Friend->isFileContext())
3557330f729Sjoerg return false;
3567330f729Sjoerg
3577330f729Sjoerg // TODO: this is very conservative
3587330f729Sjoerg return true;
3597330f729Sjoerg }
3607330f729Sjoerg
3617330f729Sjoerg // Asks whether the type in 'context' can ever instantiate to the type
3627330f729Sjoerg // in 'friend'.
MightInstantiateTo(Sema & S,CanQualType Context,CanQualType Friend)3637330f729Sjoerg static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
3647330f729Sjoerg if (Friend == Context)
3657330f729Sjoerg return true;
3667330f729Sjoerg
3677330f729Sjoerg if (!Friend->isDependentType() && !Context->isDependentType())
3687330f729Sjoerg return false;
3697330f729Sjoerg
3707330f729Sjoerg // TODO: this is very conservative.
3717330f729Sjoerg return true;
3727330f729Sjoerg }
3737330f729Sjoerg
MightInstantiateTo(Sema & S,FunctionDecl * Context,FunctionDecl * Friend)3747330f729Sjoerg static bool MightInstantiateTo(Sema &S,
3757330f729Sjoerg FunctionDecl *Context,
3767330f729Sjoerg FunctionDecl *Friend) {
3777330f729Sjoerg if (Context->getDeclName() != Friend->getDeclName())
3787330f729Sjoerg return false;
3797330f729Sjoerg
3807330f729Sjoerg if (!MightInstantiateTo(S,
3817330f729Sjoerg Context->getDeclContext(),
3827330f729Sjoerg Friend->getDeclContext()))
3837330f729Sjoerg return false;
3847330f729Sjoerg
3857330f729Sjoerg CanQual<FunctionProtoType> FriendTy
3867330f729Sjoerg = S.Context.getCanonicalType(Friend->getType())
3877330f729Sjoerg ->getAs<FunctionProtoType>();
3887330f729Sjoerg CanQual<FunctionProtoType> ContextTy
3897330f729Sjoerg = S.Context.getCanonicalType(Context->getType())
3907330f729Sjoerg ->getAs<FunctionProtoType>();
3917330f729Sjoerg
3927330f729Sjoerg // There isn't any way that I know of to add qualifiers
3937330f729Sjoerg // during instantiation.
3947330f729Sjoerg if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
3957330f729Sjoerg return false;
3967330f729Sjoerg
3977330f729Sjoerg if (FriendTy->getNumParams() != ContextTy->getNumParams())
3987330f729Sjoerg return false;
3997330f729Sjoerg
4007330f729Sjoerg if (!MightInstantiateTo(S, ContextTy->getReturnType(),
4017330f729Sjoerg FriendTy->getReturnType()))
4027330f729Sjoerg return false;
4037330f729Sjoerg
4047330f729Sjoerg for (unsigned I = 0, E = FriendTy->getNumParams(); I != E; ++I)
4057330f729Sjoerg if (!MightInstantiateTo(S, ContextTy->getParamType(I),
4067330f729Sjoerg FriendTy->getParamType(I)))
4077330f729Sjoerg return false;
4087330f729Sjoerg
4097330f729Sjoerg return true;
4107330f729Sjoerg }
4117330f729Sjoerg
MightInstantiateTo(Sema & S,FunctionTemplateDecl * Context,FunctionTemplateDecl * Friend)4127330f729Sjoerg static bool MightInstantiateTo(Sema &S,
4137330f729Sjoerg FunctionTemplateDecl *Context,
4147330f729Sjoerg FunctionTemplateDecl *Friend) {
4157330f729Sjoerg return MightInstantiateTo(S,
4167330f729Sjoerg Context->getTemplatedDecl(),
4177330f729Sjoerg Friend->getTemplatedDecl());
4187330f729Sjoerg }
4197330f729Sjoerg
MatchesFriend(Sema & S,const EffectiveContext & EC,const CXXRecordDecl * Friend)4207330f729Sjoerg static AccessResult MatchesFriend(Sema &S,
4217330f729Sjoerg const EffectiveContext &EC,
4227330f729Sjoerg const CXXRecordDecl *Friend) {
4237330f729Sjoerg if (EC.includesClass(Friend))
4247330f729Sjoerg return AR_accessible;
4257330f729Sjoerg
4267330f729Sjoerg if (EC.isDependent()) {
4277330f729Sjoerg for (const CXXRecordDecl *Context : EC.Records) {
4287330f729Sjoerg if (MightInstantiateTo(Context, Friend))
4297330f729Sjoerg return AR_dependent;
4307330f729Sjoerg }
4317330f729Sjoerg }
4327330f729Sjoerg
4337330f729Sjoerg return AR_inaccessible;
4347330f729Sjoerg }
4357330f729Sjoerg
MatchesFriend(Sema & S,const EffectiveContext & EC,CanQualType Friend)4367330f729Sjoerg static AccessResult MatchesFriend(Sema &S,
4377330f729Sjoerg const EffectiveContext &EC,
4387330f729Sjoerg CanQualType Friend) {
4397330f729Sjoerg if (const RecordType *RT = Friend->getAs<RecordType>())
4407330f729Sjoerg return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
4417330f729Sjoerg
4427330f729Sjoerg // TODO: we can do better than this
4437330f729Sjoerg if (Friend->isDependentType())
4447330f729Sjoerg return AR_dependent;
4457330f729Sjoerg
4467330f729Sjoerg return AR_inaccessible;
4477330f729Sjoerg }
4487330f729Sjoerg
4497330f729Sjoerg /// Determines whether the given friend class template matches
4507330f729Sjoerg /// anything in the effective context.
MatchesFriend(Sema & S,const EffectiveContext & EC,ClassTemplateDecl * Friend)4517330f729Sjoerg static AccessResult MatchesFriend(Sema &S,
4527330f729Sjoerg const EffectiveContext &EC,
4537330f729Sjoerg ClassTemplateDecl *Friend) {
4547330f729Sjoerg AccessResult OnFailure = AR_inaccessible;
4557330f729Sjoerg
4567330f729Sjoerg // Check whether the friend is the template of a class in the
4577330f729Sjoerg // context chain.
4587330f729Sjoerg for (SmallVectorImpl<CXXRecordDecl*>::const_iterator
4597330f729Sjoerg I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
4607330f729Sjoerg CXXRecordDecl *Record = *I;
4617330f729Sjoerg
4627330f729Sjoerg // Figure out whether the current class has a template:
4637330f729Sjoerg ClassTemplateDecl *CTD;
4647330f729Sjoerg
4657330f729Sjoerg // A specialization of the template...
4667330f729Sjoerg if (isa<ClassTemplateSpecializationDecl>(Record)) {
4677330f729Sjoerg CTD = cast<ClassTemplateSpecializationDecl>(Record)
4687330f729Sjoerg ->getSpecializedTemplate();
4697330f729Sjoerg
4707330f729Sjoerg // ... or the template pattern itself.
4717330f729Sjoerg } else {
4727330f729Sjoerg CTD = Record->getDescribedClassTemplate();
4737330f729Sjoerg if (!CTD) continue;
4747330f729Sjoerg }
4757330f729Sjoerg
4767330f729Sjoerg // It's a match.
4777330f729Sjoerg if (Friend == CTD->getCanonicalDecl())
4787330f729Sjoerg return AR_accessible;
4797330f729Sjoerg
4807330f729Sjoerg // If the context isn't dependent, it can't be a dependent match.
4817330f729Sjoerg if (!EC.isDependent())
4827330f729Sjoerg continue;
4837330f729Sjoerg
4847330f729Sjoerg // If the template names don't match, it can't be a dependent
4857330f729Sjoerg // match.
4867330f729Sjoerg if (CTD->getDeclName() != Friend->getDeclName())
4877330f729Sjoerg continue;
4887330f729Sjoerg
4897330f729Sjoerg // If the class's context can't instantiate to the friend's
4907330f729Sjoerg // context, it can't be a dependent match.
4917330f729Sjoerg if (!MightInstantiateTo(S, CTD->getDeclContext(),
4927330f729Sjoerg Friend->getDeclContext()))
4937330f729Sjoerg continue;
4947330f729Sjoerg
4957330f729Sjoerg // Otherwise, it's a dependent match.
4967330f729Sjoerg OnFailure = AR_dependent;
4977330f729Sjoerg }
4987330f729Sjoerg
4997330f729Sjoerg return OnFailure;
5007330f729Sjoerg }
5017330f729Sjoerg
5027330f729Sjoerg /// Determines whether the given friend function matches anything in
5037330f729Sjoerg /// the effective context.
MatchesFriend(Sema & S,const EffectiveContext & EC,FunctionDecl * Friend)5047330f729Sjoerg static AccessResult MatchesFriend(Sema &S,
5057330f729Sjoerg const EffectiveContext &EC,
5067330f729Sjoerg FunctionDecl *Friend) {
5077330f729Sjoerg AccessResult OnFailure = AR_inaccessible;
5087330f729Sjoerg
5097330f729Sjoerg for (SmallVectorImpl<FunctionDecl*>::const_iterator
5107330f729Sjoerg I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
5117330f729Sjoerg if (Friend == *I)
5127330f729Sjoerg return AR_accessible;
5137330f729Sjoerg
5147330f729Sjoerg if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
5157330f729Sjoerg OnFailure = AR_dependent;
5167330f729Sjoerg }
5177330f729Sjoerg
5187330f729Sjoerg return OnFailure;
5197330f729Sjoerg }
5207330f729Sjoerg
5217330f729Sjoerg /// Determines whether the given friend function template matches
5227330f729Sjoerg /// anything in the effective context.
MatchesFriend(Sema & S,const EffectiveContext & EC,FunctionTemplateDecl * Friend)5237330f729Sjoerg static AccessResult MatchesFriend(Sema &S,
5247330f729Sjoerg const EffectiveContext &EC,
5257330f729Sjoerg FunctionTemplateDecl *Friend) {
5267330f729Sjoerg if (EC.Functions.empty()) return AR_inaccessible;
5277330f729Sjoerg
5287330f729Sjoerg AccessResult OnFailure = AR_inaccessible;
5297330f729Sjoerg
5307330f729Sjoerg for (SmallVectorImpl<FunctionDecl*>::const_iterator
5317330f729Sjoerg I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
5327330f729Sjoerg
5337330f729Sjoerg FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
5347330f729Sjoerg if (!FTD)
5357330f729Sjoerg FTD = (*I)->getDescribedFunctionTemplate();
5367330f729Sjoerg if (!FTD)
5377330f729Sjoerg continue;
5387330f729Sjoerg
5397330f729Sjoerg FTD = FTD->getCanonicalDecl();
5407330f729Sjoerg
5417330f729Sjoerg if (Friend == FTD)
5427330f729Sjoerg return AR_accessible;
5437330f729Sjoerg
5447330f729Sjoerg if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
5457330f729Sjoerg OnFailure = AR_dependent;
5467330f729Sjoerg }
5477330f729Sjoerg
5487330f729Sjoerg return OnFailure;
5497330f729Sjoerg }
5507330f729Sjoerg
5517330f729Sjoerg /// Determines whether the given friend declaration matches anything
5527330f729Sjoerg /// in the effective context.
MatchesFriend(Sema & S,const EffectiveContext & EC,FriendDecl * FriendD)5537330f729Sjoerg static AccessResult MatchesFriend(Sema &S,
5547330f729Sjoerg const EffectiveContext &EC,
5557330f729Sjoerg FriendDecl *FriendD) {
5567330f729Sjoerg // Whitelist accesses if there's an invalid or unsupported friend
5577330f729Sjoerg // declaration.
5587330f729Sjoerg if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend())
5597330f729Sjoerg return AR_accessible;
5607330f729Sjoerg
5617330f729Sjoerg if (TypeSourceInfo *T = FriendD->getFriendType())
5627330f729Sjoerg return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
5637330f729Sjoerg
5647330f729Sjoerg NamedDecl *Friend
5657330f729Sjoerg = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
5667330f729Sjoerg
5677330f729Sjoerg // FIXME: declarations with dependent or templated scope.
5687330f729Sjoerg
5697330f729Sjoerg if (isa<ClassTemplateDecl>(Friend))
5707330f729Sjoerg return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
5717330f729Sjoerg
5727330f729Sjoerg if (isa<FunctionTemplateDecl>(Friend))
5737330f729Sjoerg return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
5747330f729Sjoerg
5757330f729Sjoerg if (isa<CXXRecordDecl>(Friend))
5767330f729Sjoerg return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
5777330f729Sjoerg
5787330f729Sjoerg assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
5797330f729Sjoerg return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
5807330f729Sjoerg }
5817330f729Sjoerg
GetFriendKind(Sema & S,const EffectiveContext & EC,const CXXRecordDecl * Class)5827330f729Sjoerg static AccessResult GetFriendKind(Sema &S,
5837330f729Sjoerg const EffectiveContext &EC,
5847330f729Sjoerg const CXXRecordDecl *Class) {
5857330f729Sjoerg AccessResult OnFailure = AR_inaccessible;
5867330f729Sjoerg
5877330f729Sjoerg // Okay, check friends.
5887330f729Sjoerg for (auto *Friend : Class->friends()) {
5897330f729Sjoerg switch (MatchesFriend(S, EC, Friend)) {
5907330f729Sjoerg case AR_accessible:
5917330f729Sjoerg return AR_accessible;
5927330f729Sjoerg
5937330f729Sjoerg case AR_inaccessible:
5947330f729Sjoerg continue;
5957330f729Sjoerg
5967330f729Sjoerg case AR_dependent:
5977330f729Sjoerg OnFailure = AR_dependent;
5987330f729Sjoerg break;
5997330f729Sjoerg }
6007330f729Sjoerg }
6017330f729Sjoerg
6027330f729Sjoerg // That's it, give up.
6037330f729Sjoerg return OnFailure;
6047330f729Sjoerg }
6057330f729Sjoerg
6067330f729Sjoerg namespace {
6077330f729Sjoerg
6087330f729Sjoerg /// A helper class for checking for a friend which will grant access
6097330f729Sjoerg /// to a protected instance member.
6107330f729Sjoerg struct ProtectedFriendContext {
6117330f729Sjoerg Sema &S;
6127330f729Sjoerg const EffectiveContext &EC;
6137330f729Sjoerg const CXXRecordDecl *NamingClass;
6147330f729Sjoerg bool CheckDependent;
6157330f729Sjoerg bool EverDependent;
6167330f729Sjoerg
6177330f729Sjoerg /// The path down to the current base class.
6187330f729Sjoerg SmallVector<const CXXRecordDecl*, 20> CurPath;
6197330f729Sjoerg
ProtectedFriendContext__anon05ec4eb20211::ProtectedFriendContext6207330f729Sjoerg ProtectedFriendContext(Sema &S, const EffectiveContext &EC,
6217330f729Sjoerg const CXXRecordDecl *InstanceContext,
6227330f729Sjoerg const CXXRecordDecl *NamingClass)
6237330f729Sjoerg : S(S), EC(EC), NamingClass(NamingClass),
6247330f729Sjoerg CheckDependent(InstanceContext->isDependentContext() ||
6257330f729Sjoerg NamingClass->isDependentContext()),
6267330f729Sjoerg EverDependent(false) {}
6277330f729Sjoerg
6287330f729Sjoerg /// Check classes in the current path for friendship, starting at
6297330f729Sjoerg /// the given index.
checkFriendshipAlongPath__anon05ec4eb20211::ProtectedFriendContext6307330f729Sjoerg bool checkFriendshipAlongPath(unsigned I) {
6317330f729Sjoerg assert(I < CurPath.size());
6327330f729Sjoerg for (unsigned E = CurPath.size(); I != E; ++I) {
6337330f729Sjoerg switch (GetFriendKind(S, EC, CurPath[I])) {
6347330f729Sjoerg case AR_accessible: return true;
6357330f729Sjoerg case AR_inaccessible: continue;
6367330f729Sjoerg case AR_dependent: EverDependent = true; continue;
6377330f729Sjoerg }
6387330f729Sjoerg }
6397330f729Sjoerg return false;
6407330f729Sjoerg }
6417330f729Sjoerg
6427330f729Sjoerg /// Perform a search starting at the given class.
6437330f729Sjoerg ///
6447330f729Sjoerg /// PrivateDepth is the index of the last (least derived) class
6457330f729Sjoerg /// along the current path such that a notional public member of
6467330f729Sjoerg /// the final class in the path would have access in that class.
findFriendship__anon05ec4eb20211::ProtectedFriendContext6477330f729Sjoerg bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) {
6487330f729Sjoerg // If we ever reach the naming class, check the current path for
6497330f729Sjoerg // friendship. We can also stop recursing because we obviously
6507330f729Sjoerg // won't find the naming class there again.
6517330f729Sjoerg if (Cur == NamingClass)
6527330f729Sjoerg return checkFriendshipAlongPath(PrivateDepth);
6537330f729Sjoerg
6547330f729Sjoerg if (CheckDependent && MightInstantiateTo(Cur, NamingClass))
6557330f729Sjoerg EverDependent = true;
6567330f729Sjoerg
6577330f729Sjoerg // Recurse into the base classes.
6587330f729Sjoerg for (const auto &I : Cur->bases()) {
6597330f729Sjoerg // If this is private inheritance, then a public member of the
6607330f729Sjoerg // base will not have any access in classes derived from Cur.
6617330f729Sjoerg unsigned BasePrivateDepth = PrivateDepth;
6627330f729Sjoerg if (I.getAccessSpecifier() == AS_private)
6637330f729Sjoerg BasePrivateDepth = CurPath.size() - 1;
6647330f729Sjoerg
6657330f729Sjoerg const CXXRecordDecl *RD;
6667330f729Sjoerg
6677330f729Sjoerg QualType T = I.getType();
6687330f729Sjoerg if (const RecordType *RT = T->getAs<RecordType>()) {
6697330f729Sjoerg RD = cast<CXXRecordDecl>(RT->getDecl());
6707330f729Sjoerg } else if (const InjectedClassNameType *IT
6717330f729Sjoerg = T->getAs<InjectedClassNameType>()) {
6727330f729Sjoerg RD = IT->getDecl();
6737330f729Sjoerg } else {
6747330f729Sjoerg assert(T->isDependentType() && "non-dependent base wasn't a record?");
6757330f729Sjoerg EverDependent = true;
6767330f729Sjoerg continue;
6777330f729Sjoerg }
6787330f729Sjoerg
6797330f729Sjoerg // Recurse. We don't need to clean up if this returns true.
6807330f729Sjoerg CurPath.push_back(RD);
6817330f729Sjoerg if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth))
6827330f729Sjoerg return true;
6837330f729Sjoerg CurPath.pop_back();
6847330f729Sjoerg }
6857330f729Sjoerg
6867330f729Sjoerg return false;
6877330f729Sjoerg }
6887330f729Sjoerg
findFriendship__anon05ec4eb20211::ProtectedFriendContext6897330f729Sjoerg bool findFriendship(const CXXRecordDecl *Cur) {
6907330f729Sjoerg assert(CurPath.empty());
6917330f729Sjoerg CurPath.push_back(Cur);
6927330f729Sjoerg return findFriendship(Cur, 0);
6937330f729Sjoerg }
6947330f729Sjoerg };
6957330f729Sjoerg }
6967330f729Sjoerg
6977330f729Sjoerg /// Search for a class P that EC is a friend of, under the constraint
6987330f729Sjoerg /// InstanceContext <= P
6997330f729Sjoerg /// if InstanceContext exists, or else
7007330f729Sjoerg /// NamingClass <= P
7017330f729Sjoerg /// and with the additional restriction that a protected member of
7027330f729Sjoerg /// NamingClass would have some natural access in P, which implicitly
7037330f729Sjoerg /// imposes the constraint that P <= NamingClass.
7047330f729Sjoerg ///
7057330f729Sjoerg /// This isn't quite the condition laid out in the standard.
7067330f729Sjoerg /// Instead of saying that a notional protected member of NamingClass
7077330f729Sjoerg /// would have to have some natural access in P, it says the actual
7087330f729Sjoerg /// target has to have some natural access in P, which opens up the
7097330f729Sjoerg /// possibility that the target (which is not necessarily a member
7107330f729Sjoerg /// of NamingClass) might be more accessible along some path not
7117330f729Sjoerg /// passing through it. That's really a bad idea, though, because it
7127330f729Sjoerg /// introduces two problems:
7137330f729Sjoerg /// - Most importantly, it breaks encapsulation because you can
7147330f729Sjoerg /// access a forbidden base class's members by directly subclassing
7157330f729Sjoerg /// it elsewhere.
7167330f729Sjoerg /// - It also makes access substantially harder to compute because it
7177330f729Sjoerg /// breaks the hill-climbing algorithm: knowing that the target is
7187330f729Sjoerg /// accessible in some base class would no longer let you change
7197330f729Sjoerg /// the question solely to whether the base class is accessible,
7207330f729Sjoerg /// because the original target might have been more accessible
7217330f729Sjoerg /// because of crazy subclassing.
7227330f729Sjoerg /// So we don't implement that.
GetProtectedFriendKind(Sema & S,const EffectiveContext & EC,const CXXRecordDecl * InstanceContext,const CXXRecordDecl * NamingClass)7237330f729Sjoerg static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC,
7247330f729Sjoerg const CXXRecordDecl *InstanceContext,
7257330f729Sjoerg const CXXRecordDecl *NamingClass) {
7267330f729Sjoerg assert(InstanceContext == nullptr ||
7277330f729Sjoerg InstanceContext->getCanonicalDecl() == InstanceContext);
7287330f729Sjoerg assert(NamingClass->getCanonicalDecl() == NamingClass);
7297330f729Sjoerg
7307330f729Sjoerg // If we don't have an instance context, our constraints give us
7317330f729Sjoerg // that NamingClass <= P <= NamingClass, i.e. P == NamingClass.
7327330f729Sjoerg // This is just the usual friendship check.
7337330f729Sjoerg if (!InstanceContext) return GetFriendKind(S, EC, NamingClass);
7347330f729Sjoerg
7357330f729Sjoerg ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass);
7367330f729Sjoerg if (PRC.findFriendship(InstanceContext)) return AR_accessible;
7377330f729Sjoerg if (PRC.EverDependent) return AR_dependent;
7387330f729Sjoerg return AR_inaccessible;
7397330f729Sjoerg }
7407330f729Sjoerg
HasAccess(Sema & S,const EffectiveContext & EC,const CXXRecordDecl * NamingClass,AccessSpecifier Access,const AccessTarget & Target)7417330f729Sjoerg static AccessResult HasAccess(Sema &S,
7427330f729Sjoerg const EffectiveContext &EC,
7437330f729Sjoerg const CXXRecordDecl *NamingClass,
7447330f729Sjoerg AccessSpecifier Access,
7457330f729Sjoerg const AccessTarget &Target) {
7467330f729Sjoerg assert(NamingClass->getCanonicalDecl() == NamingClass &&
7477330f729Sjoerg "declaration should be canonicalized before being passed here");
7487330f729Sjoerg
7497330f729Sjoerg if (Access == AS_public) return AR_accessible;
7507330f729Sjoerg assert(Access == AS_private || Access == AS_protected);
7517330f729Sjoerg
7527330f729Sjoerg AccessResult OnFailure = AR_inaccessible;
7537330f729Sjoerg
7547330f729Sjoerg for (EffectiveContext::record_iterator
7557330f729Sjoerg I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
7567330f729Sjoerg // All the declarations in EC have been canonicalized, so pointer
7577330f729Sjoerg // equality from this point on will work fine.
7587330f729Sjoerg const CXXRecordDecl *ECRecord = *I;
7597330f729Sjoerg
7607330f729Sjoerg // [B2] and [M2]
7617330f729Sjoerg if (Access == AS_private) {
7627330f729Sjoerg if (ECRecord == NamingClass)
7637330f729Sjoerg return AR_accessible;
7647330f729Sjoerg
7657330f729Sjoerg if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))
7667330f729Sjoerg OnFailure = AR_dependent;
7677330f729Sjoerg
7687330f729Sjoerg // [B3] and [M3]
7697330f729Sjoerg } else {
7707330f729Sjoerg assert(Access == AS_protected);
7717330f729Sjoerg switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
7727330f729Sjoerg case AR_accessible: break;
7737330f729Sjoerg case AR_inaccessible: continue;
7747330f729Sjoerg case AR_dependent: OnFailure = AR_dependent; continue;
7757330f729Sjoerg }
7767330f729Sjoerg
7777330f729Sjoerg // C++ [class.protected]p1:
7787330f729Sjoerg // An additional access check beyond those described earlier in
7797330f729Sjoerg // [class.access] is applied when a non-static data member or
7807330f729Sjoerg // non-static member function is a protected member of its naming
7817330f729Sjoerg // class. As described earlier, access to a protected member is
7827330f729Sjoerg // granted because the reference occurs in a friend or member of
7837330f729Sjoerg // some class C. If the access is to form a pointer to member,
7847330f729Sjoerg // the nested-name-specifier shall name C or a class derived from
7857330f729Sjoerg // C. All other accesses involve a (possibly implicit) object
7867330f729Sjoerg // expression. In this case, the class of the object expression
7877330f729Sjoerg // shall be C or a class derived from C.
7887330f729Sjoerg //
7897330f729Sjoerg // We interpret this as a restriction on [M3].
7907330f729Sjoerg
7917330f729Sjoerg // In this part of the code, 'C' is just our context class ECRecord.
7927330f729Sjoerg
7937330f729Sjoerg // These rules are different if we don't have an instance context.
7947330f729Sjoerg if (!Target.hasInstanceContext()) {
7957330f729Sjoerg // If it's not an instance member, these restrictions don't apply.
7967330f729Sjoerg if (!Target.isInstanceMember()) return AR_accessible;
7977330f729Sjoerg
7987330f729Sjoerg // If it's an instance member, use the pointer-to-member rule
7997330f729Sjoerg // that the naming class has to be derived from the effective
8007330f729Sjoerg // context.
8017330f729Sjoerg
8027330f729Sjoerg // Emulate a MSVC bug where the creation of pointer-to-member
8037330f729Sjoerg // to protected member of base class is allowed but only from
8047330f729Sjoerg // static member functions.
8057330f729Sjoerg if (S.getLangOpts().MSVCCompat && !EC.Functions.empty())
8067330f729Sjoerg if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front()))
8077330f729Sjoerg if (MD->isStatic()) return AR_accessible;
8087330f729Sjoerg
8097330f729Sjoerg // Despite the standard's confident wording, there is a case
8107330f729Sjoerg // where you can have an instance member that's neither in a
8117330f729Sjoerg // pointer-to-member expression nor in a member access: when
8127330f729Sjoerg // it names a field in an unevaluated context that can't be an
8137330f729Sjoerg // implicit member. Pending clarification, we just apply the
8147330f729Sjoerg // same naming-class restriction here.
8157330f729Sjoerg // FIXME: we're probably not correctly adding the
8167330f729Sjoerg // protected-member restriction when we retroactively convert
8177330f729Sjoerg // an expression to being evaluated.
8187330f729Sjoerg
8197330f729Sjoerg // We know that ECRecord derives from NamingClass. The
8207330f729Sjoerg // restriction says to check whether NamingClass derives from
8217330f729Sjoerg // ECRecord, but that's not really necessary: two distinct
8227330f729Sjoerg // classes can't be recursively derived from each other. So
8237330f729Sjoerg // along this path, we just need to check whether the classes
8247330f729Sjoerg // are equal.
8257330f729Sjoerg if (NamingClass == ECRecord) return AR_accessible;
8267330f729Sjoerg
8277330f729Sjoerg // Otherwise, this context class tells us nothing; on to the next.
8287330f729Sjoerg continue;
8297330f729Sjoerg }
8307330f729Sjoerg
8317330f729Sjoerg assert(Target.isInstanceMember());
8327330f729Sjoerg
8337330f729Sjoerg const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
8347330f729Sjoerg if (!InstanceContext) {
8357330f729Sjoerg OnFailure = AR_dependent;
8367330f729Sjoerg continue;
8377330f729Sjoerg }
8387330f729Sjoerg
8397330f729Sjoerg switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
8407330f729Sjoerg case AR_accessible: return AR_accessible;
8417330f729Sjoerg case AR_inaccessible: continue;
8427330f729Sjoerg case AR_dependent: OnFailure = AR_dependent; continue;
8437330f729Sjoerg }
8447330f729Sjoerg }
8457330f729Sjoerg }
8467330f729Sjoerg
8477330f729Sjoerg // [M3] and [B3] say that, if the target is protected in N, we grant
8487330f729Sjoerg // access if the access occurs in a friend or member of some class P
8497330f729Sjoerg // that's a subclass of N and where the target has some natural
8507330f729Sjoerg // access in P. The 'member' aspect is easy to handle because P
8517330f729Sjoerg // would necessarily be one of the effective-context records, and we
8527330f729Sjoerg // address that above. The 'friend' aspect is completely ridiculous
8537330f729Sjoerg // to implement because there are no restrictions at all on P
8547330f729Sjoerg // *unless* the [class.protected] restriction applies. If it does,
8557330f729Sjoerg // however, we should ignore whether the naming class is a friend,
8567330f729Sjoerg // and instead rely on whether any potential P is a friend.
8577330f729Sjoerg if (Access == AS_protected && Target.isInstanceMember()) {
8587330f729Sjoerg // Compute the instance context if possible.
8597330f729Sjoerg const CXXRecordDecl *InstanceContext = nullptr;
8607330f729Sjoerg if (Target.hasInstanceContext()) {
8617330f729Sjoerg InstanceContext = Target.resolveInstanceContext(S);
8627330f729Sjoerg if (!InstanceContext) return AR_dependent;
8637330f729Sjoerg }
8647330f729Sjoerg
8657330f729Sjoerg switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) {
8667330f729Sjoerg case AR_accessible: return AR_accessible;
8677330f729Sjoerg case AR_inaccessible: return OnFailure;
8687330f729Sjoerg case AR_dependent: return AR_dependent;
8697330f729Sjoerg }
8707330f729Sjoerg llvm_unreachable("impossible friendship kind");
8717330f729Sjoerg }
8727330f729Sjoerg
8737330f729Sjoerg switch (GetFriendKind(S, EC, NamingClass)) {
8747330f729Sjoerg case AR_accessible: return AR_accessible;
8757330f729Sjoerg case AR_inaccessible: return OnFailure;
8767330f729Sjoerg case AR_dependent: return AR_dependent;
8777330f729Sjoerg }
8787330f729Sjoerg
8797330f729Sjoerg // Silence bogus warnings
8807330f729Sjoerg llvm_unreachable("impossible friendship kind");
8817330f729Sjoerg }
8827330f729Sjoerg
8837330f729Sjoerg /// Finds the best path from the naming class to the declaring class,
8847330f729Sjoerg /// taking friend declarations into account.
8857330f729Sjoerg ///
8867330f729Sjoerg /// C++0x [class.access.base]p5:
8877330f729Sjoerg /// A member m is accessible at the point R when named in class N if
8887330f729Sjoerg /// [M1] m as a member of N is public, or
8897330f729Sjoerg /// [M2] m as a member of N is private, and R occurs in a member or
8907330f729Sjoerg /// friend of class N, or
8917330f729Sjoerg /// [M3] m as a member of N is protected, and R occurs in a member or
8927330f729Sjoerg /// friend of class N, or in a member or friend of a class P
8937330f729Sjoerg /// derived from N, where m as a member of P is public, private,
8947330f729Sjoerg /// or protected, or
8957330f729Sjoerg /// [M4] there exists a base class B of N that is accessible at R, and
8967330f729Sjoerg /// m is accessible at R when named in class B.
8977330f729Sjoerg ///
8987330f729Sjoerg /// C++0x [class.access.base]p4:
8997330f729Sjoerg /// A base class B of N is accessible at R, if
9007330f729Sjoerg /// [B1] an invented public member of B would be a public member of N, or
9017330f729Sjoerg /// [B2] R occurs in a member or friend of class N, and an invented public
9027330f729Sjoerg /// member of B would be a private or protected member of N, or
9037330f729Sjoerg /// [B3] R occurs in a member or friend of a class P derived from N, and an
9047330f729Sjoerg /// invented public member of B would be a private or protected member
9057330f729Sjoerg /// of P, or
9067330f729Sjoerg /// [B4] there exists a class S such that B is a base class of S accessible
9077330f729Sjoerg /// at R and S is a base class of N accessible at R.
9087330f729Sjoerg ///
9097330f729Sjoerg /// Along a single inheritance path we can restate both of these
9107330f729Sjoerg /// iteratively:
9117330f729Sjoerg ///
9127330f729Sjoerg /// First, we note that M1-4 are equivalent to B1-4 if the member is
9137330f729Sjoerg /// treated as a notional base of its declaring class with inheritance
9147330f729Sjoerg /// access equivalent to the member's access. Therefore we need only
9157330f729Sjoerg /// ask whether a class B is accessible from a class N in context R.
9167330f729Sjoerg ///
9177330f729Sjoerg /// Let B_1 .. B_n be the inheritance path in question (i.e. where
9187330f729Sjoerg /// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
9197330f729Sjoerg /// B_i). For i in 1..n, we will calculate ACAB(i), the access to the
9207330f729Sjoerg /// closest accessible base in the path:
9217330f729Sjoerg /// Access(a, b) = (* access on the base specifier from a to b *)
9227330f729Sjoerg /// Merge(a, forbidden) = forbidden
9237330f729Sjoerg /// Merge(a, private) = forbidden
9247330f729Sjoerg /// Merge(a, b) = min(a,b)
9257330f729Sjoerg /// Accessible(c, forbidden) = false
9267330f729Sjoerg /// Accessible(c, private) = (R is c) || IsFriend(c, R)
9277330f729Sjoerg /// Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
9287330f729Sjoerg /// Accessible(c, public) = true
9297330f729Sjoerg /// ACAB(n) = public
9307330f729Sjoerg /// ACAB(i) =
9317330f729Sjoerg /// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
9327330f729Sjoerg /// if Accessible(B_i, AccessToBase) then public else AccessToBase
9337330f729Sjoerg ///
9347330f729Sjoerg /// B is an accessible base of N at R iff ACAB(1) = public.
9357330f729Sjoerg ///
9367330f729Sjoerg /// \param FinalAccess the access of the "final step", or AS_public if
9377330f729Sjoerg /// there is no final step.
9387330f729Sjoerg /// \return null if friendship is dependent
FindBestPath(Sema & S,const EffectiveContext & EC,AccessTarget & Target,AccessSpecifier FinalAccess,CXXBasePaths & Paths)9397330f729Sjoerg static CXXBasePath *FindBestPath(Sema &S,
9407330f729Sjoerg const EffectiveContext &EC,
9417330f729Sjoerg AccessTarget &Target,
9427330f729Sjoerg AccessSpecifier FinalAccess,
9437330f729Sjoerg CXXBasePaths &Paths) {
9447330f729Sjoerg // Derive the paths to the desired base.
9457330f729Sjoerg const CXXRecordDecl *Derived = Target.getNamingClass();
9467330f729Sjoerg const CXXRecordDecl *Base = Target.getDeclaringClass();
9477330f729Sjoerg
9487330f729Sjoerg // FIXME: fail correctly when there are dependent paths.
9497330f729Sjoerg bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base),
9507330f729Sjoerg Paths);
9517330f729Sjoerg assert(isDerived && "derived class not actually derived from base");
9527330f729Sjoerg (void) isDerived;
9537330f729Sjoerg
9547330f729Sjoerg CXXBasePath *BestPath = nullptr;
9557330f729Sjoerg
9567330f729Sjoerg assert(FinalAccess != AS_none && "forbidden access after declaring class");
9577330f729Sjoerg
9587330f729Sjoerg bool AnyDependent = false;
9597330f729Sjoerg
9607330f729Sjoerg // Derive the friend-modified access along each path.
9617330f729Sjoerg for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
9627330f729Sjoerg PI != PE; ++PI) {
9637330f729Sjoerg AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext();
9647330f729Sjoerg
9657330f729Sjoerg // Walk through the path backwards.
9667330f729Sjoerg AccessSpecifier PathAccess = FinalAccess;
9677330f729Sjoerg CXXBasePath::iterator I = PI->end(), E = PI->begin();
9687330f729Sjoerg while (I != E) {
9697330f729Sjoerg --I;
9707330f729Sjoerg
9717330f729Sjoerg assert(PathAccess != AS_none);
9727330f729Sjoerg
9737330f729Sjoerg // If the declaration is a private member of a base class, there
9747330f729Sjoerg // is no level of friendship in derived classes that can make it
9757330f729Sjoerg // accessible.
9767330f729Sjoerg if (PathAccess == AS_private) {
9777330f729Sjoerg PathAccess = AS_none;
9787330f729Sjoerg break;
9797330f729Sjoerg }
9807330f729Sjoerg
9817330f729Sjoerg const CXXRecordDecl *NC = I->Class->getCanonicalDecl();
9827330f729Sjoerg
9837330f729Sjoerg AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
9847330f729Sjoerg PathAccess = std::max(PathAccess, BaseAccess);
9857330f729Sjoerg
9867330f729Sjoerg switch (HasAccess(S, EC, NC, PathAccess, Target)) {
9877330f729Sjoerg case AR_inaccessible: break;
9887330f729Sjoerg case AR_accessible:
9897330f729Sjoerg PathAccess = AS_public;
9907330f729Sjoerg
9917330f729Sjoerg // Future tests are not against members and so do not have
9927330f729Sjoerg // instance context.
9937330f729Sjoerg Target.suppressInstanceContext();
9947330f729Sjoerg break;
9957330f729Sjoerg case AR_dependent:
9967330f729Sjoerg AnyDependent = true;
9977330f729Sjoerg goto Next;
9987330f729Sjoerg }
9997330f729Sjoerg }
10007330f729Sjoerg
10017330f729Sjoerg // Note that we modify the path's Access field to the
10027330f729Sjoerg // friend-modified access.
10037330f729Sjoerg if (BestPath == nullptr || PathAccess < BestPath->Access) {
10047330f729Sjoerg BestPath = &*PI;
10057330f729Sjoerg BestPath->Access = PathAccess;
10067330f729Sjoerg
10077330f729Sjoerg // Short-circuit if we found a public path.
10087330f729Sjoerg if (BestPath->Access == AS_public)
10097330f729Sjoerg return BestPath;
10107330f729Sjoerg }
10117330f729Sjoerg
10127330f729Sjoerg Next: ;
10137330f729Sjoerg }
10147330f729Sjoerg
10157330f729Sjoerg assert((!BestPath || BestPath->Access != AS_public) &&
10167330f729Sjoerg "fell out of loop with public path");
10177330f729Sjoerg
10187330f729Sjoerg // We didn't find a public path, but at least one path was subject
10197330f729Sjoerg // to dependent friendship, so delay the check.
10207330f729Sjoerg if (AnyDependent)
10217330f729Sjoerg return nullptr;
10227330f729Sjoerg
10237330f729Sjoerg return BestPath;
10247330f729Sjoerg }
10257330f729Sjoerg
10267330f729Sjoerg /// Given that an entity has protected natural access, check whether
10277330f729Sjoerg /// access might be denied because of the protected member access
10287330f729Sjoerg /// restriction.
10297330f729Sjoerg ///
10307330f729Sjoerg /// \return true if a note was emitted
TryDiagnoseProtectedAccess(Sema & S,const EffectiveContext & EC,AccessTarget & Target)10317330f729Sjoerg static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
10327330f729Sjoerg AccessTarget &Target) {
10337330f729Sjoerg // Only applies to instance accesses.
10347330f729Sjoerg if (!Target.isInstanceMember())
10357330f729Sjoerg return false;
10367330f729Sjoerg
10377330f729Sjoerg assert(Target.isMemberAccess());
10387330f729Sjoerg
10397330f729Sjoerg const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass();
10407330f729Sjoerg
10417330f729Sjoerg for (EffectiveContext::record_iterator
10427330f729Sjoerg I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
10437330f729Sjoerg const CXXRecordDecl *ECRecord = *I;
10447330f729Sjoerg switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
10457330f729Sjoerg case AR_accessible: break;
10467330f729Sjoerg case AR_inaccessible: continue;
10477330f729Sjoerg case AR_dependent: continue;
10487330f729Sjoerg }
10497330f729Sjoerg
10507330f729Sjoerg // The effective context is a subclass of the declaring class.
10517330f729Sjoerg // Check whether the [class.protected] restriction is limiting
10527330f729Sjoerg // access.
10537330f729Sjoerg
10547330f729Sjoerg // To get this exactly right, this might need to be checked more
10557330f729Sjoerg // holistically; it's not necessarily the case that gaining
10567330f729Sjoerg // access here would grant us access overall.
10577330f729Sjoerg
10587330f729Sjoerg NamedDecl *D = Target.getTargetDecl();
10597330f729Sjoerg
10607330f729Sjoerg // If we don't have an instance context, [class.protected] says the
10617330f729Sjoerg // naming class has to equal the context class.
10627330f729Sjoerg if (!Target.hasInstanceContext()) {
10637330f729Sjoerg // If it does, the restriction doesn't apply.
10647330f729Sjoerg if (NamingClass == ECRecord) continue;
10657330f729Sjoerg
10667330f729Sjoerg // TODO: it would be great to have a fixit here, since this is
10677330f729Sjoerg // such an obvious error.
10687330f729Sjoerg S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject)
10697330f729Sjoerg << S.Context.getTypeDeclType(ECRecord);
10707330f729Sjoerg return true;
10717330f729Sjoerg }
10727330f729Sjoerg
10737330f729Sjoerg const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
10747330f729Sjoerg assert(InstanceContext && "diagnosing dependent access");
10757330f729Sjoerg
10767330f729Sjoerg switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
10777330f729Sjoerg case AR_accessible: continue;
10787330f729Sjoerg case AR_dependent: continue;
10797330f729Sjoerg case AR_inaccessible:
10807330f729Sjoerg break;
10817330f729Sjoerg }
10827330f729Sjoerg
10837330f729Sjoerg // Okay, the restriction seems to be what's limiting us.
10847330f729Sjoerg
10857330f729Sjoerg // Use a special diagnostic for constructors and destructors.
10867330f729Sjoerg if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) ||
10877330f729Sjoerg (isa<FunctionTemplateDecl>(D) &&
10887330f729Sjoerg isa<CXXConstructorDecl>(
10897330f729Sjoerg cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) {
10907330f729Sjoerg return S.Diag(D->getLocation(),
10917330f729Sjoerg diag::note_access_protected_restricted_ctordtor)
10927330f729Sjoerg << isa<CXXDestructorDecl>(D->getAsFunction());
10937330f729Sjoerg }
10947330f729Sjoerg
10957330f729Sjoerg // Otherwise, use the generic diagnostic.
10967330f729Sjoerg return S.Diag(D->getLocation(),
10977330f729Sjoerg diag::note_access_protected_restricted_object)
10987330f729Sjoerg << S.Context.getTypeDeclType(ECRecord);
10997330f729Sjoerg }
11007330f729Sjoerg
11017330f729Sjoerg return false;
11027330f729Sjoerg }
11037330f729Sjoerg
11047330f729Sjoerg /// We are unable to access a given declaration due to its direct
11057330f729Sjoerg /// access control; diagnose that.
diagnoseBadDirectAccess(Sema & S,const EffectiveContext & EC,AccessTarget & entity)11067330f729Sjoerg static void diagnoseBadDirectAccess(Sema &S,
11077330f729Sjoerg const EffectiveContext &EC,
11087330f729Sjoerg AccessTarget &entity) {
11097330f729Sjoerg assert(entity.isMemberAccess());
11107330f729Sjoerg NamedDecl *D = entity.getTargetDecl();
11117330f729Sjoerg
11127330f729Sjoerg if (D->getAccess() == AS_protected &&
11137330f729Sjoerg TryDiagnoseProtectedAccess(S, EC, entity))
11147330f729Sjoerg return;
11157330f729Sjoerg
11167330f729Sjoerg // Find an original declaration.
11177330f729Sjoerg while (D->isOutOfLine()) {
11187330f729Sjoerg NamedDecl *PrevDecl = nullptr;
11197330f729Sjoerg if (VarDecl *VD = dyn_cast<VarDecl>(D))
11207330f729Sjoerg PrevDecl = VD->getPreviousDecl();
11217330f729Sjoerg else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
11227330f729Sjoerg PrevDecl = FD->getPreviousDecl();
11237330f729Sjoerg else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
11247330f729Sjoerg PrevDecl = TND->getPreviousDecl();
11257330f729Sjoerg else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
11267330f729Sjoerg if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
11277330f729Sjoerg break;
11287330f729Sjoerg PrevDecl = TD->getPreviousDecl();
11297330f729Sjoerg }
11307330f729Sjoerg if (!PrevDecl) break;
11317330f729Sjoerg D = PrevDecl;
11327330f729Sjoerg }
11337330f729Sjoerg
11347330f729Sjoerg CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
11357330f729Sjoerg Decl *ImmediateChild;
11367330f729Sjoerg if (D->getDeclContext() == DeclaringClass)
11377330f729Sjoerg ImmediateChild = D;
11387330f729Sjoerg else {
11397330f729Sjoerg DeclContext *DC = D->getDeclContext();
11407330f729Sjoerg while (DC->getParent() != DeclaringClass)
11417330f729Sjoerg DC = DC->getParent();
11427330f729Sjoerg ImmediateChild = cast<Decl>(DC);
11437330f729Sjoerg }
11447330f729Sjoerg
11457330f729Sjoerg // Check whether there's an AccessSpecDecl preceding this in the
11467330f729Sjoerg // chain of the DeclContext.
11477330f729Sjoerg bool isImplicit = true;
11487330f729Sjoerg for (const auto *I : DeclaringClass->decls()) {
11497330f729Sjoerg if (I == ImmediateChild) break;
11507330f729Sjoerg if (isa<AccessSpecDecl>(I)) {
11517330f729Sjoerg isImplicit = false;
11527330f729Sjoerg break;
11537330f729Sjoerg }
11547330f729Sjoerg }
11557330f729Sjoerg
11567330f729Sjoerg S.Diag(D->getLocation(), diag::note_access_natural)
11577330f729Sjoerg << (unsigned) (D->getAccess() == AS_protected)
11587330f729Sjoerg << isImplicit;
11597330f729Sjoerg }
11607330f729Sjoerg
11617330f729Sjoerg /// Diagnose the path which caused the given declaration or base class
11627330f729Sjoerg /// to become inaccessible.
DiagnoseAccessPath(Sema & S,const EffectiveContext & EC,AccessTarget & entity)11637330f729Sjoerg static void DiagnoseAccessPath(Sema &S,
11647330f729Sjoerg const EffectiveContext &EC,
11657330f729Sjoerg AccessTarget &entity) {
11667330f729Sjoerg // Save the instance context to preserve invariants.
11677330f729Sjoerg AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext();
11687330f729Sjoerg
11697330f729Sjoerg // This basically repeats the main algorithm but keeps some more
11707330f729Sjoerg // information.
11717330f729Sjoerg
11727330f729Sjoerg // The natural access so far.
11737330f729Sjoerg AccessSpecifier accessSoFar = AS_public;
11747330f729Sjoerg
11757330f729Sjoerg // Check whether we have special rights to the declaring class.
11767330f729Sjoerg if (entity.isMemberAccess()) {
11777330f729Sjoerg NamedDecl *D = entity.getTargetDecl();
11787330f729Sjoerg accessSoFar = D->getAccess();
11797330f729Sjoerg const CXXRecordDecl *declaringClass = entity.getDeclaringClass();
11807330f729Sjoerg
11817330f729Sjoerg switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) {
11827330f729Sjoerg // If the declaration is accessible when named in its declaring
11837330f729Sjoerg // class, then we must be constrained by the path.
11847330f729Sjoerg case AR_accessible:
11857330f729Sjoerg accessSoFar = AS_public;
11867330f729Sjoerg entity.suppressInstanceContext();
11877330f729Sjoerg break;
11887330f729Sjoerg
11897330f729Sjoerg case AR_inaccessible:
11907330f729Sjoerg if (accessSoFar == AS_private ||
11917330f729Sjoerg declaringClass == entity.getEffectiveNamingClass())
11927330f729Sjoerg return diagnoseBadDirectAccess(S, EC, entity);
11937330f729Sjoerg break;
11947330f729Sjoerg
11957330f729Sjoerg case AR_dependent:
11967330f729Sjoerg llvm_unreachable("cannot diagnose dependent access");
11977330f729Sjoerg }
11987330f729Sjoerg }
11997330f729Sjoerg
12007330f729Sjoerg CXXBasePaths paths;
12017330f729Sjoerg CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths);
12027330f729Sjoerg assert(path.Access != AS_public);
12037330f729Sjoerg
12047330f729Sjoerg CXXBasePath::iterator i = path.end(), e = path.begin();
12057330f729Sjoerg CXXBasePath::iterator constrainingBase = i;
12067330f729Sjoerg while (i != e) {
12077330f729Sjoerg --i;
12087330f729Sjoerg
12097330f729Sjoerg assert(accessSoFar != AS_none && accessSoFar != AS_private);
12107330f729Sjoerg
12117330f729Sjoerg // Is the entity accessible when named in the deriving class, as
12127330f729Sjoerg // modified by the base specifier?
12137330f729Sjoerg const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl();
12147330f729Sjoerg const CXXBaseSpecifier *base = i->Base;
12157330f729Sjoerg
12167330f729Sjoerg // If the access to this base is worse than the access we have to
12177330f729Sjoerg // the declaration, remember it.
12187330f729Sjoerg AccessSpecifier baseAccess = base->getAccessSpecifier();
12197330f729Sjoerg if (baseAccess > accessSoFar) {
12207330f729Sjoerg constrainingBase = i;
12217330f729Sjoerg accessSoFar = baseAccess;
12227330f729Sjoerg }
12237330f729Sjoerg
12247330f729Sjoerg switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) {
12257330f729Sjoerg case AR_inaccessible: break;
12267330f729Sjoerg case AR_accessible:
12277330f729Sjoerg accessSoFar = AS_public;
12287330f729Sjoerg entity.suppressInstanceContext();
12297330f729Sjoerg constrainingBase = nullptr;
12307330f729Sjoerg break;
12317330f729Sjoerg case AR_dependent:
12327330f729Sjoerg llvm_unreachable("cannot diagnose dependent access");
12337330f729Sjoerg }
12347330f729Sjoerg
12357330f729Sjoerg // If this was private inheritance, but we don't have access to
12367330f729Sjoerg // the deriving class, we're done.
12377330f729Sjoerg if (accessSoFar == AS_private) {
12387330f729Sjoerg assert(baseAccess == AS_private);
12397330f729Sjoerg assert(constrainingBase == i);
12407330f729Sjoerg break;
12417330f729Sjoerg }
12427330f729Sjoerg }
12437330f729Sjoerg
12447330f729Sjoerg // If we don't have a constraining base, the access failure must be
12457330f729Sjoerg // due to the original declaration.
12467330f729Sjoerg if (constrainingBase == path.end())
12477330f729Sjoerg return diagnoseBadDirectAccess(S, EC, entity);
12487330f729Sjoerg
12497330f729Sjoerg // We're constrained by inheritance, but we want to say
12507330f729Sjoerg // "declared private here" if we're diagnosing a hierarchy
12517330f729Sjoerg // conversion and this is the final step.
12527330f729Sjoerg unsigned diagnostic;
12537330f729Sjoerg if (entity.isMemberAccess() ||
12547330f729Sjoerg constrainingBase + 1 != path.end()) {
12557330f729Sjoerg diagnostic = diag::note_access_constrained_by_path;
12567330f729Sjoerg } else {
12577330f729Sjoerg diagnostic = diag::note_access_natural;
12587330f729Sjoerg }
12597330f729Sjoerg
12607330f729Sjoerg const CXXBaseSpecifier *base = constrainingBase->Base;
12617330f729Sjoerg
12627330f729Sjoerg S.Diag(base->getSourceRange().getBegin(), diagnostic)
12637330f729Sjoerg << base->getSourceRange()
12647330f729Sjoerg << (base->getAccessSpecifier() == AS_protected)
12657330f729Sjoerg << (base->getAccessSpecifierAsWritten() == AS_none);
12667330f729Sjoerg
12677330f729Sjoerg if (entity.isMemberAccess())
12687330f729Sjoerg S.Diag(entity.getTargetDecl()->getLocation(),
12697330f729Sjoerg diag::note_member_declared_at);
12707330f729Sjoerg }
12717330f729Sjoerg
DiagnoseBadAccess(Sema & S,SourceLocation Loc,const EffectiveContext & EC,AccessTarget & Entity)12727330f729Sjoerg static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
12737330f729Sjoerg const EffectiveContext &EC,
12747330f729Sjoerg AccessTarget &Entity) {
12757330f729Sjoerg const CXXRecordDecl *NamingClass = Entity.getNamingClass();
12767330f729Sjoerg const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
12777330f729Sjoerg NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : nullptr);
12787330f729Sjoerg
12797330f729Sjoerg S.Diag(Loc, Entity.getDiag())
12807330f729Sjoerg << (Entity.getAccess() == AS_protected)
12817330f729Sjoerg << (D ? D->getDeclName() : DeclarationName())
12827330f729Sjoerg << S.Context.getTypeDeclType(NamingClass)
12837330f729Sjoerg << S.Context.getTypeDeclType(DeclaringClass);
12847330f729Sjoerg DiagnoseAccessPath(S, EC, Entity);
12857330f729Sjoerg }
12867330f729Sjoerg
12877330f729Sjoerg /// MSVC has a bug where if during an using declaration name lookup,
12887330f729Sjoerg /// the declaration found is unaccessible (private) and that declaration
12897330f729Sjoerg /// was bring into scope via another using declaration whose target
12907330f729Sjoerg /// declaration is accessible (public) then no error is generated.
12917330f729Sjoerg /// Example:
12927330f729Sjoerg /// class A {
12937330f729Sjoerg /// public:
12947330f729Sjoerg /// int f();
12957330f729Sjoerg /// };
12967330f729Sjoerg /// class B : public A {
12977330f729Sjoerg /// private:
12987330f729Sjoerg /// using A::f;
12997330f729Sjoerg /// };
13007330f729Sjoerg /// class C : public B {
13017330f729Sjoerg /// private:
13027330f729Sjoerg /// using B::f;
13037330f729Sjoerg /// };
13047330f729Sjoerg ///
13057330f729Sjoerg /// Here, B::f is private so this should fail in Standard C++, but
13067330f729Sjoerg /// because B::f refers to A::f which is public MSVC accepts it.
IsMicrosoftUsingDeclarationAccessBug(Sema & S,SourceLocation AccessLoc,AccessTarget & Entity)13077330f729Sjoerg static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
13087330f729Sjoerg SourceLocation AccessLoc,
13097330f729Sjoerg AccessTarget &Entity) {
13107330f729Sjoerg if (UsingShadowDecl *Shadow =
13117330f729Sjoerg dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) {
13127330f729Sjoerg const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl();
13137330f729Sjoerg if (Entity.getTargetDecl()->getAccess() == AS_private &&
13147330f729Sjoerg (OrigDecl->getAccess() == AS_public ||
13157330f729Sjoerg OrigDecl->getAccess() == AS_protected)) {
13167330f729Sjoerg S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible)
13177330f729Sjoerg << Shadow->getUsingDecl()->getQualifiedNameAsString()
13187330f729Sjoerg << OrigDecl->getQualifiedNameAsString();
13197330f729Sjoerg return true;
13207330f729Sjoerg }
13217330f729Sjoerg }
13227330f729Sjoerg return false;
13237330f729Sjoerg }
13247330f729Sjoerg
13257330f729Sjoerg /// Determines whether the accessed entity is accessible. Public members
13267330f729Sjoerg /// have been weeded out by this point.
IsAccessible(Sema & S,const EffectiveContext & EC,AccessTarget & Entity)13277330f729Sjoerg static AccessResult IsAccessible(Sema &S,
13287330f729Sjoerg const EffectiveContext &EC,
13297330f729Sjoerg AccessTarget &Entity) {
13307330f729Sjoerg // Determine the actual naming class.
13317330f729Sjoerg const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();
13327330f729Sjoerg
13337330f729Sjoerg AccessSpecifier UnprivilegedAccess = Entity.getAccess();
13347330f729Sjoerg assert(UnprivilegedAccess != AS_public && "public access not weeded out");
13357330f729Sjoerg
13367330f729Sjoerg // Before we try to recalculate access paths, try to white-list
13377330f729Sjoerg // accesses which just trade in on the final step, i.e. accesses
13387330f729Sjoerg // which don't require [M4] or [B4]. These are by far the most
13397330f729Sjoerg // common forms of privileged access.
13407330f729Sjoerg if (UnprivilegedAccess != AS_none) {
13417330f729Sjoerg switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) {
13427330f729Sjoerg case AR_dependent:
13437330f729Sjoerg // This is actually an interesting policy decision. We don't
13447330f729Sjoerg // *have* to delay immediately here: we can do the full access
13457330f729Sjoerg // calculation in the hope that friendship on some intermediate
13467330f729Sjoerg // class will make the declaration accessible non-dependently.
13477330f729Sjoerg // But that's not cheap, and odds are very good (note: assertion
13487330f729Sjoerg // made without data) that the friend declaration will determine
13497330f729Sjoerg // access.
13507330f729Sjoerg return AR_dependent;
13517330f729Sjoerg
13527330f729Sjoerg case AR_accessible: return AR_accessible;
13537330f729Sjoerg case AR_inaccessible: break;
13547330f729Sjoerg }
13557330f729Sjoerg }
13567330f729Sjoerg
13577330f729Sjoerg AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();
13587330f729Sjoerg
13597330f729Sjoerg // We lower member accesses to base accesses by pretending that the
13607330f729Sjoerg // member is a base class of its declaring class.
13617330f729Sjoerg AccessSpecifier FinalAccess;
13627330f729Sjoerg
13637330f729Sjoerg if (Entity.isMemberAccess()) {
13647330f729Sjoerg // Determine if the declaration is accessible from EC when named
13657330f729Sjoerg // in its declaring class.
13667330f729Sjoerg NamedDecl *Target = Entity.getTargetDecl();
13677330f729Sjoerg const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
13687330f729Sjoerg
13697330f729Sjoerg FinalAccess = Target->getAccess();
13707330f729Sjoerg switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
13717330f729Sjoerg case AR_accessible:
13727330f729Sjoerg // Target is accessible at EC when named in its declaring class.
13737330f729Sjoerg // We can now hill-climb and simply check whether the declaring
13747330f729Sjoerg // class is accessible as a base of the naming class. This is
13757330f729Sjoerg // equivalent to checking the access of a notional public
13767330f729Sjoerg // member with no instance context.
13777330f729Sjoerg FinalAccess = AS_public;
13787330f729Sjoerg Entity.suppressInstanceContext();
13797330f729Sjoerg break;
13807330f729Sjoerg case AR_inaccessible: break;
13817330f729Sjoerg case AR_dependent: return AR_dependent; // see above
13827330f729Sjoerg }
13837330f729Sjoerg
13847330f729Sjoerg if (DeclaringClass == NamingClass)
13857330f729Sjoerg return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
13867330f729Sjoerg } else {
13877330f729Sjoerg FinalAccess = AS_public;
13887330f729Sjoerg }
13897330f729Sjoerg
13907330f729Sjoerg assert(Entity.getDeclaringClass() != NamingClass);
13917330f729Sjoerg
13927330f729Sjoerg // Append the declaration's access if applicable.
13937330f729Sjoerg CXXBasePaths Paths;
13947330f729Sjoerg CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths);
13957330f729Sjoerg if (!Path)
13967330f729Sjoerg return AR_dependent;
13977330f729Sjoerg
13987330f729Sjoerg assert(Path->Access <= UnprivilegedAccess &&
13997330f729Sjoerg "access along best path worse than direct?");
14007330f729Sjoerg if (Path->Access == AS_public)
14017330f729Sjoerg return AR_accessible;
14027330f729Sjoerg return AR_inaccessible;
14037330f729Sjoerg }
14047330f729Sjoerg
DelayDependentAccess(Sema & S,const EffectiveContext & EC,SourceLocation Loc,const AccessTarget & Entity)14057330f729Sjoerg static void DelayDependentAccess(Sema &S,
14067330f729Sjoerg const EffectiveContext &EC,
14077330f729Sjoerg SourceLocation Loc,
14087330f729Sjoerg const AccessTarget &Entity) {
14097330f729Sjoerg assert(EC.isDependent() && "delaying non-dependent access");
14107330f729Sjoerg DeclContext *DC = EC.getInnerContext();
14117330f729Sjoerg assert(DC->isDependentContext() && "delaying non-dependent access");
14127330f729Sjoerg DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
14137330f729Sjoerg Loc,
14147330f729Sjoerg Entity.isMemberAccess(),
14157330f729Sjoerg Entity.getAccess(),
14167330f729Sjoerg Entity.getTargetDecl(),
14177330f729Sjoerg Entity.getNamingClass(),
14187330f729Sjoerg Entity.getBaseObjectType(),
14197330f729Sjoerg Entity.getDiag());
14207330f729Sjoerg }
14217330f729Sjoerg
14227330f729Sjoerg /// Checks access to an entity from the given effective context.
CheckEffectiveAccess(Sema & S,const EffectiveContext & EC,SourceLocation Loc,AccessTarget & Entity)14237330f729Sjoerg static AccessResult CheckEffectiveAccess(Sema &S,
14247330f729Sjoerg const EffectiveContext &EC,
14257330f729Sjoerg SourceLocation Loc,
14267330f729Sjoerg AccessTarget &Entity) {
14277330f729Sjoerg assert(Entity.getAccess() != AS_public && "called for public access!");
14287330f729Sjoerg
14297330f729Sjoerg switch (IsAccessible(S, EC, Entity)) {
14307330f729Sjoerg case AR_dependent:
14317330f729Sjoerg DelayDependentAccess(S, EC, Loc, Entity);
14327330f729Sjoerg return AR_dependent;
14337330f729Sjoerg
14347330f729Sjoerg case AR_inaccessible:
14357330f729Sjoerg if (S.getLangOpts().MSVCCompat &&
14367330f729Sjoerg IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
14377330f729Sjoerg return AR_accessible;
14387330f729Sjoerg if (!Entity.isQuiet())
14397330f729Sjoerg DiagnoseBadAccess(S, Loc, EC, Entity);
14407330f729Sjoerg return AR_inaccessible;
14417330f729Sjoerg
14427330f729Sjoerg case AR_accessible:
14437330f729Sjoerg return AR_accessible;
14447330f729Sjoerg }
14457330f729Sjoerg
14467330f729Sjoerg // silence unnecessary warning
14477330f729Sjoerg llvm_unreachable("invalid access result");
14487330f729Sjoerg }
14497330f729Sjoerg
CheckAccess(Sema & S,SourceLocation Loc,AccessTarget & Entity)14507330f729Sjoerg static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
14517330f729Sjoerg AccessTarget &Entity) {
14527330f729Sjoerg // If the access path is public, it's accessible everywhere.
14537330f729Sjoerg if (Entity.getAccess() == AS_public)
14547330f729Sjoerg return Sema::AR_accessible;
14557330f729Sjoerg
14567330f729Sjoerg // If we're currently parsing a declaration, we may need to delay
14577330f729Sjoerg // access control checking, because our effective context might be
14587330f729Sjoerg // different based on what the declaration comes out as.
14597330f729Sjoerg //
14607330f729Sjoerg // For example, we might be parsing a declaration with a scope
14617330f729Sjoerg // specifier, like this:
14627330f729Sjoerg // A::private_type A::foo() { ... }
14637330f729Sjoerg //
14647330f729Sjoerg // Or we might be parsing something that will turn out to be a friend:
14657330f729Sjoerg // void foo(A::private_type);
14667330f729Sjoerg // void B::foo(A::private_type);
14677330f729Sjoerg if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
14687330f729Sjoerg S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity));
14697330f729Sjoerg return Sema::AR_delayed;
14707330f729Sjoerg }
14717330f729Sjoerg
14727330f729Sjoerg EffectiveContext EC(S.CurContext);
14737330f729Sjoerg switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
14747330f729Sjoerg case AR_accessible: return Sema::AR_accessible;
14757330f729Sjoerg case AR_inaccessible: return Sema::AR_inaccessible;
14767330f729Sjoerg case AR_dependent: return Sema::AR_dependent;
14777330f729Sjoerg }
14787330f729Sjoerg llvm_unreachable("invalid access result");
14797330f729Sjoerg }
14807330f729Sjoerg
HandleDelayedAccessCheck(DelayedDiagnostic & DD,Decl * D)14817330f729Sjoerg void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
14827330f729Sjoerg // Access control for names used in the declarations of functions
14837330f729Sjoerg // and function templates should normally be evaluated in the context
14847330f729Sjoerg // of the declaration, just in case it's a friend of something.
14857330f729Sjoerg // However, this does not apply to local extern declarations.
14867330f729Sjoerg
14877330f729Sjoerg DeclContext *DC = D->getDeclContext();
14887330f729Sjoerg if (D->isLocalExternDecl()) {
14897330f729Sjoerg DC = D->getLexicalDeclContext();
14907330f729Sjoerg } else if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {
14917330f729Sjoerg DC = FN;
14927330f729Sjoerg } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
1493*e038c9c4Sjoerg if (isa<DeclContext>(TD->getTemplatedDecl()))
14947330f729Sjoerg DC = cast<DeclContext>(TD->getTemplatedDecl());
14957330f729Sjoerg }
14967330f729Sjoerg
14977330f729Sjoerg EffectiveContext EC(DC);
14987330f729Sjoerg
14997330f729Sjoerg AccessTarget Target(DD.getAccessData());
15007330f729Sjoerg
15017330f729Sjoerg if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible)
15027330f729Sjoerg DD.Triggered = true;
15037330f729Sjoerg }
15047330f729Sjoerg
HandleDependentAccessCheck(const DependentDiagnostic & DD,const MultiLevelTemplateArgumentList & TemplateArgs)15057330f729Sjoerg void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
15067330f729Sjoerg const MultiLevelTemplateArgumentList &TemplateArgs) {
15077330f729Sjoerg SourceLocation Loc = DD.getAccessLoc();
15087330f729Sjoerg AccessSpecifier Access = DD.getAccess();
15097330f729Sjoerg
15107330f729Sjoerg Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
15117330f729Sjoerg TemplateArgs);
15127330f729Sjoerg if (!NamingD) return;
15137330f729Sjoerg Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
15147330f729Sjoerg TemplateArgs);
15157330f729Sjoerg if (!TargetD) return;
15167330f729Sjoerg
15177330f729Sjoerg if (DD.isAccessToMember()) {
15187330f729Sjoerg CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD);
15197330f729Sjoerg NamedDecl *TargetDecl = cast<NamedDecl>(TargetD);
15207330f729Sjoerg QualType BaseObjectType = DD.getAccessBaseObjectType();
15217330f729Sjoerg if (!BaseObjectType.isNull()) {
15227330f729Sjoerg BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc,
15237330f729Sjoerg DeclarationName());
15247330f729Sjoerg if (BaseObjectType.isNull()) return;
15257330f729Sjoerg }
15267330f729Sjoerg
15277330f729Sjoerg AccessTarget Entity(Context,
15287330f729Sjoerg AccessTarget::Member,
15297330f729Sjoerg NamingClass,
15307330f729Sjoerg DeclAccessPair::make(TargetDecl, Access),
15317330f729Sjoerg BaseObjectType);
15327330f729Sjoerg Entity.setDiag(DD.getDiagnostic());
15337330f729Sjoerg CheckAccess(*this, Loc, Entity);
15347330f729Sjoerg } else {
15357330f729Sjoerg AccessTarget Entity(Context,
15367330f729Sjoerg AccessTarget::Base,
15377330f729Sjoerg cast<CXXRecordDecl>(TargetD),
15387330f729Sjoerg cast<CXXRecordDecl>(NamingD),
15397330f729Sjoerg Access);
15407330f729Sjoerg Entity.setDiag(DD.getDiagnostic());
15417330f729Sjoerg CheckAccess(*this, Loc, Entity);
15427330f729Sjoerg }
15437330f729Sjoerg }
15447330f729Sjoerg
CheckUnresolvedLookupAccess(UnresolvedLookupExpr * E,DeclAccessPair Found)15457330f729Sjoerg Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
15467330f729Sjoerg DeclAccessPair Found) {
15477330f729Sjoerg if (!getLangOpts().AccessControl ||
15487330f729Sjoerg !E->getNamingClass() ||
15497330f729Sjoerg Found.getAccess() == AS_public)
15507330f729Sjoerg return AR_accessible;
15517330f729Sjoerg
15527330f729Sjoerg AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
15537330f729Sjoerg Found, QualType());
15547330f729Sjoerg Entity.setDiag(diag::err_access) << E->getSourceRange();
15557330f729Sjoerg
15567330f729Sjoerg return CheckAccess(*this, E->getNameLoc(), Entity);
15577330f729Sjoerg }
15587330f729Sjoerg
15597330f729Sjoerg /// Perform access-control checking on a previously-unresolved member
15607330f729Sjoerg /// access which has now been resolved to a member.
CheckUnresolvedMemberAccess(UnresolvedMemberExpr * E,DeclAccessPair Found)15617330f729Sjoerg Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
15627330f729Sjoerg DeclAccessPair Found) {
15637330f729Sjoerg if (!getLangOpts().AccessControl ||
15647330f729Sjoerg Found.getAccess() == AS_public)
15657330f729Sjoerg return AR_accessible;
15667330f729Sjoerg
15677330f729Sjoerg QualType BaseType = E->getBaseType();
15687330f729Sjoerg if (E->isArrow())
15697330f729Sjoerg BaseType = BaseType->castAs<PointerType>()->getPointeeType();
15707330f729Sjoerg
15717330f729Sjoerg AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
15727330f729Sjoerg Found, BaseType);
15737330f729Sjoerg Entity.setDiag(diag::err_access) << E->getSourceRange();
15747330f729Sjoerg
15757330f729Sjoerg return CheckAccess(*this, E->getMemberLoc(), Entity);
15767330f729Sjoerg }
15777330f729Sjoerg
1578*e038c9c4Sjoerg /// Is the given member accessible for the purposes of deciding whether to
1579*e038c9c4Sjoerg /// define a special member function as deleted?
isMemberAccessibleForDeletion(CXXRecordDecl * NamingClass,DeclAccessPair Found,QualType ObjectType,SourceLocation Loc,const PartialDiagnostic & Diag)1580*e038c9c4Sjoerg bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass,
1581*e038c9c4Sjoerg DeclAccessPair Found,
1582*e038c9c4Sjoerg QualType ObjectType,
1583*e038c9c4Sjoerg SourceLocation Loc,
1584*e038c9c4Sjoerg const PartialDiagnostic &Diag) {
15857330f729Sjoerg // Fast path.
1586*e038c9c4Sjoerg if (Found.getAccess() == AS_public || !getLangOpts().AccessControl)
1587*e038c9c4Sjoerg return true;
15887330f729Sjoerg
1589*e038c9c4Sjoerg AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1590*e038c9c4Sjoerg ObjectType);
15917330f729Sjoerg
15927330f729Sjoerg // Suppress diagnostics.
1593*e038c9c4Sjoerg Entity.setDiag(Diag);
15947330f729Sjoerg
1595*e038c9c4Sjoerg switch (CheckAccess(*this, Loc, Entity)) {
15967330f729Sjoerg case AR_accessible: return true;
15977330f729Sjoerg case AR_inaccessible: return false;
15987330f729Sjoerg case AR_dependent: llvm_unreachable("dependent for =delete computation");
15997330f729Sjoerg case AR_delayed: llvm_unreachable("cannot delay =delete computation");
16007330f729Sjoerg }
16017330f729Sjoerg llvm_unreachable("bad access result");
16027330f729Sjoerg }
16037330f729Sjoerg
CheckDestructorAccess(SourceLocation Loc,CXXDestructorDecl * Dtor,const PartialDiagnostic & PDiag,QualType ObjectTy)16047330f729Sjoerg Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
16057330f729Sjoerg CXXDestructorDecl *Dtor,
16067330f729Sjoerg const PartialDiagnostic &PDiag,
16077330f729Sjoerg QualType ObjectTy) {
16087330f729Sjoerg if (!getLangOpts().AccessControl)
16097330f729Sjoerg return AR_accessible;
16107330f729Sjoerg
16117330f729Sjoerg // There's never a path involved when checking implicit destructor access.
16127330f729Sjoerg AccessSpecifier Access = Dtor->getAccess();
16137330f729Sjoerg if (Access == AS_public)
16147330f729Sjoerg return AR_accessible;
16157330f729Sjoerg
16167330f729Sjoerg CXXRecordDecl *NamingClass = Dtor->getParent();
16177330f729Sjoerg if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass);
16187330f729Sjoerg
16197330f729Sjoerg AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
16207330f729Sjoerg DeclAccessPair::make(Dtor, Access),
16217330f729Sjoerg ObjectTy);
16227330f729Sjoerg Entity.setDiag(PDiag); // TODO: avoid copy
16237330f729Sjoerg
16247330f729Sjoerg return CheckAccess(*this, Loc, Entity);
16257330f729Sjoerg }
16267330f729Sjoerg
16277330f729Sjoerg /// Checks access to a constructor.
CheckConstructorAccess(SourceLocation UseLoc,CXXConstructorDecl * Constructor,DeclAccessPair Found,const InitializedEntity & Entity,bool IsCopyBindingRefToTemp)16287330f729Sjoerg Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
16297330f729Sjoerg CXXConstructorDecl *Constructor,
16307330f729Sjoerg DeclAccessPair Found,
16317330f729Sjoerg const InitializedEntity &Entity,
16327330f729Sjoerg bool IsCopyBindingRefToTemp) {
16337330f729Sjoerg if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
16347330f729Sjoerg return AR_accessible;
16357330f729Sjoerg
16367330f729Sjoerg PartialDiagnostic PD(PDiag());
16377330f729Sjoerg switch (Entity.getKind()) {
16387330f729Sjoerg default:
16397330f729Sjoerg PD = PDiag(IsCopyBindingRefToTemp
16407330f729Sjoerg ? diag::ext_rvalue_to_reference_access_ctor
16417330f729Sjoerg : diag::err_access_ctor);
16427330f729Sjoerg
16437330f729Sjoerg break;
16447330f729Sjoerg
16457330f729Sjoerg case InitializedEntity::EK_Base:
16467330f729Sjoerg PD = PDiag(diag::err_access_base_ctor);
16477330f729Sjoerg PD << Entity.isInheritedVirtualBase()
16487330f729Sjoerg << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
16497330f729Sjoerg break;
16507330f729Sjoerg
16517330f729Sjoerg case InitializedEntity::EK_Member: {
16527330f729Sjoerg const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
16537330f729Sjoerg PD = PDiag(diag::err_access_field_ctor);
16547330f729Sjoerg PD << Field->getType() << getSpecialMember(Constructor);
16557330f729Sjoerg break;
16567330f729Sjoerg }
16577330f729Sjoerg
16587330f729Sjoerg case InitializedEntity::EK_LambdaCapture: {
16597330f729Sjoerg StringRef VarName = Entity.getCapturedVarName();
16607330f729Sjoerg PD = PDiag(diag::err_access_lambda_capture);
16617330f729Sjoerg PD << VarName << Entity.getType() << getSpecialMember(Constructor);
16627330f729Sjoerg break;
16637330f729Sjoerg }
16647330f729Sjoerg
16657330f729Sjoerg }
16667330f729Sjoerg
16677330f729Sjoerg return CheckConstructorAccess(UseLoc, Constructor, Found, Entity, PD);
16687330f729Sjoerg }
16697330f729Sjoerg
16707330f729Sjoerg /// Checks access to a constructor.
CheckConstructorAccess(SourceLocation UseLoc,CXXConstructorDecl * Constructor,DeclAccessPair Found,const InitializedEntity & Entity,const PartialDiagnostic & PD)16717330f729Sjoerg Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
16727330f729Sjoerg CXXConstructorDecl *Constructor,
16737330f729Sjoerg DeclAccessPair Found,
16747330f729Sjoerg const InitializedEntity &Entity,
16757330f729Sjoerg const PartialDiagnostic &PD) {
16767330f729Sjoerg if (!getLangOpts().AccessControl ||
16777330f729Sjoerg Found.getAccess() == AS_public)
16787330f729Sjoerg return AR_accessible;
16797330f729Sjoerg
16807330f729Sjoerg CXXRecordDecl *NamingClass = Constructor->getParent();
16817330f729Sjoerg
16827330f729Sjoerg // Initializing a base sub-object is an instance method call on an
16837330f729Sjoerg // object of the derived class. Otherwise, we have an instance method
16847330f729Sjoerg // call on an object of the constructed type.
16857330f729Sjoerg //
16867330f729Sjoerg // FIXME: If we have a parent, we're initializing the base class subobject
16877330f729Sjoerg // in aggregate initialization. It's not clear whether the object class
16887330f729Sjoerg // should be the base class or the derived class in that case.
16897330f729Sjoerg CXXRecordDecl *ObjectClass;
16907330f729Sjoerg if ((Entity.getKind() == InitializedEntity::EK_Base ||
16917330f729Sjoerg Entity.getKind() == InitializedEntity::EK_Delegating) &&
16927330f729Sjoerg !Entity.getParent()) {
16937330f729Sjoerg ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent();
16947330f729Sjoerg } else if (auto *Shadow =
16957330f729Sjoerg dyn_cast<ConstructorUsingShadowDecl>(Found.getDecl())) {
16967330f729Sjoerg // If we're using an inheriting constructor to construct an object,
16977330f729Sjoerg // the object class is the derived class, not the base class.
16987330f729Sjoerg ObjectClass = Shadow->getParent();
16997330f729Sjoerg } else {
17007330f729Sjoerg ObjectClass = NamingClass;
17017330f729Sjoerg }
17027330f729Sjoerg
17037330f729Sjoerg AccessTarget AccessEntity(
17047330f729Sjoerg Context, AccessTarget::Member, NamingClass,
17057330f729Sjoerg DeclAccessPair::make(Constructor, Found.getAccess()),
17067330f729Sjoerg Context.getTypeDeclType(ObjectClass));
17077330f729Sjoerg AccessEntity.setDiag(PD);
17087330f729Sjoerg
17097330f729Sjoerg return CheckAccess(*this, UseLoc, AccessEntity);
17107330f729Sjoerg }
17117330f729Sjoerg
17127330f729Sjoerg /// Checks access to an overloaded operator new or delete.
CheckAllocationAccess(SourceLocation OpLoc,SourceRange PlacementRange,CXXRecordDecl * NamingClass,DeclAccessPair Found,bool Diagnose)17137330f729Sjoerg Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
17147330f729Sjoerg SourceRange PlacementRange,
17157330f729Sjoerg CXXRecordDecl *NamingClass,
17167330f729Sjoerg DeclAccessPair Found,
17177330f729Sjoerg bool Diagnose) {
17187330f729Sjoerg if (!getLangOpts().AccessControl ||
17197330f729Sjoerg !NamingClass ||
17207330f729Sjoerg Found.getAccess() == AS_public)
17217330f729Sjoerg return AR_accessible;
17227330f729Sjoerg
17237330f729Sjoerg AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
17247330f729Sjoerg QualType());
17257330f729Sjoerg if (Diagnose)
17267330f729Sjoerg Entity.setDiag(diag::err_access)
17277330f729Sjoerg << PlacementRange;
17287330f729Sjoerg
17297330f729Sjoerg return CheckAccess(*this, OpLoc, Entity);
17307330f729Sjoerg }
17317330f729Sjoerg
17327330f729Sjoerg /// Checks access to a member.
CheckMemberAccess(SourceLocation UseLoc,CXXRecordDecl * NamingClass,DeclAccessPair Found)17337330f729Sjoerg Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc,
17347330f729Sjoerg CXXRecordDecl *NamingClass,
17357330f729Sjoerg DeclAccessPair Found) {
17367330f729Sjoerg if (!getLangOpts().AccessControl ||
17377330f729Sjoerg !NamingClass ||
17387330f729Sjoerg Found.getAccess() == AS_public)
17397330f729Sjoerg return AR_accessible;
17407330f729Sjoerg
17417330f729Sjoerg AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
17427330f729Sjoerg Found, QualType());
17437330f729Sjoerg
17447330f729Sjoerg return CheckAccess(*this, UseLoc, Entity);
17457330f729Sjoerg }
17467330f729Sjoerg
17477330f729Sjoerg /// Checks implicit access to a member in a structured binding.
17487330f729Sjoerg Sema::AccessResult
CheckStructuredBindingMemberAccess(SourceLocation UseLoc,CXXRecordDecl * DecomposedClass,DeclAccessPair Field)17497330f729Sjoerg Sema::CheckStructuredBindingMemberAccess(SourceLocation UseLoc,
17507330f729Sjoerg CXXRecordDecl *DecomposedClass,
17517330f729Sjoerg DeclAccessPair Field) {
17527330f729Sjoerg if (!getLangOpts().AccessControl ||
17537330f729Sjoerg Field.getAccess() == AS_public)
17547330f729Sjoerg return AR_accessible;
17557330f729Sjoerg
17567330f729Sjoerg AccessTarget Entity(Context, AccessTarget::Member, DecomposedClass, Field,
17577330f729Sjoerg Context.getRecordType(DecomposedClass));
17587330f729Sjoerg Entity.setDiag(diag::err_decomp_decl_inaccessible_field);
17597330f729Sjoerg
17607330f729Sjoerg return CheckAccess(*this, UseLoc, Entity);
17617330f729Sjoerg }
17627330f729Sjoerg
17637330f729Sjoerg /// Checks access to an overloaded member operator, including
17647330f729Sjoerg /// conversion operators.
CheckMemberOperatorAccess(SourceLocation OpLoc,Expr * ObjectExpr,Expr * ArgExpr,DeclAccessPair Found)17657330f729Sjoerg Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
17667330f729Sjoerg Expr *ObjectExpr,
17677330f729Sjoerg Expr *ArgExpr,
17687330f729Sjoerg DeclAccessPair Found) {
17697330f729Sjoerg if (!getLangOpts().AccessControl ||
17707330f729Sjoerg Found.getAccess() == AS_public)
17717330f729Sjoerg return AR_accessible;
17727330f729Sjoerg
17737330f729Sjoerg const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();
17747330f729Sjoerg CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
17757330f729Sjoerg
17767330f729Sjoerg AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
17777330f729Sjoerg ObjectExpr->getType());
17787330f729Sjoerg Entity.setDiag(diag::err_access)
17797330f729Sjoerg << ObjectExpr->getSourceRange()
17807330f729Sjoerg << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
17817330f729Sjoerg
17827330f729Sjoerg return CheckAccess(*this, OpLoc, Entity);
17837330f729Sjoerg }
17847330f729Sjoerg
17857330f729Sjoerg /// Checks access to the target of a friend declaration.
CheckFriendAccess(NamedDecl * target)17867330f729Sjoerg Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
17877330f729Sjoerg assert(isa<CXXMethodDecl>(target->getAsFunction()));
17887330f729Sjoerg
17897330f729Sjoerg // Friendship lookup is a redeclaration lookup, so there's never an
17907330f729Sjoerg // inheritance path modifying access.
17917330f729Sjoerg AccessSpecifier access = target->getAccess();
17927330f729Sjoerg
17937330f729Sjoerg if (!getLangOpts().AccessControl || access == AS_public)
17947330f729Sjoerg return AR_accessible;
17957330f729Sjoerg
17967330f729Sjoerg CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction());
17977330f729Sjoerg
17987330f729Sjoerg AccessTarget entity(Context, AccessTarget::Member,
17997330f729Sjoerg cast<CXXRecordDecl>(target->getDeclContext()),
18007330f729Sjoerg DeclAccessPair::make(target, access),
18017330f729Sjoerg /*no instance context*/ QualType());
18027330f729Sjoerg entity.setDiag(diag::err_access_friend_function)
18037330f729Sjoerg << (method->getQualifier() ? method->getQualifierLoc().getSourceRange()
18047330f729Sjoerg : method->getNameInfo().getSourceRange());
18057330f729Sjoerg
18067330f729Sjoerg // We need to bypass delayed-diagnostics because we might be called
18077330f729Sjoerg // while the ParsingDeclarator is active.
18087330f729Sjoerg EffectiveContext EC(CurContext);
18097330f729Sjoerg switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) {
18107330f729Sjoerg case ::AR_accessible: return Sema::AR_accessible;
18117330f729Sjoerg case ::AR_inaccessible: return Sema::AR_inaccessible;
18127330f729Sjoerg case ::AR_dependent: return Sema::AR_dependent;
18137330f729Sjoerg }
18147330f729Sjoerg llvm_unreachable("invalid access result");
18157330f729Sjoerg }
18167330f729Sjoerg
CheckAddressOfMemberAccess(Expr * OvlExpr,DeclAccessPair Found)18177330f729Sjoerg Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
18187330f729Sjoerg DeclAccessPair Found) {
18197330f729Sjoerg if (!getLangOpts().AccessControl ||
18207330f729Sjoerg Found.getAccess() == AS_none ||
18217330f729Sjoerg Found.getAccess() == AS_public)
18227330f729Sjoerg return AR_accessible;
18237330f729Sjoerg
18247330f729Sjoerg OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression;
18257330f729Sjoerg CXXRecordDecl *NamingClass = Ovl->getNamingClass();
18267330f729Sjoerg
18277330f729Sjoerg AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
18287330f729Sjoerg /*no instance context*/ QualType());
18297330f729Sjoerg Entity.setDiag(diag::err_access)
18307330f729Sjoerg << Ovl->getSourceRange();
18317330f729Sjoerg
18327330f729Sjoerg return CheckAccess(*this, Ovl->getNameLoc(), Entity);
18337330f729Sjoerg }
18347330f729Sjoerg
18357330f729Sjoerg /// Checks access for a hierarchy conversion.
18367330f729Sjoerg ///
18377330f729Sjoerg /// \param ForceCheck true if this check should be performed even if access
18387330f729Sjoerg /// control is disabled; some things rely on this for semantics
18397330f729Sjoerg /// \param ForceUnprivileged true if this check should proceed as if the
18407330f729Sjoerg /// context had no special privileges
CheckBaseClassAccess(SourceLocation AccessLoc,QualType Base,QualType Derived,const CXXBasePath & Path,unsigned DiagID,bool ForceCheck,bool ForceUnprivileged)18417330f729Sjoerg Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
18427330f729Sjoerg QualType Base,
18437330f729Sjoerg QualType Derived,
18447330f729Sjoerg const CXXBasePath &Path,
18457330f729Sjoerg unsigned DiagID,
18467330f729Sjoerg bool ForceCheck,
18477330f729Sjoerg bool ForceUnprivileged) {
18487330f729Sjoerg if (!ForceCheck && !getLangOpts().AccessControl)
18497330f729Sjoerg return AR_accessible;
18507330f729Sjoerg
18517330f729Sjoerg if (Path.Access == AS_public)
18527330f729Sjoerg return AR_accessible;
18537330f729Sjoerg
18547330f729Sjoerg CXXRecordDecl *BaseD, *DerivedD;
18557330f729Sjoerg BaseD = cast<CXXRecordDecl>(Base->castAs<RecordType>()->getDecl());
18567330f729Sjoerg DerivedD = cast<CXXRecordDecl>(Derived->castAs<RecordType>()->getDecl());
18577330f729Sjoerg
18587330f729Sjoerg AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,
18597330f729Sjoerg Path.Access);
18607330f729Sjoerg if (DiagID)
18617330f729Sjoerg Entity.setDiag(DiagID) << Derived << Base;
18627330f729Sjoerg
18637330f729Sjoerg if (ForceUnprivileged) {
18647330f729Sjoerg switch (CheckEffectiveAccess(*this, EffectiveContext(),
18657330f729Sjoerg AccessLoc, Entity)) {
18667330f729Sjoerg case ::AR_accessible: return Sema::AR_accessible;
18677330f729Sjoerg case ::AR_inaccessible: return Sema::AR_inaccessible;
18687330f729Sjoerg case ::AR_dependent: return Sema::AR_dependent;
18697330f729Sjoerg }
18707330f729Sjoerg llvm_unreachable("unexpected result from CheckEffectiveAccess");
18717330f729Sjoerg }
18727330f729Sjoerg return CheckAccess(*this, AccessLoc, Entity);
18737330f729Sjoerg }
18747330f729Sjoerg
18757330f729Sjoerg /// Checks access to all the declarations in the given result set.
CheckLookupAccess(const LookupResult & R)18767330f729Sjoerg void Sema::CheckLookupAccess(const LookupResult &R) {
18777330f729Sjoerg assert(getLangOpts().AccessControl
18787330f729Sjoerg && "performing access check without access control");
18797330f729Sjoerg assert(R.getNamingClass() && "performing access check without naming class");
18807330f729Sjoerg
18817330f729Sjoerg for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
18827330f729Sjoerg if (I.getAccess() != AS_public) {
18837330f729Sjoerg AccessTarget Entity(Context, AccessedEntity::Member,
18847330f729Sjoerg R.getNamingClass(), I.getPair(),
18857330f729Sjoerg R.getBaseObjectType());
18867330f729Sjoerg Entity.setDiag(diag::err_access);
18877330f729Sjoerg CheckAccess(*this, R.getNameLoc(), Entity);
18887330f729Sjoerg }
18897330f729Sjoerg }
18907330f729Sjoerg }
18917330f729Sjoerg
18927330f729Sjoerg /// Checks access to Target from the given class. The check will take access
18937330f729Sjoerg /// specifiers into account, but no member access expressions and such.
18947330f729Sjoerg ///
18957330f729Sjoerg /// \param Target the declaration to check if it can be accessed
18967330f729Sjoerg /// \param NamingClass the class in which the lookup was started.
18977330f729Sjoerg /// \param BaseType type of the left side of member access expression.
18987330f729Sjoerg /// \p BaseType and \p NamingClass are used for C++ access control.
18997330f729Sjoerg /// Depending on the lookup case, they should be set to the following:
19007330f729Sjoerg /// - lhs.target (member access without a qualifier):
19017330f729Sjoerg /// \p BaseType and \p NamingClass are both the type of 'lhs'.
19027330f729Sjoerg /// - lhs.X::target (member access with a qualifier):
19037330f729Sjoerg /// BaseType is the type of 'lhs', NamingClass is 'X'
19047330f729Sjoerg /// - X::target (qualified lookup without member access):
19057330f729Sjoerg /// BaseType is null, NamingClass is 'X'.
19067330f729Sjoerg /// - target (unqualified lookup).
19077330f729Sjoerg /// BaseType is null, NamingClass is the parent class of 'target'.
19087330f729Sjoerg /// \return true if the Target is accessible from the Class, false otherwise.
IsSimplyAccessible(NamedDecl * Target,CXXRecordDecl * NamingClass,QualType BaseType)19097330f729Sjoerg bool Sema::IsSimplyAccessible(NamedDecl *Target, CXXRecordDecl *NamingClass,
19107330f729Sjoerg QualType BaseType) {
19117330f729Sjoerg // Perform the C++ accessibility checks first.
19127330f729Sjoerg if (Target->isCXXClassMember() && NamingClass) {
19137330f729Sjoerg if (!getLangOpts().CPlusPlus)
19147330f729Sjoerg return false;
19157330f729Sjoerg // The unprivileged access is AS_none as we don't know how the member was
19167330f729Sjoerg // accessed, which is described by the access in DeclAccessPair.
19177330f729Sjoerg // `IsAccessible` will examine the actual access of Target (i.e.
19187330f729Sjoerg // Decl->getAccess()) when calculating the access.
19197330f729Sjoerg AccessTarget Entity(Context, AccessedEntity::Member, NamingClass,
19207330f729Sjoerg DeclAccessPair::make(Target, AS_none), BaseType);
19217330f729Sjoerg EffectiveContext EC(CurContext);
19227330f729Sjoerg return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
19237330f729Sjoerg }
19247330f729Sjoerg
19257330f729Sjoerg if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Target)) {
19267330f729Sjoerg // @public and @package ivars are always accessible.
19277330f729Sjoerg if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||
19287330f729Sjoerg Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package)
19297330f729Sjoerg return true;
19307330f729Sjoerg
19317330f729Sjoerg // If we are inside a class or category implementation, determine the
19327330f729Sjoerg // interface we're in.
19337330f729Sjoerg ObjCInterfaceDecl *ClassOfMethodDecl = nullptr;
19347330f729Sjoerg if (ObjCMethodDecl *MD = getCurMethodDecl())
19357330f729Sjoerg ClassOfMethodDecl = MD->getClassInterface();
19367330f729Sjoerg else if (FunctionDecl *FD = getCurFunctionDecl()) {
19377330f729Sjoerg if (ObjCImplDecl *Impl
19387330f729Sjoerg = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) {
19397330f729Sjoerg if (ObjCImplementationDecl *IMPD
19407330f729Sjoerg = dyn_cast<ObjCImplementationDecl>(Impl))
19417330f729Sjoerg ClassOfMethodDecl = IMPD->getClassInterface();
19427330f729Sjoerg else if (ObjCCategoryImplDecl* CatImplClass
19437330f729Sjoerg = dyn_cast<ObjCCategoryImplDecl>(Impl))
19447330f729Sjoerg ClassOfMethodDecl = CatImplClass->getClassInterface();
19457330f729Sjoerg }
19467330f729Sjoerg }
19477330f729Sjoerg
19487330f729Sjoerg // If we're not in an interface, this ivar is inaccessible.
19497330f729Sjoerg if (!ClassOfMethodDecl)
19507330f729Sjoerg return false;
19517330f729Sjoerg
19527330f729Sjoerg // If we're inside the same interface that owns the ivar, we're fine.
19537330f729Sjoerg if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface()))
19547330f729Sjoerg return true;
19557330f729Sjoerg
19567330f729Sjoerg // If the ivar is private, it's inaccessible.
19577330f729Sjoerg if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private)
19587330f729Sjoerg return false;
19597330f729Sjoerg
19607330f729Sjoerg return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl);
19617330f729Sjoerg }
19627330f729Sjoerg
19637330f729Sjoerg return true;
19647330f729Sjoerg }
1965