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