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