10b57cec5SDimitry Andric //===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file provides Sema routines for C++ access control semantics. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 140b57cec5SDimitry Andric #include "clang/AST/CXXInheritance.h" 150b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h" 160b57cec5SDimitry Andric #include "clang/AST/DeclFriend.h" 170b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h" 180b57cec5SDimitry Andric #include "clang/AST/DependentDiagnostic.h" 190b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h" 20*0fca6ea1SDimitry Andric #include "clang/Basic/Specifiers.h" 210b57cec5SDimitry Andric #include "clang/Sema/DelayedDiagnostic.h" 220b57cec5SDimitry Andric #include "clang/Sema/Initialization.h" 230b57cec5SDimitry Andric #include "clang/Sema/Lookup.h" 24*0fca6ea1SDimitry Andric #include "clang/Sema/SemaInternal.h" 25*0fca6ea1SDimitry Andric #include "llvm/ADT/STLForwardCompat.h" 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace clang; 280b57cec5SDimitry Andric using namespace sema; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric /// A copy of Sema's enum without AR_delayed. 310b57cec5SDimitry Andric enum AccessResult { 320b57cec5SDimitry Andric AR_accessible, 330b57cec5SDimitry Andric AR_inaccessible, 340b57cec5SDimitry Andric AR_dependent 350b57cec5SDimitry Andric }; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, 380b57cec5SDimitry Andric NamedDecl *PrevMemberDecl, 390b57cec5SDimitry Andric AccessSpecifier LexicalAS) { 400b57cec5SDimitry Andric if (!PrevMemberDecl) { 410b57cec5SDimitry Andric // Use the lexical access specifier. 420b57cec5SDimitry Andric MemberDecl->setAccess(LexicalAS); 430b57cec5SDimitry Andric return false; 440b57cec5SDimitry Andric } 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric // C++ [class.access.spec]p3: When a member is redeclared its access 470b57cec5SDimitry Andric // specifier must be same as its initial declaration. 480b57cec5SDimitry Andric if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { 490b57cec5SDimitry Andric Diag(MemberDecl->getLocation(), 500b57cec5SDimitry Andric diag::err_class_redeclared_with_different_access) 510b57cec5SDimitry Andric << MemberDecl << LexicalAS; 520b57cec5SDimitry Andric Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) 530b57cec5SDimitry Andric << PrevMemberDecl << PrevMemberDecl->getAccess(); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric MemberDecl->setAccess(LexicalAS); 560b57cec5SDimitry Andric return true; 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric MemberDecl->setAccess(PrevMemberDecl->getAccess()); 600b57cec5SDimitry Andric return false; 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { 640b57cec5SDimitry Andric DeclContext *DC = D->getDeclContext(); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric // This can only happen at top: enum decls only "publish" their 670b57cec5SDimitry Andric // immediate members. 680b57cec5SDimitry Andric if (isa<EnumDecl>(DC)) 690b57cec5SDimitry Andric DC = cast<EnumDecl>(DC)->getDeclContext(); 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); 720b57cec5SDimitry Andric while (DeclaringClass->isAnonymousStructOrUnion()) 730b57cec5SDimitry Andric DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); 740b57cec5SDimitry Andric return DeclaringClass; 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric namespace { 780b57cec5SDimitry Andric struct EffectiveContext { 790b57cec5SDimitry Andric EffectiveContext() : Inner(nullptr), Dependent(false) {} 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric explicit EffectiveContext(DeclContext *DC) 820b57cec5SDimitry Andric : Inner(DC), 830b57cec5SDimitry Andric Dependent(DC->isDependentContext()) { 840b57cec5SDimitry Andric 85fe6060f1SDimitry Andric // An implicit deduction guide is semantically in the context enclosing the 86fe6060f1SDimitry Andric // class template, but for access purposes behaves like the constructor 87fe6060f1SDimitry Andric // from which it was produced. 88fe6060f1SDimitry Andric if (auto *DGD = dyn_cast<CXXDeductionGuideDecl>(DC)) { 89fe6060f1SDimitry Andric if (DGD->isImplicit()) { 90fe6060f1SDimitry Andric DC = DGD->getCorrespondingConstructor(); 91fe6060f1SDimitry Andric if (!DC) { 92fe6060f1SDimitry Andric // The copy deduction candidate doesn't have a corresponding 93fe6060f1SDimitry Andric // constructor. 94fe6060f1SDimitry Andric DC = cast<DeclContext>(DGD->getDeducedTemplate()->getTemplatedDecl()); 95fe6060f1SDimitry Andric } 96fe6060f1SDimitry Andric } 97fe6060f1SDimitry Andric } 98fe6060f1SDimitry Andric 990b57cec5SDimitry Andric // C++11 [class.access.nest]p1: 1000b57cec5SDimitry Andric // A nested class is a member and as such has the same access 1010b57cec5SDimitry Andric // rights as any other member. 1020b57cec5SDimitry Andric // C++11 [class.access]p2: 1030b57cec5SDimitry Andric // A member of a class can also access all the names to which 1040b57cec5SDimitry Andric // the class has access. A local class of a member function 1050b57cec5SDimitry Andric // may access the same names that the member function itself 1060b57cec5SDimitry Andric // may access. 1070b57cec5SDimitry Andric // This almost implies that the privileges of nesting are transitive. 1080b57cec5SDimitry Andric // Technically it says nothing about the local classes of non-member 1090b57cec5SDimitry Andric // functions (which can gain privileges through friendship), but we 1100b57cec5SDimitry Andric // take that as an oversight. 1110b57cec5SDimitry Andric while (true) { 1120b57cec5SDimitry Andric // We want to add canonical declarations to the EC lists for 1130b57cec5SDimitry Andric // simplicity of checking, but we need to walk up through the 1140b57cec5SDimitry Andric // actual current DC chain. Otherwise, something like a local 1150b57cec5SDimitry Andric // extern or friend which happens to be the canonical 1160b57cec5SDimitry Andric // declaration will really mess us up. 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric if (isa<CXXRecordDecl>(DC)) { 1190b57cec5SDimitry Andric CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); 1200b57cec5SDimitry Andric Records.push_back(Record->getCanonicalDecl()); 1210b57cec5SDimitry Andric DC = Record->getDeclContext(); 1220b57cec5SDimitry Andric } else if (isa<FunctionDecl>(DC)) { 1230b57cec5SDimitry Andric FunctionDecl *Function = cast<FunctionDecl>(DC); 1240b57cec5SDimitry Andric Functions.push_back(Function->getCanonicalDecl()); 1250b57cec5SDimitry Andric if (Function->getFriendObjectKind()) 1260b57cec5SDimitry Andric DC = Function->getLexicalDeclContext(); 1270b57cec5SDimitry Andric else 1280b57cec5SDimitry Andric DC = Function->getDeclContext(); 1290b57cec5SDimitry Andric } else if (DC->isFileContext()) { 1300b57cec5SDimitry Andric break; 1310b57cec5SDimitry Andric } else { 1320b57cec5SDimitry Andric DC = DC->getParent(); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric bool isDependent() const { return Dependent; } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric bool includesClass(const CXXRecordDecl *R) const { 1400b57cec5SDimitry Andric R = R->getCanonicalDecl(); 141349cc55cSDimitry Andric return llvm::is_contained(Records, R); 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric /// Retrieves the innermost "useful" context. Can be null if we're 1450b57cec5SDimitry Andric /// doing access-control without privileges. 1460b57cec5SDimitry Andric DeclContext *getInnerContext() const { 1470b57cec5SDimitry Andric return Inner; 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric DeclContext *Inner; 1530b57cec5SDimitry Andric SmallVector<FunctionDecl*, 4> Functions; 1540b57cec5SDimitry Andric SmallVector<CXXRecordDecl*, 4> Records; 1550b57cec5SDimitry Andric bool Dependent; 1560b57cec5SDimitry Andric }; 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric /// Like sema::AccessedEntity, but kindly lets us scribble all over 1590b57cec5SDimitry Andric /// it. 1600b57cec5SDimitry Andric struct AccessTarget : public AccessedEntity { 1610b57cec5SDimitry Andric AccessTarget(const AccessedEntity &Entity) 1620b57cec5SDimitry Andric : AccessedEntity(Entity) { 1630b57cec5SDimitry Andric initialize(); 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric AccessTarget(ASTContext &Context, 1670b57cec5SDimitry Andric MemberNonce _, 1680b57cec5SDimitry Andric CXXRecordDecl *NamingClass, 1690b57cec5SDimitry Andric DeclAccessPair FoundDecl, 1700b57cec5SDimitry Andric QualType BaseObjectType) 1710b57cec5SDimitry Andric : AccessedEntity(Context.getDiagAllocator(), Member, NamingClass, 1720b57cec5SDimitry Andric FoundDecl, BaseObjectType) { 1730b57cec5SDimitry Andric initialize(); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric AccessTarget(ASTContext &Context, 1770b57cec5SDimitry Andric BaseNonce _, 1780b57cec5SDimitry Andric CXXRecordDecl *BaseClass, 1790b57cec5SDimitry Andric CXXRecordDecl *DerivedClass, 1800b57cec5SDimitry Andric AccessSpecifier Access) 1810b57cec5SDimitry Andric : AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass, 1820b57cec5SDimitry Andric Access) { 1830b57cec5SDimitry Andric initialize(); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric bool isInstanceMember() const { 1870b57cec5SDimitry Andric return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember()); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric bool hasInstanceContext() const { 1910b57cec5SDimitry Andric return HasInstanceContext; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric class SavedInstanceContext { 1950b57cec5SDimitry Andric public: 1960b57cec5SDimitry Andric SavedInstanceContext(SavedInstanceContext &&S) 1970b57cec5SDimitry Andric : Target(S.Target), Has(S.Has) { 1980b57cec5SDimitry Andric S.Target = nullptr; 1990b57cec5SDimitry Andric } 20006c3fb27SDimitry Andric 20106c3fb27SDimitry Andric // The move assignment operator is defined as deleted pending further 20206c3fb27SDimitry Andric // motivation. 20306c3fb27SDimitry Andric SavedInstanceContext &operator=(SavedInstanceContext &&) = delete; 20406c3fb27SDimitry Andric 20506c3fb27SDimitry Andric // The copy constrcutor and copy assignment operator is defined as deleted 20606c3fb27SDimitry Andric // pending further motivation. 20706c3fb27SDimitry Andric SavedInstanceContext(const SavedInstanceContext &) = delete; 20806c3fb27SDimitry Andric SavedInstanceContext &operator=(const SavedInstanceContext &) = delete; 20906c3fb27SDimitry Andric 2100b57cec5SDimitry Andric ~SavedInstanceContext() { 2110b57cec5SDimitry Andric if (Target) 2120b57cec5SDimitry Andric Target->HasInstanceContext = Has; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric private: 2160b57cec5SDimitry Andric friend struct AccessTarget; 2170b57cec5SDimitry Andric explicit SavedInstanceContext(AccessTarget &Target) 2180b57cec5SDimitry Andric : Target(&Target), Has(Target.HasInstanceContext) {} 2190b57cec5SDimitry Andric AccessTarget *Target; 2200b57cec5SDimitry Andric bool Has; 2210b57cec5SDimitry Andric }; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric SavedInstanceContext saveInstanceContext() { 2240b57cec5SDimitry Andric return SavedInstanceContext(*this); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric void suppressInstanceContext() { 2280b57cec5SDimitry Andric HasInstanceContext = false; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric const CXXRecordDecl *resolveInstanceContext(Sema &S) const { 2320b57cec5SDimitry Andric assert(HasInstanceContext); 2330b57cec5SDimitry Andric if (CalculatedInstanceContext) 2340b57cec5SDimitry Andric return InstanceContext; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric CalculatedInstanceContext = true; 2370b57cec5SDimitry Andric DeclContext *IC = S.computeDeclContext(getBaseObjectType()); 2380b57cec5SDimitry Andric InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() 2390b57cec5SDimitry Andric : nullptr); 2400b57cec5SDimitry Andric return InstanceContext; 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric const CXXRecordDecl *getDeclaringClass() const { 2440b57cec5SDimitry Andric return DeclaringClass; 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric /// The "effective" naming class is the canonical non-anonymous 2480b57cec5SDimitry Andric /// class containing the actual naming class. 2490b57cec5SDimitry Andric const CXXRecordDecl *getEffectiveNamingClass() const { 2500b57cec5SDimitry Andric const CXXRecordDecl *namingClass = getNamingClass(); 2510b57cec5SDimitry Andric while (namingClass->isAnonymousStructOrUnion()) 2520b57cec5SDimitry Andric namingClass = cast<CXXRecordDecl>(namingClass->getParent()); 2530b57cec5SDimitry Andric return namingClass->getCanonicalDecl(); 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric private: 2570b57cec5SDimitry Andric void initialize() { 2580b57cec5SDimitry Andric HasInstanceContext = (isMemberAccess() && 2590b57cec5SDimitry Andric !getBaseObjectType().isNull() && 2600b57cec5SDimitry Andric getTargetDecl()->isCXXInstanceMember()); 2610b57cec5SDimitry Andric CalculatedInstanceContext = false; 2620b57cec5SDimitry Andric InstanceContext = nullptr; 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric if (isMemberAccess()) 2650b57cec5SDimitry Andric DeclaringClass = FindDeclaringClass(getTargetDecl()); 2660b57cec5SDimitry Andric else 2670b57cec5SDimitry Andric DeclaringClass = getBaseClass(); 2680b57cec5SDimitry Andric DeclaringClass = DeclaringClass->getCanonicalDecl(); 2690b57cec5SDimitry Andric } 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric bool HasInstanceContext : 1; 2720b57cec5SDimitry Andric mutable bool CalculatedInstanceContext : 1; 2730b57cec5SDimitry Andric mutable const CXXRecordDecl *InstanceContext; 2740b57cec5SDimitry Andric const CXXRecordDecl *DeclaringClass; 2750b57cec5SDimitry Andric }; 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric /// Checks whether one class might instantiate to the other. 2800b57cec5SDimitry Andric static bool MightInstantiateTo(const CXXRecordDecl *From, 2810b57cec5SDimitry Andric const CXXRecordDecl *To) { 2820b57cec5SDimitry Andric // Declaration names are always preserved by instantiation. 2830b57cec5SDimitry Andric if (From->getDeclName() != To->getDeclName()) 2840b57cec5SDimitry Andric return false; 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext(); 2870b57cec5SDimitry Andric const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext(); 2880b57cec5SDimitry Andric if (FromDC == ToDC) return true; 2890b57cec5SDimitry Andric if (FromDC->isFileContext() || ToDC->isFileContext()) return false; 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric // Be conservative. 2920b57cec5SDimitry Andric return true; 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric /// Checks whether one class is derived from another, inclusively. 2960b57cec5SDimitry Andric /// Properly indicates when it couldn't be determined due to 2970b57cec5SDimitry Andric /// dependence. 2980b57cec5SDimitry Andric /// 2990b57cec5SDimitry Andric /// This should probably be donated to AST or at least Sema. 3000b57cec5SDimitry Andric static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, 3010b57cec5SDimitry Andric const CXXRecordDecl *Target) { 3020b57cec5SDimitry Andric assert(Derived->getCanonicalDecl() == Derived); 3030b57cec5SDimitry Andric assert(Target->getCanonicalDecl() == Target); 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric if (Derived == Target) return AR_accessible; 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric bool CheckDependent = Derived->isDependentContext(); 3080b57cec5SDimitry Andric if (CheckDependent && MightInstantiateTo(Derived, Target)) 3090b57cec5SDimitry Andric return AR_dependent; 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric AccessResult OnFailure = AR_inaccessible; 3120b57cec5SDimitry Andric SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric while (true) { 3150b57cec5SDimitry Andric if (Derived->isDependentContext() && !Derived->hasDefinition() && 3160b57cec5SDimitry Andric !Derived->isLambda()) 3170b57cec5SDimitry Andric return AR_dependent; 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric for (const auto &I : Derived->bases()) { 3200b57cec5SDimitry Andric const CXXRecordDecl *RD; 3210b57cec5SDimitry Andric 3220b57cec5SDimitry Andric QualType T = I.getType(); 3230b57cec5SDimitry Andric if (const RecordType *RT = T->getAs<RecordType>()) { 3240b57cec5SDimitry Andric RD = cast<CXXRecordDecl>(RT->getDecl()); 3250b57cec5SDimitry Andric } else if (const InjectedClassNameType *IT 3260b57cec5SDimitry Andric = T->getAs<InjectedClassNameType>()) { 3270b57cec5SDimitry Andric RD = IT->getDecl(); 3280b57cec5SDimitry Andric } else { 3290b57cec5SDimitry Andric assert(T->isDependentType() && "non-dependent base wasn't a record?"); 3300b57cec5SDimitry Andric OnFailure = AR_dependent; 3310b57cec5SDimitry Andric continue; 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric RD = RD->getCanonicalDecl(); 3350b57cec5SDimitry Andric if (RD == Target) return AR_accessible; 3360b57cec5SDimitry Andric if (CheckDependent && MightInstantiateTo(RD, Target)) 3370b57cec5SDimitry Andric OnFailure = AR_dependent; 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric Queue.push_back(RD); 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric if (Queue.empty()) break; 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric Derived = Queue.pop_back_val(); 3450b57cec5SDimitry Andric } 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric return OnFailure; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric static bool MightInstantiateTo(Sema &S, DeclContext *Context, 3520b57cec5SDimitry Andric DeclContext *Friend) { 3530b57cec5SDimitry Andric if (Friend == Context) 3540b57cec5SDimitry Andric return true; 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric assert(!Friend->isDependentContext() && 3570b57cec5SDimitry Andric "can't handle friends with dependent contexts here"); 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric if (!Context->isDependentContext()) 3600b57cec5SDimitry Andric return false; 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric if (Friend->isFileContext()) 3630b57cec5SDimitry Andric return false; 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric // TODO: this is very conservative 3660b57cec5SDimitry Andric return true; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric // Asks whether the type in 'context' can ever instantiate to the type 3700b57cec5SDimitry Andric // in 'friend'. 3710b57cec5SDimitry Andric static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) { 3720b57cec5SDimitry Andric if (Friend == Context) 3730b57cec5SDimitry Andric return true; 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric if (!Friend->isDependentType() && !Context->isDependentType()) 3760b57cec5SDimitry Andric return false; 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric // TODO: this is very conservative. 3790b57cec5SDimitry Andric return true; 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric static bool MightInstantiateTo(Sema &S, 3830b57cec5SDimitry Andric FunctionDecl *Context, 3840b57cec5SDimitry Andric FunctionDecl *Friend) { 3850b57cec5SDimitry Andric if (Context->getDeclName() != Friend->getDeclName()) 3860b57cec5SDimitry Andric return false; 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric if (!MightInstantiateTo(S, 3890b57cec5SDimitry Andric Context->getDeclContext(), 3900b57cec5SDimitry Andric Friend->getDeclContext())) 3910b57cec5SDimitry Andric return false; 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric CanQual<FunctionProtoType> FriendTy 3940b57cec5SDimitry Andric = S.Context.getCanonicalType(Friend->getType()) 3950b57cec5SDimitry Andric ->getAs<FunctionProtoType>(); 3960b57cec5SDimitry Andric CanQual<FunctionProtoType> ContextTy 3970b57cec5SDimitry Andric = S.Context.getCanonicalType(Context->getType()) 3980b57cec5SDimitry Andric ->getAs<FunctionProtoType>(); 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric // There isn't any way that I know of to add qualifiers 4010b57cec5SDimitry Andric // during instantiation. 4020b57cec5SDimitry Andric if (FriendTy.getQualifiers() != ContextTy.getQualifiers()) 4030b57cec5SDimitry Andric return false; 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric if (FriendTy->getNumParams() != ContextTy->getNumParams()) 4060b57cec5SDimitry Andric return false; 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric if (!MightInstantiateTo(S, ContextTy->getReturnType(), 4090b57cec5SDimitry Andric FriendTy->getReturnType())) 4100b57cec5SDimitry Andric return false; 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric for (unsigned I = 0, E = FriendTy->getNumParams(); I != E; ++I) 4130b57cec5SDimitry Andric if (!MightInstantiateTo(S, ContextTy->getParamType(I), 4140b57cec5SDimitry Andric FriendTy->getParamType(I))) 4150b57cec5SDimitry Andric return false; 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric return true; 4180b57cec5SDimitry Andric } 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric static bool MightInstantiateTo(Sema &S, 4210b57cec5SDimitry Andric FunctionTemplateDecl *Context, 4220b57cec5SDimitry Andric FunctionTemplateDecl *Friend) { 4230b57cec5SDimitry Andric return MightInstantiateTo(S, 4240b57cec5SDimitry Andric Context->getTemplatedDecl(), 4250b57cec5SDimitry Andric Friend->getTemplatedDecl()); 4260b57cec5SDimitry Andric } 4270b57cec5SDimitry Andric 4280b57cec5SDimitry Andric static AccessResult MatchesFriend(Sema &S, 4290b57cec5SDimitry Andric const EffectiveContext &EC, 4300b57cec5SDimitry Andric const CXXRecordDecl *Friend) { 4310b57cec5SDimitry Andric if (EC.includesClass(Friend)) 4320b57cec5SDimitry Andric return AR_accessible; 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric if (EC.isDependent()) { 4350b57cec5SDimitry Andric for (const CXXRecordDecl *Context : EC.Records) { 4360b57cec5SDimitry Andric if (MightInstantiateTo(Context, Friend)) 4370b57cec5SDimitry Andric return AR_dependent; 4380b57cec5SDimitry Andric } 4390b57cec5SDimitry Andric } 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric return AR_inaccessible; 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric static AccessResult MatchesFriend(Sema &S, 4450b57cec5SDimitry Andric const EffectiveContext &EC, 4460b57cec5SDimitry Andric CanQualType Friend) { 4470b57cec5SDimitry Andric if (const RecordType *RT = Friend->getAs<RecordType>()) 4480b57cec5SDimitry Andric return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric // TODO: we can do better than this 4510b57cec5SDimitry Andric if (Friend->isDependentType()) 4520b57cec5SDimitry Andric return AR_dependent; 4530b57cec5SDimitry Andric 4540b57cec5SDimitry Andric return AR_inaccessible; 4550b57cec5SDimitry Andric } 4560b57cec5SDimitry Andric 4570b57cec5SDimitry Andric /// Determines whether the given friend class template matches 4580b57cec5SDimitry Andric /// anything in the effective context. 4590b57cec5SDimitry Andric static AccessResult MatchesFriend(Sema &S, 4600b57cec5SDimitry Andric const EffectiveContext &EC, 4610b57cec5SDimitry Andric ClassTemplateDecl *Friend) { 4620b57cec5SDimitry Andric AccessResult OnFailure = AR_inaccessible; 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric // Check whether the friend is the template of a class in the 4650b57cec5SDimitry Andric // context chain. 4660b57cec5SDimitry Andric for (SmallVectorImpl<CXXRecordDecl*>::const_iterator 4670b57cec5SDimitry Andric I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 4680b57cec5SDimitry Andric CXXRecordDecl *Record = *I; 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric // Figure out whether the current class has a template: 4710b57cec5SDimitry Andric ClassTemplateDecl *CTD; 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric // A specialization of the template... 4740b57cec5SDimitry Andric if (isa<ClassTemplateSpecializationDecl>(Record)) { 4750b57cec5SDimitry Andric CTD = cast<ClassTemplateSpecializationDecl>(Record) 4760b57cec5SDimitry Andric ->getSpecializedTemplate(); 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric // ... or the template pattern itself. 4790b57cec5SDimitry Andric } else { 4800b57cec5SDimitry Andric CTD = Record->getDescribedClassTemplate(); 4810b57cec5SDimitry Andric if (!CTD) continue; 4820b57cec5SDimitry Andric } 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric // It's a match. 4850b57cec5SDimitry Andric if (Friend == CTD->getCanonicalDecl()) 4860b57cec5SDimitry Andric return AR_accessible; 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric // If the context isn't dependent, it can't be a dependent match. 4890b57cec5SDimitry Andric if (!EC.isDependent()) 4900b57cec5SDimitry Andric continue; 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric // If the template names don't match, it can't be a dependent 4930b57cec5SDimitry Andric // match. 4940b57cec5SDimitry Andric if (CTD->getDeclName() != Friend->getDeclName()) 4950b57cec5SDimitry Andric continue; 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric // If the class's context can't instantiate to the friend's 4980b57cec5SDimitry Andric // context, it can't be a dependent match. 4990b57cec5SDimitry Andric if (!MightInstantiateTo(S, CTD->getDeclContext(), 5000b57cec5SDimitry Andric Friend->getDeclContext())) 5010b57cec5SDimitry Andric continue; 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric // Otherwise, it's a dependent match. 5040b57cec5SDimitry Andric OnFailure = AR_dependent; 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric return OnFailure; 5080b57cec5SDimitry Andric } 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric /// Determines whether the given friend function matches anything in 5110b57cec5SDimitry Andric /// the effective context. 5120b57cec5SDimitry Andric static AccessResult MatchesFriend(Sema &S, 5130b57cec5SDimitry Andric const EffectiveContext &EC, 5140b57cec5SDimitry Andric FunctionDecl *Friend) { 5150b57cec5SDimitry Andric AccessResult OnFailure = AR_inaccessible; 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric for (SmallVectorImpl<FunctionDecl*>::const_iterator 5180b57cec5SDimitry Andric I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { 5190b57cec5SDimitry Andric if (Friend == *I) 5200b57cec5SDimitry Andric return AR_accessible; 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) 5230b57cec5SDimitry Andric OnFailure = AR_dependent; 5240b57cec5SDimitry Andric } 5250b57cec5SDimitry Andric 5260b57cec5SDimitry Andric return OnFailure; 5270b57cec5SDimitry Andric } 5280b57cec5SDimitry Andric 5290b57cec5SDimitry Andric /// Determines whether the given friend function template matches 5300b57cec5SDimitry Andric /// anything in the effective context. 5310b57cec5SDimitry Andric static AccessResult MatchesFriend(Sema &S, 5320b57cec5SDimitry Andric const EffectiveContext &EC, 5330b57cec5SDimitry Andric FunctionTemplateDecl *Friend) { 5340b57cec5SDimitry Andric if (EC.Functions.empty()) return AR_inaccessible; 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric AccessResult OnFailure = AR_inaccessible; 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric for (SmallVectorImpl<FunctionDecl*>::const_iterator 5390b57cec5SDimitry Andric I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); 5420b57cec5SDimitry Andric if (!FTD) 5430b57cec5SDimitry Andric FTD = (*I)->getDescribedFunctionTemplate(); 5440b57cec5SDimitry Andric if (!FTD) 5450b57cec5SDimitry Andric continue; 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric FTD = FTD->getCanonicalDecl(); 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric if (Friend == FTD) 5500b57cec5SDimitry Andric return AR_accessible; 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) 5530b57cec5SDimitry Andric OnFailure = AR_dependent; 5540b57cec5SDimitry Andric } 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric return OnFailure; 5570b57cec5SDimitry Andric } 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric /// Determines whether the given friend declaration matches anything 5600b57cec5SDimitry Andric /// in the effective context. 5610b57cec5SDimitry Andric static AccessResult MatchesFriend(Sema &S, 5620b57cec5SDimitry Andric const EffectiveContext &EC, 5630b57cec5SDimitry Andric FriendDecl *FriendD) { 5640b57cec5SDimitry Andric // Whitelist accesses if there's an invalid or unsupported friend 5650b57cec5SDimitry Andric // declaration. 5660b57cec5SDimitry Andric if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend()) 5670b57cec5SDimitry Andric return AR_accessible; 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric if (TypeSourceInfo *T = FriendD->getFriendType()) 5700b57cec5SDimitry Andric return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric NamedDecl *Friend 5730b57cec5SDimitry Andric = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl()); 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric // FIXME: declarations with dependent or templated scope. 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric if (isa<ClassTemplateDecl>(Friend)) 5780b57cec5SDimitry Andric return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend)); 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric if (isa<FunctionTemplateDecl>(Friend)) 5810b57cec5SDimitry Andric return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend)); 5820b57cec5SDimitry Andric 5830b57cec5SDimitry Andric if (isa<CXXRecordDecl>(Friend)) 5840b57cec5SDimitry Andric return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend)); 5850b57cec5SDimitry Andric 5860b57cec5SDimitry Andric assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind"); 5870b57cec5SDimitry Andric return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); 5880b57cec5SDimitry Andric } 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric static AccessResult GetFriendKind(Sema &S, 5910b57cec5SDimitry Andric const EffectiveContext &EC, 5920b57cec5SDimitry Andric const CXXRecordDecl *Class) { 5930b57cec5SDimitry Andric AccessResult OnFailure = AR_inaccessible; 5940b57cec5SDimitry Andric 5950b57cec5SDimitry Andric // Okay, check friends. 5960b57cec5SDimitry Andric for (auto *Friend : Class->friends()) { 5970b57cec5SDimitry Andric switch (MatchesFriend(S, EC, Friend)) { 5980b57cec5SDimitry Andric case AR_accessible: 5990b57cec5SDimitry Andric return AR_accessible; 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric case AR_inaccessible: 6020b57cec5SDimitry Andric continue; 6030b57cec5SDimitry Andric 6040b57cec5SDimitry Andric case AR_dependent: 6050b57cec5SDimitry Andric OnFailure = AR_dependent; 6060b57cec5SDimitry Andric break; 6070b57cec5SDimitry Andric } 6080b57cec5SDimitry Andric } 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric // That's it, give up. 6110b57cec5SDimitry Andric return OnFailure; 6120b57cec5SDimitry Andric } 6130b57cec5SDimitry Andric 6140b57cec5SDimitry Andric namespace { 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric /// A helper class for checking for a friend which will grant access 6170b57cec5SDimitry Andric /// to a protected instance member. 6180b57cec5SDimitry Andric struct ProtectedFriendContext { 6190b57cec5SDimitry Andric Sema &S; 6200b57cec5SDimitry Andric const EffectiveContext &EC; 6210b57cec5SDimitry Andric const CXXRecordDecl *NamingClass; 6220b57cec5SDimitry Andric bool CheckDependent; 6230b57cec5SDimitry Andric bool EverDependent; 6240b57cec5SDimitry Andric 6250b57cec5SDimitry Andric /// The path down to the current base class. 6260b57cec5SDimitry Andric SmallVector<const CXXRecordDecl*, 20> CurPath; 6270b57cec5SDimitry Andric 6280b57cec5SDimitry Andric ProtectedFriendContext(Sema &S, const EffectiveContext &EC, 6290b57cec5SDimitry Andric const CXXRecordDecl *InstanceContext, 6300b57cec5SDimitry Andric const CXXRecordDecl *NamingClass) 6310b57cec5SDimitry Andric : S(S), EC(EC), NamingClass(NamingClass), 6320b57cec5SDimitry Andric CheckDependent(InstanceContext->isDependentContext() || 6330b57cec5SDimitry Andric NamingClass->isDependentContext()), 6340b57cec5SDimitry Andric EverDependent(false) {} 6350b57cec5SDimitry Andric 6360b57cec5SDimitry Andric /// Check classes in the current path for friendship, starting at 6370b57cec5SDimitry Andric /// the given index. 6380b57cec5SDimitry Andric bool checkFriendshipAlongPath(unsigned I) { 6390b57cec5SDimitry Andric assert(I < CurPath.size()); 6400b57cec5SDimitry Andric for (unsigned E = CurPath.size(); I != E; ++I) { 6410b57cec5SDimitry Andric switch (GetFriendKind(S, EC, CurPath[I])) { 6420b57cec5SDimitry Andric case AR_accessible: return true; 6430b57cec5SDimitry Andric case AR_inaccessible: continue; 6440b57cec5SDimitry Andric case AR_dependent: EverDependent = true; continue; 6450b57cec5SDimitry Andric } 6460b57cec5SDimitry Andric } 6470b57cec5SDimitry Andric return false; 6480b57cec5SDimitry Andric } 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric /// Perform a search starting at the given class. 6510b57cec5SDimitry Andric /// 6520b57cec5SDimitry Andric /// PrivateDepth is the index of the last (least derived) class 6530b57cec5SDimitry Andric /// along the current path such that a notional public member of 6540b57cec5SDimitry Andric /// the final class in the path would have access in that class. 6550b57cec5SDimitry Andric bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) { 6560b57cec5SDimitry Andric // If we ever reach the naming class, check the current path for 6570b57cec5SDimitry Andric // friendship. We can also stop recursing because we obviously 6580b57cec5SDimitry Andric // won't find the naming class there again. 6590b57cec5SDimitry Andric if (Cur == NamingClass) 6600b57cec5SDimitry Andric return checkFriendshipAlongPath(PrivateDepth); 6610b57cec5SDimitry Andric 6620b57cec5SDimitry Andric if (CheckDependent && MightInstantiateTo(Cur, NamingClass)) 6630b57cec5SDimitry Andric EverDependent = true; 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric // Recurse into the base classes. 6660b57cec5SDimitry Andric for (const auto &I : Cur->bases()) { 6670b57cec5SDimitry Andric // If this is private inheritance, then a public member of the 6680b57cec5SDimitry Andric // base will not have any access in classes derived from Cur. 6690b57cec5SDimitry Andric unsigned BasePrivateDepth = PrivateDepth; 6700b57cec5SDimitry Andric if (I.getAccessSpecifier() == AS_private) 6710b57cec5SDimitry Andric BasePrivateDepth = CurPath.size() - 1; 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric const CXXRecordDecl *RD; 6740b57cec5SDimitry Andric 6750b57cec5SDimitry Andric QualType T = I.getType(); 6760b57cec5SDimitry Andric if (const RecordType *RT = T->getAs<RecordType>()) { 6770b57cec5SDimitry Andric RD = cast<CXXRecordDecl>(RT->getDecl()); 6780b57cec5SDimitry Andric } else if (const InjectedClassNameType *IT 6790b57cec5SDimitry Andric = T->getAs<InjectedClassNameType>()) { 6800b57cec5SDimitry Andric RD = IT->getDecl(); 6810b57cec5SDimitry Andric } else { 6820b57cec5SDimitry Andric assert(T->isDependentType() && "non-dependent base wasn't a record?"); 6830b57cec5SDimitry Andric EverDependent = true; 6840b57cec5SDimitry Andric continue; 6850b57cec5SDimitry Andric } 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric // Recurse. We don't need to clean up if this returns true. 6880b57cec5SDimitry Andric CurPath.push_back(RD); 6890b57cec5SDimitry Andric if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth)) 6900b57cec5SDimitry Andric return true; 6910b57cec5SDimitry Andric CurPath.pop_back(); 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric return false; 6950b57cec5SDimitry Andric } 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric bool findFriendship(const CXXRecordDecl *Cur) { 6980b57cec5SDimitry Andric assert(CurPath.empty()); 6990b57cec5SDimitry Andric CurPath.push_back(Cur); 7000b57cec5SDimitry Andric return findFriendship(Cur, 0); 7010b57cec5SDimitry Andric } 7020b57cec5SDimitry Andric }; 7030b57cec5SDimitry Andric } 7040b57cec5SDimitry Andric 7050b57cec5SDimitry Andric /// Search for a class P that EC is a friend of, under the constraint 7060b57cec5SDimitry Andric /// InstanceContext <= P 7070b57cec5SDimitry Andric /// if InstanceContext exists, or else 7080b57cec5SDimitry Andric /// NamingClass <= P 7090b57cec5SDimitry Andric /// and with the additional restriction that a protected member of 7100b57cec5SDimitry Andric /// NamingClass would have some natural access in P, which implicitly 7110b57cec5SDimitry Andric /// imposes the constraint that P <= NamingClass. 7120b57cec5SDimitry Andric /// 7130b57cec5SDimitry Andric /// This isn't quite the condition laid out in the standard. 7140b57cec5SDimitry Andric /// Instead of saying that a notional protected member of NamingClass 7150b57cec5SDimitry Andric /// would have to have some natural access in P, it says the actual 7160b57cec5SDimitry Andric /// target has to have some natural access in P, which opens up the 7170b57cec5SDimitry Andric /// possibility that the target (which is not necessarily a member 7180b57cec5SDimitry Andric /// of NamingClass) might be more accessible along some path not 7190b57cec5SDimitry Andric /// passing through it. That's really a bad idea, though, because it 7200b57cec5SDimitry Andric /// introduces two problems: 7210b57cec5SDimitry Andric /// - Most importantly, it breaks encapsulation because you can 7220b57cec5SDimitry Andric /// access a forbidden base class's members by directly subclassing 7230b57cec5SDimitry Andric /// it elsewhere. 7240b57cec5SDimitry Andric /// - It also makes access substantially harder to compute because it 7250b57cec5SDimitry Andric /// breaks the hill-climbing algorithm: knowing that the target is 7260b57cec5SDimitry Andric /// accessible in some base class would no longer let you change 7270b57cec5SDimitry Andric /// the question solely to whether the base class is accessible, 7280b57cec5SDimitry Andric /// because the original target might have been more accessible 7290b57cec5SDimitry Andric /// because of crazy subclassing. 7300b57cec5SDimitry Andric /// So we don't implement that. 7310b57cec5SDimitry Andric static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC, 7320b57cec5SDimitry Andric const CXXRecordDecl *InstanceContext, 7330b57cec5SDimitry Andric const CXXRecordDecl *NamingClass) { 7340b57cec5SDimitry Andric assert(InstanceContext == nullptr || 7350b57cec5SDimitry Andric InstanceContext->getCanonicalDecl() == InstanceContext); 7360b57cec5SDimitry Andric assert(NamingClass->getCanonicalDecl() == NamingClass); 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric // If we don't have an instance context, our constraints give us 7390b57cec5SDimitry Andric // that NamingClass <= P <= NamingClass, i.e. P == NamingClass. 7400b57cec5SDimitry Andric // This is just the usual friendship check. 7410b57cec5SDimitry Andric if (!InstanceContext) return GetFriendKind(S, EC, NamingClass); 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass); 7440b57cec5SDimitry Andric if (PRC.findFriendship(InstanceContext)) return AR_accessible; 7450b57cec5SDimitry Andric if (PRC.EverDependent) return AR_dependent; 7460b57cec5SDimitry Andric return AR_inaccessible; 7470b57cec5SDimitry Andric } 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric static AccessResult HasAccess(Sema &S, 7500b57cec5SDimitry Andric const EffectiveContext &EC, 7510b57cec5SDimitry Andric const CXXRecordDecl *NamingClass, 7520b57cec5SDimitry Andric AccessSpecifier Access, 7530b57cec5SDimitry Andric const AccessTarget &Target) { 7540b57cec5SDimitry Andric assert(NamingClass->getCanonicalDecl() == NamingClass && 7550b57cec5SDimitry Andric "declaration should be canonicalized before being passed here"); 7560b57cec5SDimitry Andric 7570b57cec5SDimitry Andric if (Access == AS_public) return AR_accessible; 7580b57cec5SDimitry Andric assert(Access == AS_private || Access == AS_protected); 7590b57cec5SDimitry Andric 7600b57cec5SDimitry Andric AccessResult OnFailure = AR_inaccessible; 7610b57cec5SDimitry Andric 7620b57cec5SDimitry Andric for (EffectiveContext::record_iterator 7630b57cec5SDimitry Andric I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 7640b57cec5SDimitry Andric // All the declarations in EC have been canonicalized, so pointer 7650b57cec5SDimitry Andric // equality from this point on will work fine. 7660b57cec5SDimitry Andric const CXXRecordDecl *ECRecord = *I; 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric // [B2] and [M2] 7690b57cec5SDimitry Andric if (Access == AS_private) { 7700b57cec5SDimitry Andric if (ECRecord == NamingClass) 7710b57cec5SDimitry Andric return AR_accessible; 7720b57cec5SDimitry Andric 7730b57cec5SDimitry Andric if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass)) 7740b57cec5SDimitry Andric OnFailure = AR_dependent; 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric // [B3] and [M3] 7770b57cec5SDimitry Andric } else { 7780b57cec5SDimitry Andric assert(Access == AS_protected); 7790b57cec5SDimitry Andric switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { 7800b57cec5SDimitry Andric case AR_accessible: break; 7810b57cec5SDimitry Andric case AR_inaccessible: continue; 7820b57cec5SDimitry Andric case AR_dependent: OnFailure = AR_dependent; continue; 7830b57cec5SDimitry Andric } 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric // C++ [class.protected]p1: 7860b57cec5SDimitry Andric // An additional access check beyond those described earlier in 7870b57cec5SDimitry Andric // [class.access] is applied when a non-static data member or 7880b57cec5SDimitry Andric // non-static member function is a protected member of its naming 7890b57cec5SDimitry Andric // class. As described earlier, access to a protected member is 7900b57cec5SDimitry Andric // granted because the reference occurs in a friend or member of 7910b57cec5SDimitry Andric // some class C. If the access is to form a pointer to member, 7920b57cec5SDimitry Andric // the nested-name-specifier shall name C or a class derived from 7930b57cec5SDimitry Andric // C. All other accesses involve a (possibly implicit) object 7940b57cec5SDimitry Andric // expression. In this case, the class of the object expression 7950b57cec5SDimitry Andric // shall be C or a class derived from C. 7960b57cec5SDimitry Andric // 7970b57cec5SDimitry Andric // We interpret this as a restriction on [M3]. 7980b57cec5SDimitry Andric 7990b57cec5SDimitry Andric // In this part of the code, 'C' is just our context class ECRecord. 8000b57cec5SDimitry Andric 8010b57cec5SDimitry Andric // These rules are different if we don't have an instance context. 8020b57cec5SDimitry Andric if (!Target.hasInstanceContext()) { 8030b57cec5SDimitry Andric // If it's not an instance member, these restrictions don't apply. 8040b57cec5SDimitry Andric if (!Target.isInstanceMember()) return AR_accessible; 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric // If it's an instance member, use the pointer-to-member rule 8070b57cec5SDimitry Andric // that the naming class has to be derived from the effective 8080b57cec5SDimitry Andric // context. 8090b57cec5SDimitry Andric 8100b57cec5SDimitry Andric // Emulate a MSVC bug where the creation of pointer-to-member 8110b57cec5SDimitry Andric // to protected member of base class is allowed but only from 8120b57cec5SDimitry Andric // static member functions. 8130b57cec5SDimitry Andric if (S.getLangOpts().MSVCCompat && !EC.Functions.empty()) 8140b57cec5SDimitry Andric if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front())) 8150b57cec5SDimitry Andric if (MD->isStatic()) return AR_accessible; 8160b57cec5SDimitry Andric 8170b57cec5SDimitry Andric // Despite the standard's confident wording, there is a case 8180b57cec5SDimitry Andric // where you can have an instance member that's neither in a 8190b57cec5SDimitry Andric // pointer-to-member expression nor in a member access: when 8200b57cec5SDimitry Andric // it names a field in an unevaluated context that can't be an 8210b57cec5SDimitry Andric // implicit member. Pending clarification, we just apply the 8220b57cec5SDimitry Andric // same naming-class restriction here. 8230b57cec5SDimitry Andric // FIXME: we're probably not correctly adding the 8240b57cec5SDimitry Andric // protected-member restriction when we retroactively convert 8250b57cec5SDimitry Andric // an expression to being evaluated. 8260b57cec5SDimitry Andric 8270b57cec5SDimitry Andric // We know that ECRecord derives from NamingClass. The 8280b57cec5SDimitry Andric // restriction says to check whether NamingClass derives from 8290b57cec5SDimitry Andric // ECRecord, but that's not really necessary: two distinct 8300b57cec5SDimitry Andric // classes can't be recursively derived from each other. So 8310b57cec5SDimitry Andric // along this path, we just need to check whether the classes 8320b57cec5SDimitry Andric // are equal. 8330b57cec5SDimitry Andric if (NamingClass == ECRecord) return AR_accessible; 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric // Otherwise, this context class tells us nothing; on to the next. 8360b57cec5SDimitry Andric continue; 8370b57cec5SDimitry Andric } 8380b57cec5SDimitry Andric 8390b57cec5SDimitry Andric assert(Target.isInstanceMember()); 8400b57cec5SDimitry Andric 8410b57cec5SDimitry Andric const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); 8420b57cec5SDimitry Andric if (!InstanceContext) { 8430b57cec5SDimitry Andric OnFailure = AR_dependent; 8440b57cec5SDimitry Andric continue; 8450b57cec5SDimitry Andric } 8460b57cec5SDimitry Andric 8470b57cec5SDimitry Andric switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { 8480b57cec5SDimitry Andric case AR_accessible: return AR_accessible; 8490b57cec5SDimitry Andric case AR_inaccessible: continue; 8500b57cec5SDimitry Andric case AR_dependent: OnFailure = AR_dependent; continue; 8510b57cec5SDimitry Andric } 8520b57cec5SDimitry Andric } 8530b57cec5SDimitry Andric } 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric // [M3] and [B3] say that, if the target is protected in N, we grant 8560b57cec5SDimitry Andric // access if the access occurs in a friend or member of some class P 8570b57cec5SDimitry Andric // that's a subclass of N and where the target has some natural 8580b57cec5SDimitry Andric // access in P. The 'member' aspect is easy to handle because P 8590b57cec5SDimitry Andric // would necessarily be one of the effective-context records, and we 8600b57cec5SDimitry Andric // address that above. The 'friend' aspect is completely ridiculous 8610b57cec5SDimitry Andric // to implement because there are no restrictions at all on P 8620b57cec5SDimitry Andric // *unless* the [class.protected] restriction applies. If it does, 8630b57cec5SDimitry Andric // however, we should ignore whether the naming class is a friend, 8640b57cec5SDimitry Andric // and instead rely on whether any potential P is a friend. 8650b57cec5SDimitry Andric if (Access == AS_protected && Target.isInstanceMember()) { 8660b57cec5SDimitry Andric // Compute the instance context if possible. 8670b57cec5SDimitry Andric const CXXRecordDecl *InstanceContext = nullptr; 8680b57cec5SDimitry Andric if (Target.hasInstanceContext()) { 8690b57cec5SDimitry Andric InstanceContext = Target.resolveInstanceContext(S); 8700b57cec5SDimitry Andric if (!InstanceContext) return AR_dependent; 8710b57cec5SDimitry Andric } 8720b57cec5SDimitry Andric 8730b57cec5SDimitry Andric switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) { 8740b57cec5SDimitry Andric case AR_accessible: return AR_accessible; 8750b57cec5SDimitry Andric case AR_inaccessible: return OnFailure; 8760b57cec5SDimitry Andric case AR_dependent: return AR_dependent; 8770b57cec5SDimitry Andric } 8780b57cec5SDimitry Andric llvm_unreachable("impossible friendship kind"); 8790b57cec5SDimitry Andric } 8800b57cec5SDimitry Andric 8810b57cec5SDimitry Andric switch (GetFriendKind(S, EC, NamingClass)) { 8820b57cec5SDimitry Andric case AR_accessible: return AR_accessible; 8830b57cec5SDimitry Andric case AR_inaccessible: return OnFailure; 8840b57cec5SDimitry Andric case AR_dependent: return AR_dependent; 8850b57cec5SDimitry Andric } 8860b57cec5SDimitry Andric 8870b57cec5SDimitry Andric // Silence bogus warnings 8880b57cec5SDimitry Andric llvm_unreachable("impossible friendship kind"); 8890b57cec5SDimitry Andric } 8900b57cec5SDimitry Andric 8910b57cec5SDimitry Andric /// Finds the best path from the naming class to the declaring class, 8920b57cec5SDimitry Andric /// taking friend declarations into account. 8930b57cec5SDimitry Andric /// 8940b57cec5SDimitry Andric /// C++0x [class.access.base]p5: 8950b57cec5SDimitry Andric /// A member m is accessible at the point R when named in class N if 8960b57cec5SDimitry Andric /// [M1] m as a member of N is public, or 8970b57cec5SDimitry Andric /// [M2] m as a member of N is private, and R occurs in a member or 8980b57cec5SDimitry Andric /// friend of class N, or 8990b57cec5SDimitry Andric /// [M3] m as a member of N is protected, and R occurs in a member or 9000b57cec5SDimitry Andric /// friend of class N, or in a member or friend of a class P 9010b57cec5SDimitry Andric /// derived from N, where m as a member of P is public, private, 9020b57cec5SDimitry Andric /// or protected, or 9030b57cec5SDimitry Andric /// [M4] there exists a base class B of N that is accessible at R, and 9040b57cec5SDimitry Andric /// m is accessible at R when named in class B. 9050b57cec5SDimitry Andric /// 9060b57cec5SDimitry Andric /// C++0x [class.access.base]p4: 9070b57cec5SDimitry Andric /// A base class B of N is accessible at R, if 9080b57cec5SDimitry Andric /// [B1] an invented public member of B would be a public member of N, or 9090b57cec5SDimitry Andric /// [B2] R occurs in a member or friend of class N, and an invented public 9100b57cec5SDimitry Andric /// member of B would be a private or protected member of N, or 9110b57cec5SDimitry Andric /// [B3] R occurs in a member or friend of a class P derived from N, and an 9120b57cec5SDimitry Andric /// invented public member of B would be a private or protected member 9130b57cec5SDimitry Andric /// of P, or 9140b57cec5SDimitry Andric /// [B4] there exists a class S such that B is a base class of S accessible 9150b57cec5SDimitry Andric /// at R and S is a base class of N accessible at R. 9160b57cec5SDimitry Andric /// 9170b57cec5SDimitry Andric /// Along a single inheritance path we can restate both of these 9180b57cec5SDimitry Andric /// iteratively: 9190b57cec5SDimitry Andric /// 9200b57cec5SDimitry Andric /// First, we note that M1-4 are equivalent to B1-4 if the member is 9210b57cec5SDimitry Andric /// treated as a notional base of its declaring class with inheritance 9220b57cec5SDimitry Andric /// access equivalent to the member's access. Therefore we need only 9230b57cec5SDimitry Andric /// ask whether a class B is accessible from a class N in context R. 9240b57cec5SDimitry Andric /// 9250b57cec5SDimitry Andric /// Let B_1 .. B_n be the inheritance path in question (i.e. where 9260b57cec5SDimitry Andric /// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of 9270b57cec5SDimitry Andric /// B_i). For i in 1..n, we will calculate ACAB(i), the access to the 9280b57cec5SDimitry Andric /// closest accessible base in the path: 9290b57cec5SDimitry Andric /// Access(a, b) = (* access on the base specifier from a to b *) 9300b57cec5SDimitry Andric /// Merge(a, forbidden) = forbidden 9310b57cec5SDimitry Andric /// Merge(a, private) = forbidden 9320b57cec5SDimitry Andric /// Merge(a, b) = min(a,b) 9330b57cec5SDimitry Andric /// Accessible(c, forbidden) = false 9340b57cec5SDimitry Andric /// Accessible(c, private) = (R is c) || IsFriend(c, R) 9350b57cec5SDimitry Andric /// Accessible(c, protected) = (R derived from c) || IsFriend(c, R) 9360b57cec5SDimitry Andric /// Accessible(c, public) = true 9370b57cec5SDimitry Andric /// ACAB(n) = public 9380b57cec5SDimitry Andric /// ACAB(i) = 9390b57cec5SDimitry Andric /// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in 9400b57cec5SDimitry Andric /// if Accessible(B_i, AccessToBase) then public else AccessToBase 9410b57cec5SDimitry Andric /// 9420b57cec5SDimitry Andric /// B is an accessible base of N at R iff ACAB(1) = public. 9430b57cec5SDimitry Andric /// 9440b57cec5SDimitry Andric /// \param FinalAccess the access of the "final step", or AS_public if 9450b57cec5SDimitry Andric /// there is no final step. 9460b57cec5SDimitry Andric /// \return null if friendship is dependent 9470b57cec5SDimitry Andric static CXXBasePath *FindBestPath(Sema &S, 9480b57cec5SDimitry Andric const EffectiveContext &EC, 9490b57cec5SDimitry Andric AccessTarget &Target, 9500b57cec5SDimitry Andric AccessSpecifier FinalAccess, 9510b57cec5SDimitry Andric CXXBasePaths &Paths) { 9520b57cec5SDimitry Andric // Derive the paths to the desired base. 9530b57cec5SDimitry Andric const CXXRecordDecl *Derived = Target.getNamingClass(); 9540b57cec5SDimitry Andric const CXXRecordDecl *Base = Target.getDeclaringClass(); 9550b57cec5SDimitry Andric 9560b57cec5SDimitry Andric // FIXME: fail correctly when there are dependent paths. 9570b57cec5SDimitry Andric bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base), 9580b57cec5SDimitry Andric Paths); 9590b57cec5SDimitry Andric assert(isDerived && "derived class not actually derived from base"); 9600b57cec5SDimitry Andric (void) isDerived; 9610b57cec5SDimitry Andric 9620b57cec5SDimitry Andric CXXBasePath *BestPath = nullptr; 9630b57cec5SDimitry Andric 9640b57cec5SDimitry Andric assert(FinalAccess != AS_none && "forbidden access after declaring class"); 9650b57cec5SDimitry Andric 9660b57cec5SDimitry Andric bool AnyDependent = false; 9670b57cec5SDimitry Andric 9680b57cec5SDimitry Andric // Derive the friend-modified access along each path. 9690b57cec5SDimitry Andric for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); 9700b57cec5SDimitry Andric PI != PE; ++PI) { 9710b57cec5SDimitry Andric AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext(); 9720b57cec5SDimitry Andric 9730b57cec5SDimitry Andric // Walk through the path backwards. 9740b57cec5SDimitry Andric AccessSpecifier PathAccess = FinalAccess; 9750b57cec5SDimitry Andric CXXBasePath::iterator I = PI->end(), E = PI->begin(); 9760b57cec5SDimitry Andric while (I != E) { 9770b57cec5SDimitry Andric --I; 9780b57cec5SDimitry Andric 9790b57cec5SDimitry Andric assert(PathAccess != AS_none); 9800b57cec5SDimitry Andric 9810b57cec5SDimitry Andric // If the declaration is a private member of a base class, there 9820b57cec5SDimitry Andric // is no level of friendship in derived classes that can make it 9830b57cec5SDimitry Andric // accessible. 9840b57cec5SDimitry Andric if (PathAccess == AS_private) { 9850b57cec5SDimitry Andric PathAccess = AS_none; 9860b57cec5SDimitry Andric break; 9870b57cec5SDimitry Andric } 9880b57cec5SDimitry Andric 9890b57cec5SDimitry Andric const CXXRecordDecl *NC = I->Class->getCanonicalDecl(); 9900b57cec5SDimitry Andric 9910b57cec5SDimitry Andric AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); 9920b57cec5SDimitry Andric PathAccess = std::max(PathAccess, BaseAccess); 9930b57cec5SDimitry Andric 9940b57cec5SDimitry Andric switch (HasAccess(S, EC, NC, PathAccess, Target)) { 9950b57cec5SDimitry Andric case AR_inaccessible: break; 9960b57cec5SDimitry Andric case AR_accessible: 9970b57cec5SDimitry Andric PathAccess = AS_public; 9980b57cec5SDimitry Andric 9990b57cec5SDimitry Andric // Future tests are not against members and so do not have 10000b57cec5SDimitry Andric // instance context. 10010b57cec5SDimitry Andric Target.suppressInstanceContext(); 10020b57cec5SDimitry Andric break; 10030b57cec5SDimitry Andric case AR_dependent: 10040b57cec5SDimitry Andric AnyDependent = true; 10050b57cec5SDimitry Andric goto Next; 10060b57cec5SDimitry Andric } 10070b57cec5SDimitry Andric } 10080b57cec5SDimitry Andric 10090b57cec5SDimitry Andric // Note that we modify the path's Access field to the 10100b57cec5SDimitry Andric // friend-modified access. 10110b57cec5SDimitry Andric if (BestPath == nullptr || PathAccess < BestPath->Access) { 10120b57cec5SDimitry Andric BestPath = &*PI; 10130b57cec5SDimitry Andric BestPath->Access = PathAccess; 10140b57cec5SDimitry Andric 10150b57cec5SDimitry Andric // Short-circuit if we found a public path. 10160b57cec5SDimitry Andric if (BestPath->Access == AS_public) 10170b57cec5SDimitry Andric return BestPath; 10180b57cec5SDimitry Andric } 10190b57cec5SDimitry Andric 10200b57cec5SDimitry Andric Next: ; 10210b57cec5SDimitry Andric } 10220b57cec5SDimitry Andric 10230b57cec5SDimitry Andric assert((!BestPath || BestPath->Access != AS_public) && 10240b57cec5SDimitry Andric "fell out of loop with public path"); 10250b57cec5SDimitry Andric 10260b57cec5SDimitry Andric // We didn't find a public path, but at least one path was subject 10270b57cec5SDimitry Andric // to dependent friendship, so delay the check. 10280b57cec5SDimitry Andric if (AnyDependent) 10290b57cec5SDimitry Andric return nullptr; 10300b57cec5SDimitry Andric 10310b57cec5SDimitry Andric return BestPath; 10320b57cec5SDimitry Andric } 10330b57cec5SDimitry Andric 10340b57cec5SDimitry Andric /// Given that an entity has protected natural access, check whether 10350b57cec5SDimitry Andric /// access might be denied because of the protected member access 10360b57cec5SDimitry Andric /// restriction. 10370b57cec5SDimitry Andric /// 10380b57cec5SDimitry Andric /// \return true if a note was emitted 10390b57cec5SDimitry Andric static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC, 10400b57cec5SDimitry Andric AccessTarget &Target) { 10410b57cec5SDimitry Andric // Only applies to instance accesses. 10420b57cec5SDimitry Andric if (!Target.isInstanceMember()) 10430b57cec5SDimitry Andric return false; 10440b57cec5SDimitry Andric 10450b57cec5SDimitry Andric assert(Target.isMemberAccess()); 10460b57cec5SDimitry Andric 10470b57cec5SDimitry Andric const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass(); 10480b57cec5SDimitry Andric 10490b57cec5SDimitry Andric for (EffectiveContext::record_iterator 10500b57cec5SDimitry Andric I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 10510b57cec5SDimitry Andric const CXXRecordDecl *ECRecord = *I; 10520b57cec5SDimitry Andric switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { 10530b57cec5SDimitry Andric case AR_accessible: break; 10540b57cec5SDimitry Andric case AR_inaccessible: continue; 10550b57cec5SDimitry Andric case AR_dependent: continue; 10560b57cec5SDimitry Andric } 10570b57cec5SDimitry Andric 10580b57cec5SDimitry Andric // The effective context is a subclass of the declaring class. 10590b57cec5SDimitry Andric // Check whether the [class.protected] restriction is limiting 10600b57cec5SDimitry Andric // access. 10610b57cec5SDimitry Andric 10620b57cec5SDimitry Andric // To get this exactly right, this might need to be checked more 10630b57cec5SDimitry Andric // holistically; it's not necessarily the case that gaining 10640b57cec5SDimitry Andric // access here would grant us access overall. 10650b57cec5SDimitry Andric 10660b57cec5SDimitry Andric NamedDecl *D = Target.getTargetDecl(); 10670b57cec5SDimitry Andric 10680b57cec5SDimitry Andric // If we don't have an instance context, [class.protected] says the 10690b57cec5SDimitry Andric // naming class has to equal the context class. 10700b57cec5SDimitry Andric if (!Target.hasInstanceContext()) { 10710b57cec5SDimitry Andric // If it does, the restriction doesn't apply. 10720b57cec5SDimitry Andric if (NamingClass == ECRecord) continue; 10730b57cec5SDimitry Andric 10740b57cec5SDimitry Andric // TODO: it would be great to have a fixit here, since this is 10750b57cec5SDimitry Andric // such an obvious error. 10760b57cec5SDimitry Andric S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject) 10770b57cec5SDimitry Andric << S.Context.getTypeDeclType(ECRecord); 10780b57cec5SDimitry Andric return true; 10790b57cec5SDimitry Andric } 10800b57cec5SDimitry Andric 10810b57cec5SDimitry Andric const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); 10820b57cec5SDimitry Andric assert(InstanceContext && "diagnosing dependent access"); 10830b57cec5SDimitry Andric 10840b57cec5SDimitry Andric switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { 10850b57cec5SDimitry Andric case AR_accessible: continue; 10860b57cec5SDimitry Andric case AR_dependent: continue; 10870b57cec5SDimitry Andric case AR_inaccessible: 10880b57cec5SDimitry Andric break; 10890b57cec5SDimitry Andric } 10900b57cec5SDimitry Andric 10910b57cec5SDimitry Andric // Okay, the restriction seems to be what's limiting us. 10920b57cec5SDimitry Andric 10930b57cec5SDimitry Andric // Use a special diagnostic for constructors and destructors. 10940b57cec5SDimitry Andric if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) || 10950b57cec5SDimitry Andric (isa<FunctionTemplateDecl>(D) && 10960b57cec5SDimitry Andric isa<CXXConstructorDecl>( 10970b57cec5SDimitry Andric cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) { 10980b57cec5SDimitry Andric return S.Diag(D->getLocation(), 10990b57cec5SDimitry Andric diag::note_access_protected_restricted_ctordtor) 11000b57cec5SDimitry Andric << isa<CXXDestructorDecl>(D->getAsFunction()); 11010b57cec5SDimitry Andric } 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric // Otherwise, use the generic diagnostic. 11040b57cec5SDimitry Andric return S.Diag(D->getLocation(), 11050b57cec5SDimitry Andric diag::note_access_protected_restricted_object) 11060b57cec5SDimitry Andric << S.Context.getTypeDeclType(ECRecord); 11070b57cec5SDimitry Andric } 11080b57cec5SDimitry Andric 11090b57cec5SDimitry Andric return false; 11100b57cec5SDimitry Andric } 11110b57cec5SDimitry Andric 11120b57cec5SDimitry Andric /// We are unable to access a given declaration due to its direct 11130b57cec5SDimitry Andric /// access control; diagnose that. 11140b57cec5SDimitry Andric static void diagnoseBadDirectAccess(Sema &S, 11150b57cec5SDimitry Andric const EffectiveContext &EC, 11160b57cec5SDimitry Andric AccessTarget &entity) { 11170b57cec5SDimitry Andric assert(entity.isMemberAccess()); 11180b57cec5SDimitry Andric NamedDecl *D = entity.getTargetDecl(); 11190b57cec5SDimitry Andric 11200b57cec5SDimitry Andric if (D->getAccess() == AS_protected && 11210b57cec5SDimitry Andric TryDiagnoseProtectedAccess(S, EC, entity)) 11220b57cec5SDimitry Andric return; 11230b57cec5SDimitry Andric 11240b57cec5SDimitry Andric // Find an original declaration. 11250b57cec5SDimitry Andric while (D->isOutOfLine()) { 11260b57cec5SDimitry Andric NamedDecl *PrevDecl = nullptr; 11270b57cec5SDimitry Andric if (VarDecl *VD = dyn_cast<VarDecl>(D)) 11280b57cec5SDimitry Andric PrevDecl = VD->getPreviousDecl(); 11290b57cec5SDimitry Andric else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 11300b57cec5SDimitry Andric PrevDecl = FD->getPreviousDecl(); 11310b57cec5SDimitry Andric else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D)) 11320b57cec5SDimitry Andric PrevDecl = TND->getPreviousDecl(); 11330b57cec5SDimitry Andric else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { 11340b57cec5SDimitry Andric if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName()) 11350b57cec5SDimitry Andric break; 11360b57cec5SDimitry Andric PrevDecl = TD->getPreviousDecl(); 11370b57cec5SDimitry Andric } 11380b57cec5SDimitry Andric if (!PrevDecl) break; 11390b57cec5SDimitry Andric D = PrevDecl; 11400b57cec5SDimitry Andric } 11410b57cec5SDimitry Andric 11420b57cec5SDimitry Andric CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); 11430b57cec5SDimitry Andric Decl *ImmediateChild; 11440b57cec5SDimitry Andric if (D->getDeclContext() == DeclaringClass) 11450b57cec5SDimitry Andric ImmediateChild = D; 11460b57cec5SDimitry Andric else { 11470b57cec5SDimitry Andric DeclContext *DC = D->getDeclContext(); 11480b57cec5SDimitry Andric while (DC->getParent() != DeclaringClass) 11490b57cec5SDimitry Andric DC = DC->getParent(); 11500b57cec5SDimitry Andric ImmediateChild = cast<Decl>(DC); 11510b57cec5SDimitry Andric } 11520b57cec5SDimitry Andric 11530b57cec5SDimitry Andric // Check whether there's an AccessSpecDecl preceding this in the 11540b57cec5SDimitry Andric // chain of the DeclContext. 11550b57cec5SDimitry Andric bool isImplicit = true; 11560b57cec5SDimitry Andric for (const auto *I : DeclaringClass->decls()) { 11570b57cec5SDimitry Andric if (I == ImmediateChild) break; 11580b57cec5SDimitry Andric if (isa<AccessSpecDecl>(I)) { 11590b57cec5SDimitry Andric isImplicit = false; 11600b57cec5SDimitry Andric break; 11610b57cec5SDimitry Andric } 11620b57cec5SDimitry Andric } 11630b57cec5SDimitry Andric 11640b57cec5SDimitry Andric S.Diag(D->getLocation(), diag::note_access_natural) 11650b57cec5SDimitry Andric << (unsigned) (D->getAccess() == AS_protected) 11660b57cec5SDimitry Andric << isImplicit; 11670b57cec5SDimitry Andric } 11680b57cec5SDimitry Andric 11690b57cec5SDimitry Andric /// Diagnose the path which caused the given declaration or base class 11700b57cec5SDimitry Andric /// to become inaccessible. 11710b57cec5SDimitry Andric static void DiagnoseAccessPath(Sema &S, 11720b57cec5SDimitry Andric const EffectiveContext &EC, 11730b57cec5SDimitry Andric AccessTarget &entity) { 11740b57cec5SDimitry Andric // Save the instance context to preserve invariants. 11750b57cec5SDimitry Andric AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext(); 11760b57cec5SDimitry Andric 11770b57cec5SDimitry Andric // This basically repeats the main algorithm but keeps some more 11780b57cec5SDimitry Andric // information. 11790b57cec5SDimitry Andric 11800b57cec5SDimitry Andric // The natural access so far. 11810b57cec5SDimitry Andric AccessSpecifier accessSoFar = AS_public; 11820b57cec5SDimitry Andric 11830b57cec5SDimitry Andric // Check whether we have special rights to the declaring class. 11840b57cec5SDimitry Andric if (entity.isMemberAccess()) { 11850b57cec5SDimitry Andric NamedDecl *D = entity.getTargetDecl(); 11860b57cec5SDimitry Andric accessSoFar = D->getAccess(); 11870b57cec5SDimitry Andric const CXXRecordDecl *declaringClass = entity.getDeclaringClass(); 11880b57cec5SDimitry Andric 11890b57cec5SDimitry Andric switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) { 11900b57cec5SDimitry Andric // If the declaration is accessible when named in its declaring 11910b57cec5SDimitry Andric // class, then we must be constrained by the path. 11920b57cec5SDimitry Andric case AR_accessible: 11930b57cec5SDimitry Andric accessSoFar = AS_public; 11940b57cec5SDimitry Andric entity.suppressInstanceContext(); 11950b57cec5SDimitry Andric break; 11960b57cec5SDimitry Andric 11970b57cec5SDimitry Andric case AR_inaccessible: 11980b57cec5SDimitry Andric if (accessSoFar == AS_private || 11990b57cec5SDimitry Andric declaringClass == entity.getEffectiveNamingClass()) 12000b57cec5SDimitry Andric return diagnoseBadDirectAccess(S, EC, entity); 12010b57cec5SDimitry Andric break; 12020b57cec5SDimitry Andric 12030b57cec5SDimitry Andric case AR_dependent: 12040b57cec5SDimitry Andric llvm_unreachable("cannot diagnose dependent access"); 12050b57cec5SDimitry Andric } 12060b57cec5SDimitry Andric } 12070b57cec5SDimitry Andric 12080b57cec5SDimitry Andric CXXBasePaths paths; 12090b57cec5SDimitry Andric CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths); 12100b57cec5SDimitry Andric assert(path.Access != AS_public); 12110b57cec5SDimitry Andric 12120b57cec5SDimitry Andric CXXBasePath::iterator i = path.end(), e = path.begin(); 12130b57cec5SDimitry Andric CXXBasePath::iterator constrainingBase = i; 12140b57cec5SDimitry Andric while (i != e) { 12150b57cec5SDimitry Andric --i; 12160b57cec5SDimitry Andric 12170b57cec5SDimitry Andric assert(accessSoFar != AS_none && accessSoFar != AS_private); 12180b57cec5SDimitry Andric 12190b57cec5SDimitry Andric // Is the entity accessible when named in the deriving class, as 12200b57cec5SDimitry Andric // modified by the base specifier? 12210b57cec5SDimitry Andric const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl(); 12220b57cec5SDimitry Andric const CXXBaseSpecifier *base = i->Base; 12230b57cec5SDimitry Andric 12240b57cec5SDimitry Andric // If the access to this base is worse than the access we have to 12250b57cec5SDimitry Andric // the declaration, remember it. 12260b57cec5SDimitry Andric AccessSpecifier baseAccess = base->getAccessSpecifier(); 12270b57cec5SDimitry Andric if (baseAccess > accessSoFar) { 12280b57cec5SDimitry Andric constrainingBase = i; 12290b57cec5SDimitry Andric accessSoFar = baseAccess; 12300b57cec5SDimitry Andric } 12310b57cec5SDimitry Andric 12320b57cec5SDimitry Andric switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) { 12330b57cec5SDimitry Andric case AR_inaccessible: break; 12340b57cec5SDimitry Andric case AR_accessible: 12350b57cec5SDimitry Andric accessSoFar = AS_public; 12360b57cec5SDimitry Andric entity.suppressInstanceContext(); 12370b57cec5SDimitry Andric constrainingBase = nullptr; 12380b57cec5SDimitry Andric break; 12390b57cec5SDimitry Andric case AR_dependent: 12400b57cec5SDimitry Andric llvm_unreachable("cannot diagnose dependent access"); 12410b57cec5SDimitry Andric } 12420b57cec5SDimitry Andric 12430b57cec5SDimitry Andric // If this was private inheritance, but we don't have access to 12440b57cec5SDimitry Andric // the deriving class, we're done. 12450b57cec5SDimitry Andric if (accessSoFar == AS_private) { 12460b57cec5SDimitry Andric assert(baseAccess == AS_private); 12470b57cec5SDimitry Andric assert(constrainingBase == i); 12480b57cec5SDimitry Andric break; 12490b57cec5SDimitry Andric } 12500b57cec5SDimitry Andric } 12510b57cec5SDimitry Andric 12520b57cec5SDimitry Andric // If we don't have a constraining base, the access failure must be 12530b57cec5SDimitry Andric // due to the original declaration. 12540b57cec5SDimitry Andric if (constrainingBase == path.end()) 12550b57cec5SDimitry Andric return diagnoseBadDirectAccess(S, EC, entity); 12560b57cec5SDimitry Andric 12570b57cec5SDimitry Andric // We're constrained by inheritance, but we want to say 12580b57cec5SDimitry Andric // "declared private here" if we're diagnosing a hierarchy 12590b57cec5SDimitry Andric // conversion and this is the final step. 12600b57cec5SDimitry Andric unsigned diagnostic; 12610b57cec5SDimitry Andric if (entity.isMemberAccess() || 12620b57cec5SDimitry Andric constrainingBase + 1 != path.end()) { 12630b57cec5SDimitry Andric diagnostic = diag::note_access_constrained_by_path; 12640b57cec5SDimitry Andric } else { 12650b57cec5SDimitry Andric diagnostic = diag::note_access_natural; 12660b57cec5SDimitry Andric } 12670b57cec5SDimitry Andric 12680b57cec5SDimitry Andric const CXXBaseSpecifier *base = constrainingBase->Base; 12690b57cec5SDimitry Andric 12700b57cec5SDimitry Andric S.Diag(base->getSourceRange().getBegin(), diagnostic) 12710b57cec5SDimitry Andric << base->getSourceRange() 12720b57cec5SDimitry Andric << (base->getAccessSpecifier() == AS_protected) 12730b57cec5SDimitry Andric << (base->getAccessSpecifierAsWritten() == AS_none); 12740b57cec5SDimitry Andric 12750b57cec5SDimitry Andric if (entity.isMemberAccess()) 12760b57cec5SDimitry Andric S.Diag(entity.getTargetDecl()->getLocation(), 12770b57cec5SDimitry Andric diag::note_member_declared_at); 12780b57cec5SDimitry Andric } 12790b57cec5SDimitry Andric 12800b57cec5SDimitry Andric static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, 12810b57cec5SDimitry Andric const EffectiveContext &EC, 12820b57cec5SDimitry Andric AccessTarget &Entity) { 12830b57cec5SDimitry Andric const CXXRecordDecl *NamingClass = Entity.getNamingClass(); 12840b57cec5SDimitry Andric const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); 12850b57cec5SDimitry Andric NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : nullptr); 12860b57cec5SDimitry Andric 12870b57cec5SDimitry Andric S.Diag(Loc, Entity.getDiag()) 12880b57cec5SDimitry Andric << (Entity.getAccess() == AS_protected) 12890b57cec5SDimitry Andric << (D ? D->getDeclName() : DeclarationName()) 12900b57cec5SDimitry Andric << S.Context.getTypeDeclType(NamingClass) 12910b57cec5SDimitry Andric << S.Context.getTypeDeclType(DeclaringClass); 12920b57cec5SDimitry Andric DiagnoseAccessPath(S, EC, Entity); 12930b57cec5SDimitry Andric } 12940b57cec5SDimitry Andric 12950b57cec5SDimitry Andric /// MSVC has a bug where if during an using declaration name lookup, 12960b57cec5SDimitry Andric /// the declaration found is unaccessible (private) and that declaration 12970b57cec5SDimitry Andric /// was bring into scope via another using declaration whose target 12980b57cec5SDimitry Andric /// declaration is accessible (public) then no error is generated. 12990b57cec5SDimitry Andric /// Example: 13000b57cec5SDimitry Andric /// class A { 13010b57cec5SDimitry Andric /// public: 13020b57cec5SDimitry Andric /// int f(); 13030b57cec5SDimitry Andric /// }; 13040b57cec5SDimitry Andric /// class B : public A { 13050b57cec5SDimitry Andric /// private: 13060b57cec5SDimitry Andric /// using A::f; 13070b57cec5SDimitry Andric /// }; 13080b57cec5SDimitry Andric /// class C : public B { 13090b57cec5SDimitry Andric /// private: 13100b57cec5SDimitry Andric /// using B::f; 13110b57cec5SDimitry Andric /// }; 13120b57cec5SDimitry Andric /// 13130b57cec5SDimitry Andric /// Here, B::f is private so this should fail in Standard C++, but 13140b57cec5SDimitry Andric /// because B::f refers to A::f which is public MSVC accepts it. 13150b57cec5SDimitry Andric static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S, 13160b57cec5SDimitry Andric SourceLocation AccessLoc, 13170b57cec5SDimitry Andric AccessTarget &Entity) { 13180b57cec5SDimitry Andric if (UsingShadowDecl *Shadow = 1319fe6060f1SDimitry Andric dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) 1320fe6060f1SDimitry Andric if (UsingDecl *UD = dyn_cast<UsingDecl>(Shadow->getIntroducer())) { 13210b57cec5SDimitry Andric const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl(); 13220b57cec5SDimitry Andric if (Entity.getTargetDecl()->getAccess() == AS_private && 13230b57cec5SDimitry Andric (OrigDecl->getAccess() == AS_public || 13240b57cec5SDimitry Andric OrigDecl->getAccess() == AS_protected)) { 13250b57cec5SDimitry Andric S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible) 1326fe6060f1SDimitry Andric << UD->getQualifiedNameAsString() 13270b57cec5SDimitry Andric << OrigDecl->getQualifiedNameAsString(); 13280b57cec5SDimitry Andric return true; 13290b57cec5SDimitry Andric } 13300b57cec5SDimitry Andric } 13310b57cec5SDimitry Andric return false; 13320b57cec5SDimitry Andric } 13330b57cec5SDimitry Andric 13340b57cec5SDimitry Andric /// Determines whether the accessed entity is accessible. Public members 13350b57cec5SDimitry Andric /// have been weeded out by this point. 13360b57cec5SDimitry Andric static AccessResult IsAccessible(Sema &S, 13370b57cec5SDimitry Andric const EffectiveContext &EC, 13380b57cec5SDimitry Andric AccessTarget &Entity) { 13390b57cec5SDimitry Andric // Determine the actual naming class. 13400b57cec5SDimitry Andric const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass(); 13410b57cec5SDimitry Andric 13420b57cec5SDimitry Andric AccessSpecifier UnprivilegedAccess = Entity.getAccess(); 13430b57cec5SDimitry Andric assert(UnprivilegedAccess != AS_public && "public access not weeded out"); 13440b57cec5SDimitry Andric 13450b57cec5SDimitry Andric // Before we try to recalculate access paths, try to white-list 13460b57cec5SDimitry Andric // accesses which just trade in on the final step, i.e. accesses 13470b57cec5SDimitry Andric // which don't require [M4] or [B4]. These are by far the most 13480b57cec5SDimitry Andric // common forms of privileged access. 13490b57cec5SDimitry Andric if (UnprivilegedAccess != AS_none) { 13500b57cec5SDimitry Andric switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) { 13510b57cec5SDimitry Andric case AR_dependent: 13520b57cec5SDimitry Andric // This is actually an interesting policy decision. We don't 13530b57cec5SDimitry Andric // *have* to delay immediately here: we can do the full access 13540b57cec5SDimitry Andric // calculation in the hope that friendship on some intermediate 13550b57cec5SDimitry Andric // class will make the declaration accessible non-dependently. 13560b57cec5SDimitry Andric // But that's not cheap, and odds are very good (note: assertion 13570b57cec5SDimitry Andric // made without data) that the friend declaration will determine 13580b57cec5SDimitry Andric // access. 13590b57cec5SDimitry Andric return AR_dependent; 13600b57cec5SDimitry Andric 13610b57cec5SDimitry Andric case AR_accessible: return AR_accessible; 13620b57cec5SDimitry Andric case AR_inaccessible: break; 13630b57cec5SDimitry Andric } 13640b57cec5SDimitry Andric } 13650b57cec5SDimitry Andric 13660b57cec5SDimitry Andric AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext(); 13670b57cec5SDimitry Andric 13680b57cec5SDimitry Andric // We lower member accesses to base accesses by pretending that the 13690b57cec5SDimitry Andric // member is a base class of its declaring class. 13700b57cec5SDimitry Andric AccessSpecifier FinalAccess; 13710b57cec5SDimitry Andric 13720b57cec5SDimitry Andric if (Entity.isMemberAccess()) { 13730b57cec5SDimitry Andric // Determine if the declaration is accessible from EC when named 13740b57cec5SDimitry Andric // in its declaring class. 13750b57cec5SDimitry Andric NamedDecl *Target = Entity.getTargetDecl(); 13760b57cec5SDimitry Andric const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); 13770b57cec5SDimitry Andric 13780b57cec5SDimitry Andric FinalAccess = Target->getAccess(); 13790b57cec5SDimitry Andric switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) { 13800b57cec5SDimitry Andric case AR_accessible: 13810b57cec5SDimitry Andric // Target is accessible at EC when named in its declaring class. 13820b57cec5SDimitry Andric // We can now hill-climb and simply check whether the declaring 13830b57cec5SDimitry Andric // class is accessible as a base of the naming class. This is 13840b57cec5SDimitry Andric // equivalent to checking the access of a notional public 13850b57cec5SDimitry Andric // member with no instance context. 13860b57cec5SDimitry Andric FinalAccess = AS_public; 13870b57cec5SDimitry Andric Entity.suppressInstanceContext(); 13880b57cec5SDimitry Andric break; 13890b57cec5SDimitry Andric case AR_inaccessible: break; 13900b57cec5SDimitry Andric case AR_dependent: return AR_dependent; // see above 13910b57cec5SDimitry Andric } 13920b57cec5SDimitry Andric 13930b57cec5SDimitry Andric if (DeclaringClass == NamingClass) 13940b57cec5SDimitry Andric return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible); 13950b57cec5SDimitry Andric } else { 13960b57cec5SDimitry Andric FinalAccess = AS_public; 13970b57cec5SDimitry Andric } 13980b57cec5SDimitry Andric 13990b57cec5SDimitry Andric assert(Entity.getDeclaringClass() != NamingClass); 14000b57cec5SDimitry Andric 14010b57cec5SDimitry Andric // Append the declaration's access if applicable. 14020b57cec5SDimitry Andric CXXBasePaths Paths; 14030b57cec5SDimitry Andric CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); 14040b57cec5SDimitry Andric if (!Path) 14050b57cec5SDimitry Andric return AR_dependent; 14060b57cec5SDimitry Andric 14070b57cec5SDimitry Andric assert(Path->Access <= UnprivilegedAccess && 14080b57cec5SDimitry Andric "access along best path worse than direct?"); 14090b57cec5SDimitry Andric if (Path->Access == AS_public) 14100b57cec5SDimitry Andric return AR_accessible; 14110b57cec5SDimitry Andric return AR_inaccessible; 14120b57cec5SDimitry Andric } 14130b57cec5SDimitry Andric 14140b57cec5SDimitry Andric static void DelayDependentAccess(Sema &S, 14150b57cec5SDimitry Andric const EffectiveContext &EC, 14160b57cec5SDimitry Andric SourceLocation Loc, 14170b57cec5SDimitry Andric const AccessTarget &Entity) { 14180b57cec5SDimitry Andric assert(EC.isDependent() && "delaying non-dependent access"); 14190b57cec5SDimitry Andric DeclContext *DC = EC.getInnerContext(); 14200b57cec5SDimitry Andric assert(DC->isDependentContext() && "delaying non-dependent access"); 14210b57cec5SDimitry Andric DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access, 14220b57cec5SDimitry Andric Loc, 14230b57cec5SDimitry Andric Entity.isMemberAccess(), 14240b57cec5SDimitry Andric Entity.getAccess(), 14250b57cec5SDimitry Andric Entity.getTargetDecl(), 14260b57cec5SDimitry Andric Entity.getNamingClass(), 14270b57cec5SDimitry Andric Entity.getBaseObjectType(), 14280b57cec5SDimitry Andric Entity.getDiag()); 14290b57cec5SDimitry Andric } 14300b57cec5SDimitry Andric 14310b57cec5SDimitry Andric /// Checks access to an entity from the given effective context. 14320b57cec5SDimitry Andric static AccessResult CheckEffectiveAccess(Sema &S, 14330b57cec5SDimitry Andric const EffectiveContext &EC, 14340b57cec5SDimitry Andric SourceLocation Loc, 14350b57cec5SDimitry Andric AccessTarget &Entity) { 14360b57cec5SDimitry Andric assert(Entity.getAccess() != AS_public && "called for public access!"); 14370b57cec5SDimitry Andric 14380b57cec5SDimitry Andric switch (IsAccessible(S, EC, Entity)) { 14390b57cec5SDimitry Andric case AR_dependent: 14400b57cec5SDimitry Andric DelayDependentAccess(S, EC, Loc, Entity); 14410b57cec5SDimitry Andric return AR_dependent; 14420b57cec5SDimitry Andric 14430b57cec5SDimitry Andric case AR_inaccessible: 14440b57cec5SDimitry Andric if (S.getLangOpts().MSVCCompat && 14450b57cec5SDimitry Andric IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) 14460b57cec5SDimitry Andric return AR_accessible; 14470b57cec5SDimitry Andric if (!Entity.isQuiet()) 14480b57cec5SDimitry Andric DiagnoseBadAccess(S, Loc, EC, Entity); 14490b57cec5SDimitry Andric return AR_inaccessible; 14500b57cec5SDimitry Andric 14510b57cec5SDimitry Andric case AR_accessible: 14520b57cec5SDimitry Andric return AR_accessible; 14530b57cec5SDimitry Andric } 14540b57cec5SDimitry Andric 14550b57cec5SDimitry Andric // silence unnecessary warning 14560b57cec5SDimitry Andric llvm_unreachable("invalid access result"); 14570b57cec5SDimitry Andric } 14580b57cec5SDimitry Andric 14590b57cec5SDimitry Andric static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, 14600b57cec5SDimitry Andric AccessTarget &Entity) { 14610b57cec5SDimitry Andric // If the access path is public, it's accessible everywhere. 14620b57cec5SDimitry Andric if (Entity.getAccess() == AS_public) 14630b57cec5SDimitry Andric return Sema::AR_accessible; 14640b57cec5SDimitry Andric 14650b57cec5SDimitry Andric // If we're currently parsing a declaration, we may need to delay 14660b57cec5SDimitry Andric // access control checking, because our effective context might be 14670b57cec5SDimitry Andric // different based on what the declaration comes out as. 14680b57cec5SDimitry Andric // 14690b57cec5SDimitry Andric // For example, we might be parsing a declaration with a scope 14700b57cec5SDimitry Andric // specifier, like this: 14710b57cec5SDimitry Andric // A::private_type A::foo() { ... } 14720b57cec5SDimitry Andric // 1473*0fca6ea1SDimitry Andric // friend declaration should not be delayed because it may lead to incorrect 1474*0fca6ea1SDimitry Andric // redeclaration chain, such as: 1475*0fca6ea1SDimitry Andric // class D { 1476*0fca6ea1SDimitry Andric // class E{ 1477*0fca6ea1SDimitry Andric // class F{}; 1478*0fca6ea1SDimitry Andric // friend void foo(D::E::F& q); 1479*0fca6ea1SDimitry Andric // }; 1480*0fca6ea1SDimitry Andric // friend void foo(D::E::F& q); 1481*0fca6ea1SDimitry Andric // }; 14820b57cec5SDimitry Andric if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { 1483*0fca6ea1SDimitry Andric // [class.friend]p9: 1484*0fca6ea1SDimitry Andric // A member nominated by a friend declaration shall be accessible in the 1485*0fca6ea1SDimitry Andric // class containing the friend declaration. The meaning of the friend 1486*0fca6ea1SDimitry Andric // declaration is the same whether the friend declaration appears in the 1487*0fca6ea1SDimitry Andric // private, protected, or public ([class.mem]) portion of the class 1488*0fca6ea1SDimitry Andric // member-specification. 1489*0fca6ea1SDimitry Andric Scope *TS = S.getCurScope(); 1490*0fca6ea1SDimitry Andric bool IsFriendDeclaration = false; 1491*0fca6ea1SDimitry Andric while (TS && !IsFriendDeclaration) { 1492*0fca6ea1SDimitry Andric IsFriendDeclaration = TS->isFriendScope(); 1493*0fca6ea1SDimitry Andric TS = TS->getParent(); 1494*0fca6ea1SDimitry Andric } 1495*0fca6ea1SDimitry Andric if (!IsFriendDeclaration) { 14960b57cec5SDimitry Andric S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity)); 14970b57cec5SDimitry Andric return Sema::AR_delayed; 14980b57cec5SDimitry Andric } 1499*0fca6ea1SDimitry Andric } 15000b57cec5SDimitry Andric 15010b57cec5SDimitry Andric EffectiveContext EC(S.CurContext); 15020b57cec5SDimitry Andric switch (CheckEffectiveAccess(S, EC, Loc, Entity)) { 15030b57cec5SDimitry Andric case AR_accessible: return Sema::AR_accessible; 15040b57cec5SDimitry Andric case AR_inaccessible: return Sema::AR_inaccessible; 15050b57cec5SDimitry Andric case AR_dependent: return Sema::AR_dependent; 15060b57cec5SDimitry Andric } 15070b57cec5SDimitry Andric llvm_unreachable("invalid access result"); 15080b57cec5SDimitry Andric } 15090b57cec5SDimitry Andric 15100b57cec5SDimitry Andric void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) { 15110b57cec5SDimitry Andric // Access control for names used in the declarations of functions 15120b57cec5SDimitry Andric // and function templates should normally be evaluated in the context 15130b57cec5SDimitry Andric // of the declaration, just in case it's a friend of something. 15140b57cec5SDimitry Andric // However, this does not apply to local extern declarations. 15150b57cec5SDimitry Andric 15160b57cec5SDimitry Andric DeclContext *DC = D->getDeclContext(); 15170b57cec5SDimitry Andric if (D->isLocalExternDecl()) { 15180b57cec5SDimitry Andric DC = D->getLexicalDeclContext(); 15190b57cec5SDimitry Andric } else if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) { 15200b57cec5SDimitry Andric DC = FN; 15210b57cec5SDimitry Andric } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) { 1522e8d8bef9SDimitry Andric if (isa<DeclContext>(TD->getTemplatedDecl())) 15230b57cec5SDimitry Andric DC = cast<DeclContext>(TD->getTemplatedDecl()); 1524bdd1243dSDimitry Andric } else if (auto *RD = dyn_cast<RequiresExprBodyDecl>(D)) { 1525bdd1243dSDimitry Andric DC = RD; 15260b57cec5SDimitry Andric } 15270b57cec5SDimitry Andric 15280b57cec5SDimitry Andric EffectiveContext EC(DC); 15290b57cec5SDimitry Andric 15300b57cec5SDimitry Andric AccessTarget Target(DD.getAccessData()); 15310b57cec5SDimitry Andric 15320b57cec5SDimitry Andric if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible) 15330b57cec5SDimitry Andric DD.Triggered = true; 15340b57cec5SDimitry Andric } 15350b57cec5SDimitry Andric 15360b57cec5SDimitry Andric void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, 15370b57cec5SDimitry Andric const MultiLevelTemplateArgumentList &TemplateArgs) { 15380b57cec5SDimitry Andric SourceLocation Loc = DD.getAccessLoc(); 15390b57cec5SDimitry Andric AccessSpecifier Access = DD.getAccess(); 15400b57cec5SDimitry Andric 15410b57cec5SDimitry Andric Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(), 15420b57cec5SDimitry Andric TemplateArgs); 15430b57cec5SDimitry Andric if (!NamingD) return; 15440b57cec5SDimitry Andric Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(), 15450b57cec5SDimitry Andric TemplateArgs); 15460b57cec5SDimitry Andric if (!TargetD) return; 15470b57cec5SDimitry Andric 15480b57cec5SDimitry Andric if (DD.isAccessToMember()) { 15490b57cec5SDimitry Andric CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD); 15500b57cec5SDimitry Andric NamedDecl *TargetDecl = cast<NamedDecl>(TargetD); 15510b57cec5SDimitry Andric QualType BaseObjectType = DD.getAccessBaseObjectType(); 15520b57cec5SDimitry Andric if (!BaseObjectType.isNull()) { 15530b57cec5SDimitry Andric BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc, 15540b57cec5SDimitry Andric DeclarationName()); 15550b57cec5SDimitry Andric if (BaseObjectType.isNull()) return; 15560b57cec5SDimitry Andric } 15570b57cec5SDimitry Andric 15580b57cec5SDimitry Andric AccessTarget Entity(Context, 15590b57cec5SDimitry Andric AccessTarget::Member, 15600b57cec5SDimitry Andric NamingClass, 15610b57cec5SDimitry Andric DeclAccessPair::make(TargetDecl, Access), 15620b57cec5SDimitry Andric BaseObjectType); 15630b57cec5SDimitry Andric Entity.setDiag(DD.getDiagnostic()); 15640b57cec5SDimitry Andric CheckAccess(*this, Loc, Entity); 15650b57cec5SDimitry Andric } else { 15660b57cec5SDimitry Andric AccessTarget Entity(Context, 15670b57cec5SDimitry Andric AccessTarget::Base, 15680b57cec5SDimitry Andric cast<CXXRecordDecl>(TargetD), 15690b57cec5SDimitry Andric cast<CXXRecordDecl>(NamingD), 15700b57cec5SDimitry Andric Access); 15710b57cec5SDimitry Andric Entity.setDiag(DD.getDiagnostic()); 15720b57cec5SDimitry Andric CheckAccess(*this, Loc, Entity); 15730b57cec5SDimitry Andric } 15740b57cec5SDimitry Andric } 15750b57cec5SDimitry Andric 15760b57cec5SDimitry Andric Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, 15770b57cec5SDimitry Andric DeclAccessPair Found) { 15780b57cec5SDimitry Andric if (!getLangOpts().AccessControl || 15790b57cec5SDimitry Andric !E->getNamingClass() || 15800b57cec5SDimitry Andric Found.getAccess() == AS_public) 15810b57cec5SDimitry Andric return AR_accessible; 15820b57cec5SDimitry Andric 15830b57cec5SDimitry Andric AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), 15840b57cec5SDimitry Andric Found, QualType()); 15850b57cec5SDimitry Andric Entity.setDiag(diag::err_access) << E->getSourceRange(); 15860b57cec5SDimitry Andric 15870b57cec5SDimitry Andric return CheckAccess(*this, E->getNameLoc(), Entity); 15880b57cec5SDimitry Andric } 15890b57cec5SDimitry Andric 15900b57cec5SDimitry Andric Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, 15910b57cec5SDimitry Andric DeclAccessPair Found) { 15920b57cec5SDimitry Andric if (!getLangOpts().AccessControl || 15930b57cec5SDimitry Andric Found.getAccess() == AS_public) 15940b57cec5SDimitry Andric return AR_accessible; 15950b57cec5SDimitry Andric 15960b57cec5SDimitry Andric QualType BaseType = E->getBaseType(); 15970b57cec5SDimitry Andric if (E->isArrow()) 1598a7dea167SDimitry Andric BaseType = BaseType->castAs<PointerType>()->getPointeeType(); 15990b57cec5SDimitry Andric 16000b57cec5SDimitry Andric AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), 16010b57cec5SDimitry Andric Found, BaseType); 16020b57cec5SDimitry Andric Entity.setDiag(diag::err_access) << E->getSourceRange(); 16030b57cec5SDimitry Andric 16040b57cec5SDimitry Andric return CheckAccess(*this, E->getMemberLoc(), Entity); 16050b57cec5SDimitry Andric } 16060b57cec5SDimitry Andric 1607480093f4SDimitry Andric bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass, 1608480093f4SDimitry Andric DeclAccessPair Found, 1609480093f4SDimitry Andric QualType ObjectType, 1610480093f4SDimitry Andric SourceLocation Loc, 1611480093f4SDimitry Andric const PartialDiagnostic &Diag) { 16120b57cec5SDimitry Andric // Fast path. 1613480093f4SDimitry Andric if (Found.getAccess() == AS_public || !getLangOpts().AccessControl) 1614480093f4SDimitry Andric return true; 16150b57cec5SDimitry Andric 1616480093f4SDimitry Andric AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 1617480093f4SDimitry Andric ObjectType); 16180b57cec5SDimitry Andric 16190b57cec5SDimitry Andric // Suppress diagnostics. 1620480093f4SDimitry Andric Entity.setDiag(Diag); 16210b57cec5SDimitry Andric 1622480093f4SDimitry Andric switch (CheckAccess(*this, Loc, Entity)) { 16230b57cec5SDimitry Andric case AR_accessible: return true; 16240b57cec5SDimitry Andric case AR_inaccessible: return false; 16250b57cec5SDimitry Andric case AR_dependent: llvm_unreachable("dependent for =delete computation"); 16260b57cec5SDimitry Andric case AR_delayed: llvm_unreachable("cannot delay =delete computation"); 16270b57cec5SDimitry Andric } 16280b57cec5SDimitry Andric llvm_unreachable("bad access result"); 16290b57cec5SDimitry Andric } 16300b57cec5SDimitry Andric 16310b57cec5SDimitry Andric Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, 16320b57cec5SDimitry Andric CXXDestructorDecl *Dtor, 16330b57cec5SDimitry Andric const PartialDiagnostic &PDiag, 16340b57cec5SDimitry Andric QualType ObjectTy) { 16350b57cec5SDimitry Andric if (!getLangOpts().AccessControl) 16360b57cec5SDimitry Andric return AR_accessible; 16370b57cec5SDimitry Andric 16380b57cec5SDimitry Andric // There's never a path involved when checking implicit destructor access. 16390b57cec5SDimitry Andric AccessSpecifier Access = Dtor->getAccess(); 16400b57cec5SDimitry Andric if (Access == AS_public) 16410b57cec5SDimitry Andric return AR_accessible; 16420b57cec5SDimitry Andric 16430b57cec5SDimitry Andric CXXRecordDecl *NamingClass = Dtor->getParent(); 16440b57cec5SDimitry Andric if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass); 16450b57cec5SDimitry Andric 16460b57cec5SDimitry Andric AccessTarget Entity(Context, AccessTarget::Member, NamingClass, 16470b57cec5SDimitry Andric DeclAccessPair::make(Dtor, Access), 16480b57cec5SDimitry Andric ObjectTy); 16490b57cec5SDimitry Andric Entity.setDiag(PDiag); // TODO: avoid copy 16500b57cec5SDimitry Andric 16510b57cec5SDimitry Andric return CheckAccess(*this, Loc, Entity); 16520b57cec5SDimitry Andric } 16530b57cec5SDimitry Andric 16540b57cec5SDimitry Andric Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, 16550b57cec5SDimitry Andric CXXConstructorDecl *Constructor, 16560b57cec5SDimitry Andric DeclAccessPair Found, 16570b57cec5SDimitry Andric const InitializedEntity &Entity, 16580b57cec5SDimitry Andric bool IsCopyBindingRefToTemp) { 16590b57cec5SDimitry Andric if (!getLangOpts().AccessControl || Found.getAccess() == AS_public) 16600b57cec5SDimitry Andric return AR_accessible; 16610b57cec5SDimitry Andric 16620b57cec5SDimitry Andric PartialDiagnostic PD(PDiag()); 16630b57cec5SDimitry Andric switch (Entity.getKind()) { 16640b57cec5SDimitry Andric default: 16650b57cec5SDimitry Andric PD = PDiag(IsCopyBindingRefToTemp 16660b57cec5SDimitry Andric ? diag::ext_rvalue_to_reference_access_ctor 16670b57cec5SDimitry Andric : diag::err_access_ctor); 16680b57cec5SDimitry Andric 16690b57cec5SDimitry Andric break; 16700b57cec5SDimitry Andric 16710b57cec5SDimitry Andric case InitializedEntity::EK_Base: 16720b57cec5SDimitry Andric PD = PDiag(diag::err_access_base_ctor); 16730b57cec5SDimitry Andric PD << Entity.isInheritedVirtualBase() 1674*0fca6ea1SDimitry Andric << Entity.getBaseSpecifier()->getType() 1675*0fca6ea1SDimitry Andric << llvm::to_underlying(getSpecialMember(Constructor)); 16760b57cec5SDimitry Andric break; 16770b57cec5SDimitry Andric 16782efbaac7SDimitry Andric case InitializedEntity::EK_Member: 16792efbaac7SDimitry Andric case InitializedEntity::EK_ParenAggInitMember: { 16800b57cec5SDimitry Andric const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); 16810b57cec5SDimitry Andric PD = PDiag(diag::err_access_field_ctor); 1682*0fca6ea1SDimitry Andric PD << Field->getType() 1683*0fca6ea1SDimitry Andric << llvm::to_underlying(getSpecialMember(Constructor)); 16840b57cec5SDimitry Andric break; 16850b57cec5SDimitry Andric } 16860b57cec5SDimitry Andric 16870b57cec5SDimitry Andric case InitializedEntity::EK_LambdaCapture: { 16880b57cec5SDimitry Andric StringRef VarName = Entity.getCapturedVarName(); 16890b57cec5SDimitry Andric PD = PDiag(diag::err_access_lambda_capture); 1690*0fca6ea1SDimitry Andric PD << VarName << Entity.getType() 1691*0fca6ea1SDimitry Andric << llvm::to_underlying(getSpecialMember(Constructor)); 16920b57cec5SDimitry Andric break; 16930b57cec5SDimitry Andric } 16940b57cec5SDimitry Andric 16950b57cec5SDimitry Andric } 16960b57cec5SDimitry Andric 16970b57cec5SDimitry Andric return CheckConstructorAccess(UseLoc, Constructor, Found, Entity, PD); 16980b57cec5SDimitry Andric } 16990b57cec5SDimitry Andric 17000b57cec5SDimitry Andric Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, 17010b57cec5SDimitry Andric CXXConstructorDecl *Constructor, 17020b57cec5SDimitry Andric DeclAccessPair Found, 17030b57cec5SDimitry Andric const InitializedEntity &Entity, 17040b57cec5SDimitry Andric const PartialDiagnostic &PD) { 17050b57cec5SDimitry Andric if (!getLangOpts().AccessControl || 17060b57cec5SDimitry Andric Found.getAccess() == AS_public) 17070b57cec5SDimitry Andric return AR_accessible; 17080b57cec5SDimitry Andric 17090b57cec5SDimitry Andric CXXRecordDecl *NamingClass = Constructor->getParent(); 17100b57cec5SDimitry Andric 17110b57cec5SDimitry Andric // Initializing a base sub-object is an instance method call on an 17120b57cec5SDimitry Andric // object of the derived class. Otherwise, we have an instance method 17130b57cec5SDimitry Andric // call on an object of the constructed type. 17140b57cec5SDimitry Andric // 17150b57cec5SDimitry Andric // FIXME: If we have a parent, we're initializing the base class subobject 17160b57cec5SDimitry Andric // in aggregate initialization. It's not clear whether the object class 17170b57cec5SDimitry Andric // should be the base class or the derived class in that case. 17180b57cec5SDimitry Andric CXXRecordDecl *ObjectClass; 17190b57cec5SDimitry Andric if ((Entity.getKind() == InitializedEntity::EK_Base || 17200b57cec5SDimitry Andric Entity.getKind() == InitializedEntity::EK_Delegating) && 17210b57cec5SDimitry Andric !Entity.getParent()) { 17220b57cec5SDimitry Andric ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent(); 17230b57cec5SDimitry Andric } else if (auto *Shadow = 17240b57cec5SDimitry Andric dyn_cast<ConstructorUsingShadowDecl>(Found.getDecl())) { 17250b57cec5SDimitry Andric // If we're using an inheriting constructor to construct an object, 17260b57cec5SDimitry Andric // the object class is the derived class, not the base class. 17270b57cec5SDimitry Andric ObjectClass = Shadow->getParent(); 17280b57cec5SDimitry Andric } else { 17290b57cec5SDimitry Andric ObjectClass = NamingClass; 17300b57cec5SDimitry Andric } 17310b57cec5SDimitry Andric 17320b57cec5SDimitry Andric AccessTarget AccessEntity( 17330b57cec5SDimitry Andric Context, AccessTarget::Member, NamingClass, 17340b57cec5SDimitry Andric DeclAccessPair::make(Constructor, Found.getAccess()), 17350b57cec5SDimitry Andric Context.getTypeDeclType(ObjectClass)); 17360b57cec5SDimitry Andric AccessEntity.setDiag(PD); 17370b57cec5SDimitry Andric 17380b57cec5SDimitry Andric return CheckAccess(*this, UseLoc, AccessEntity); 17390b57cec5SDimitry Andric } 17400b57cec5SDimitry Andric 17410b57cec5SDimitry Andric Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, 17420b57cec5SDimitry Andric SourceRange PlacementRange, 17430b57cec5SDimitry Andric CXXRecordDecl *NamingClass, 17440b57cec5SDimitry Andric DeclAccessPair Found, 17450b57cec5SDimitry Andric bool Diagnose) { 17460b57cec5SDimitry Andric if (!getLangOpts().AccessControl || 17470b57cec5SDimitry Andric !NamingClass || 17480b57cec5SDimitry Andric Found.getAccess() == AS_public) 17490b57cec5SDimitry Andric return AR_accessible; 17500b57cec5SDimitry Andric 17510b57cec5SDimitry Andric AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 17520b57cec5SDimitry Andric QualType()); 17530b57cec5SDimitry Andric if (Diagnose) 17540b57cec5SDimitry Andric Entity.setDiag(diag::err_access) 17550b57cec5SDimitry Andric << PlacementRange; 17560b57cec5SDimitry Andric 17570b57cec5SDimitry Andric return CheckAccess(*this, OpLoc, Entity); 17580b57cec5SDimitry Andric } 17590b57cec5SDimitry Andric 17600b57cec5SDimitry Andric Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc, 17610b57cec5SDimitry Andric CXXRecordDecl *NamingClass, 17620b57cec5SDimitry Andric DeclAccessPair Found) { 17630b57cec5SDimitry Andric if (!getLangOpts().AccessControl || 17640b57cec5SDimitry Andric !NamingClass || 17650b57cec5SDimitry Andric Found.getAccess() == AS_public) 17660b57cec5SDimitry Andric return AR_accessible; 17670b57cec5SDimitry Andric 17680b57cec5SDimitry Andric AccessTarget Entity(Context, AccessTarget::Member, NamingClass, 17690b57cec5SDimitry Andric Found, QualType()); 17700b57cec5SDimitry Andric 17710b57cec5SDimitry Andric return CheckAccess(*this, UseLoc, Entity); 17720b57cec5SDimitry Andric } 17730b57cec5SDimitry Andric 17740b57cec5SDimitry Andric Sema::AccessResult 17750b57cec5SDimitry Andric Sema::CheckStructuredBindingMemberAccess(SourceLocation UseLoc, 17760b57cec5SDimitry Andric CXXRecordDecl *DecomposedClass, 17770b57cec5SDimitry Andric DeclAccessPair Field) { 17780b57cec5SDimitry Andric if (!getLangOpts().AccessControl || 17790b57cec5SDimitry Andric Field.getAccess() == AS_public) 17800b57cec5SDimitry Andric return AR_accessible; 17810b57cec5SDimitry Andric 17820b57cec5SDimitry Andric AccessTarget Entity(Context, AccessTarget::Member, DecomposedClass, Field, 17830b57cec5SDimitry Andric Context.getRecordType(DecomposedClass)); 17840b57cec5SDimitry Andric Entity.setDiag(diag::err_decomp_decl_inaccessible_field); 17850b57cec5SDimitry Andric 17860b57cec5SDimitry Andric return CheckAccess(*this, UseLoc, Entity); 17870b57cec5SDimitry Andric } 17880b57cec5SDimitry Andric 17890b57cec5SDimitry Andric Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, 17900b57cec5SDimitry Andric Expr *ObjectExpr, 179181ad6265SDimitry Andric const SourceRange &Range, 17920b57cec5SDimitry Andric DeclAccessPair Found) { 179381ad6265SDimitry Andric if (!getLangOpts().AccessControl || Found.getAccess() == AS_public) 17940b57cec5SDimitry Andric return AR_accessible; 17950b57cec5SDimitry Andric 17960b57cec5SDimitry Andric const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>(); 17970b57cec5SDimitry Andric CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); 17980b57cec5SDimitry Andric 17990b57cec5SDimitry Andric AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 18000b57cec5SDimitry Andric ObjectExpr->getType()); 180181ad6265SDimitry Andric Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << Range; 18020b57cec5SDimitry Andric 18030b57cec5SDimitry Andric return CheckAccess(*this, OpLoc, Entity); 18040b57cec5SDimitry Andric } 18050b57cec5SDimitry Andric 180681ad6265SDimitry Andric Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, 180781ad6265SDimitry Andric Expr *ObjectExpr, 180881ad6265SDimitry Andric Expr *ArgExpr, 180981ad6265SDimitry Andric DeclAccessPair Found) { 181081ad6265SDimitry Andric return CheckMemberOperatorAccess( 181181ad6265SDimitry Andric OpLoc, ObjectExpr, ArgExpr ? ArgExpr->getSourceRange() : SourceRange(), 181281ad6265SDimitry Andric Found); 181381ad6265SDimitry Andric } 181481ad6265SDimitry Andric 181581ad6265SDimitry Andric Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, 181681ad6265SDimitry Andric Expr *ObjectExpr, 181781ad6265SDimitry Andric ArrayRef<Expr *> ArgExprs, 181881ad6265SDimitry Andric DeclAccessPair FoundDecl) { 181981ad6265SDimitry Andric SourceRange R; 182081ad6265SDimitry Andric if (!ArgExprs.empty()) { 182181ad6265SDimitry Andric R = SourceRange(ArgExprs.front()->getBeginLoc(), 182281ad6265SDimitry Andric ArgExprs.back()->getEndLoc()); 182381ad6265SDimitry Andric } 182481ad6265SDimitry Andric 182581ad6265SDimitry Andric return CheckMemberOperatorAccess(OpLoc, ObjectExpr, R, FoundDecl); 182681ad6265SDimitry Andric } 182781ad6265SDimitry Andric 18280b57cec5SDimitry Andric Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) { 18290b57cec5SDimitry Andric assert(isa<CXXMethodDecl>(target->getAsFunction())); 18300b57cec5SDimitry Andric 18310b57cec5SDimitry Andric // Friendship lookup is a redeclaration lookup, so there's never an 18320b57cec5SDimitry Andric // inheritance path modifying access. 18330b57cec5SDimitry Andric AccessSpecifier access = target->getAccess(); 18340b57cec5SDimitry Andric 18350b57cec5SDimitry Andric if (!getLangOpts().AccessControl || access == AS_public) 18360b57cec5SDimitry Andric return AR_accessible; 18370b57cec5SDimitry Andric 18380b57cec5SDimitry Andric CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction()); 18390b57cec5SDimitry Andric 18400b57cec5SDimitry Andric AccessTarget entity(Context, AccessTarget::Member, 18410b57cec5SDimitry Andric cast<CXXRecordDecl>(target->getDeclContext()), 18420b57cec5SDimitry Andric DeclAccessPair::make(target, access), 18430b57cec5SDimitry Andric /*no instance context*/ QualType()); 18440b57cec5SDimitry Andric entity.setDiag(diag::err_access_friend_function) 18450b57cec5SDimitry Andric << (method->getQualifier() ? method->getQualifierLoc().getSourceRange() 18460b57cec5SDimitry Andric : method->getNameInfo().getSourceRange()); 18470b57cec5SDimitry Andric 18480b57cec5SDimitry Andric // We need to bypass delayed-diagnostics because we might be called 18490b57cec5SDimitry Andric // while the ParsingDeclarator is active. 18500b57cec5SDimitry Andric EffectiveContext EC(CurContext); 18510b57cec5SDimitry Andric switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) { 18520b57cec5SDimitry Andric case ::AR_accessible: return Sema::AR_accessible; 18530b57cec5SDimitry Andric case ::AR_inaccessible: return Sema::AR_inaccessible; 18540b57cec5SDimitry Andric case ::AR_dependent: return Sema::AR_dependent; 18550b57cec5SDimitry Andric } 18560b57cec5SDimitry Andric llvm_unreachable("invalid access result"); 18570b57cec5SDimitry Andric } 18580b57cec5SDimitry Andric 18590b57cec5SDimitry Andric Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, 18600b57cec5SDimitry Andric DeclAccessPair Found) { 18610b57cec5SDimitry Andric if (!getLangOpts().AccessControl || 18620b57cec5SDimitry Andric Found.getAccess() == AS_none || 18630b57cec5SDimitry Andric Found.getAccess() == AS_public) 18640b57cec5SDimitry Andric return AR_accessible; 18650b57cec5SDimitry Andric 18660b57cec5SDimitry Andric OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression; 18670b57cec5SDimitry Andric CXXRecordDecl *NamingClass = Ovl->getNamingClass(); 18680b57cec5SDimitry Andric 18690b57cec5SDimitry Andric AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 18700b57cec5SDimitry Andric /*no instance context*/ QualType()); 18710b57cec5SDimitry Andric Entity.setDiag(diag::err_access) 18720b57cec5SDimitry Andric << Ovl->getSourceRange(); 18730b57cec5SDimitry Andric 18740b57cec5SDimitry Andric return CheckAccess(*this, Ovl->getNameLoc(), Entity); 18750b57cec5SDimitry Andric } 18760b57cec5SDimitry Andric 18770b57cec5SDimitry Andric Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, 18780b57cec5SDimitry Andric QualType Base, 18790b57cec5SDimitry Andric QualType Derived, 18800b57cec5SDimitry Andric const CXXBasePath &Path, 18810b57cec5SDimitry Andric unsigned DiagID, 18820b57cec5SDimitry Andric bool ForceCheck, 18830b57cec5SDimitry Andric bool ForceUnprivileged) { 18840b57cec5SDimitry Andric if (!ForceCheck && !getLangOpts().AccessControl) 18850b57cec5SDimitry Andric return AR_accessible; 18860b57cec5SDimitry Andric 18870b57cec5SDimitry Andric if (Path.Access == AS_public) 18880b57cec5SDimitry Andric return AR_accessible; 18890b57cec5SDimitry Andric 18900b57cec5SDimitry Andric CXXRecordDecl *BaseD, *DerivedD; 1891a7dea167SDimitry Andric BaseD = cast<CXXRecordDecl>(Base->castAs<RecordType>()->getDecl()); 1892a7dea167SDimitry Andric DerivedD = cast<CXXRecordDecl>(Derived->castAs<RecordType>()->getDecl()); 18930b57cec5SDimitry Andric 18940b57cec5SDimitry Andric AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD, 18950b57cec5SDimitry Andric Path.Access); 18960b57cec5SDimitry Andric if (DiagID) 18970b57cec5SDimitry Andric Entity.setDiag(DiagID) << Derived << Base; 18980b57cec5SDimitry Andric 18990b57cec5SDimitry Andric if (ForceUnprivileged) { 19000b57cec5SDimitry Andric switch (CheckEffectiveAccess(*this, EffectiveContext(), 19010b57cec5SDimitry Andric AccessLoc, Entity)) { 19020b57cec5SDimitry Andric case ::AR_accessible: return Sema::AR_accessible; 19030b57cec5SDimitry Andric case ::AR_inaccessible: return Sema::AR_inaccessible; 19040b57cec5SDimitry Andric case ::AR_dependent: return Sema::AR_dependent; 19050b57cec5SDimitry Andric } 19060b57cec5SDimitry Andric llvm_unreachable("unexpected result from CheckEffectiveAccess"); 19070b57cec5SDimitry Andric } 19080b57cec5SDimitry Andric return CheckAccess(*this, AccessLoc, Entity); 19090b57cec5SDimitry Andric } 19100b57cec5SDimitry Andric 19110b57cec5SDimitry Andric void Sema::CheckLookupAccess(const LookupResult &R) { 19120b57cec5SDimitry Andric assert(getLangOpts().AccessControl 19130b57cec5SDimitry Andric && "performing access check without access control"); 19140b57cec5SDimitry Andric assert(R.getNamingClass() && "performing access check without naming class"); 19150b57cec5SDimitry Andric 19160b57cec5SDimitry Andric for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { 19170b57cec5SDimitry Andric if (I.getAccess() != AS_public) { 19180b57cec5SDimitry Andric AccessTarget Entity(Context, AccessedEntity::Member, 19190b57cec5SDimitry Andric R.getNamingClass(), I.getPair(), 19200b57cec5SDimitry Andric R.getBaseObjectType()); 19210b57cec5SDimitry Andric Entity.setDiag(diag::err_access); 19220b57cec5SDimitry Andric CheckAccess(*this, R.getNameLoc(), Entity); 19230b57cec5SDimitry Andric } 19240b57cec5SDimitry Andric } 19250b57cec5SDimitry Andric } 19260b57cec5SDimitry Andric 19270b57cec5SDimitry Andric bool Sema::IsSimplyAccessible(NamedDecl *Target, CXXRecordDecl *NamingClass, 19280b57cec5SDimitry Andric QualType BaseType) { 19290b57cec5SDimitry Andric // Perform the C++ accessibility checks first. 19300b57cec5SDimitry Andric if (Target->isCXXClassMember() && NamingClass) { 19310b57cec5SDimitry Andric if (!getLangOpts().CPlusPlus) 19320b57cec5SDimitry Andric return false; 19330b57cec5SDimitry Andric // The unprivileged access is AS_none as we don't know how the member was 19340b57cec5SDimitry Andric // accessed, which is described by the access in DeclAccessPair. 19350b57cec5SDimitry Andric // `IsAccessible` will examine the actual access of Target (i.e. 19360b57cec5SDimitry Andric // Decl->getAccess()) when calculating the access. 19370b57cec5SDimitry Andric AccessTarget Entity(Context, AccessedEntity::Member, NamingClass, 19380b57cec5SDimitry Andric DeclAccessPair::make(Target, AS_none), BaseType); 19390b57cec5SDimitry Andric EffectiveContext EC(CurContext); 19400b57cec5SDimitry Andric return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; 19410b57cec5SDimitry Andric } 19420b57cec5SDimitry Andric 19430b57cec5SDimitry Andric if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Target)) { 19440b57cec5SDimitry Andric // @public and @package ivars are always accessible. 19450b57cec5SDimitry Andric if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public || 19460b57cec5SDimitry Andric Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package) 19470b57cec5SDimitry Andric return true; 19480b57cec5SDimitry Andric 19490b57cec5SDimitry Andric // If we are inside a class or category implementation, determine the 19500b57cec5SDimitry Andric // interface we're in. 19510b57cec5SDimitry Andric ObjCInterfaceDecl *ClassOfMethodDecl = nullptr; 19520b57cec5SDimitry Andric if (ObjCMethodDecl *MD = getCurMethodDecl()) 19530b57cec5SDimitry Andric ClassOfMethodDecl = MD->getClassInterface(); 19540b57cec5SDimitry Andric else if (FunctionDecl *FD = getCurFunctionDecl()) { 19550b57cec5SDimitry Andric if (ObjCImplDecl *Impl 19560b57cec5SDimitry Andric = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) { 19570b57cec5SDimitry Andric if (ObjCImplementationDecl *IMPD 19580b57cec5SDimitry Andric = dyn_cast<ObjCImplementationDecl>(Impl)) 19590b57cec5SDimitry Andric ClassOfMethodDecl = IMPD->getClassInterface(); 19600b57cec5SDimitry Andric else if (ObjCCategoryImplDecl* CatImplClass 19610b57cec5SDimitry Andric = dyn_cast<ObjCCategoryImplDecl>(Impl)) 19620b57cec5SDimitry Andric ClassOfMethodDecl = CatImplClass->getClassInterface(); 19630b57cec5SDimitry Andric } 19640b57cec5SDimitry Andric } 19650b57cec5SDimitry Andric 19660b57cec5SDimitry Andric // If we're not in an interface, this ivar is inaccessible. 19670b57cec5SDimitry Andric if (!ClassOfMethodDecl) 19680b57cec5SDimitry Andric return false; 19690b57cec5SDimitry Andric 19700b57cec5SDimitry Andric // If we're inside the same interface that owns the ivar, we're fine. 19710b57cec5SDimitry Andric if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface())) 19720b57cec5SDimitry Andric return true; 19730b57cec5SDimitry Andric 19740b57cec5SDimitry Andric // If the ivar is private, it's inaccessible. 19750b57cec5SDimitry Andric if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private) 19760b57cec5SDimitry Andric return false; 19770b57cec5SDimitry Andric 19780b57cec5SDimitry Andric return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl); 19790b57cec5SDimitry Andric } 19800b57cec5SDimitry Andric 19810b57cec5SDimitry Andric return true; 19820b57cec5SDimitry Andric } 1983