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