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