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

source code of clang/lib/Sema/SemaAccess.cpp