xref: /freebsd-src/contrib/llvm-project/clang/lib/Sema/SemaAccess.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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