xref: /minix3/external/bsd/llvm/dist/clang/lib/Sema/SemaAccess.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This file provides Sema routines for C++ access control semantics.
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
13f4a2713aSLionel Sambuc 
14f4a2713aSLionel Sambuc #include "clang/Sema/SemaInternal.h"
15f4a2713aSLionel Sambuc #include "clang/AST/ASTContext.h"
16f4a2713aSLionel Sambuc #include "clang/AST/CXXInheritance.h"
17f4a2713aSLionel Sambuc #include "clang/AST/DeclCXX.h"
18f4a2713aSLionel Sambuc #include "clang/AST/DeclFriend.h"
19f4a2713aSLionel Sambuc #include "clang/AST/DeclObjC.h"
20f4a2713aSLionel Sambuc #include "clang/AST/DependentDiagnostic.h"
21f4a2713aSLionel Sambuc #include "clang/AST/ExprCXX.h"
22f4a2713aSLionel Sambuc #include "clang/Sema/DelayedDiagnostic.h"
23f4a2713aSLionel Sambuc #include "clang/Sema/Initialization.h"
24f4a2713aSLionel Sambuc #include "clang/Sema/Lookup.h"
25f4a2713aSLionel Sambuc 
26f4a2713aSLionel Sambuc using namespace clang;
27f4a2713aSLionel Sambuc using namespace sema;
28f4a2713aSLionel Sambuc 
29f4a2713aSLionel Sambuc /// A copy of Sema's enum without AR_delayed.
30f4a2713aSLionel Sambuc enum AccessResult {
31f4a2713aSLionel Sambuc   AR_accessible,
32f4a2713aSLionel Sambuc   AR_inaccessible,
33f4a2713aSLionel Sambuc   AR_dependent
34f4a2713aSLionel Sambuc };
35f4a2713aSLionel Sambuc 
36f4a2713aSLionel Sambuc /// SetMemberAccessSpecifier - Set the access specifier of a member.
37f4a2713aSLionel Sambuc /// Returns true on error (when the previous member decl access specifier
38f4a2713aSLionel Sambuc /// is different from the new member decl access specifier).
SetMemberAccessSpecifier(NamedDecl * MemberDecl,NamedDecl * PrevMemberDecl,AccessSpecifier LexicalAS)39f4a2713aSLionel Sambuc bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
40f4a2713aSLionel Sambuc                                     NamedDecl *PrevMemberDecl,
41f4a2713aSLionel Sambuc                                     AccessSpecifier LexicalAS) {
42f4a2713aSLionel Sambuc   if (!PrevMemberDecl) {
43f4a2713aSLionel Sambuc     // Use the lexical access specifier.
44f4a2713aSLionel Sambuc     MemberDecl->setAccess(LexicalAS);
45f4a2713aSLionel Sambuc     return false;
46f4a2713aSLionel Sambuc   }
47f4a2713aSLionel Sambuc 
48f4a2713aSLionel Sambuc   // C++ [class.access.spec]p3: When a member is redeclared its access
49f4a2713aSLionel Sambuc   // specifier must be same as its initial declaration.
50f4a2713aSLionel Sambuc   if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
51f4a2713aSLionel Sambuc     Diag(MemberDecl->getLocation(),
52f4a2713aSLionel Sambuc          diag::err_class_redeclared_with_different_access)
53f4a2713aSLionel Sambuc       << MemberDecl << LexicalAS;
54f4a2713aSLionel Sambuc     Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
55f4a2713aSLionel Sambuc       << PrevMemberDecl << PrevMemberDecl->getAccess();
56f4a2713aSLionel Sambuc 
57f4a2713aSLionel Sambuc     MemberDecl->setAccess(LexicalAS);
58f4a2713aSLionel Sambuc     return true;
59f4a2713aSLionel Sambuc   }
60f4a2713aSLionel Sambuc 
61f4a2713aSLionel Sambuc   MemberDecl->setAccess(PrevMemberDecl->getAccess());
62f4a2713aSLionel Sambuc   return false;
63f4a2713aSLionel Sambuc }
64f4a2713aSLionel Sambuc 
FindDeclaringClass(NamedDecl * D)65f4a2713aSLionel Sambuc static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
66f4a2713aSLionel Sambuc   DeclContext *DC = D->getDeclContext();
67f4a2713aSLionel Sambuc 
68f4a2713aSLionel Sambuc   // This can only happen at top: enum decls only "publish" their
69f4a2713aSLionel Sambuc   // immediate members.
70f4a2713aSLionel Sambuc   if (isa<EnumDecl>(DC))
71f4a2713aSLionel Sambuc     DC = cast<EnumDecl>(DC)->getDeclContext();
72f4a2713aSLionel Sambuc 
73f4a2713aSLionel Sambuc   CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
74f4a2713aSLionel Sambuc   while (DeclaringClass->isAnonymousStructOrUnion())
75f4a2713aSLionel Sambuc     DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
76f4a2713aSLionel Sambuc   return DeclaringClass;
77f4a2713aSLionel Sambuc }
78f4a2713aSLionel Sambuc 
79f4a2713aSLionel Sambuc namespace {
80f4a2713aSLionel Sambuc struct EffectiveContext {
EffectiveContext__anon35c5671a0111::EffectiveContext81*0a6a1f1dSLionel Sambuc   EffectiveContext() : Inner(nullptr), Dependent(false) {}
82f4a2713aSLionel Sambuc 
EffectiveContext__anon35c5671a0111::EffectiveContext83f4a2713aSLionel Sambuc   explicit EffectiveContext(DeclContext *DC)
84f4a2713aSLionel Sambuc     : Inner(DC),
85f4a2713aSLionel Sambuc       Dependent(DC->isDependentContext()) {
86f4a2713aSLionel Sambuc 
87f4a2713aSLionel Sambuc     // C++11 [class.access.nest]p1:
88f4a2713aSLionel Sambuc     //   A nested class is a member and as such has the same access
89f4a2713aSLionel Sambuc     //   rights as any other member.
90f4a2713aSLionel Sambuc     // C++11 [class.access]p2:
91f4a2713aSLionel Sambuc     //   A member of a class can also access all the names to which
92f4a2713aSLionel Sambuc     //   the class has access.  A local class of a member function
93f4a2713aSLionel Sambuc     //   may access the same names that the member function itself
94f4a2713aSLionel Sambuc     //   may access.
95f4a2713aSLionel Sambuc     // This almost implies that the privileges of nesting are transitive.
96f4a2713aSLionel Sambuc     // Technically it says nothing about the local classes of non-member
97f4a2713aSLionel Sambuc     // functions (which can gain privileges through friendship), but we
98f4a2713aSLionel Sambuc     // take that as an oversight.
99f4a2713aSLionel Sambuc     while (true) {
100f4a2713aSLionel Sambuc       // We want to add canonical declarations to the EC lists for
101f4a2713aSLionel Sambuc       // simplicity of checking, but we need to walk up through the
102f4a2713aSLionel Sambuc       // actual current DC chain.  Otherwise, something like a local
103f4a2713aSLionel Sambuc       // extern or friend which happens to be the canonical
104f4a2713aSLionel Sambuc       // declaration will really mess us up.
105f4a2713aSLionel Sambuc 
106f4a2713aSLionel Sambuc       if (isa<CXXRecordDecl>(DC)) {
107f4a2713aSLionel Sambuc         CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
108f4a2713aSLionel Sambuc         Records.push_back(Record->getCanonicalDecl());
109f4a2713aSLionel Sambuc         DC = Record->getDeclContext();
110f4a2713aSLionel Sambuc       } else if (isa<FunctionDecl>(DC)) {
111f4a2713aSLionel Sambuc         FunctionDecl *Function = cast<FunctionDecl>(DC);
112f4a2713aSLionel Sambuc         Functions.push_back(Function->getCanonicalDecl());
113f4a2713aSLionel Sambuc         if (Function->getFriendObjectKind())
114f4a2713aSLionel Sambuc           DC = Function->getLexicalDeclContext();
115f4a2713aSLionel Sambuc         else
116f4a2713aSLionel Sambuc           DC = Function->getDeclContext();
117f4a2713aSLionel Sambuc       } else if (DC->isFileContext()) {
118f4a2713aSLionel Sambuc         break;
119f4a2713aSLionel Sambuc       } else {
120f4a2713aSLionel Sambuc         DC = DC->getParent();
121f4a2713aSLionel Sambuc       }
122f4a2713aSLionel Sambuc     }
123f4a2713aSLionel Sambuc   }
124f4a2713aSLionel Sambuc 
isDependent__anon35c5671a0111::EffectiveContext125f4a2713aSLionel Sambuc   bool isDependent() const { return Dependent; }
126f4a2713aSLionel Sambuc 
includesClass__anon35c5671a0111::EffectiveContext127f4a2713aSLionel Sambuc   bool includesClass(const CXXRecordDecl *R) const {
128f4a2713aSLionel Sambuc     R = R->getCanonicalDecl();
129f4a2713aSLionel Sambuc     return std::find(Records.begin(), Records.end(), R)
130f4a2713aSLionel Sambuc              != Records.end();
131f4a2713aSLionel Sambuc   }
132f4a2713aSLionel Sambuc 
133f4a2713aSLionel Sambuc   /// Retrieves the innermost "useful" context.  Can be null if we're
134f4a2713aSLionel Sambuc   /// doing access-control without privileges.
getInnerContext__anon35c5671a0111::EffectiveContext135f4a2713aSLionel Sambuc   DeclContext *getInnerContext() const {
136f4a2713aSLionel Sambuc     return Inner;
137f4a2713aSLionel Sambuc   }
138f4a2713aSLionel Sambuc 
139f4a2713aSLionel Sambuc   typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
140f4a2713aSLionel Sambuc 
141f4a2713aSLionel Sambuc   DeclContext *Inner;
142f4a2713aSLionel Sambuc   SmallVector<FunctionDecl*, 4> Functions;
143f4a2713aSLionel Sambuc   SmallVector<CXXRecordDecl*, 4> Records;
144f4a2713aSLionel Sambuc   bool Dependent;
145f4a2713aSLionel Sambuc };
146f4a2713aSLionel Sambuc 
147f4a2713aSLionel Sambuc /// Like sema::AccessedEntity, but kindly lets us scribble all over
148f4a2713aSLionel Sambuc /// it.
149f4a2713aSLionel Sambuc struct AccessTarget : public AccessedEntity {
AccessTarget__anon35c5671a0111::AccessTarget150f4a2713aSLionel Sambuc   AccessTarget(const AccessedEntity &Entity)
151f4a2713aSLionel Sambuc     : AccessedEntity(Entity) {
152f4a2713aSLionel Sambuc     initialize();
153f4a2713aSLionel Sambuc   }
154f4a2713aSLionel Sambuc 
AccessTarget__anon35c5671a0111::AccessTarget155f4a2713aSLionel Sambuc   AccessTarget(ASTContext &Context,
156f4a2713aSLionel Sambuc                MemberNonce _,
157f4a2713aSLionel Sambuc                CXXRecordDecl *NamingClass,
158f4a2713aSLionel Sambuc                DeclAccessPair FoundDecl,
159f4a2713aSLionel Sambuc                QualType BaseObjectType)
160f4a2713aSLionel Sambuc     : AccessedEntity(Context.getDiagAllocator(), Member, NamingClass,
161f4a2713aSLionel Sambuc                      FoundDecl, BaseObjectType) {
162f4a2713aSLionel Sambuc     initialize();
163f4a2713aSLionel Sambuc   }
164f4a2713aSLionel Sambuc 
AccessTarget__anon35c5671a0111::AccessTarget165f4a2713aSLionel Sambuc   AccessTarget(ASTContext &Context,
166f4a2713aSLionel Sambuc                BaseNonce _,
167f4a2713aSLionel Sambuc                CXXRecordDecl *BaseClass,
168f4a2713aSLionel Sambuc                CXXRecordDecl *DerivedClass,
169f4a2713aSLionel Sambuc                AccessSpecifier Access)
170f4a2713aSLionel Sambuc     : AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass,
171f4a2713aSLionel Sambuc                      Access) {
172f4a2713aSLionel Sambuc     initialize();
173f4a2713aSLionel Sambuc   }
174f4a2713aSLionel Sambuc 
isInstanceMember__anon35c5671a0111::AccessTarget175f4a2713aSLionel Sambuc   bool isInstanceMember() const {
176f4a2713aSLionel Sambuc     return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember());
177f4a2713aSLionel Sambuc   }
178f4a2713aSLionel Sambuc 
hasInstanceContext__anon35c5671a0111::AccessTarget179f4a2713aSLionel Sambuc   bool hasInstanceContext() const {
180f4a2713aSLionel Sambuc     return HasInstanceContext;
181f4a2713aSLionel Sambuc   }
182f4a2713aSLionel Sambuc 
183f4a2713aSLionel Sambuc   class SavedInstanceContext {
184f4a2713aSLionel Sambuc   public:
~SavedInstanceContext()185f4a2713aSLionel Sambuc     ~SavedInstanceContext() {
186f4a2713aSLionel Sambuc       Target.HasInstanceContext = Has;
187f4a2713aSLionel Sambuc     }
188f4a2713aSLionel Sambuc 
189f4a2713aSLionel Sambuc   private:
190f4a2713aSLionel Sambuc     friend struct AccessTarget;
SavedInstanceContext(AccessTarget & Target)191f4a2713aSLionel Sambuc     explicit SavedInstanceContext(AccessTarget &Target)
192f4a2713aSLionel Sambuc       : Target(Target), Has(Target.HasInstanceContext) {}
193f4a2713aSLionel Sambuc     AccessTarget &Target;
194f4a2713aSLionel Sambuc     bool Has;
195f4a2713aSLionel Sambuc   };
196f4a2713aSLionel Sambuc 
saveInstanceContext__anon35c5671a0111::AccessTarget197f4a2713aSLionel Sambuc   SavedInstanceContext saveInstanceContext() {
198f4a2713aSLionel Sambuc     return SavedInstanceContext(*this);
199f4a2713aSLionel Sambuc   }
200f4a2713aSLionel Sambuc 
suppressInstanceContext__anon35c5671a0111::AccessTarget201f4a2713aSLionel Sambuc   void suppressInstanceContext() {
202f4a2713aSLionel Sambuc     HasInstanceContext = false;
203f4a2713aSLionel Sambuc   }
204f4a2713aSLionel Sambuc 
resolveInstanceContext__anon35c5671a0111::AccessTarget205f4a2713aSLionel Sambuc   const CXXRecordDecl *resolveInstanceContext(Sema &S) const {
206f4a2713aSLionel Sambuc     assert(HasInstanceContext);
207f4a2713aSLionel Sambuc     if (CalculatedInstanceContext)
208f4a2713aSLionel Sambuc       return InstanceContext;
209f4a2713aSLionel Sambuc 
210f4a2713aSLionel Sambuc     CalculatedInstanceContext = true;
211f4a2713aSLionel Sambuc     DeclContext *IC = S.computeDeclContext(getBaseObjectType());
212*0a6a1f1dSLionel Sambuc     InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl()
213*0a6a1f1dSLionel Sambuc                           : nullptr);
214f4a2713aSLionel Sambuc     return InstanceContext;
215f4a2713aSLionel Sambuc   }
216f4a2713aSLionel Sambuc 
getDeclaringClass__anon35c5671a0111::AccessTarget217f4a2713aSLionel Sambuc   const CXXRecordDecl *getDeclaringClass() const {
218f4a2713aSLionel Sambuc     return DeclaringClass;
219f4a2713aSLionel Sambuc   }
220f4a2713aSLionel Sambuc 
221f4a2713aSLionel Sambuc   /// The "effective" naming class is the canonical non-anonymous
222f4a2713aSLionel Sambuc   /// class containing the actual naming class.
getEffectiveNamingClass__anon35c5671a0111::AccessTarget223f4a2713aSLionel Sambuc   const CXXRecordDecl *getEffectiveNamingClass() const {
224f4a2713aSLionel Sambuc     const CXXRecordDecl *namingClass = getNamingClass();
225f4a2713aSLionel Sambuc     while (namingClass->isAnonymousStructOrUnion())
226f4a2713aSLionel Sambuc       namingClass = cast<CXXRecordDecl>(namingClass->getParent());
227f4a2713aSLionel Sambuc     return namingClass->getCanonicalDecl();
228f4a2713aSLionel Sambuc   }
229f4a2713aSLionel Sambuc 
230f4a2713aSLionel Sambuc private:
initialize__anon35c5671a0111::AccessTarget231f4a2713aSLionel Sambuc   void initialize() {
232f4a2713aSLionel Sambuc     HasInstanceContext = (isMemberAccess() &&
233f4a2713aSLionel Sambuc                           !getBaseObjectType().isNull() &&
234f4a2713aSLionel Sambuc                           getTargetDecl()->isCXXInstanceMember());
235f4a2713aSLionel Sambuc     CalculatedInstanceContext = false;
236*0a6a1f1dSLionel Sambuc     InstanceContext = nullptr;
237f4a2713aSLionel Sambuc 
238f4a2713aSLionel Sambuc     if (isMemberAccess())
239f4a2713aSLionel Sambuc       DeclaringClass = FindDeclaringClass(getTargetDecl());
240f4a2713aSLionel Sambuc     else
241f4a2713aSLionel Sambuc       DeclaringClass = getBaseClass();
242f4a2713aSLionel Sambuc     DeclaringClass = DeclaringClass->getCanonicalDecl();
243f4a2713aSLionel Sambuc   }
244f4a2713aSLionel Sambuc 
245f4a2713aSLionel Sambuc   bool HasInstanceContext : 1;
246f4a2713aSLionel Sambuc   mutable bool CalculatedInstanceContext : 1;
247f4a2713aSLionel Sambuc   mutable const CXXRecordDecl *InstanceContext;
248f4a2713aSLionel Sambuc   const CXXRecordDecl *DeclaringClass;
249f4a2713aSLionel Sambuc };
250f4a2713aSLionel Sambuc 
251f4a2713aSLionel Sambuc }
252f4a2713aSLionel Sambuc 
253f4a2713aSLionel Sambuc /// Checks whether one class might instantiate to the other.
MightInstantiateTo(const CXXRecordDecl * From,const CXXRecordDecl * To)254f4a2713aSLionel Sambuc static bool MightInstantiateTo(const CXXRecordDecl *From,
255f4a2713aSLionel Sambuc                                const CXXRecordDecl *To) {
256f4a2713aSLionel Sambuc   // Declaration names are always preserved by instantiation.
257f4a2713aSLionel Sambuc   if (From->getDeclName() != To->getDeclName())
258f4a2713aSLionel Sambuc     return false;
259f4a2713aSLionel Sambuc 
260f4a2713aSLionel Sambuc   const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();
261f4a2713aSLionel Sambuc   const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();
262f4a2713aSLionel Sambuc   if (FromDC == ToDC) return true;
263f4a2713aSLionel Sambuc   if (FromDC->isFileContext() || ToDC->isFileContext()) return false;
264f4a2713aSLionel Sambuc 
265f4a2713aSLionel Sambuc   // Be conservative.
266f4a2713aSLionel Sambuc   return true;
267f4a2713aSLionel Sambuc }
268f4a2713aSLionel Sambuc 
269f4a2713aSLionel Sambuc /// Checks whether one class is derived from another, inclusively.
270f4a2713aSLionel Sambuc /// Properly indicates when it couldn't be determined due to
271f4a2713aSLionel Sambuc /// dependence.
272f4a2713aSLionel Sambuc ///
273f4a2713aSLionel Sambuc /// This should probably be donated to AST or at least Sema.
IsDerivedFromInclusive(const CXXRecordDecl * Derived,const CXXRecordDecl * Target)274f4a2713aSLionel Sambuc static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
275f4a2713aSLionel Sambuc                                            const CXXRecordDecl *Target) {
276f4a2713aSLionel Sambuc   assert(Derived->getCanonicalDecl() == Derived);
277f4a2713aSLionel Sambuc   assert(Target->getCanonicalDecl() == Target);
278f4a2713aSLionel Sambuc 
279f4a2713aSLionel Sambuc   if (Derived == Target) return AR_accessible;
280f4a2713aSLionel Sambuc 
281f4a2713aSLionel Sambuc   bool CheckDependent = Derived->isDependentContext();
282f4a2713aSLionel Sambuc   if (CheckDependent && MightInstantiateTo(Derived, Target))
283f4a2713aSLionel Sambuc     return AR_dependent;
284f4a2713aSLionel Sambuc 
285f4a2713aSLionel Sambuc   AccessResult OnFailure = AR_inaccessible;
286f4a2713aSLionel Sambuc   SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
287f4a2713aSLionel Sambuc 
288f4a2713aSLionel Sambuc   while (true) {
289f4a2713aSLionel Sambuc     if (Derived->isDependentContext() && !Derived->hasDefinition())
290f4a2713aSLionel Sambuc       return AR_dependent;
291f4a2713aSLionel Sambuc 
292*0a6a1f1dSLionel Sambuc     for (const auto &I : Derived->bases()) {
293f4a2713aSLionel Sambuc       const CXXRecordDecl *RD;
294f4a2713aSLionel Sambuc 
295*0a6a1f1dSLionel Sambuc       QualType T = I.getType();
296f4a2713aSLionel Sambuc       if (const RecordType *RT = T->getAs<RecordType>()) {
297f4a2713aSLionel Sambuc         RD = cast<CXXRecordDecl>(RT->getDecl());
298f4a2713aSLionel Sambuc       } else if (const InjectedClassNameType *IT
299f4a2713aSLionel Sambuc                    = T->getAs<InjectedClassNameType>()) {
300f4a2713aSLionel Sambuc         RD = IT->getDecl();
301f4a2713aSLionel Sambuc       } else {
302f4a2713aSLionel Sambuc         assert(T->isDependentType() && "non-dependent base wasn't a record?");
303f4a2713aSLionel Sambuc         OnFailure = AR_dependent;
304f4a2713aSLionel Sambuc         continue;
305f4a2713aSLionel Sambuc       }
306f4a2713aSLionel Sambuc 
307f4a2713aSLionel Sambuc       RD = RD->getCanonicalDecl();
308f4a2713aSLionel Sambuc       if (RD == Target) return AR_accessible;
309f4a2713aSLionel Sambuc       if (CheckDependent && MightInstantiateTo(RD, Target))
310f4a2713aSLionel Sambuc         OnFailure = AR_dependent;
311f4a2713aSLionel Sambuc 
312f4a2713aSLionel Sambuc       Queue.push_back(RD);
313f4a2713aSLionel Sambuc     }
314f4a2713aSLionel Sambuc 
315f4a2713aSLionel Sambuc     if (Queue.empty()) break;
316f4a2713aSLionel Sambuc 
317f4a2713aSLionel Sambuc     Derived = Queue.pop_back_val();
318f4a2713aSLionel Sambuc   }
319f4a2713aSLionel Sambuc 
320f4a2713aSLionel Sambuc   return OnFailure;
321f4a2713aSLionel Sambuc }
322f4a2713aSLionel Sambuc 
323f4a2713aSLionel Sambuc 
MightInstantiateTo(Sema & S,DeclContext * Context,DeclContext * Friend)324f4a2713aSLionel Sambuc static bool MightInstantiateTo(Sema &S, DeclContext *Context,
325f4a2713aSLionel Sambuc                                DeclContext *Friend) {
326f4a2713aSLionel Sambuc   if (Friend == Context)
327f4a2713aSLionel Sambuc     return true;
328f4a2713aSLionel Sambuc 
329f4a2713aSLionel Sambuc   assert(!Friend->isDependentContext() &&
330f4a2713aSLionel Sambuc          "can't handle friends with dependent contexts here");
331f4a2713aSLionel Sambuc 
332f4a2713aSLionel Sambuc   if (!Context->isDependentContext())
333f4a2713aSLionel Sambuc     return false;
334f4a2713aSLionel Sambuc 
335f4a2713aSLionel Sambuc   if (Friend->isFileContext())
336f4a2713aSLionel Sambuc     return false;
337f4a2713aSLionel Sambuc 
338f4a2713aSLionel Sambuc   // TODO: this is very conservative
339f4a2713aSLionel Sambuc   return true;
340f4a2713aSLionel Sambuc }
341f4a2713aSLionel Sambuc 
342f4a2713aSLionel Sambuc // Asks whether the type in 'context' can ever instantiate to the type
343f4a2713aSLionel Sambuc // in 'friend'.
MightInstantiateTo(Sema & S,CanQualType Context,CanQualType Friend)344f4a2713aSLionel Sambuc static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
345f4a2713aSLionel Sambuc   if (Friend == Context)
346f4a2713aSLionel Sambuc     return true;
347f4a2713aSLionel Sambuc 
348f4a2713aSLionel Sambuc   if (!Friend->isDependentType() && !Context->isDependentType())
349f4a2713aSLionel Sambuc     return false;
350f4a2713aSLionel Sambuc 
351f4a2713aSLionel Sambuc   // TODO: this is very conservative.
352f4a2713aSLionel Sambuc   return true;
353f4a2713aSLionel Sambuc }
354f4a2713aSLionel Sambuc 
MightInstantiateTo(Sema & S,FunctionDecl * Context,FunctionDecl * Friend)355f4a2713aSLionel Sambuc static bool MightInstantiateTo(Sema &S,
356f4a2713aSLionel Sambuc                                FunctionDecl *Context,
357f4a2713aSLionel Sambuc                                FunctionDecl *Friend) {
358f4a2713aSLionel Sambuc   if (Context->getDeclName() != Friend->getDeclName())
359f4a2713aSLionel Sambuc     return false;
360f4a2713aSLionel Sambuc 
361f4a2713aSLionel Sambuc   if (!MightInstantiateTo(S,
362f4a2713aSLionel Sambuc                           Context->getDeclContext(),
363f4a2713aSLionel Sambuc                           Friend->getDeclContext()))
364f4a2713aSLionel Sambuc     return false;
365f4a2713aSLionel Sambuc 
366f4a2713aSLionel Sambuc   CanQual<FunctionProtoType> FriendTy
367f4a2713aSLionel Sambuc     = S.Context.getCanonicalType(Friend->getType())
368f4a2713aSLionel Sambuc          ->getAs<FunctionProtoType>();
369f4a2713aSLionel Sambuc   CanQual<FunctionProtoType> ContextTy
370f4a2713aSLionel Sambuc     = S.Context.getCanonicalType(Context->getType())
371f4a2713aSLionel Sambuc          ->getAs<FunctionProtoType>();
372f4a2713aSLionel Sambuc 
373f4a2713aSLionel Sambuc   // There isn't any way that I know of to add qualifiers
374f4a2713aSLionel Sambuc   // during instantiation.
375f4a2713aSLionel Sambuc   if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
376f4a2713aSLionel Sambuc     return false;
377f4a2713aSLionel Sambuc 
378*0a6a1f1dSLionel Sambuc   if (FriendTy->getNumParams() != ContextTy->getNumParams())
379f4a2713aSLionel Sambuc     return false;
380f4a2713aSLionel Sambuc 
381*0a6a1f1dSLionel Sambuc   if (!MightInstantiateTo(S, ContextTy->getReturnType(),
382*0a6a1f1dSLionel Sambuc                           FriendTy->getReturnType()))
383f4a2713aSLionel Sambuc     return false;
384f4a2713aSLionel Sambuc 
385*0a6a1f1dSLionel Sambuc   for (unsigned I = 0, E = FriendTy->getNumParams(); I != E; ++I)
386*0a6a1f1dSLionel Sambuc     if (!MightInstantiateTo(S, ContextTy->getParamType(I),
387*0a6a1f1dSLionel Sambuc                             FriendTy->getParamType(I)))
388f4a2713aSLionel Sambuc       return false;
389f4a2713aSLionel Sambuc 
390f4a2713aSLionel Sambuc   return true;
391f4a2713aSLionel Sambuc }
392f4a2713aSLionel Sambuc 
MightInstantiateTo(Sema & S,FunctionTemplateDecl * Context,FunctionTemplateDecl * Friend)393f4a2713aSLionel Sambuc static bool MightInstantiateTo(Sema &S,
394f4a2713aSLionel Sambuc                                FunctionTemplateDecl *Context,
395f4a2713aSLionel Sambuc                                FunctionTemplateDecl *Friend) {
396f4a2713aSLionel Sambuc   return MightInstantiateTo(S,
397f4a2713aSLionel Sambuc                             Context->getTemplatedDecl(),
398f4a2713aSLionel Sambuc                             Friend->getTemplatedDecl());
399f4a2713aSLionel Sambuc }
400f4a2713aSLionel Sambuc 
MatchesFriend(Sema & S,const EffectiveContext & EC,const CXXRecordDecl * Friend)401f4a2713aSLionel Sambuc static AccessResult MatchesFriend(Sema &S,
402f4a2713aSLionel Sambuc                                   const EffectiveContext &EC,
403f4a2713aSLionel Sambuc                                   const CXXRecordDecl *Friend) {
404f4a2713aSLionel Sambuc   if (EC.includesClass(Friend))
405f4a2713aSLionel Sambuc     return AR_accessible;
406f4a2713aSLionel Sambuc 
407f4a2713aSLionel Sambuc   if (EC.isDependent()) {
408f4a2713aSLionel Sambuc     CanQualType FriendTy
409f4a2713aSLionel Sambuc       = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend));
410f4a2713aSLionel Sambuc 
411f4a2713aSLionel Sambuc     for (EffectiveContext::record_iterator
412f4a2713aSLionel Sambuc            I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
413f4a2713aSLionel Sambuc       CanQualType ContextTy
414f4a2713aSLionel Sambuc         = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
415f4a2713aSLionel Sambuc       if (MightInstantiateTo(S, ContextTy, FriendTy))
416f4a2713aSLionel Sambuc         return AR_dependent;
417f4a2713aSLionel Sambuc     }
418f4a2713aSLionel Sambuc   }
419f4a2713aSLionel Sambuc 
420f4a2713aSLionel Sambuc   return AR_inaccessible;
421f4a2713aSLionel Sambuc }
422f4a2713aSLionel Sambuc 
MatchesFriend(Sema & S,const EffectiveContext & EC,CanQualType Friend)423f4a2713aSLionel Sambuc static AccessResult MatchesFriend(Sema &S,
424f4a2713aSLionel Sambuc                                   const EffectiveContext &EC,
425f4a2713aSLionel Sambuc                                   CanQualType Friend) {
426f4a2713aSLionel Sambuc   if (const RecordType *RT = Friend->getAs<RecordType>())
427f4a2713aSLionel Sambuc     return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
428f4a2713aSLionel Sambuc 
429f4a2713aSLionel Sambuc   // TODO: we can do better than this
430f4a2713aSLionel Sambuc   if (Friend->isDependentType())
431f4a2713aSLionel Sambuc     return AR_dependent;
432f4a2713aSLionel Sambuc 
433f4a2713aSLionel Sambuc   return AR_inaccessible;
434f4a2713aSLionel Sambuc }
435f4a2713aSLionel Sambuc 
436f4a2713aSLionel Sambuc /// Determines whether the given friend class template matches
437f4a2713aSLionel Sambuc /// anything in the effective context.
MatchesFriend(Sema & S,const EffectiveContext & EC,ClassTemplateDecl * Friend)438f4a2713aSLionel Sambuc static AccessResult MatchesFriend(Sema &S,
439f4a2713aSLionel Sambuc                                   const EffectiveContext &EC,
440f4a2713aSLionel Sambuc                                   ClassTemplateDecl *Friend) {
441f4a2713aSLionel Sambuc   AccessResult OnFailure = AR_inaccessible;
442f4a2713aSLionel Sambuc 
443f4a2713aSLionel Sambuc   // Check whether the friend is the template of a class in the
444f4a2713aSLionel Sambuc   // context chain.
445f4a2713aSLionel Sambuc   for (SmallVectorImpl<CXXRecordDecl*>::const_iterator
446f4a2713aSLionel Sambuc          I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
447f4a2713aSLionel Sambuc     CXXRecordDecl *Record = *I;
448f4a2713aSLionel Sambuc 
449f4a2713aSLionel Sambuc     // Figure out whether the current class has a template:
450f4a2713aSLionel Sambuc     ClassTemplateDecl *CTD;
451f4a2713aSLionel Sambuc 
452f4a2713aSLionel Sambuc     // A specialization of the template...
453f4a2713aSLionel Sambuc     if (isa<ClassTemplateSpecializationDecl>(Record)) {
454f4a2713aSLionel Sambuc       CTD = cast<ClassTemplateSpecializationDecl>(Record)
455f4a2713aSLionel Sambuc         ->getSpecializedTemplate();
456f4a2713aSLionel Sambuc 
457f4a2713aSLionel Sambuc     // ... or the template pattern itself.
458f4a2713aSLionel Sambuc     } else {
459f4a2713aSLionel Sambuc       CTD = Record->getDescribedClassTemplate();
460f4a2713aSLionel Sambuc       if (!CTD) continue;
461f4a2713aSLionel Sambuc     }
462f4a2713aSLionel Sambuc 
463f4a2713aSLionel Sambuc     // It's a match.
464f4a2713aSLionel Sambuc     if (Friend == CTD->getCanonicalDecl())
465f4a2713aSLionel Sambuc       return AR_accessible;
466f4a2713aSLionel Sambuc 
467f4a2713aSLionel Sambuc     // If the context isn't dependent, it can't be a dependent match.
468f4a2713aSLionel Sambuc     if (!EC.isDependent())
469f4a2713aSLionel Sambuc       continue;
470f4a2713aSLionel Sambuc 
471f4a2713aSLionel Sambuc     // If the template names don't match, it can't be a dependent
472f4a2713aSLionel Sambuc     // match.
473f4a2713aSLionel Sambuc     if (CTD->getDeclName() != Friend->getDeclName())
474f4a2713aSLionel Sambuc       continue;
475f4a2713aSLionel Sambuc 
476f4a2713aSLionel Sambuc     // If the class's context can't instantiate to the friend's
477f4a2713aSLionel Sambuc     // context, it can't be a dependent match.
478f4a2713aSLionel Sambuc     if (!MightInstantiateTo(S, CTD->getDeclContext(),
479f4a2713aSLionel Sambuc                             Friend->getDeclContext()))
480f4a2713aSLionel Sambuc       continue;
481f4a2713aSLionel Sambuc 
482f4a2713aSLionel Sambuc     // Otherwise, it's a dependent match.
483f4a2713aSLionel Sambuc     OnFailure = AR_dependent;
484f4a2713aSLionel Sambuc   }
485f4a2713aSLionel Sambuc 
486f4a2713aSLionel Sambuc   return OnFailure;
487f4a2713aSLionel Sambuc }
488f4a2713aSLionel Sambuc 
489f4a2713aSLionel Sambuc /// Determines whether the given friend function matches anything in
490f4a2713aSLionel Sambuc /// the effective context.
MatchesFriend(Sema & S,const EffectiveContext & EC,FunctionDecl * Friend)491f4a2713aSLionel Sambuc static AccessResult MatchesFriend(Sema &S,
492f4a2713aSLionel Sambuc                                   const EffectiveContext &EC,
493f4a2713aSLionel Sambuc                                   FunctionDecl *Friend) {
494f4a2713aSLionel Sambuc   AccessResult OnFailure = AR_inaccessible;
495f4a2713aSLionel Sambuc 
496f4a2713aSLionel Sambuc   for (SmallVectorImpl<FunctionDecl*>::const_iterator
497f4a2713aSLionel Sambuc          I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
498f4a2713aSLionel Sambuc     if (Friend == *I)
499f4a2713aSLionel Sambuc       return AR_accessible;
500f4a2713aSLionel Sambuc 
501f4a2713aSLionel Sambuc     if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
502f4a2713aSLionel Sambuc       OnFailure = AR_dependent;
503f4a2713aSLionel Sambuc   }
504f4a2713aSLionel Sambuc 
505f4a2713aSLionel Sambuc   return OnFailure;
506f4a2713aSLionel Sambuc }
507f4a2713aSLionel Sambuc 
508f4a2713aSLionel Sambuc /// Determines whether the given friend function template matches
509f4a2713aSLionel Sambuc /// anything in the effective context.
MatchesFriend(Sema & S,const EffectiveContext & EC,FunctionTemplateDecl * Friend)510f4a2713aSLionel Sambuc static AccessResult MatchesFriend(Sema &S,
511f4a2713aSLionel Sambuc                                   const EffectiveContext &EC,
512f4a2713aSLionel Sambuc                                   FunctionTemplateDecl *Friend) {
513f4a2713aSLionel Sambuc   if (EC.Functions.empty()) return AR_inaccessible;
514f4a2713aSLionel Sambuc 
515f4a2713aSLionel Sambuc   AccessResult OnFailure = AR_inaccessible;
516f4a2713aSLionel Sambuc 
517f4a2713aSLionel Sambuc   for (SmallVectorImpl<FunctionDecl*>::const_iterator
518f4a2713aSLionel Sambuc          I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
519f4a2713aSLionel Sambuc 
520f4a2713aSLionel Sambuc     FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
521f4a2713aSLionel Sambuc     if (!FTD)
522f4a2713aSLionel Sambuc       FTD = (*I)->getDescribedFunctionTemplate();
523f4a2713aSLionel Sambuc     if (!FTD)
524f4a2713aSLionel Sambuc       continue;
525f4a2713aSLionel Sambuc 
526f4a2713aSLionel Sambuc     FTD = FTD->getCanonicalDecl();
527f4a2713aSLionel Sambuc 
528f4a2713aSLionel Sambuc     if (Friend == FTD)
529f4a2713aSLionel Sambuc       return AR_accessible;
530f4a2713aSLionel Sambuc 
531f4a2713aSLionel Sambuc     if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
532f4a2713aSLionel Sambuc       OnFailure = AR_dependent;
533f4a2713aSLionel Sambuc   }
534f4a2713aSLionel Sambuc 
535f4a2713aSLionel Sambuc   return OnFailure;
536f4a2713aSLionel Sambuc }
537f4a2713aSLionel Sambuc 
538f4a2713aSLionel Sambuc /// Determines whether the given friend declaration matches anything
539f4a2713aSLionel Sambuc /// in the effective context.
MatchesFriend(Sema & S,const EffectiveContext & EC,FriendDecl * FriendD)540f4a2713aSLionel Sambuc static AccessResult MatchesFriend(Sema &S,
541f4a2713aSLionel Sambuc                                   const EffectiveContext &EC,
542f4a2713aSLionel Sambuc                                   FriendDecl *FriendD) {
543f4a2713aSLionel Sambuc   // Whitelist accesses if there's an invalid or unsupported friend
544f4a2713aSLionel Sambuc   // declaration.
545f4a2713aSLionel Sambuc   if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend())
546f4a2713aSLionel Sambuc     return AR_accessible;
547f4a2713aSLionel Sambuc 
548f4a2713aSLionel Sambuc   if (TypeSourceInfo *T = FriendD->getFriendType())
549f4a2713aSLionel Sambuc     return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
550f4a2713aSLionel Sambuc 
551f4a2713aSLionel Sambuc   NamedDecl *Friend
552f4a2713aSLionel Sambuc     = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
553f4a2713aSLionel Sambuc 
554f4a2713aSLionel Sambuc   // FIXME: declarations with dependent or templated scope.
555f4a2713aSLionel Sambuc 
556f4a2713aSLionel Sambuc   if (isa<ClassTemplateDecl>(Friend))
557f4a2713aSLionel Sambuc     return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
558f4a2713aSLionel Sambuc 
559f4a2713aSLionel Sambuc   if (isa<FunctionTemplateDecl>(Friend))
560f4a2713aSLionel Sambuc     return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
561f4a2713aSLionel Sambuc 
562f4a2713aSLionel Sambuc   if (isa<CXXRecordDecl>(Friend))
563f4a2713aSLionel Sambuc     return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
564f4a2713aSLionel Sambuc 
565f4a2713aSLionel Sambuc   assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
566f4a2713aSLionel Sambuc   return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
567f4a2713aSLionel Sambuc }
568f4a2713aSLionel Sambuc 
GetFriendKind(Sema & S,const EffectiveContext & EC,const CXXRecordDecl * Class)569f4a2713aSLionel Sambuc static AccessResult GetFriendKind(Sema &S,
570f4a2713aSLionel Sambuc                                   const EffectiveContext &EC,
571f4a2713aSLionel Sambuc                                   const CXXRecordDecl *Class) {
572f4a2713aSLionel Sambuc   AccessResult OnFailure = AR_inaccessible;
573f4a2713aSLionel Sambuc 
574f4a2713aSLionel Sambuc   // Okay, check friends.
575*0a6a1f1dSLionel Sambuc   for (auto *Friend : Class->friends()) {
576f4a2713aSLionel Sambuc     switch (MatchesFriend(S, EC, Friend)) {
577f4a2713aSLionel Sambuc     case AR_accessible:
578f4a2713aSLionel Sambuc       return AR_accessible;
579f4a2713aSLionel Sambuc 
580f4a2713aSLionel Sambuc     case AR_inaccessible:
581f4a2713aSLionel Sambuc       continue;
582f4a2713aSLionel Sambuc 
583f4a2713aSLionel Sambuc     case AR_dependent:
584f4a2713aSLionel Sambuc       OnFailure = AR_dependent;
585f4a2713aSLionel Sambuc       break;
586f4a2713aSLionel Sambuc     }
587f4a2713aSLionel Sambuc   }
588f4a2713aSLionel Sambuc 
589f4a2713aSLionel Sambuc   // That's it, give up.
590f4a2713aSLionel Sambuc   return OnFailure;
591f4a2713aSLionel Sambuc }
592f4a2713aSLionel Sambuc 
593f4a2713aSLionel Sambuc namespace {
594f4a2713aSLionel Sambuc 
595f4a2713aSLionel Sambuc /// A helper class for checking for a friend which will grant access
596f4a2713aSLionel Sambuc /// to a protected instance member.
597f4a2713aSLionel Sambuc struct ProtectedFriendContext {
598f4a2713aSLionel Sambuc   Sema &S;
599f4a2713aSLionel Sambuc   const EffectiveContext &EC;
600f4a2713aSLionel Sambuc   const CXXRecordDecl *NamingClass;
601f4a2713aSLionel Sambuc   bool CheckDependent;
602f4a2713aSLionel Sambuc   bool EverDependent;
603f4a2713aSLionel Sambuc 
604f4a2713aSLionel Sambuc   /// The path down to the current base class.
605f4a2713aSLionel Sambuc   SmallVector<const CXXRecordDecl*, 20> CurPath;
606f4a2713aSLionel Sambuc 
ProtectedFriendContext__anon35c5671a0211::ProtectedFriendContext607f4a2713aSLionel Sambuc   ProtectedFriendContext(Sema &S, const EffectiveContext &EC,
608f4a2713aSLionel Sambuc                          const CXXRecordDecl *InstanceContext,
609f4a2713aSLionel Sambuc                          const CXXRecordDecl *NamingClass)
610f4a2713aSLionel Sambuc     : S(S), EC(EC), NamingClass(NamingClass),
611f4a2713aSLionel Sambuc       CheckDependent(InstanceContext->isDependentContext() ||
612f4a2713aSLionel Sambuc                      NamingClass->isDependentContext()),
613f4a2713aSLionel Sambuc       EverDependent(false) {}
614f4a2713aSLionel Sambuc 
615f4a2713aSLionel Sambuc   /// Check classes in the current path for friendship, starting at
616f4a2713aSLionel Sambuc   /// the given index.
checkFriendshipAlongPath__anon35c5671a0211::ProtectedFriendContext617f4a2713aSLionel Sambuc   bool checkFriendshipAlongPath(unsigned I) {
618f4a2713aSLionel Sambuc     assert(I < CurPath.size());
619f4a2713aSLionel Sambuc     for (unsigned E = CurPath.size(); I != E; ++I) {
620f4a2713aSLionel Sambuc       switch (GetFriendKind(S, EC, CurPath[I])) {
621f4a2713aSLionel Sambuc       case AR_accessible:   return true;
622f4a2713aSLionel Sambuc       case AR_inaccessible: continue;
623f4a2713aSLionel Sambuc       case AR_dependent:    EverDependent = true; continue;
624f4a2713aSLionel Sambuc       }
625f4a2713aSLionel Sambuc     }
626f4a2713aSLionel Sambuc     return false;
627f4a2713aSLionel Sambuc   }
628f4a2713aSLionel Sambuc 
629f4a2713aSLionel Sambuc   /// Perform a search starting at the given class.
630f4a2713aSLionel Sambuc   ///
631f4a2713aSLionel Sambuc   /// PrivateDepth is the index of the last (least derived) class
632f4a2713aSLionel Sambuc   /// along the current path such that a notional public member of
633f4a2713aSLionel Sambuc   /// the final class in the path would have access in that class.
findFriendship__anon35c5671a0211::ProtectedFriendContext634f4a2713aSLionel Sambuc   bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) {
635f4a2713aSLionel Sambuc     // If we ever reach the naming class, check the current path for
636f4a2713aSLionel Sambuc     // friendship.  We can also stop recursing because we obviously
637f4a2713aSLionel Sambuc     // won't find the naming class there again.
638f4a2713aSLionel Sambuc     if (Cur == NamingClass)
639f4a2713aSLionel Sambuc       return checkFriendshipAlongPath(PrivateDepth);
640f4a2713aSLionel Sambuc 
641f4a2713aSLionel Sambuc     if (CheckDependent && MightInstantiateTo(Cur, NamingClass))
642f4a2713aSLionel Sambuc       EverDependent = true;
643f4a2713aSLionel Sambuc 
644f4a2713aSLionel Sambuc     // Recurse into the base classes.
645*0a6a1f1dSLionel Sambuc     for (const auto &I : Cur->bases()) {
646f4a2713aSLionel Sambuc       // If this is private inheritance, then a public member of the
647f4a2713aSLionel Sambuc       // base will not have any access in classes derived from Cur.
648f4a2713aSLionel Sambuc       unsigned BasePrivateDepth = PrivateDepth;
649*0a6a1f1dSLionel Sambuc       if (I.getAccessSpecifier() == AS_private)
650f4a2713aSLionel Sambuc         BasePrivateDepth = CurPath.size() - 1;
651f4a2713aSLionel Sambuc 
652f4a2713aSLionel Sambuc       const CXXRecordDecl *RD;
653f4a2713aSLionel Sambuc 
654*0a6a1f1dSLionel Sambuc       QualType T = I.getType();
655f4a2713aSLionel Sambuc       if (const RecordType *RT = T->getAs<RecordType>()) {
656f4a2713aSLionel Sambuc         RD = cast<CXXRecordDecl>(RT->getDecl());
657f4a2713aSLionel Sambuc       } else if (const InjectedClassNameType *IT
658f4a2713aSLionel Sambuc                    = T->getAs<InjectedClassNameType>()) {
659f4a2713aSLionel Sambuc         RD = IT->getDecl();
660f4a2713aSLionel Sambuc       } else {
661f4a2713aSLionel Sambuc         assert(T->isDependentType() && "non-dependent base wasn't a record?");
662f4a2713aSLionel Sambuc         EverDependent = true;
663f4a2713aSLionel Sambuc         continue;
664f4a2713aSLionel Sambuc       }
665f4a2713aSLionel Sambuc 
666f4a2713aSLionel Sambuc       // Recurse.  We don't need to clean up if this returns true.
667f4a2713aSLionel Sambuc       CurPath.push_back(RD);
668f4a2713aSLionel Sambuc       if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth))
669f4a2713aSLionel Sambuc         return true;
670f4a2713aSLionel Sambuc       CurPath.pop_back();
671f4a2713aSLionel Sambuc     }
672f4a2713aSLionel Sambuc 
673f4a2713aSLionel Sambuc     return false;
674f4a2713aSLionel Sambuc   }
675f4a2713aSLionel Sambuc 
findFriendship__anon35c5671a0211::ProtectedFriendContext676f4a2713aSLionel Sambuc   bool findFriendship(const CXXRecordDecl *Cur) {
677f4a2713aSLionel Sambuc     assert(CurPath.empty());
678f4a2713aSLionel Sambuc     CurPath.push_back(Cur);
679f4a2713aSLionel Sambuc     return findFriendship(Cur, 0);
680f4a2713aSLionel Sambuc   }
681f4a2713aSLionel Sambuc };
682f4a2713aSLionel Sambuc }
683f4a2713aSLionel Sambuc 
684f4a2713aSLionel Sambuc /// Search for a class P that EC is a friend of, under the constraint
685f4a2713aSLionel Sambuc ///   InstanceContext <= P
686f4a2713aSLionel Sambuc /// if InstanceContext exists, or else
687f4a2713aSLionel Sambuc ///   NamingClass <= P
688f4a2713aSLionel Sambuc /// and with the additional restriction that a protected member of
689f4a2713aSLionel Sambuc /// NamingClass would have some natural access in P, which implicitly
690f4a2713aSLionel Sambuc /// imposes the constraint that P <= NamingClass.
691f4a2713aSLionel Sambuc ///
692f4a2713aSLionel Sambuc /// This isn't quite the condition laid out in the standard.
693f4a2713aSLionel Sambuc /// Instead of saying that a notional protected member of NamingClass
694f4a2713aSLionel Sambuc /// would have to have some natural access in P, it says the actual
695f4a2713aSLionel Sambuc /// target has to have some natural access in P, which opens up the
696f4a2713aSLionel Sambuc /// possibility that the target (which is not necessarily a member
697f4a2713aSLionel Sambuc /// of NamingClass) might be more accessible along some path not
698f4a2713aSLionel Sambuc /// passing through it.  That's really a bad idea, though, because it
699f4a2713aSLionel Sambuc /// introduces two problems:
700f4a2713aSLionel Sambuc ///   - Most importantly, it breaks encapsulation because you can
701f4a2713aSLionel Sambuc ///     access a forbidden base class's members by directly subclassing
702f4a2713aSLionel Sambuc ///     it elsewhere.
703f4a2713aSLionel Sambuc ///   - It also makes access substantially harder to compute because it
704f4a2713aSLionel Sambuc ///     breaks the hill-climbing algorithm: knowing that the target is
705f4a2713aSLionel Sambuc ///     accessible in some base class would no longer let you change
706f4a2713aSLionel Sambuc ///     the question solely to whether the base class is accessible,
707f4a2713aSLionel Sambuc ///     because the original target might have been more accessible
708f4a2713aSLionel Sambuc ///     because of crazy subclassing.
709f4a2713aSLionel Sambuc /// So we don't implement that.
GetProtectedFriendKind(Sema & S,const EffectiveContext & EC,const CXXRecordDecl * InstanceContext,const CXXRecordDecl * NamingClass)710f4a2713aSLionel Sambuc static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC,
711f4a2713aSLionel Sambuc                                            const CXXRecordDecl *InstanceContext,
712f4a2713aSLionel Sambuc                                            const CXXRecordDecl *NamingClass) {
713*0a6a1f1dSLionel Sambuc   assert(InstanceContext == nullptr ||
714f4a2713aSLionel Sambuc          InstanceContext->getCanonicalDecl() == InstanceContext);
715f4a2713aSLionel Sambuc   assert(NamingClass->getCanonicalDecl() == NamingClass);
716f4a2713aSLionel Sambuc 
717f4a2713aSLionel Sambuc   // If we don't have an instance context, our constraints give us
718f4a2713aSLionel Sambuc   // that NamingClass <= P <= NamingClass, i.e. P == NamingClass.
719f4a2713aSLionel Sambuc   // This is just the usual friendship check.
720f4a2713aSLionel Sambuc   if (!InstanceContext) return GetFriendKind(S, EC, NamingClass);
721f4a2713aSLionel Sambuc 
722f4a2713aSLionel Sambuc   ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass);
723f4a2713aSLionel Sambuc   if (PRC.findFriendship(InstanceContext)) return AR_accessible;
724f4a2713aSLionel Sambuc   if (PRC.EverDependent) return AR_dependent;
725f4a2713aSLionel Sambuc   return AR_inaccessible;
726f4a2713aSLionel Sambuc }
727f4a2713aSLionel Sambuc 
HasAccess(Sema & S,const EffectiveContext & EC,const CXXRecordDecl * NamingClass,AccessSpecifier Access,const AccessTarget & Target)728f4a2713aSLionel Sambuc static AccessResult HasAccess(Sema &S,
729f4a2713aSLionel Sambuc                               const EffectiveContext &EC,
730f4a2713aSLionel Sambuc                               const CXXRecordDecl *NamingClass,
731f4a2713aSLionel Sambuc                               AccessSpecifier Access,
732f4a2713aSLionel Sambuc                               const AccessTarget &Target) {
733f4a2713aSLionel Sambuc   assert(NamingClass->getCanonicalDecl() == NamingClass &&
734f4a2713aSLionel Sambuc          "declaration should be canonicalized before being passed here");
735f4a2713aSLionel Sambuc 
736f4a2713aSLionel Sambuc   if (Access == AS_public) return AR_accessible;
737f4a2713aSLionel Sambuc   assert(Access == AS_private || Access == AS_protected);
738f4a2713aSLionel Sambuc 
739f4a2713aSLionel Sambuc   AccessResult OnFailure = AR_inaccessible;
740f4a2713aSLionel Sambuc 
741f4a2713aSLionel Sambuc   for (EffectiveContext::record_iterator
742f4a2713aSLionel Sambuc          I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
743f4a2713aSLionel Sambuc     // All the declarations in EC have been canonicalized, so pointer
744f4a2713aSLionel Sambuc     // equality from this point on will work fine.
745f4a2713aSLionel Sambuc     const CXXRecordDecl *ECRecord = *I;
746f4a2713aSLionel Sambuc 
747f4a2713aSLionel Sambuc     // [B2] and [M2]
748f4a2713aSLionel Sambuc     if (Access == AS_private) {
749f4a2713aSLionel Sambuc       if (ECRecord == NamingClass)
750f4a2713aSLionel Sambuc         return AR_accessible;
751f4a2713aSLionel Sambuc 
752f4a2713aSLionel Sambuc       if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))
753f4a2713aSLionel Sambuc         OnFailure = AR_dependent;
754f4a2713aSLionel Sambuc 
755f4a2713aSLionel Sambuc     // [B3] and [M3]
756f4a2713aSLionel Sambuc     } else {
757f4a2713aSLionel Sambuc       assert(Access == AS_protected);
758f4a2713aSLionel Sambuc       switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
759f4a2713aSLionel Sambuc       case AR_accessible: break;
760f4a2713aSLionel Sambuc       case AR_inaccessible: continue;
761f4a2713aSLionel Sambuc       case AR_dependent: OnFailure = AR_dependent; continue;
762f4a2713aSLionel Sambuc       }
763f4a2713aSLionel Sambuc 
764f4a2713aSLionel Sambuc       // C++ [class.protected]p1:
765f4a2713aSLionel Sambuc       //   An additional access check beyond those described earlier in
766f4a2713aSLionel Sambuc       //   [class.access] is applied when a non-static data member or
767f4a2713aSLionel Sambuc       //   non-static member function is a protected member of its naming
768f4a2713aSLionel Sambuc       //   class.  As described earlier, access to a protected member is
769f4a2713aSLionel Sambuc       //   granted because the reference occurs in a friend or member of
770f4a2713aSLionel Sambuc       //   some class C.  If the access is to form a pointer to member,
771f4a2713aSLionel Sambuc       //   the nested-name-specifier shall name C or a class derived from
772f4a2713aSLionel Sambuc       //   C. All other accesses involve a (possibly implicit) object
773f4a2713aSLionel Sambuc       //   expression. In this case, the class of the object expression
774f4a2713aSLionel Sambuc       //   shall be C or a class derived from C.
775f4a2713aSLionel Sambuc       //
776f4a2713aSLionel Sambuc       // We interpret this as a restriction on [M3].
777f4a2713aSLionel Sambuc 
778f4a2713aSLionel Sambuc       // In this part of the code, 'C' is just our context class ECRecord.
779f4a2713aSLionel Sambuc 
780f4a2713aSLionel Sambuc       // These rules are different if we don't have an instance context.
781f4a2713aSLionel Sambuc       if (!Target.hasInstanceContext()) {
782f4a2713aSLionel Sambuc         // If it's not an instance member, these restrictions don't apply.
783f4a2713aSLionel Sambuc         if (!Target.isInstanceMember()) return AR_accessible;
784f4a2713aSLionel Sambuc 
785f4a2713aSLionel Sambuc         // If it's an instance member, use the pointer-to-member rule
786f4a2713aSLionel Sambuc         // that the naming class has to be derived from the effective
787f4a2713aSLionel Sambuc         // context.
788f4a2713aSLionel Sambuc 
789f4a2713aSLionel Sambuc         // Emulate a MSVC bug where the creation of pointer-to-member
790f4a2713aSLionel Sambuc         // to protected member of base class is allowed but only from
791f4a2713aSLionel Sambuc         // static member functions.
792*0a6a1f1dSLionel Sambuc         if (S.getLangOpts().MSVCCompat && !EC.Functions.empty())
793f4a2713aSLionel Sambuc           if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front()))
794f4a2713aSLionel Sambuc             if (MD->isStatic()) return AR_accessible;
795f4a2713aSLionel Sambuc 
796f4a2713aSLionel Sambuc         // Despite the standard's confident wording, there is a case
797f4a2713aSLionel Sambuc         // where you can have an instance member that's neither in a
798f4a2713aSLionel Sambuc         // pointer-to-member expression nor in a member access:  when
799f4a2713aSLionel Sambuc         // it names a field in an unevaluated context that can't be an
800f4a2713aSLionel Sambuc         // implicit member.  Pending clarification, we just apply the
801f4a2713aSLionel Sambuc         // same naming-class restriction here.
802f4a2713aSLionel Sambuc         //   FIXME: we're probably not correctly adding the
803f4a2713aSLionel Sambuc         //   protected-member restriction when we retroactively convert
804f4a2713aSLionel Sambuc         //   an expression to being evaluated.
805f4a2713aSLionel Sambuc 
806f4a2713aSLionel Sambuc         // We know that ECRecord derives from NamingClass.  The
807f4a2713aSLionel Sambuc         // restriction says to check whether NamingClass derives from
808f4a2713aSLionel Sambuc         // ECRecord, but that's not really necessary: two distinct
809f4a2713aSLionel Sambuc         // classes can't be recursively derived from each other.  So
810f4a2713aSLionel Sambuc         // along this path, we just need to check whether the classes
811f4a2713aSLionel Sambuc         // are equal.
812f4a2713aSLionel Sambuc         if (NamingClass == ECRecord) return AR_accessible;
813f4a2713aSLionel Sambuc 
814f4a2713aSLionel Sambuc         // Otherwise, this context class tells us nothing;  on to the next.
815f4a2713aSLionel Sambuc         continue;
816f4a2713aSLionel Sambuc       }
817f4a2713aSLionel Sambuc 
818f4a2713aSLionel Sambuc       assert(Target.isInstanceMember());
819f4a2713aSLionel Sambuc 
820f4a2713aSLionel Sambuc       const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
821f4a2713aSLionel Sambuc       if (!InstanceContext) {
822f4a2713aSLionel Sambuc         OnFailure = AR_dependent;
823f4a2713aSLionel Sambuc         continue;
824f4a2713aSLionel Sambuc       }
825f4a2713aSLionel Sambuc 
826f4a2713aSLionel Sambuc       switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
827f4a2713aSLionel Sambuc       case AR_accessible: return AR_accessible;
828f4a2713aSLionel Sambuc       case AR_inaccessible: continue;
829f4a2713aSLionel Sambuc       case AR_dependent: OnFailure = AR_dependent; continue;
830f4a2713aSLionel Sambuc       }
831f4a2713aSLionel Sambuc     }
832f4a2713aSLionel Sambuc   }
833f4a2713aSLionel Sambuc 
834f4a2713aSLionel Sambuc   // [M3] and [B3] say that, if the target is protected in N, we grant
835f4a2713aSLionel Sambuc   // access if the access occurs in a friend or member of some class P
836f4a2713aSLionel Sambuc   // that's a subclass of N and where the target has some natural
837f4a2713aSLionel Sambuc   // access in P.  The 'member' aspect is easy to handle because P
838f4a2713aSLionel Sambuc   // would necessarily be one of the effective-context records, and we
839f4a2713aSLionel Sambuc   // address that above.  The 'friend' aspect is completely ridiculous
840f4a2713aSLionel Sambuc   // to implement because there are no restrictions at all on P
841f4a2713aSLionel Sambuc   // *unless* the [class.protected] restriction applies.  If it does,
842f4a2713aSLionel Sambuc   // however, we should ignore whether the naming class is a friend,
843f4a2713aSLionel Sambuc   // and instead rely on whether any potential P is a friend.
844f4a2713aSLionel Sambuc   if (Access == AS_protected && Target.isInstanceMember()) {
845f4a2713aSLionel Sambuc     // Compute the instance context if possible.
846*0a6a1f1dSLionel Sambuc     const CXXRecordDecl *InstanceContext = nullptr;
847f4a2713aSLionel Sambuc     if (Target.hasInstanceContext()) {
848f4a2713aSLionel Sambuc       InstanceContext = Target.resolveInstanceContext(S);
849f4a2713aSLionel Sambuc       if (!InstanceContext) return AR_dependent;
850f4a2713aSLionel Sambuc     }
851f4a2713aSLionel Sambuc 
852f4a2713aSLionel Sambuc     switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) {
853f4a2713aSLionel Sambuc     case AR_accessible: return AR_accessible;
854f4a2713aSLionel Sambuc     case AR_inaccessible: return OnFailure;
855f4a2713aSLionel Sambuc     case AR_dependent: return AR_dependent;
856f4a2713aSLionel Sambuc     }
857f4a2713aSLionel Sambuc     llvm_unreachable("impossible friendship kind");
858f4a2713aSLionel Sambuc   }
859f4a2713aSLionel Sambuc 
860f4a2713aSLionel Sambuc   switch (GetFriendKind(S, EC, NamingClass)) {
861f4a2713aSLionel Sambuc   case AR_accessible: return AR_accessible;
862f4a2713aSLionel Sambuc   case AR_inaccessible: return OnFailure;
863f4a2713aSLionel Sambuc   case AR_dependent: return AR_dependent;
864f4a2713aSLionel Sambuc   }
865f4a2713aSLionel Sambuc 
866f4a2713aSLionel Sambuc   // Silence bogus warnings
867f4a2713aSLionel Sambuc   llvm_unreachable("impossible friendship kind");
868f4a2713aSLionel Sambuc }
869f4a2713aSLionel Sambuc 
870f4a2713aSLionel Sambuc /// Finds the best path from the naming class to the declaring class,
871f4a2713aSLionel Sambuc /// taking friend declarations into account.
872f4a2713aSLionel Sambuc ///
873f4a2713aSLionel Sambuc /// C++0x [class.access.base]p5:
874f4a2713aSLionel Sambuc ///   A member m is accessible at the point R when named in class N if
875f4a2713aSLionel Sambuc ///   [M1] m as a member of N is public, or
876f4a2713aSLionel Sambuc ///   [M2] m as a member of N is private, and R occurs in a member or
877f4a2713aSLionel Sambuc ///        friend of class N, or
878f4a2713aSLionel Sambuc ///   [M3] m as a member of N is protected, and R occurs in a member or
879f4a2713aSLionel Sambuc ///        friend of class N, or in a member or friend of a class P
880f4a2713aSLionel Sambuc ///        derived from N, where m as a member of P is public, private,
881f4a2713aSLionel Sambuc ///        or protected, or
882f4a2713aSLionel Sambuc ///   [M4] there exists a base class B of N that is accessible at R, and
883f4a2713aSLionel Sambuc ///        m is accessible at R when named in class B.
884f4a2713aSLionel Sambuc ///
885f4a2713aSLionel Sambuc /// C++0x [class.access.base]p4:
886f4a2713aSLionel Sambuc ///   A base class B of N is accessible at R, if
887f4a2713aSLionel Sambuc ///   [B1] an invented public member of B would be a public member of N, or
888f4a2713aSLionel Sambuc ///   [B2] R occurs in a member or friend of class N, and an invented public
889f4a2713aSLionel Sambuc ///        member of B would be a private or protected member of N, or
890f4a2713aSLionel Sambuc ///   [B3] R occurs in a member or friend of a class P derived from N, and an
891f4a2713aSLionel Sambuc ///        invented public member of B would be a private or protected member
892f4a2713aSLionel Sambuc ///        of P, or
893f4a2713aSLionel Sambuc ///   [B4] there exists a class S such that B is a base class of S accessible
894f4a2713aSLionel Sambuc ///        at R and S is a base class of N accessible at R.
895f4a2713aSLionel Sambuc ///
896f4a2713aSLionel Sambuc /// Along a single inheritance path we can restate both of these
897f4a2713aSLionel Sambuc /// iteratively:
898f4a2713aSLionel Sambuc ///
899f4a2713aSLionel Sambuc /// First, we note that M1-4 are equivalent to B1-4 if the member is
900f4a2713aSLionel Sambuc /// treated as a notional base of its declaring class with inheritance
901f4a2713aSLionel Sambuc /// access equivalent to the member's access.  Therefore we need only
902f4a2713aSLionel Sambuc /// ask whether a class B is accessible from a class N in context R.
903f4a2713aSLionel Sambuc ///
904f4a2713aSLionel Sambuc /// Let B_1 .. B_n be the inheritance path in question (i.e. where
905f4a2713aSLionel Sambuc /// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
906f4a2713aSLionel Sambuc /// B_i).  For i in 1..n, we will calculate ACAB(i), the access to the
907f4a2713aSLionel Sambuc /// closest accessible base in the path:
908f4a2713aSLionel Sambuc ///   Access(a, b) = (* access on the base specifier from a to b *)
909f4a2713aSLionel Sambuc ///   Merge(a, forbidden) = forbidden
910f4a2713aSLionel Sambuc ///   Merge(a, private) = forbidden
911f4a2713aSLionel Sambuc ///   Merge(a, b) = min(a,b)
912f4a2713aSLionel Sambuc ///   Accessible(c, forbidden) = false
913f4a2713aSLionel Sambuc ///   Accessible(c, private) = (R is c) || IsFriend(c, R)
914f4a2713aSLionel Sambuc ///   Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
915f4a2713aSLionel Sambuc ///   Accessible(c, public) = true
916f4a2713aSLionel Sambuc ///   ACAB(n) = public
917f4a2713aSLionel Sambuc ///   ACAB(i) =
918f4a2713aSLionel Sambuc ///     let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
919f4a2713aSLionel Sambuc ///     if Accessible(B_i, AccessToBase) then public else AccessToBase
920f4a2713aSLionel Sambuc ///
921f4a2713aSLionel Sambuc /// B is an accessible base of N at R iff ACAB(1) = public.
922f4a2713aSLionel Sambuc ///
923f4a2713aSLionel Sambuc /// \param FinalAccess the access of the "final step", or AS_public if
924f4a2713aSLionel Sambuc ///   there is no final step.
925f4a2713aSLionel Sambuc /// \return null if friendship is dependent
FindBestPath(Sema & S,const EffectiveContext & EC,AccessTarget & Target,AccessSpecifier FinalAccess,CXXBasePaths & Paths)926f4a2713aSLionel Sambuc static CXXBasePath *FindBestPath(Sema &S,
927f4a2713aSLionel Sambuc                                  const EffectiveContext &EC,
928f4a2713aSLionel Sambuc                                  AccessTarget &Target,
929f4a2713aSLionel Sambuc                                  AccessSpecifier FinalAccess,
930f4a2713aSLionel Sambuc                                  CXXBasePaths &Paths) {
931f4a2713aSLionel Sambuc   // Derive the paths to the desired base.
932f4a2713aSLionel Sambuc   const CXXRecordDecl *Derived = Target.getNamingClass();
933f4a2713aSLionel Sambuc   const CXXRecordDecl *Base = Target.getDeclaringClass();
934f4a2713aSLionel Sambuc 
935f4a2713aSLionel Sambuc   // FIXME: fail correctly when there are dependent paths.
936f4a2713aSLionel Sambuc   bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base),
937f4a2713aSLionel Sambuc                                           Paths);
938f4a2713aSLionel Sambuc   assert(isDerived && "derived class not actually derived from base");
939f4a2713aSLionel Sambuc   (void) isDerived;
940f4a2713aSLionel Sambuc 
941*0a6a1f1dSLionel Sambuc   CXXBasePath *BestPath = nullptr;
942f4a2713aSLionel Sambuc 
943f4a2713aSLionel Sambuc   assert(FinalAccess != AS_none && "forbidden access after declaring class");
944f4a2713aSLionel Sambuc 
945f4a2713aSLionel Sambuc   bool AnyDependent = false;
946f4a2713aSLionel Sambuc 
947f4a2713aSLionel Sambuc   // Derive the friend-modified access along each path.
948f4a2713aSLionel Sambuc   for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
949f4a2713aSLionel Sambuc          PI != PE; ++PI) {
950f4a2713aSLionel Sambuc     AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext();
951f4a2713aSLionel Sambuc 
952f4a2713aSLionel Sambuc     // Walk through the path backwards.
953f4a2713aSLionel Sambuc     AccessSpecifier PathAccess = FinalAccess;
954f4a2713aSLionel Sambuc     CXXBasePath::iterator I = PI->end(), E = PI->begin();
955f4a2713aSLionel Sambuc     while (I != E) {
956f4a2713aSLionel Sambuc       --I;
957f4a2713aSLionel Sambuc 
958f4a2713aSLionel Sambuc       assert(PathAccess != AS_none);
959f4a2713aSLionel Sambuc 
960f4a2713aSLionel Sambuc       // If the declaration is a private member of a base class, there
961f4a2713aSLionel Sambuc       // is no level of friendship in derived classes that can make it
962f4a2713aSLionel Sambuc       // accessible.
963f4a2713aSLionel Sambuc       if (PathAccess == AS_private) {
964f4a2713aSLionel Sambuc         PathAccess = AS_none;
965f4a2713aSLionel Sambuc         break;
966f4a2713aSLionel Sambuc       }
967f4a2713aSLionel Sambuc 
968f4a2713aSLionel Sambuc       const CXXRecordDecl *NC = I->Class->getCanonicalDecl();
969f4a2713aSLionel Sambuc 
970f4a2713aSLionel Sambuc       AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
971f4a2713aSLionel Sambuc       PathAccess = std::max(PathAccess, BaseAccess);
972f4a2713aSLionel Sambuc 
973f4a2713aSLionel Sambuc       switch (HasAccess(S, EC, NC, PathAccess, Target)) {
974f4a2713aSLionel Sambuc       case AR_inaccessible: break;
975f4a2713aSLionel Sambuc       case AR_accessible:
976f4a2713aSLionel Sambuc         PathAccess = AS_public;
977f4a2713aSLionel Sambuc 
978f4a2713aSLionel Sambuc         // Future tests are not against members and so do not have
979f4a2713aSLionel Sambuc         // instance context.
980f4a2713aSLionel Sambuc         Target.suppressInstanceContext();
981f4a2713aSLionel Sambuc         break;
982f4a2713aSLionel Sambuc       case AR_dependent:
983f4a2713aSLionel Sambuc         AnyDependent = true;
984f4a2713aSLionel Sambuc         goto Next;
985f4a2713aSLionel Sambuc       }
986f4a2713aSLionel Sambuc     }
987f4a2713aSLionel Sambuc 
988f4a2713aSLionel Sambuc     // Note that we modify the path's Access field to the
989f4a2713aSLionel Sambuc     // friend-modified access.
990*0a6a1f1dSLionel Sambuc     if (BestPath == nullptr || PathAccess < BestPath->Access) {
991f4a2713aSLionel Sambuc       BestPath = &*PI;
992f4a2713aSLionel Sambuc       BestPath->Access = PathAccess;
993f4a2713aSLionel Sambuc 
994f4a2713aSLionel Sambuc       // Short-circuit if we found a public path.
995f4a2713aSLionel Sambuc       if (BestPath->Access == AS_public)
996f4a2713aSLionel Sambuc         return BestPath;
997f4a2713aSLionel Sambuc     }
998f4a2713aSLionel Sambuc 
999f4a2713aSLionel Sambuc   Next: ;
1000f4a2713aSLionel Sambuc   }
1001f4a2713aSLionel Sambuc 
1002f4a2713aSLionel Sambuc   assert((!BestPath || BestPath->Access != AS_public) &&
1003f4a2713aSLionel Sambuc          "fell out of loop with public path");
1004f4a2713aSLionel Sambuc 
1005f4a2713aSLionel Sambuc   // We didn't find a public path, but at least one path was subject
1006f4a2713aSLionel Sambuc   // to dependent friendship, so delay the check.
1007f4a2713aSLionel Sambuc   if (AnyDependent)
1008*0a6a1f1dSLionel Sambuc     return nullptr;
1009f4a2713aSLionel Sambuc 
1010f4a2713aSLionel Sambuc   return BestPath;
1011f4a2713aSLionel Sambuc }
1012f4a2713aSLionel Sambuc 
1013f4a2713aSLionel Sambuc /// Given that an entity has protected natural access, check whether
1014f4a2713aSLionel Sambuc /// access might be denied because of the protected member access
1015f4a2713aSLionel Sambuc /// restriction.
1016f4a2713aSLionel Sambuc ///
1017f4a2713aSLionel Sambuc /// \return true if a note was emitted
TryDiagnoseProtectedAccess(Sema & S,const EffectiveContext & EC,AccessTarget & Target)1018f4a2713aSLionel Sambuc static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
1019f4a2713aSLionel Sambuc                                        AccessTarget &Target) {
1020f4a2713aSLionel Sambuc   // Only applies to instance accesses.
1021f4a2713aSLionel Sambuc   if (!Target.isInstanceMember())
1022f4a2713aSLionel Sambuc     return false;
1023f4a2713aSLionel Sambuc 
1024f4a2713aSLionel Sambuc   assert(Target.isMemberAccess());
1025f4a2713aSLionel Sambuc 
1026f4a2713aSLionel Sambuc   const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass();
1027f4a2713aSLionel Sambuc 
1028f4a2713aSLionel Sambuc   for (EffectiveContext::record_iterator
1029f4a2713aSLionel Sambuc          I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
1030f4a2713aSLionel Sambuc     const CXXRecordDecl *ECRecord = *I;
1031f4a2713aSLionel Sambuc     switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
1032f4a2713aSLionel Sambuc     case AR_accessible: break;
1033f4a2713aSLionel Sambuc     case AR_inaccessible: continue;
1034f4a2713aSLionel Sambuc     case AR_dependent: continue;
1035f4a2713aSLionel Sambuc     }
1036f4a2713aSLionel Sambuc 
1037f4a2713aSLionel Sambuc     // The effective context is a subclass of the declaring class.
1038f4a2713aSLionel Sambuc     // Check whether the [class.protected] restriction is limiting
1039f4a2713aSLionel Sambuc     // access.
1040f4a2713aSLionel Sambuc 
1041f4a2713aSLionel Sambuc     // To get this exactly right, this might need to be checked more
1042f4a2713aSLionel Sambuc     // holistically;  it's not necessarily the case that gaining
1043f4a2713aSLionel Sambuc     // access here would grant us access overall.
1044f4a2713aSLionel Sambuc 
1045f4a2713aSLionel Sambuc     NamedDecl *D = Target.getTargetDecl();
1046f4a2713aSLionel Sambuc 
1047f4a2713aSLionel Sambuc     // If we don't have an instance context, [class.protected] says the
1048f4a2713aSLionel Sambuc     // naming class has to equal the context class.
1049f4a2713aSLionel Sambuc     if (!Target.hasInstanceContext()) {
1050f4a2713aSLionel Sambuc       // If it does, the restriction doesn't apply.
1051f4a2713aSLionel Sambuc       if (NamingClass == ECRecord) continue;
1052f4a2713aSLionel Sambuc 
1053f4a2713aSLionel Sambuc       // TODO: it would be great to have a fixit here, since this is
1054f4a2713aSLionel Sambuc       // such an obvious error.
1055f4a2713aSLionel Sambuc       S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject)
1056f4a2713aSLionel Sambuc         << S.Context.getTypeDeclType(ECRecord);
1057f4a2713aSLionel Sambuc       return true;
1058f4a2713aSLionel Sambuc     }
1059f4a2713aSLionel Sambuc 
1060f4a2713aSLionel Sambuc     const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
1061f4a2713aSLionel Sambuc     assert(InstanceContext && "diagnosing dependent access");
1062f4a2713aSLionel Sambuc 
1063f4a2713aSLionel Sambuc     switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
1064f4a2713aSLionel Sambuc     case AR_accessible: continue;
1065f4a2713aSLionel Sambuc     case AR_dependent: continue;
1066f4a2713aSLionel Sambuc     case AR_inaccessible:
1067f4a2713aSLionel Sambuc       break;
1068f4a2713aSLionel Sambuc     }
1069f4a2713aSLionel Sambuc 
1070f4a2713aSLionel Sambuc     // Okay, the restriction seems to be what's limiting us.
1071f4a2713aSLionel Sambuc 
1072f4a2713aSLionel Sambuc     // Use a special diagnostic for constructors and destructors.
1073f4a2713aSLionel Sambuc     if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) ||
1074f4a2713aSLionel Sambuc         (isa<FunctionTemplateDecl>(D) &&
1075f4a2713aSLionel Sambuc          isa<CXXConstructorDecl>(
1076f4a2713aSLionel Sambuc                 cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) {
1077*0a6a1f1dSLionel Sambuc       return S.Diag(D->getLocation(),
1078*0a6a1f1dSLionel Sambuc                     diag::note_access_protected_restricted_ctordtor)
1079*0a6a1f1dSLionel Sambuc              << isa<CXXDestructorDecl>(D->getAsFunction());
1080f4a2713aSLionel Sambuc     }
1081f4a2713aSLionel Sambuc 
1082f4a2713aSLionel Sambuc     // Otherwise, use the generic diagnostic.
1083*0a6a1f1dSLionel Sambuc     return S.Diag(D->getLocation(),
1084*0a6a1f1dSLionel Sambuc                   diag::note_access_protected_restricted_object)
1085f4a2713aSLionel Sambuc            << S.Context.getTypeDeclType(ECRecord);
1086f4a2713aSLionel Sambuc   }
1087f4a2713aSLionel Sambuc 
1088f4a2713aSLionel Sambuc   return false;
1089f4a2713aSLionel Sambuc }
1090f4a2713aSLionel Sambuc 
1091f4a2713aSLionel Sambuc /// We are unable to access a given declaration due to its direct
1092f4a2713aSLionel Sambuc /// access control;  diagnose that.
diagnoseBadDirectAccess(Sema & S,const EffectiveContext & EC,AccessTarget & entity)1093f4a2713aSLionel Sambuc static void diagnoseBadDirectAccess(Sema &S,
1094f4a2713aSLionel Sambuc                                     const EffectiveContext &EC,
1095f4a2713aSLionel Sambuc                                     AccessTarget &entity) {
1096f4a2713aSLionel Sambuc   assert(entity.isMemberAccess());
1097f4a2713aSLionel Sambuc   NamedDecl *D = entity.getTargetDecl();
1098f4a2713aSLionel Sambuc 
1099f4a2713aSLionel Sambuc   if (D->getAccess() == AS_protected &&
1100f4a2713aSLionel Sambuc       TryDiagnoseProtectedAccess(S, EC, entity))
1101f4a2713aSLionel Sambuc     return;
1102f4a2713aSLionel Sambuc 
1103f4a2713aSLionel Sambuc   // Find an original declaration.
1104f4a2713aSLionel Sambuc   while (D->isOutOfLine()) {
1105*0a6a1f1dSLionel Sambuc     NamedDecl *PrevDecl = nullptr;
1106f4a2713aSLionel Sambuc     if (VarDecl *VD = dyn_cast<VarDecl>(D))
1107f4a2713aSLionel Sambuc       PrevDecl = VD->getPreviousDecl();
1108f4a2713aSLionel Sambuc     else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
1109f4a2713aSLionel Sambuc       PrevDecl = FD->getPreviousDecl();
1110f4a2713aSLionel Sambuc     else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
1111f4a2713aSLionel Sambuc       PrevDecl = TND->getPreviousDecl();
1112f4a2713aSLionel Sambuc     else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
1113f4a2713aSLionel Sambuc       if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
1114f4a2713aSLionel Sambuc         break;
1115f4a2713aSLionel Sambuc       PrevDecl = TD->getPreviousDecl();
1116f4a2713aSLionel Sambuc     }
1117f4a2713aSLionel Sambuc     if (!PrevDecl) break;
1118f4a2713aSLionel Sambuc     D = PrevDecl;
1119f4a2713aSLionel Sambuc   }
1120f4a2713aSLionel Sambuc 
1121f4a2713aSLionel Sambuc   CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
1122f4a2713aSLionel Sambuc   Decl *ImmediateChild;
1123f4a2713aSLionel Sambuc   if (D->getDeclContext() == DeclaringClass)
1124f4a2713aSLionel Sambuc     ImmediateChild = D;
1125f4a2713aSLionel Sambuc   else {
1126f4a2713aSLionel Sambuc     DeclContext *DC = D->getDeclContext();
1127f4a2713aSLionel Sambuc     while (DC->getParent() != DeclaringClass)
1128f4a2713aSLionel Sambuc       DC = DC->getParent();
1129f4a2713aSLionel Sambuc     ImmediateChild = cast<Decl>(DC);
1130f4a2713aSLionel Sambuc   }
1131f4a2713aSLionel Sambuc 
1132f4a2713aSLionel Sambuc   // Check whether there's an AccessSpecDecl preceding this in the
1133f4a2713aSLionel Sambuc   // chain of the DeclContext.
1134f4a2713aSLionel Sambuc   bool isImplicit = true;
1135*0a6a1f1dSLionel Sambuc   for (const auto *I : DeclaringClass->decls()) {
1136*0a6a1f1dSLionel Sambuc     if (I == ImmediateChild) break;
1137*0a6a1f1dSLionel Sambuc     if (isa<AccessSpecDecl>(I)) {
1138f4a2713aSLionel Sambuc       isImplicit = false;
1139f4a2713aSLionel Sambuc       break;
1140f4a2713aSLionel Sambuc     }
1141f4a2713aSLionel Sambuc   }
1142f4a2713aSLionel Sambuc 
1143f4a2713aSLionel Sambuc   S.Diag(D->getLocation(), diag::note_access_natural)
1144f4a2713aSLionel Sambuc     << (unsigned) (D->getAccess() == AS_protected)
1145f4a2713aSLionel Sambuc     << isImplicit;
1146f4a2713aSLionel Sambuc }
1147f4a2713aSLionel Sambuc 
1148f4a2713aSLionel Sambuc /// Diagnose the path which caused the given declaration or base class
1149f4a2713aSLionel Sambuc /// to become inaccessible.
DiagnoseAccessPath(Sema & S,const EffectiveContext & EC,AccessTarget & entity)1150f4a2713aSLionel Sambuc static void DiagnoseAccessPath(Sema &S,
1151f4a2713aSLionel Sambuc                                const EffectiveContext &EC,
1152f4a2713aSLionel Sambuc                                AccessTarget &entity) {
1153f4a2713aSLionel Sambuc   // Save the instance context to preserve invariants.
1154f4a2713aSLionel Sambuc   AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext();
1155f4a2713aSLionel Sambuc 
1156f4a2713aSLionel Sambuc   // This basically repeats the main algorithm but keeps some more
1157f4a2713aSLionel Sambuc   // information.
1158f4a2713aSLionel Sambuc 
1159f4a2713aSLionel Sambuc   // The natural access so far.
1160f4a2713aSLionel Sambuc   AccessSpecifier accessSoFar = AS_public;
1161f4a2713aSLionel Sambuc 
1162f4a2713aSLionel Sambuc   // Check whether we have special rights to the declaring class.
1163f4a2713aSLionel Sambuc   if (entity.isMemberAccess()) {
1164f4a2713aSLionel Sambuc     NamedDecl *D = entity.getTargetDecl();
1165f4a2713aSLionel Sambuc     accessSoFar = D->getAccess();
1166f4a2713aSLionel Sambuc     const CXXRecordDecl *declaringClass = entity.getDeclaringClass();
1167f4a2713aSLionel Sambuc 
1168f4a2713aSLionel Sambuc     switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) {
1169f4a2713aSLionel Sambuc     // If the declaration is accessible when named in its declaring
1170f4a2713aSLionel Sambuc     // class, then we must be constrained by the path.
1171f4a2713aSLionel Sambuc     case AR_accessible:
1172f4a2713aSLionel Sambuc       accessSoFar = AS_public;
1173f4a2713aSLionel Sambuc       entity.suppressInstanceContext();
1174f4a2713aSLionel Sambuc       break;
1175f4a2713aSLionel Sambuc 
1176f4a2713aSLionel Sambuc     case AR_inaccessible:
1177f4a2713aSLionel Sambuc       if (accessSoFar == AS_private ||
1178f4a2713aSLionel Sambuc           declaringClass == entity.getEffectiveNamingClass())
1179f4a2713aSLionel Sambuc         return diagnoseBadDirectAccess(S, EC, entity);
1180f4a2713aSLionel Sambuc       break;
1181f4a2713aSLionel Sambuc 
1182f4a2713aSLionel Sambuc     case AR_dependent:
1183f4a2713aSLionel Sambuc       llvm_unreachable("cannot diagnose dependent access");
1184f4a2713aSLionel Sambuc     }
1185f4a2713aSLionel Sambuc   }
1186f4a2713aSLionel Sambuc 
1187f4a2713aSLionel Sambuc   CXXBasePaths paths;
1188f4a2713aSLionel Sambuc   CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths);
1189f4a2713aSLionel Sambuc   assert(path.Access != AS_public);
1190f4a2713aSLionel Sambuc 
1191f4a2713aSLionel Sambuc   CXXBasePath::iterator i = path.end(), e = path.begin();
1192f4a2713aSLionel Sambuc   CXXBasePath::iterator constrainingBase = i;
1193f4a2713aSLionel Sambuc   while (i != e) {
1194f4a2713aSLionel Sambuc     --i;
1195f4a2713aSLionel Sambuc 
1196f4a2713aSLionel Sambuc     assert(accessSoFar != AS_none && accessSoFar != AS_private);
1197f4a2713aSLionel Sambuc 
1198f4a2713aSLionel Sambuc     // Is the entity accessible when named in the deriving class, as
1199f4a2713aSLionel Sambuc     // modified by the base specifier?
1200f4a2713aSLionel Sambuc     const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl();
1201f4a2713aSLionel Sambuc     const CXXBaseSpecifier *base = i->Base;
1202f4a2713aSLionel Sambuc 
1203f4a2713aSLionel Sambuc     // If the access to this base is worse than the access we have to
1204f4a2713aSLionel Sambuc     // the declaration, remember it.
1205f4a2713aSLionel Sambuc     AccessSpecifier baseAccess = base->getAccessSpecifier();
1206f4a2713aSLionel Sambuc     if (baseAccess > accessSoFar) {
1207f4a2713aSLionel Sambuc       constrainingBase = i;
1208f4a2713aSLionel Sambuc       accessSoFar = baseAccess;
1209f4a2713aSLionel Sambuc     }
1210f4a2713aSLionel Sambuc 
1211f4a2713aSLionel Sambuc     switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) {
1212f4a2713aSLionel Sambuc     case AR_inaccessible: break;
1213f4a2713aSLionel Sambuc     case AR_accessible:
1214f4a2713aSLionel Sambuc       accessSoFar = AS_public;
1215f4a2713aSLionel Sambuc       entity.suppressInstanceContext();
1216*0a6a1f1dSLionel Sambuc       constrainingBase = nullptr;
1217f4a2713aSLionel Sambuc       break;
1218f4a2713aSLionel Sambuc     case AR_dependent:
1219f4a2713aSLionel Sambuc       llvm_unreachable("cannot diagnose dependent access");
1220f4a2713aSLionel Sambuc     }
1221f4a2713aSLionel Sambuc 
1222f4a2713aSLionel Sambuc     // If this was private inheritance, but we don't have access to
1223f4a2713aSLionel Sambuc     // the deriving class, we're done.
1224f4a2713aSLionel Sambuc     if (accessSoFar == AS_private) {
1225f4a2713aSLionel Sambuc       assert(baseAccess == AS_private);
1226f4a2713aSLionel Sambuc       assert(constrainingBase == i);
1227f4a2713aSLionel Sambuc       break;
1228f4a2713aSLionel Sambuc     }
1229f4a2713aSLionel Sambuc   }
1230f4a2713aSLionel Sambuc 
1231f4a2713aSLionel Sambuc   // If we don't have a constraining base, the access failure must be
1232f4a2713aSLionel Sambuc   // due to the original declaration.
1233f4a2713aSLionel Sambuc   if (constrainingBase == path.end())
1234f4a2713aSLionel Sambuc     return diagnoseBadDirectAccess(S, EC, entity);
1235f4a2713aSLionel Sambuc 
1236f4a2713aSLionel Sambuc   // We're constrained by inheritance, but we want to say
1237f4a2713aSLionel Sambuc   // "declared private here" if we're diagnosing a hierarchy
1238f4a2713aSLionel Sambuc   // conversion and this is the final step.
1239f4a2713aSLionel Sambuc   unsigned diagnostic;
1240f4a2713aSLionel Sambuc   if (entity.isMemberAccess() ||
1241f4a2713aSLionel Sambuc       constrainingBase + 1 != path.end()) {
1242f4a2713aSLionel Sambuc     diagnostic = diag::note_access_constrained_by_path;
1243f4a2713aSLionel Sambuc   } else {
1244f4a2713aSLionel Sambuc     diagnostic = diag::note_access_natural;
1245f4a2713aSLionel Sambuc   }
1246f4a2713aSLionel Sambuc 
1247f4a2713aSLionel Sambuc   const CXXBaseSpecifier *base = constrainingBase->Base;
1248f4a2713aSLionel Sambuc 
1249f4a2713aSLionel Sambuc   S.Diag(base->getSourceRange().getBegin(), diagnostic)
1250f4a2713aSLionel Sambuc     << base->getSourceRange()
1251f4a2713aSLionel Sambuc     << (base->getAccessSpecifier() == AS_protected)
1252f4a2713aSLionel Sambuc     << (base->getAccessSpecifierAsWritten() == AS_none);
1253f4a2713aSLionel Sambuc 
1254f4a2713aSLionel Sambuc   if (entity.isMemberAccess())
1255*0a6a1f1dSLionel Sambuc     S.Diag(entity.getTargetDecl()->getLocation(),
1256*0a6a1f1dSLionel Sambuc            diag::note_member_declared_at);
1257f4a2713aSLionel Sambuc }
1258f4a2713aSLionel Sambuc 
DiagnoseBadAccess(Sema & S,SourceLocation Loc,const EffectiveContext & EC,AccessTarget & Entity)1259f4a2713aSLionel Sambuc static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
1260f4a2713aSLionel Sambuc                               const EffectiveContext &EC,
1261f4a2713aSLionel Sambuc                               AccessTarget &Entity) {
1262f4a2713aSLionel Sambuc   const CXXRecordDecl *NamingClass = Entity.getNamingClass();
1263f4a2713aSLionel Sambuc   const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
1264*0a6a1f1dSLionel Sambuc   NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : nullptr);
1265f4a2713aSLionel Sambuc 
1266f4a2713aSLionel Sambuc   S.Diag(Loc, Entity.getDiag())
1267f4a2713aSLionel Sambuc     << (Entity.getAccess() == AS_protected)
1268f4a2713aSLionel Sambuc     << (D ? D->getDeclName() : DeclarationName())
1269f4a2713aSLionel Sambuc     << S.Context.getTypeDeclType(NamingClass)
1270f4a2713aSLionel Sambuc     << S.Context.getTypeDeclType(DeclaringClass);
1271f4a2713aSLionel Sambuc   DiagnoseAccessPath(S, EC, Entity);
1272f4a2713aSLionel Sambuc }
1273f4a2713aSLionel Sambuc 
1274f4a2713aSLionel Sambuc /// MSVC has a bug where if during an using declaration name lookup,
1275f4a2713aSLionel Sambuc /// the declaration found is unaccessible (private) and that declaration
1276f4a2713aSLionel Sambuc /// was bring into scope via another using declaration whose target
1277f4a2713aSLionel Sambuc /// declaration is accessible (public) then no error is generated.
1278f4a2713aSLionel Sambuc /// Example:
1279f4a2713aSLionel Sambuc ///   class A {
1280f4a2713aSLionel Sambuc ///   public:
1281f4a2713aSLionel Sambuc ///     int f();
1282f4a2713aSLionel Sambuc ///   };
1283f4a2713aSLionel Sambuc ///   class B : public A {
1284f4a2713aSLionel Sambuc ///   private:
1285f4a2713aSLionel Sambuc ///     using A::f;
1286f4a2713aSLionel Sambuc ///   };
1287f4a2713aSLionel Sambuc ///   class C : public B {
1288f4a2713aSLionel Sambuc ///   private:
1289f4a2713aSLionel Sambuc ///     using B::f;
1290f4a2713aSLionel Sambuc ///   };
1291f4a2713aSLionel Sambuc ///
1292f4a2713aSLionel Sambuc /// Here, B::f is private so this should fail in Standard C++, but
1293f4a2713aSLionel Sambuc /// because B::f refers to A::f which is public MSVC accepts it.
IsMicrosoftUsingDeclarationAccessBug(Sema & S,SourceLocation AccessLoc,AccessTarget & Entity)1294f4a2713aSLionel Sambuc static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
1295f4a2713aSLionel Sambuc                                                  SourceLocation AccessLoc,
1296f4a2713aSLionel Sambuc                                                  AccessTarget &Entity) {
1297f4a2713aSLionel Sambuc   if (UsingShadowDecl *Shadow =
1298f4a2713aSLionel Sambuc                          dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) {
1299f4a2713aSLionel Sambuc     const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl();
1300f4a2713aSLionel Sambuc     if (Entity.getTargetDecl()->getAccess() == AS_private &&
1301f4a2713aSLionel Sambuc         (OrigDecl->getAccess() == AS_public ||
1302f4a2713aSLionel Sambuc          OrigDecl->getAccess() == AS_protected)) {
1303f4a2713aSLionel Sambuc       S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible)
1304f4a2713aSLionel Sambuc         << Shadow->getUsingDecl()->getQualifiedNameAsString()
1305f4a2713aSLionel Sambuc         << OrigDecl->getQualifiedNameAsString();
1306f4a2713aSLionel Sambuc       return true;
1307f4a2713aSLionel Sambuc     }
1308f4a2713aSLionel Sambuc   }
1309f4a2713aSLionel Sambuc   return false;
1310f4a2713aSLionel Sambuc }
1311f4a2713aSLionel Sambuc 
1312f4a2713aSLionel Sambuc /// Determines whether the accessed entity is accessible.  Public members
1313f4a2713aSLionel Sambuc /// have been weeded out by this point.
IsAccessible(Sema & S,const EffectiveContext & EC,AccessTarget & Entity)1314f4a2713aSLionel Sambuc static AccessResult IsAccessible(Sema &S,
1315f4a2713aSLionel Sambuc                                  const EffectiveContext &EC,
1316f4a2713aSLionel Sambuc                                  AccessTarget &Entity) {
1317f4a2713aSLionel Sambuc   // Determine the actual naming class.
1318f4a2713aSLionel Sambuc   const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();
1319f4a2713aSLionel Sambuc 
1320f4a2713aSLionel Sambuc   AccessSpecifier UnprivilegedAccess = Entity.getAccess();
1321f4a2713aSLionel Sambuc   assert(UnprivilegedAccess != AS_public && "public access not weeded out");
1322f4a2713aSLionel Sambuc 
1323f4a2713aSLionel Sambuc   // Before we try to recalculate access paths, try to white-list
1324f4a2713aSLionel Sambuc   // accesses which just trade in on the final step, i.e. accesses
1325f4a2713aSLionel Sambuc   // which don't require [M4] or [B4]. These are by far the most
1326f4a2713aSLionel Sambuc   // common forms of privileged access.
1327f4a2713aSLionel Sambuc   if (UnprivilegedAccess != AS_none) {
1328f4a2713aSLionel Sambuc     switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) {
1329f4a2713aSLionel Sambuc     case AR_dependent:
1330f4a2713aSLionel Sambuc       // This is actually an interesting policy decision.  We don't
1331f4a2713aSLionel Sambuc       // *have* to delay immediately here: we can do the full access
1332f4a2713aSLionel Sambuc       // calculation in the hope that friendship on some intermediate
1333f4a2713aSLionel Sambuc       // class will make the declaration accessible non-dependently.
1334f4a2713aSLionel Sambuc       // But that's not cheap, and odds are very good (note: assertion
1335f4a2713aSLionel Sambuc       // made without data) that the friend declaration will determine
1336f4a2713aSLionel Sambuc       // access.
1337f4a2713aSLionel Sambuc       return AR_dependent;
1338f4a2713aSLionel Sambuc 
1339f4a2713aSLionel Sambuc     case AR_accessible: return AR_accessible;
1340f4a2713aSLionel Sambuc     case AR_inaccessible: break;
1341f4a2713aSLionel Sambuc     }
1342f4a2713aSLionel Sambuc   }
1343f4a2713aSLionel Sambuc 
1344f4a2713aSLionel Sambuc   AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();
1345f4a2713aSLionel Sambuc 
1346f4a2713aSLionel Sambuc   // We lower member accesses to base accesses by pretending that the
1347f4a2713aSLionel Sambuc   // member is a base class of its declaring class.
1348f4a2713aSLionel Sambuc   AccessSpecifier FinalAccess;
1349f4a2713aSLionel Sambuc 
1350f4a2713aSLionel Sambuc   if (Entity.isMemberAccess()) {
1351f4a2713aSLionel Sambuc     // Determine if the declaration is accessible from EC when named
1352f4a2713aSLionel Sambuc     // in its declaring class.
1353f4a2713aSLionel Sambuc     NamedDecl *Target = Entity.getTargetDecl();
1354f4a2713aSLionel Sambuc     const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
1355f4a2713aSLionel Sambuc 
1356f4a2713aSLionel Sambuc     FinalAccess = Target->getAccess();
1357f4a2713aSLionel Sambuc     switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
1358f4a2713aSLionel Sambuc     case AR_accessible:
1359f4a2713aSLionel Sambuc       // Target is accessible at EC when named in its declaring class.
1360f4a2713aSLionel Sambuc       // We can now hill-climb and simply check whether the declaring
1361f4a2713aSLionel Sambuc       // class is accessible as a base of the naming class.  This is
1362f4a2713aSLionel Sambuc       // equivalent to checking the access of a notional public
1363f4a2713aSLionel Sambuc       // member with no instance context.
1364f4a2713aSLionel Sambuc       FinalAccess = AS_public;
1365f4a2713aSLionel Sambuc       Entity.suppressInstanceContext();
1366f4a2713aSLionel Sambuc       break;
1367f4a2713aSLionel Sambuc     case AR_inaccessible: break;
1368f4a2713aSLionel Sambuc     case AR_dependent: return AR_dependent; // see above
1369f4a2713aSLionel Sambuc     }
1370f4a2713aSLionel Sambuc 
1371f4a2713aSLionel Sambuc     if (DeclaringClass == NamingClass)
1372f4a2713aSLionel Sambuc       return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
1373f4a2713aSLionel Sambuc   } else {
1374f4a2713aSLionel Sambuc     FinalAccess = AS_public;
1375f4a2713aSLionel Sambuc   }
1376f4a2713aSLionel Sambuc 
1377f4a2713aSLionel Sambuc   assert(Entity.getDeclaringClass() != NamingClass);
1378f4a2713aSLionel Sambuc 
1379f4a2713aSLionel Sambuc   // Append the declaration's access if applicable.
1380f4a2713aSLionel Sambuc   CXXBasePaths Paths;
1381f4a2713aSLionel Sambuc   CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths);
1382f4a2713aSLionel Sambuc   if (!Path)
1383f4a2713aSLionel Sambuc     return AR_dependent;
1384f4a2713aSLionel Sambuc 
1385f4a2713aSLionel Sambuc   assert(Path->Access <= UnprivilegedAccess &&
1386f4a2713aSLionel Sambuc          "access along best path worse than direct?");
1387f4a2713aSLionel Sambuc   if (Path->Access == AS_public)
1388f4a2713aSLionel Sambuc     return AR_accessible;
1389f4a2713aSLionel Sambuc   return AR_inaccessible;
1390f4a2713aSLionel Sambuc }
1391f4a2713aSLionel Sambuc 
DelayDependentAccess(Sema & S,const EffectiveContext & EC,SourceLocation Loc,const AccessTarget & Entity)1392f4a2713aSLionel Sambuc static void DelayDependentAccess(Sema &S,
1393f4a2713aSLionel Sambuc                                  const EffectiveContext &EC,
1394f4a2713aSLionel Sambuc                                  SourceLocation Loc,
1395f4a2713aSLionel Sambuc                                  const AccessTarget &Entity) {
1396f4a2713aSLionel Sambuc   assert(EC.isDependent() && "delaying non-dependent access");
1397f4a2713aSLionel Sambuc   DeclContext *DC = EC.getInnerContext();
1398f4a2713aSLionel Sambuc   assert(DC->isDependentContext() && "delaying non-dependent access");
1399f4a2713aSLionel Sambuc   DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
1400f4a2713aSLionel Sambuc                               Loc,
1401f4a2713aSLionel Sambuc                               Entity.isMemberAccess(),
1402f4a2713aSLionel Sambuc                               Entity.getAccess(),
1403f4a2713aSLionel Sambuc                               Entity.getTargetDecl(),
1404f4a2713aSLionel Sambuc                               Entity.getNamingClass(),
1405f4a2713aSLionel Sambuc                               Entity.getBaseObjectType(),
1406f4a2713aSLionel Sambuc                               Entity.getDiag());
1407f4a2713aSLionel Sambuc }
1408f4a2713aSLionel Sambuc 
1409f4a2713aSLionel Sambuc /// Checks access to an entity from the given effective context.
CheckEffectiveAccess(Sema & S,const EffectiveContext & EC,SourceLocation Loc,AccessTarget & Entity)1410f4a2713aSLionel Sambuc static AccessResult CheckEffectiveAccess(Sema &S,
1411f4a2713aSLionel Sambuc                                          const EffectiveContext &EC,
1412f4a2713aSLionel Sambuc                                          SourceLocation Loc,
1413f4a2713aSLionel Sambuc                                          AccessTarget &Entity) {
1414f4a2713aSLionel Sambuc   assert(Entity.getAccess() != AS_public && "called for public access!");
1415f4a2713aSLionel Sambuc 
1416f4a2713aSLionel Sambuc   switch (IsAccessible(S, EC, Entity)) {
1417f4a2713aSLionel Sambuc   case AR_dependent:
1418f4a2713aSLionel Sambuc     DelayDependentAccess(S, EC, Loc, Entity);
1419f4a2713aSLionel Sambuc     return AR_dependent;
1420f4a2713aSLionel Sambuc 
1421f4a2713aSLionel Sambuc   case AR_inaccessible:
1422*0a6a1f1dSLionel Sambuc     if (S.getLangOpts().MSVCCompat &&
1423*0a6a1f1dSLionel Sambuc         IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
1424*0a6a1f1dSLionel Sambuc       return AR_accessible;
1425f4a2713aSLionel Sambuc     if (!Entity.isQuiet())
1426f4a2713aSLionel Sambuc       DiagnoseBadAccess(S, Loc, EC, Entity);
1427f4a2713aSLionel Sambuc     return AR_inaccessible;
1428f4a2713aSLionel Sambuc 
1429f4a2713aSLionel Sambuc   case AR_accessible:
1430f4a2713aSLionel Sambuc     return AR_accessible;
1431f4a2713aSLionel Sambuc   }
1432f4a2713aSLionel Sambuc 
1433f4a2713aSLionel Sambuc   // silence unnecessary warning
1434f4a2713aSLionel Sambuc   llvm_unreachable("invalid access result");
1435f4a2713aSLionel Sambuc }
1436f4a2713aSLionel Sambuc 
CheckAccess(Sema & S,SourceLocation Loc,AccessTarget & Entity)1437f4a2713aSLionel Sambuc static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
1438f4a2713aSLionel Sambuc                                       AccessTarget &Entity) {
1439f4a2713aSLionel Sambuc   // If the access path is public, it's accessible everywhere.
1440f4a2713aSLionel Sambuc   if (Entity.getAccess() == AS_public)
1441f4a2713aSLionel Sambuc     return Sema::AR_accessible;
1442f4a2713aSLionel Sambuc 
1443f4a2713aSLionel Sambuc   // If we're currently parsing a declaration, we may need to delay
1444f4a2713aSLionel Sambuc   // access control checking, because our effective context might be
1445f4a2713aSLionel Sambuc   // different based on what the declaration comes out as.
1446f4a2713aSLionel Sambuc   //
1447f4a2713aSLionel Sambuc   // For example, we might be parsing a declaration with a scope
1448f4a2713aSLionel Sambuc   // specifier, like this:
1449f4a2713aSLionel Sambuc   //   A::private_type A::foo() { ... }
1450f4a2713aSLionel Sambuc   //
1451f4a2713aSLionel Sambuc   // Or we might be parsing something that will turn out to be a friend:
1452f4a2713aSLionel Sambuc   //   void foo(A::private_type);
1453f4a2713aSLionel Sambuc   //   void B::foo(A::private_type);
1454f4a2713aSLionel Sambuc   if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
1455f4a2713aSLionel Sambuc     S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity));
1456f4a2713aSLionel Sambuc     return Sema::AR_delayed;
1457f4a2713aSLionel Sambuc   }
1458f4a2713aSLionel Sambuc 
1459f4a2713aSLionel Sambuc   EffectiveContext EC(S.CurContext);
1460f4a2713aSLionel Sambuc   switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
1461f4a2713aSLionel Sambuc   case AR_accessible: return Sema::AR_accessible;
1462f4a2713aSLionel Sambuc   case AR_inaccessible: return Sema::AR_inaccessible;
1463f4a2713aSLionel Sambuc   case AR_dependent: return Sema::AR_dependent;
1464f4a2713aSLionel Sambuc   }
1465f4a2713aSLionel Sambuc   llvm_unreachable("falling off end");
1466f4a2713aSLionel Sambuc }
1467f4a2713aSLionel Sambuc 
HandleDelayedAccessCheck(DelayedDiagnostic & DD,Decl * D)1468f4a2713aSLionel Sambuc void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
1469f4a2713aSLionel Sambuc   // Access control for names used in the declarations of functions
1470f4a2713aSLionel Sambuc   // and function templates should normally be evaluated in the context
1471f4a2713aSLionel Sambuc   // of the declaration, just in case it's a friend of something.
1472f4a2713aSLionel Sambuc   // However, this does not apply to local extern declarations.
1473f4a2713aSLionel Sambuc 
1474f4a2713aSLionel Sambuc   DeclContext *DC = D->getDeclContext();
1475*0a6a1f1dSLionel Sambuc   if (D->isLocalExternDecl()) {
1476f4a2713aSLionel Sambuc     DC = D->getLexicalDeclContext();
1477*0a6a1f1dSLionel Sambuc   } else if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {
1478f4a2713aSLionel Sambuc     DC = FN;
1479f4a2713aSLionel Sambuc   } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
1480f4a2713aSLionel Sambuc     DC = cast<DeclContext>(TD->getTemplatedDecl());
1481f4a2713aSLionel Sambuc   }
1482f4a2713aSLionel Sambuc 
1483f4a2713aSLionel Sambuc   EffectiveContext EC(DC);
1484f4a2713aSLionel Sambuc 
1485f4a2713aSLionel Sambuc   AccessTarget Target(DD.getAccessData());
1486f4a2713aSLionel Sambuc 
1487f4a2713aSLionel Sambuc   if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible)
1488f4a2713aSLionel Sambuc     DD.Triggered = true;
1489f4a2713aSLionel Sambuc }
1490f4a2713aSLionel Sambuc 
HandleDependentAccessCheck(const DependentDiagnostic & DD,const MultiLevelTemplateArgumentList & TemplateArgs)1491f4a2713aSLionel Sambuc void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
1492f4a2713aSLionel Sambuc                         const MultiLevelTemplateArgumentList &TemplateArgs) {
1493f4a2713aSLionel Sambuc   SourceLocation Loc = DD.getAccessLoc();
1494f4a2713aSLionel Sambuc   AccessSpecifier Access = DD.getAccess();
1495f4a2713aSLionel Sambuc 
1496f4a2713aSLionel Sambuc   Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
1497f4a2713aSLionel Sambuc                                        TemplateArgs);
1498f4a2713aSLionel Sambuc   if (!NamingD) return;
1499f4a2713aSLionel Sambuc   Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
1500f4a2713aSLionel Sambuc                                        TemplateArgs);
1501f4a2713aSLionel Sambuc   if (!TargetD) return;
1502f4a2713aSLionel Sambuc 
1503f4a2713aSLionel Sambuc   if (DD.isAccessToMember()) {
1504f4a2713aSLionel Sambuc     CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD);
1505f4a2713aSLionel Sambuc     NamedDecl *TargetDecl = cast<NamedDecl>(TargetD);
1506f4a2713aSLionel Sambuc     QualType BaseObjectType = DD.getAccessBaseObjectType();
1507f4a2713aSLionel Sambuc     if (!BaseObjectType.isNull()) {
1508f4a2713aSLionel Sambuc       BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc,
1509f4a2713aSLionel Sambuc                                  DeclarationName());
1510f4a2713aSLionel Sambuc       if (BaseObjectType.isNull()) return;
1511f4a2713aSLionel Sambuc     }
1512f4a2713aSLionel Sambuc 
1513f4a2713aSLionel Sambuc     AccessTarget Entity(Context,
1514f4a2713aSLionel Sambuc                         AccessTarget::Member,
1515f4a2713aSLionel Sambuc                         NamingClass,
1516f4a2713aSLionel Sambuc                         DeclAccessPair::make(TargetDecl, Access),
1517f4a2713aSLionel Sambuc                         BaseObjectType);
1518f4a2713aSLionel Sambuc     Entity.setDiag(DD.getDiagnostic());
1519f4a2713aSLionel Sambuc     CheckAccess(*this, Loc, Entity);
1520f4a2713aSLionel Sambuc   } else {
1521f4a2713aSLionel Sambuc     AccessTarget Entity(Context,
1522f4a2713aSLionel Sambuc                         AccessTarget::Base,
1523f4a2713aSLionel Sambuc                         cast<CXXRecordDecl>(TargetD),
1524f4a2713aSLionel Sambuc                         cast<CXXRecordDecl>(NamingD),
1525f4a2713aSLionel Sambuc                         Access);
1526f4a2713aSLionel Sambuc     Entity.setDiag(DD.getDiagnostic());
1527f4a2713aSLionel Sambuc     CheckAccess(*this, Loc, Entity);
1528f4a2713aSLionel Sambuc   }
1529f4a2713aSLionel Sambuc }
1530f4a2713aSLionel Sambuc 
CheckUnresolvedLookupAccess(UnresolvedLookupExpr * E,DeclAccessPair Found)1531f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
1532f4a2713aSLionel Sambuc                                                      DeclAccessPair Found) {
1533f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl ||
1534f4a2713aSLionel Sambuc       !E->getNamingClass() ||
1535f4a2713aSLionel Sambuc       Found.getAccess() == AS_public)
1536f4a2713aSLionel Sambuc     return AR_accessible;
1537f4a2713aSLionel Sambuc 
1538f4a2713aSLionel Sambuc   AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
1539f4a2713aSLionel Sambuc                       Found, QualType());
1540f4a2713aSLionel Sambuc   Entity.setDiag(diag::err_access) << E->getSourceRange();
1541f4a2713aSLionel Sambuc 
1542f4a2713aSLionel Sambuc   return CheckAccess(*this, E->getNameLoc(), Entity);
1543f4a2713aSLionel Sambuc }
1544f4a2713aSLionel Sambuc 
1545f4a2713aSLionel Sambuc /// Perform access-control checking on a previously-unresolved member
1546f4a2713aSLionel Sambuc /// access which has now been resolved to a member.
CheckUnresolvedMemberAccess(UnresolvedMemberExpr * E,DeclAccessPair Found)1547f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
1548f4a2713aSLionel Sambuc                                                      DeclAccessPair Found) {
1549f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl ||
1550f4a2713aSLionel Sambuc       Found.getAccess() == AS_public)
1551f4a2713aSLionel Sambuc     return AR_accessible;
1552f4a2713aSLionel Sambuc 
1553f4a2713aSLionel Sambuc   QualType BaseType = E->getBaseType();
1554f4a2713aSLionel Sambuc   if (E->isArrow())
1555f4a2713aSLionel Sambuc     BaseType = BaseType->getAs<PointerType>()->getPointeeType();
1556f4a2713aSLionel Sambuc 
1557f4a2713aSLionel Sambuc   AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
1558f4a2713aSLionel Sambuc                       Found, BaseType);
1559f4a2713aSLionel Sambuc   Entity.setDiag(diag::err_access) << E->getSourceRange();
1560f4a2713aSLionel Sambuc 
1561f4a2713aSLionel Sambuc   return CheckAccess(*this, E->getMemberLoc(), Entity);
1562f4a2713aSLionel Sambuc }
1563f4a2713aSLionel Sambuc 
1564f4a2713aSLionel Sambuc /// Is the given special member function accessible for the purposes of
1565f4a2713aSLionel Sambuc /// deciding whether to define a special member function as deleted?
isSpecialMemberAccessibleForDeletion(CXXMethodDecl * decl,AccessSpecifier access,QualType objectType)1566f4a2713aSLionel Sambuc bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl,
1567f4a2713aSLionel Sambuc                                                 AccessSpecifier access,
1568f4a2713aSLionel Sambuc                                                 QualType objectType) {
1569f4a2713aSLionel Sambuc   // Fast path.
1570f4a2713aSLionel Sambuc   if (access == AS_public || !getLangOpts().AccessControl) return true;
1571f4a2713aSLionel Sambuc 
1572f4a2713aSLionel Sambuc   AccessTarget entity(Context, AccessTarget::Member, decl->getParent(),
1573f4a2713aSLionel Sambuc                       DeclAccessPair::make(decl, access), objectType);
1574f4a2713aSLionel Sambuc 
1575f4a2713aSLionel Sambuc   // Suppress diagnostics.
1576f4a2713aSLionel Sambuc   entity.setDiag(PDiag());
1577f4a2713aSLionel Sambuc 
1578f4a2713aSLionel Sambuc   switch (CheckAccess(*this, SourceLocation(), entity)) {
1579f4a2713aSLionel Sambuc   case AR_accessible: return true;
1580f4a2713aSLionel Sambuc   case AR_inaccessible: return false;
1581f4a2713aSLionel Sambuc   case AR_dependent: llvm_unreachable("dependent for =delete computation");
1582f4a2713aSLionel Sambuc   case AR_delayed: llvm_unreachable("cannot delay =delete computation");
1583f4a2713aSLionel Sambuc   }
1584f4a2713aSLionel Sambuc   llvm_unreachable("bad access result");
1585f4a2713aSLionel Sambuc }
1586f4a2713aSLionel Sambuc 
CheckDestructorAccess(SourceLocation Loc,CXXDestructorDecl * Dtor,const PartialDiagnostic & PDiag,QualType ObjectTy)1587f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
1588f4a2713aSLionel Sambuc                                                CXXDestructorDecl *Dtor,
1589f4a2713aSLionel Sambuc                                                const PartialDiagnostic &PDiag,
1590f4a2713aSLionel Sambuc                                                QualType ObjectTy) {
1591f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl)
1592f4a2713aSLionel Sambuc     return AR_accessible;
1593f4a2713aSLionel Sambuc 
1594f4a2713aSLionel Sambuc   // There's never a path involved when checking implicit destructor access.
1595f4a2713aSLionel Sambuc   AccessSpecifier Access = Dtor->getAccess();
1596f4a2713aSLionel Sambuc   if (Access == AS_public)
1597f4a2713aSLionel Sambuc     return AR_accessible;
1598f4a2713aSLionel Sambuc 
1599f4a2713aSLionel Sambuc   CXXRecordDecl *NamingClass = Dtor->getParent();
1600f4a2713aSLionel Sambuc   if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass);
1601f4a2713aSLionel Sambuc 
1602f4a2713aSLionel Sambuc   AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
1603f4a2713aSLionel Sambuc                       DeclAccessPair::make(Dtor, Access),
1604f4a2713aSLionel Sambuc                       ObjectTy);
1605f4a2713aSLionel Sambuc   Entity.setDiag(PDiag); // TODO: avoid copy
1606f4a2713aSLionel Sambuc 
1607f4a2713aSLionel Sambuc   return CheckAccess(*this, Loc, Entity);
1608f4a2713aSLionel Sambuc }
1609f4a2713aSLionel Sambuc 
1610f4a2713aSLionel Sambuc /// Checks access to a constructor.
CheckConstructorAccess(SourceLocation UseLoc,CXXConstructorDecl * Constructor,const InitializedEntity & Entity,AccessSpecifier Access,bool IsCopyBindingRefToTemp)1611f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
1612f4a2713aSLionel Sambuc                                                 CXXConstructorDecl *Constructor,
1613f4a2713aSLionel Sambuc                                                 const InitializedEntity &Entity,
1614f4a2713aSLionel Sambuc                                                 AccessSpecifier Access,
1615f4a2713aSLionel Sambuc                                                 bool IsCopyBindingRefToTemp) {
1616f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl || Access == AS_public)
1617f4a2713aSLionel Sambuc     return AR_accessible;
1618f4a2713aSLionel Sambuc 
1619f4a2713aSLionel Sambuc   PartialDiagnostic PD(PDiag());
1620f4a2713aSLionel Sambuc   switch (Entity.getKind()) {
1621f4a2713aSLionel Sambuc   default:
1622f4a2713aSLionel Sambuc     PD = PDiag(IsCopyBindingRefToTemp
1623f4a2713aSLionel Sambuc                  ? diag::ext_rvalue_to_reference_access_ctor
1624f4a2713aSLionel Sambuc                  : diag::err_access_ctor);
1625f4a2713aSLionel Sambuc 
1626f4a2713aSLionel Sambuc     break;
1627f4a2713aSLionel Sambuc 
1628f4a2713aSLionel Sambuc   case InitializedEntity::EK_Base:
1629f4a2713aSLionel Sambuc     PD = PDiag(diag::err_access_base_ctor);
1630f4a2713aSLionel Sambuc     PD << Entity.isInheritedVirtualBase()
1631f4a2713aSLionel Sambuc        << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
1632f4a2713aSLionel Sambuc     break;
1633f4a2713aSLionel Sambuc 
1634f4a2713aSLionel Sambuc   case InitializedEntity::EK_Member: {
1635f4a2713aSLionel Sambuc     const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
1636f4a2713aSLionel Sambuc     PD = PDiag(diag::err_access_field_ctor);
1637f4a2713aSLionel Sambuc     PD << Field->getType() << getSpecialMember(Constructor);
1638f4a2713aSLionel Sambuc     break;
1639f4a2713aSLionel Sambuc   }
1640f4a2713aSLionel Sambuc 
1641f4a2713aSLionel Sambuc   case InitializedEntity::EK_LambdaCapture: {
1642*0a6a1f1dSLionel Sambuc     StringRef VarName = Entity.getCapturedVarName();
1643f4a2713aSLionel Sambuc     PD = PDiag(diag::err_access_lambda_capture);
1644*0a6a1f1dSLionel Sambuc     PD << VarName << Entity.getType() << getSpecialMember(Constructor);
1645f4a2713aSLionel Sambuc     break;
1646f4a2713aSLionel Sambuc   }
1647f4a2713aSLionel Sambuc 
1648f4a2713aSLionel Sambuc   }
1649f4a2713aSLionel Sambuc 
1650f4a2713aSLionel Sambuc   return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD);
1651f4a2713aSLionel Sambuc }
1652f4a2713aSLionel Sambuc 
1653f4a2713aSLionel Sambuc /// Checks access to a constructor.
CheckConstructorAccess(SourceLocation UseLoc,CXXConstructorDecl * Constructor,const InitializedEntity & Entity,AccessSpecifier Access,const PartialDiagnostic & PD)1654f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
1655f4a2713aSLionel Sambuc                                                 CXXConstructorDecl *Constructor,
1656f4a2713aSLionel Sambuc                                                 const InitializedEntity &Entity,
1657f4a2713aSLionel Sambuc                                                 AccessSpecifier Access,
1658f4a2713aSLionel Sambuc                                                 const PartialDiagnostic &PD) {
1659f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl ||
1660f4a2713aSLionel Sambuc       Access == AS_public)
1661f4a2713aSLionel Sambuc     return AR_accessible;
1662f4a2713aSLionel Sambuc 
1663f4a2713aSLionel Sambuc   CXXRecordDecl *NamingClass = Constructor->getParent();
1664f4a2713aSLionel Sambuc 
1665f4a2713aSLionel Sambuc   // Initializing a base sub-object is an instance method call on an
1666f4a2713aSLionel Sambuc   // object of the derived class.  Otherwise, we have an instance method
1667f4a2713aSLionel Sambuc   // call on an object of the constructed type.
1668f4a2713aSLionel Sambuc   CXXRecordDecl *ObjectClass;
1669f4a2713aSLionel Sambuc   if (Entity.getKind() == InitializedEntity::EK_Base) {
1670f4a2713aSLionel Sambuc     ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent();
1671f4a2713aSLionel Sambuc   } else {
1672f4a2713aSLionel Sambuc     ObjectClass = NamingClass;
1673f4a2713aSLionel Sambuc   }
1674f4a2713aSLionel Sambuc 
1675f4a2713aSLionel Sambuc   AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
1676f4a2713aSLionel Sambuc                             DeclAccessPair::make(Constructor, Access),
1677f4a2713aSLionel Sambuc                             Context.getTypeDeclType(ObjectClass));
1678f4a2713aSLionel Sambuc   AccessEntity.setDiag(PD);
1679f4a2713aSLionel Sambuc 
1680f4a2713aSLionel Sambuc   return CheckAccess(*this, UseLoc, AccessEntity);
1681f4a2713aSLionel Sambuc }
1682f4a2713aSLionel Sambuc 
1683f4a2713aSLionel Sambuc /// Checks access to an overloaded operator new or delete.
CheckAllocationAccess(SourceLocation OpLoc,SourceRange PlacementRange,CXXRecordDecl * NamingClass,DeclAccessPair Found,bool Diagnose)1684f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
1685f4a2713aSLionel Sambuc                                                SourceRange PlacementRange,
1686f4a2713aSLionel Sambuc                                                CXXRecordDecl *NamingClass,
1687f4a2713aSLionel Sambuc                                                DeclAccessPair Found,
1688f4a2713aSLionel Sambuc                                                bool Diagnose) {
1689f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl ||
1690f4a2713aSLionel Sambuc       !NamingClass ||
1691f4a2713aSLionel Sambuc       Found.getAccess() == AS_public)
1692f4a2713aSLionel Sambuc     return AR_accessible;
1693f4a2713aSLionel Sambuc 
1694f4a2713aSLionel Sambuc   AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1695f4a2713aSLionel Sambuc                       QualType());
1696f4a2713aSLionel Sambuc   if (Diagnose)
1697f4a2713aSLionel Sambuc     Entity.setDiag(diag::err_access)
1698f4a2713aSLionel Sambuc       << PlacementRange;
1699f4a2713aSLionel Sambuc 
1700f4a2713aSLionel Sambuc   return CheckAccess(*this, OpLoc, Entity);
1701f4a2713aSLionel Sambuc }
1702f4a2713aSLionel Sambuc 
1703f4a2713aSLionel Sambuc /// \brief Checks access to a member.
CheckMemberAccess(SourceLocation UseLoc,CXXRecordDecl * NamingClass,DeclAccessPair Found)1704f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc,
1705f4a2713aSLionel Sambuc                                            CXXRecordDecl *NamingClass,
1706f4a2713aSLionel Sambuc                                            DeclAccessPair Found) {
1707f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl ||
1708f4a2713aSLionel Sambuc       !NamingClass ||
1709f4a2713aSLionel Sambuc       Found.getAccess() == AS_public)
1710f4a2713aSLionel Sambuc     return AR_accessible;
1711f4a2713aSLionel Sambuc 
1712f4a2713aSLionel Sambuc   AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
1713f4a2713aSLionel Sambuc                       Found, QualType());
1714f4a2713aSLionel Sambuc 
1715f4a2713aSLionel Sambuc   return CheckAccess(*this, UseLoc, Entity);
1716f4a2713aSLionel Sambuc }
1717f4a2713aSLionel Sambuc 
1718f4a2713aSLionel Sambuc /// Checks access to an overloaded member operator, including
1719f4a2713aSLionel Sambuc /// conversion operators.
CheckMemberOperatorAccess(SourceLocation OpLoc,Expr * ObjectExpr,Expr * ArgExpr,DeclAccessPair Found)1720f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
1721f4a2713aSLionel Sambuc                                                    Expr *ObjectExpr,
1722f4a2713aSLionel Sambuc                                                    Expr *ArgExpr,
1723f4a2713aSLionel Sambuc                                                    DeclAccessPair Found) {
1724f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl ||
1725f4a2713aSLionel Sambuc       Found.getAccess() == AS_public)
1726f4a2713aSLionel Sambuc     return AR_accessible;
1727f4a2713aSLionel Sambuc 
1728f4a2713aSLionel Sambuc   const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();
1729f4a2713aSLionel Sambuc   CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
1730f4a2713aSLionel Sambuc 
1731f4a2713aSLionel Sambuc   AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1732f4a2713aSLionel Sambuc                       ObjectExpr->getType());
1733f4a2713aSLionel Sambuc   Entity.setDiag(diag::err_access)
1734f4a2713aSLionel Sambuc     << ObjectExpr->getSourceRange()
1735f4a2713aSLionel Sambuc     << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
1736f4a2713aSLionel Sambuc 
1737f4a2713aSLionel Sambuc   return CheckAccess(*this, OpLoc, Entity);
1738f4a2713aSLionel Sambuc }
1739f4a2713aSLionel Sambuc 
1740f4a2713aSLionel Sambuc /// Checks access to the target of a friend declaration.
CheckFriendAccess(NamedDecl * target)1741f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
1742*0a6a1f1dSLionel Sambuc   assert(isa<CXXMethodDecl>(target->getAsFunction()));
1743f4a2713aSLionel Sambuc 
1744f4a2713aSLionel Sambuc   // Friendship lookup is a redeclaration lookup, so there's never an
1745f4a2713aSLionel Sambuc   // inheritance path modifying access.
1746f4a2713aSLionel Sambuc   AccessSpecifier access = target->getAccess();
1747f4a2713aSLionel Sambuc 
1748f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl || access == AS_public)
1749f4a2713aSLionel Sambuc     return AR_accessible;
1750f4a2713aSLionel Sambuc 
1751*0a6a1f1dSLionel Sambuc   CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction());
1752f4a2713aSLionel Sambuc 
1753f4a2713aSLionel Sambuc   AccessTarget entity(Context, AccessTarget::Member,
1754f4a2713aSLionel Sambuc                       cast<CXXRecordDecl>(target->getDeclContext()),
1755f4a2713aSLionel Sambuc                       DeclAccessPair::make(target, access),
1756f4a2713aSLionel Sambuc                       /*no instance context*/ QualType());
1757f4a2713aSLionel Sambuc   entity.setDiag(diag::err_access_friend_function)
1758*0a6a1f1dSLionel Sambuc       << (method->getQualifier() ? method->getQualifierLoc().getSourceRange()
1759*0a6a1f1dSLionel Sambuc                                  : method->getNameInfo().getSourceRange());
1760f4a2713aSLionel Sambuc 
1761f4a2713aSLionel Sambuc   // We need to bypass delayed-diagnostics because we might be called
1762f4a2713aSLionel Sambuc   // while the ParsingDeclarator is active.
1763f4a2713aSLionel Sambuc   EffectiveContext EC(CurContext);
1764f4a2713aSLionel Sambuc   switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) {
1765f4a2713aSLionel Sambuc   case AR_accessible: return Sema::AR_accessible;
1766f4a2713aSLionel Sambuc   case AR_inaccessible: return Sema::AR_inaccessible;
1767f4a2713aSLionel Sambuc   case AR_dependent: return Sema::AR_dependent;
1768f4a2713aSLionel Sambuc   }
1769f4a2713aSLionel Sambuc   llvm_unreachable("falling off end");
1770f4a2713aSLionel Sambuc }
1771f4a2713aSLionel Sambuc 
CheckAddressOfMemberAccess(Expr * OvlExpr,DeclAccessPair Found)1772f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
1773f4a2713aSLionel Sambuc                                                     DeclAccessPair Found) {
1774f4a2713aSLionel Sambuc   if (!getLangOpts().AccessControl ||
1775f4a2713aSLionel Sambuc       Found.getAccess() == AS_none ||
1776f4a2713aSLionel Sambuc       Found.getAccess() == AS_public)
1777f4a2713aSLionel Sambuc     return AR_accessible;
1778f4a2713aSLionel Sambuc 
1779f4a2713aSLionel Sambuc   OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression;
1780f4a2713aSLionel Sambuc   CXXRecordDecl *NamingClass = Ovl->getNamingClass();
1781f4a2713aSLionel Sambuc 
1782f4a2713aSLionel Sambuc   AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1783f4a2713aSLionel Sambuc                       /*no instance context*/ QualType());
1784f4a2713aSLionel Sambuc   Entity.setDiag(diag::err_access)
1785f4a2713aSLionel Sambuc     << Ovl->getSourceRange();
1786f4a2713aSLionel Sambuc 
1787f4a2713aSLionel Sambuc   return CheckAccess(*this, Ovl->getNameLoc(), Entity);
1788f4a2713aSLionel Sambuc }
1789f4a2713aSLionel Sambuc 
1790f4a2713aSLionel Sambuc /// Checks access for a hierarchy conversion.
1791f4a2713aSLionel Sambuc ///
1792f4a2713aSLionel Sambuc /// \param ForceCheck true if this check should be performed even if access
1793f4a2713aSLionel Sambuc ///     control is disabled;  some things rely on this for semantics
1794f4a2713aSLionel Sambuc /// \param ForceUnprivileged true if this check should proceed as if the
1795f4a2713aSLionel Sambuc ///     context had no special privileges
CheckBaseClassAccess(SourceLocation AccessLoc,QualType Base,QualType Derived,const CXXBasePath & Path,unsigned DiagID,bool ForceCheck,bool ForceUnprivileged)1796f4a2713aSLionel Sambuc Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
1797f4a2713aSLionel Sambuc                                               QualType Base,
1798f4a2713aSLionel Sambuc                                               QualType Derived,
1799f4a2713aSLionel Sambuc                                               const CXXBasePath &Path,
1800f4a2713aSLionel Sambuc                                               unsigned DiagID,
1801f4a2713aSLionel Sambuc                                               bool ForceCheck,
1802f4a2713aSLionel Sambuc                                               bool ForceUnprivileged) {
1803f4a2713aSLionel Sambuc   if (!ForceCheck && !getLangOpts().AccessControl)
1804f4a2713aSLionel Sambuc     return AR_accessible;
1805f4a2713aSLionel Sambuc 
1806f4a2713aSLionel Sambuc   if (Path.Access == AS_public)
1807f4a2713aSLionel Sambuc     return AR_accessible;
1808f4a2713aSLionel Sambuc 
1809f4a2713aSLionel Sambuc   CXXRecordDecl *BaseD, *DerivedD;
1810f4a2713aSLionel Sambuc   BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
1811f4a2713aSLionel Sambuc   DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
1812f4a2713aSLionel Sambuc 
1813f4a2713aSLionel Sambuc   AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,
1814f4a2713aSLionel Sambuc                       Path.Access);
1815f4a2713aSLionel Sambuc   if (DiagID)
1816f4a2713aSLionel Sambuc     Entity.setDiag(DiagID) << Derived << Base;
1817f4a2713aSLionel Sambuc 
1818f4a2713aSLionel Sambuc   if (ForceUnprivileged) {
1819f4a2713aSLionel Sambuc     switch (CheckEffectiveAccess(*this, EffectiveContext(),
1820f4a2713aSLionel Sambuc                                  AccessLoc, Entity)) {
1821f4a2713aSLionel Sambuc     case ::AR_accessible: return Sema::AR_accessible;
1822f4a2713aSLionel Sambuc     case ::AR_inaccessible: return Sema::AR_inaccessible;
1823f4a2713aSLionel Sambuc     case ::AR_dependent: return Sema::AR_dependent;
1824f4a2713aSLionel Sambuc     }
1825f4a2713aSLionel Sambuc     llvm_unreachable("unexpected result from CheckEffectiveAccess");
1826f4a2713aSLionel Sambuc   }
1827f4a2713aSLionel Sambuc   return CheckAccess(*this, AccessLoc, Entity);
1828f4a2713aSLionel Sambuc }
1829f4a2713aSLionel Sambuc 
1830f4a2713aSLionel Sambuc /// Checks access to all the declarations in the given result set.
CheckLookupAccess(const LookupResult & R)1831f4a2713aSLionel Sambuc void Sema::CheckLookupAccess(const LookupResult &R) {
1832f4a2713aSLionel Sambuc   assert(getLangOpts().AccessControl
1833f4a2713aSLionel Sambuc          && "performing access check without access control");
1834f4a2713aSLionel Sambuc   assert(R.getNamingClass() && "performing access check without naming class");
1835f4a2713aSLionel Sambuc 
1836f4a2713aSLionel Sambuc   for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
1837f4a2713aSLionel Sambuc     if (I.getAccess() != AS_public) {
1838f4a2713aSLionel Sambuc       AccessTarget Entity(Context, AccessedEntity::Member,
1839f4a2713aSLionel Sambuc                           R.getNamingClass(), I.getPair(),
1840f4a2713aSLionel Sambuc                           R.getBaseObjectType());
1841f4a2713aSLionel Sambuc       Entity.setDiag(diag::err_access);
1842f4a2713aSLionel Sambuc       CheckAccess(*this, R.getNameLoc(), Entity);
1843f4a2713aSLionel Sambuc     }
1844f4a2713aSLionel Sambuc   }
1845f4a2713aSLionel Sambuc }
1846f4a2713aSLionel Sambuc 
1847f4a2713aSLionel Sambuc /// Checks access to Decl from the given class. The check will take access
1848f4a2713aSLionel Sambuc /// specifiers into account, but no member access expressions and such.
1849f4a2713aSLionel Sambuc ///
1850f4a2713aSLionel Sambuc /// \param Decl the declaration to check if it can be accessed
1851f4a2713aSLionel Sambuc /// \param Ctx the class/context from which to start the search
1852f4a2713aSLionel Sambuc /// \return true if the Decl is accessible from the Class, false otherwise.
IsSimplyAccessible(NamedDecl * Decl,DeclContext * Ctx)1853f4a2713aSLionel Sambuc bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) {
1854f4a2713aSLionel Sambuc   if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) {
1855f4a2713aSLionel Sambuc     if (!Decl->isCXXClassMember())
1856f4a2713aSLionel Sambuc       return true;
1857f4a2713aSLionel Sambuc 
1858f4a2713aSLionel Sambuc     QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal();
1859f4a2713aSLionel Sambuc     AccessTarget Entity(Context, AccessedEntity::Member, Class,
1860f4a2713aSLionel Sambuc                         DeclAccessPair::make(Decl, Decl->getAccess()),
1861f4a2713aSLionel Sambuc                         qType);
1862f4a2713aSLionel Sambuc     if (Entity.getAccess() == AS_public)
1863f4a2713aSLionel Sambuc       return true;
1864f4a2713aSLionel Sambuc 
1865f4a2713aSLionel Sambuc     EffectiveContext EC(CurContext);
1866f4a2713aSLionel Sambuc     return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
1867f4a2713aSLionel Sambuc   }
1868f4a2713aSLionel Sambuc 
1869f4a2713aSLionel Sambuc   if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) {
1870f4a2713aSLionel Sambuc     // @public and @package ivars are always accessible.
1871f4a2713aSLionel Sambuc     if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||
1872f4a2713aSLionel Sambuc         Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package)
1873f4a2713aSLionel Sambuc       return true;
1874f4a2713aSLionel Sambuc 
1875f4a2713aSLionel Sambuc     // If we are inside a class or category implementation, determine the
1876f4a2713aSLionel Sambuc     // interface we're in.
1877*0a6a1f1dSLionel Sambuc     ObjCInterfaceDecl *ClassOfMethodDecl = nullptr;
1878f4a2713aSLionel Sambuc     if (ObjCMethodDecl *MD = getCurMethodDecl())
1879f4a2713aSLionel Sambuc       ClassOfMethodDecl =  MD->getClassInterface();
1880f4a2713aSLionel Sambuc     else if (FunctionDecl *FD = getCurFunctionDecl()) {
1881f4a2713aSLionel Sambuc       if (ObjCImplDecl *Impl
1882f4a2713aSLionel Sambuc             = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) {
1883f4a2713aSLionel Sambuc         if (ObjCImplementationDecl *IMPD
1884f4a2713aSLionel Sambuc               = dyn_cast<ObjCImplementationDecl>(Impl))
1885f4a2713aSLionel Sambuc           ClassOfMethodDecl = IMPD->getClassInterface();
1886f4a2713aSLionel Sambuc         else if (ObjCCategoryImplDecl* CatImplClass
1887f4a2713aSLionel Sambuc                    = dyn_cast<ObjCCategoryImplDecl>(Impl))
1888f4a2713aSLionel Sambuc           ClassOfMethodDecl = CatImplClass->getClassInterface();
1889f4a2713aSLionel Sambuc       }
1890f4a2713aSLionel Sambuc     }
1891f4a2713aSLionel Sambuc 
1892f4a2713aSLionel Sambuc     // If we're not in an interface, this ivar is inaccessible.
1893f4a2713aSLionel Sambuc     if (!ClassOfMethodDecl)
1894f4a2713aSLionel Sambuc       return false;
1895f4a2713aSLionel Sambuc 
1896f4a2713aSLionel Sambuc     // If we're inside the same interface that owns the ivar, we're fine.
1897f4a2713aSLionel Sambuc     if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface()))
1898f4a2713aSLionel Sambuc       return true;
1899f4a2713aSLionel Sambuc 
1900f4a2713aSLionel Sambuc     // If the ivar is private, it's inaccessible.
1901f4a2713aSLionel Sambuc     if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private)
1902f4a2713aSLionel Sambuc       return false;
1903f4a2713aSLionel Sambuc 
1904f4a2713aSLionel Sambuc     return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl);
1905f4a2713aSLionel Sambuc   }
1906f4a2713aSLionel Sambuc 
1907f4a2713aSLionel Sambuc   return true;
1908f4a2713aSLionel Sambuc }
1909