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(MemberDecl->getLocation(),
48 diag::err_class_redeclared_with_different_access)
49 << MemberDecl << LexicalAS;
50 Diag(PrevMemberDecl->getLocation(), 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>(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(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>(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(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->getDeclContext(),
388 Friend->getDeclContext()))
389 return false;
390
391 CanQual<FunctionProtoType> FriendTy
392 = S.Context.getCanonicalType(Friend->getType())
393 ->getAs<FunctionProtoType>();
394 CanQual<FunctionProtoType> ContextTy
395 = S.Context.getCanonicalType(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, ContextTy->getReturnType(),
407 FriendTy->getReturnType()))
408 return false;
409
410 for (unsigned I = 0, E = FriendTy->getNumParams(); I != E; ++I)
411 if (!MightInstantiateTo(S, ContextTy->getParamType(I),
412 FriendTy->getParamType(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, CTD->getDeclContext(),
498 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, T->getType()->getCanonicalTypeUnqualified());
569
570 NamedDecl *Friend
571 = cast<NamedDecl>(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(D->getLocation(), diag::note_access_protected_restricted_noobject)
1075 << S.Context.getTypeDeclType(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(D->getLocation(),
1097 diag::note_access_protected_restricted_ctordtor)
1098 << isa<CXXDestructorDecl>(D->getAsFunction());
1099 }
1100
1101 // Otherwise, use the generic diagnostic.
1102 return S.Diag(D->getLocation(),
1103 diag::note_access_protected_restricted_object)
1104 << S.Context.getTypeDeclType(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 (isa<RecordDecl>(Val: D) && cast<RecordDecl>(Val: D)->isInjectedClassName())
1133 break;
1134 PrevDecl = TD->getPreviousDecl();
1135 }
1136 if (!PrevDecl) break;
1137 D = PrevDecl;
1138 }
1139
1140 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
1141 Decl *ImmediateChild;
1142 if (D->getDeclContext() == DeclaringClass)
1143 ImmediateChild = D;
1144 else {
1145 DeclContext *DC = D->getDeclContext();
1146 while (DC->getParent() != DeclaringClass)
1147 DC = DC->getParent();
1148 ImmediateChild = cast<Decl>(Val: DC);
1149 }
1150
1151 // Check whether there's an AccessSpecDecl preceding this in the
1152 // chain of the DeclContext.
1153 bool isImplicit = true;
1154 for (const auto *I : DeclaringClass->decls()) {
1155 if (I == ImmediateChild) break;
1156 if (isa<AccessSpecDecl>(I)) {
1157 isImplicit = false;
1158 break;
1159 }
1160 }
1161
1162 S.Diag(D->getLocation(), diag::note_access_natural)
1163 << (unsigned) (D->getAccess() == AS_protected)
1164 << isImplicit;
1165}
1166
1167/// Diagnose the path which caused the given declaration or base class
1168/// to become inaccessible.
1169static void DiagnoseAccessPath(Sema &S,
1170 const EffectiveContext &EC,
1171 AccessTarget &entity) {
1172 // Save the instance context to preserve invariants.
1173 AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext();
1174
1175 // This basically repeats the main algorithm but keeps some more
1176 // information.
1177
1178 // The natural access so far.
1179 AccessSpecifier accessSoFar = AS_public;
1180
1181 // Check whether we have special rights to the declaring class.
1182 if (entity.isMemberAccess()) {
1183 NamedDecl *D = entity.getTargetDecl();
1184 accessSoFar = D->getAccess();
1185 const CXXRecordDecl *declaringClass = entity.getDeclaringClass();
1186
1187 switch (HasAccess(S, EC, NamingClass: declaringClass, Access: accessSoFar, Target: entity)) {
1188 // If the declaration is accessible when named in its declaring
1189 // class, then we must be constrained by the path.
1190 case AR_accessible:
1191 accessSoFar = AS_public;
1192 entity.suppressInstanceContext();
1193 break;
1194
1195 case AR_inaccessible:
1196 if (accessSoFar == AS_private ||
1197 declaringClass == entity.getEffectiveNamingClass())
1198 return diagnoseBadDirectAccess(S, EC, entity);
1199 break;
1200
1201 case AR_dependent:
1202 llvm_unreachable("cannot diagnose dependent access");
1203 }
1204 }
1205
1206 CXXBasePaths paths;
1207 CXXBasePath &path = *FindBestPath(S, EC, Target&: entity, FinalAccess: accessSoFar, Paths&: paths);
1208 assert(path.Access != AS_public);
1209
1210 CXXBasePath::iterator i = path.end(), e = path.begin();
1211 CXXBasePath::iterator constrainingBase = i;
1212 while (i != e) {
1213 --i;
1214
1215 assert(accessSoFar != AS_none && accessSoFar != AS_private);
1216
1217 // Is the entity accessible when named in the deriving class, as
1218 // modified by the base specifier?
1219 const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl();
1220 const CXXBaseSpecifier *base = i->Base;
1221
1222 // If the access to this base is worse than the access we have to
1223 // the declaration, remember it.
1224 AccessSpecifier baseAccess = base->getAccessSpecifier();
1225 if (baseAccess > accessSoFar) {
1226 constrainingBase = i;
1227 accessSoFar = baseAccess;
1228 }
1229
1230 switch (HasAccess(S, EC, NamingClass: derivingClass, Access: accessSoFar, Target: entity)) {
1231 case AR_inaccessible: break;
1232 case AR_accessible:
1233 accessSoFar = AS_public;
1234 entity.suppressInstanceContext();
1235 constrainingBase = nullptr;
1236 break;
1237 case AR_dependent:
1238 llvm_unreachable("cannot diagnose dependent access");
1239 }
1240
1241 // If this was private inheritance, but we don't have access to
1242 // the deriving class, we're done.
1243 if (accessSoFar == AS_private) {
1244 assert(baseAccess == AS_private);
1245 assert(constrainingBase == i);
1246 break;
1247 }
1248 }
1249
1250 // If we don't have a constraining base, the access failure must be
1251 // due to the original declaration.
1252 if (constrainingBase == path.end())
1253 return diagnoseBadDirectAccess(S, EC, entity);
1254
1255 // We're constrained by inheritance, but we want to say
1256 // "declared private here" if we're diagnosing a hierarchy
1257 // conversion and this is the final step.
1258 unsigned diagnostic;
1259 if (entity.isMemberAccess() ||
1260 constrainingBase + 1 != path.end()) {
1261 diagnostic = diag::note_access_constrained_by_path;
1262 } else {
1263 diagnostic = diag::note_access_natural;
1264 }
1265
1266 const CXXBaseSpecifier *base = constrainingBase->Base;
1267
1268 S.Diag(base->getSourceRange().getBegin(), diagnostic)
1269 << base->getSourceRange()
1270 << (base->getAccessSpecifier() == AS_protected)
1271 << (base->getAccessSpecifierAsWritten() == AS_none);
1272
1273 if (entity.isMemberAccess())
1274 S.Diag(entity.getTargetDecl()->getLocation(),
1275 diag::note_member_declared_at);
1276}
1277
1278static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
1279 const EffectiveContext &EC,
1280 AccessTarget &Entity) {
1281 const CXXRecordDecl *NamingClass = Entity.getNamingClass();
1282 const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
1283 NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : nullptr);
1284
1285 S.Diag(Loc, Entity.getDiag())
1286 << (Entity.getAccess() == AS_protected)
1287 << (D ? D->getDeclName() : DeclarationName())
1288 << S.Context.getTypeDeclType(NamingClass)
1289 << S.Context.getTypeDeclType(DeclaringClass);
1290 DiagnoseAccessPath(S, EC, entity&: Entity);
1291}
1292
1293/// MSVC has a bug where if during an using declaration name lookup,
1294/// the declaration found is unaccessible (private) and that declaration
1295/// was bring into scope via another using declaration whose target
1296/// declaration is accessible (public) then no error is generated.
1297/// Example:
1298/// class A {
1299/// public:
1300/// int f();
1301/// };
1302/// class B : public A {
1303/// private:
1304/// using A::f;
1305/// };
1306/// class C : public B {
1307/// private:
1308/// using B::f;
1309/// };
1310///
1311/// Here, B::f is private so this should fail in Standard C++, but
1312/// because B::f refers to A::f which is public MSVC accepts it.
1313static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
1314 SourceLocation AccessLoc,
1315 AccessTarget &Entity) {
1316 if (UsingShadowDecl *Shadow =
1317 dyn_cast<UsingShadowDecl>(Entity.getTargetDecl()))
1318 if (UsingDecl *UD = dyn_cast<UsingDecl>(Val: Shadow->getIntroducer())) {
1319 const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl();
1320 if (Entity.getTargetDecl()->getAccess() == AS_private &&
1321 (OrigDecl->getAccess() == AS_public ||
1322 OrigDecl->getAccess() == AS_protected)) {
1323 S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible)
1324 << UD->getQualifiedNameAsString()
1325 << OrigDecl->getQualifiedNameAsString();
1326 return true;
1327 }
1328 }
1329 return false;
1330}
1331
1332/// Determines whether the accessed entity is accessible. Public members
1333/// have been weeded out by this point.
1334static AccessResult IsAccessible(Sema &S,
1335 const EffectiveContext &EC,
1336 AccessTarget &Entity) {
1337 // Determine the actual naming class.
1338 const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();
1339
1340 AccessSpecifier UnprivilegedAccess = Entity.getAccess();
1341 assert(UnprivilegedAccess != AS_public && "public access not weeded out");
1342
1343 // Before we try to recalculate access paths, try to white-list
1344 // accesses which just trade in on the final step, i.e. accesses
1345 // which don't require [M4] or [B4]. These are by far the most
1346 // common forms of privileged access.
1347 if (UnprivilegedAccess != AS_none) {
1348 switch (HasAccess(S, EC, NamingClass, Access: UnprivilegedAccess, Target: Entity)) {
1349 case AR_dependent:
1350 // This is actually an interesting policy decision. We don't
1351 // *have* to delay immediately here: we can do the full access
1352 // calculation in the hope that friendship on some intermediate
1353 // class will make the declaration accessible non-dependently.
1354 // But that's not cheap, and odds are very good (note: assertion
1355 // made without data) that the friend declaration will determine
1356 // access.
1357 return AR_dependent;
1358
1359 case AR_accessible: return AR_accessible;
1360 case AR_inaccessible: break;
1361 }
1362 }
1363
1364 AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();
1365
1366 // We lower member accesses to base accesses by pretending that the
1367 // member is a base class of its declaring class.
1368 AccessSpecifier FinalAccess;
1369
1370 if (Entity.isMemberAccess()) {
1371 // Determine if the declaration is accessible from EC when named
1372 // in its declaring class.
1373 NamedDecl *Target = Entity.getTargetDecl();
1374 const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
1375
1376 FinalAccess = Target->getAccess();
1377 switch (HasAccess(S, EC, NamingClass: DeclaringClass, Access: FinalAccess, Target: Entity)) {
1378 case AR_accessible:
1379 // Target is accessible at EC when named in its declaring class.
1380 // We can now hill-climb and simply check whether the declaring
1381 // class is accessible as a base of the naming class. This is
1382 // equivalent to checking the access of a notional public
1383 // member with no instance context.
1384 FinalAccess = AS_public;
1385 Entity.suppressInstanceContext();
1386 break;
1387 case AR_inaccessible: break;
1388 case AR_dependent: return AR_dependent; // see above
1389 }
1390
1391 if (DeclaringClass == NamingClass)
1392 return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
1393 } else {
1394 FinalAccess = AS_public;
1395 }
1396
1397 assert(Entity.getDeclaringClass() != NamingClass);
1398
1399 // Append the declaration's access if applicable.
1400 CXXBasePaths Paths;
1401 CXXBasePath *Path = FindBestPath(S, EC, Target&: Entity, FinalAccess, Paths);
1402 if (!Path)
1403 return AR_dependent;
1404
1405 assert(Path->Access <= UnprivilegedAccess &&
1406 "access along best path worse than direct?");
1407 if (Path->Access == AS_public)
1408 return AR_accessible;
1409 return AR_inaccessible;
1410}
1411
1412static void DelayDependentAccess(Sema &S,
1413 const EffectiveContext &EC,
1414 SourceLocation Loc,
1415 const AccessTarget &Entity) {
1416 assert(EC.isDependent() && "delaying non-dependent access");
1417 DeclContext *DC = EC.getInnerContext();
1418 assert(DC->isDependentContext() && "delaying non-dependent access");
1419 DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
1420 Loc,
1421 Entity.isMemberAccess(),
1422 Entity.getAccess(),
1423 Entity.getTargetDecl(),
1424 Entity.getNamingClass(),
1425 Entity.getBaseObjectType(),
1426 Entity.getDiag());
1427}
1428
1429/// Checks access to an entity from the given effective context.
1430static AccessResult CheckEffectiveAccess(Sema &S,
1431 const EffectiveContext &EC,
1432 SourceLocation Loc,
1433 AccessTarget &Entity) {
1434 assert(Entity.getAccess() != AS_public && "called for public access!");
1435
1436 switch (IsAccessible(S, EC, Entity)) {
1437 case AR_dependent:
1438 DelayDependentAccess(S, EC, Loc, Entity);
1439 return AR_dependent;
1440
1441 case AR_inaccessible:
1442 if (S.getLangOpts().MSVCCompat &&
1443 IsMicrosoftUsingDeclarationAccessBug(S, AccessLoc: Loc, Entity))
1444 return AR_accessible;
1445 if (!Entity.isQuiet())
1446 DiagnoseBadAccess(S, Loc, EC, Entity);
1447 return AR_inaccessible;
1448
1449 case AR_accessible:
1450 return AR_accessible;
1451 }
1452
1453 // silence unnecessary warning
1454 llvm_unreachable("invalid access result");
1455}
1456
1457static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
1458 AccessTarget &Entity) {
1459 // If the access path is public, it's accessible everywhere.
1460 if (Entity.getAccess() == AS_public)
1461 return Sema::AR_accessible;
1462
1463 // If we're currently parsing a declaration, we may need to delay
1464 // access control checking, because our effective context might be
1465 // different based on what the declaration comes out as.
1466 //
1467 // For example, we might be parsing a declaration with a scope
1468 // specifier, like this:
1469 // A::private_type A::foo() { ... }
1470 //
1471 // friend declaration should not be delayed because it may lead to incorrect
1472 // redeclaration chain, such as:
1473 // class D {
1474 // class E{
1475 // class F{};
1476 // friend void foo(D::E::F& q);
1477 // };
1478 // friend void foo(D::E::F& q);
1479 // };
1480 if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
1481 // [class.friend]p9:
1482 // A member nominated by a friend declaration shall be accessible in the
1483 // class containing the friend declaration. The meaning of the friend
1484 // declaration is the same whether the friend declaration appears in the
1485 // private, protected, or public ([class.mem]) portion of the class
1486 // member-specification.
1487 Scope *TS = S.getCurScope();
1488 bool IsFriendDeclaration = false;
1489 while (TS && !IsFriendDeclaration) {
1490 IsFriendDeclaration = TS->isFriendScope();
1491 TS = TS->getParent();
1492 }
1493 if (!IsFriendDeclaration) {
1494 S.DelayedDiagnostics.add(diag: DelayedDiagnostic::makeAccess(Loc, Entity));
1495 return Sema::AR_delayed;
1496 }
1497 }
1498
1499 EffectiveContext EC(S.CurContext);
1500 switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
1501 case AR_accessible: return Sema::AR_accessible;
1502 case AR_inaccessible: return Sema::AR_inaccessible;
1503 case AR_dependent: return Sema::AR_dependent;
1504 }
1505 llvm_unreachable("invalid access result");
1506}
1507
1508void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
1509 // Access control for names used in the declarations of functions
1510 // and function templates should normally be evaluated in the context
1511 // of the declaration, just in case it's a friend of something.
1512 // However, this does not apply to local extern declarations.
1513
1514 DeclContext *DC = D->getDeclContext();
1515 if (D->isLocalExternDecl()) {
1516 DC = D->getLexicalDeclContext();
1517 } else if (FunctionDecl *FN = dyn_cast<FunctionDecl>(Val: D)) {
1518 DC = FN;
1519 } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(Val: D)) {
1520 if (auto *D = dyn_cast_if_present<DeclContext>(Val: TD->getTemplatedDecl()))
1521 DC = D;
1522 } else if (auto *RD = dyn_cast<RequiresExprBodyDecl>(Val: D)) {
1523 DC = RD;
1524 }
1525
1526 EffectiveContext EC(DC);
1527
1528 AccessTarget Target(DD.getAccessData());
1529
1530 if (CheckEffectiveAccess(S&: *this, EC, Loc: DD.Loc, Entity&: Target) == ::AR_inaccessible)
1531 DD.Triggered = true;
1532}
1533
1534void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
1535 const MultiLevelTemplateArgumentList &TemplateArgs) {
1536 SourceLocation Loc = DD.getAccessLoc();
1537 AccessSpecifier Access = DD.getAccess();
1538
1539 Decl *NamingD = FindInstantiatedDecl(Loc, D: DD.getAccessNamingClass(),
1540 TemplateArgs);
1541 if (!NamingD) return;
1542 Decl *TargetD = FindInstantiatedDecl(Loc, D: DD.getAccessTarget(),
1543 TemplateArgs);
1544 if (!TargetD) return;
1545
1546 if (DD.isAccessToMember()) {
1547 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Val: NamingD);
1548 NamedDecl *TargetDecl = cast<NamedDecl>(Val: TargetD);
1549 QualType BaseObjectType = DD.getAccessBaseObjectType();
1550 if (!BaseObjectType.isNull()) {
1551 BaseObjectType = SubstType(T: BaseObjectType, TemplateArgs, Loc,
1552 Entity: DeclarationName());
1553 if (BaseObjectType.isNull()) return;
1554 }
1555
1556 AccessTarget Entity(Context,
1557 AccessTarget::Member,
1558 NamingClass,
1559 DeclAccessPair::make(D: TargetDecl, AS: Access),
1560 BaseObjectType);
1561 Entity.setDiag(DD.getDiagnostic());
1562 CheckAccess(S&: *this, Loc, Entity);
1563 } else {
1564 AccessTarget Entity(Context,
1565 AccessTarget::Base,
1566 cast<CXXRecordDecl>(Val: TargetD),
1567 cast<CXXRecordDecl>(Val: NamingD),
1568 Access);
1569 Entity.setDiag(DD.getDiagnostic());
1570 CheckAccess(S&: *this, Loc, Entity);
1571 }
1572}
1573
1574Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
1575 DeclAccessPair Found) {
1576 if (!getLangOpts().AccessControl ||
1577 !E->getNamingClass() ||
1578 Found.getAccess() == AS_public)
1579 return AR_accessible;
1580
1581 AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
1582 Found, QualType());
1583 Entity.setDiag(diag::err_access) << E->getSourceRange();
1584
1585 return CheckAccess(*this, E->getNameLoc(), Entity);
1586}
1587
1588Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
1589 DeclAccessPair Found) {
1590 if (!getLangOpts().AccessControl ||
1591 Found.getAccess() == AS_public)
1592 return AR_accessible;
1593
1594 QualType BaseType = E->getBaseType();
1595 if (E->isArrow())
1596 BaseType = BaseType->castAs<PointerType>()->getPointeeType();
1597
1598 AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
1599 Found, BaseType);
1600 Entity.setDiag(diag::err_access) << E->getSourceRange();
1601
1602 return CheckAccess(S&: *this, Loc: E->getMemberLoc(), Entity);
1603}
1604
1605bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass,
1606 DeclAccessPair Found,
1607 QualType ObjectType,
1608 SourceLocation Loc,
1609 const PartialDiagnostic &Diag) {
1610 // Fast path.
1611 if (Found.getAccess() == AS_public || !getLangOpts().AccessControl)
1612 return true;
1613
1614 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1615 ObjectType);
1616
1617 // Suppress diagnostics.
1618 Entity.setDiag(Diag);
1619
1620 switch (CheckAccess(S&: *this, Loc, Entity)) {
1621 case AR_accessible: return true;
1622 case AR_inaccessible: return false;
1623 case AR_dependent: llvm_unreachable("dependent for =delete computation");
1624 case AR_delayed: llvm_unreachable("cannot delay =delete computation");
1625 }
1626 llvm_unreachable("bad access result");
1627}
1628
1629Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
1630 CXXDestructorDecl *Dtor,
1631 const PartialDiagnostic &PDiag,
1632 QualType ObjectTy) {
1633 if (!getLangOpts().AccessControl)
1634 return AR_accessible;
1635
1636 // There's never a path involved when checking implicit destructor access.
1637 AccessSpecifier Access = Dtor->getAccess();
1638 if (Access == AS_public)
1639 return AR_accessible;
1640
1641 CXXRecordDecl *NamingClass = Dtor->getParent();
1642 if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass);
1643
1644 AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
1645 DeclAccessPair::make(Dtor, Access),
1646 ObjectTy);
1647 Entity.setDiag(PDiag); // TODO: avoid copy
1648
1649 return CheckAccess(S&: *this, Loc, Entity);
1650}
1651
1652Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
1653 CXXConstructorDecl *Constructor,
1654 DeclAccessPair Found,
1655 const InitializedEntity &Entity,
1656 bool IsCopyBindingRefToTemp) {
1657 if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
1658 return AR_accessible;
1659
1660 PartialDiagnostic PD(PDiag());
1661 switch (Entity.getKind()) {
1662 default:
1663 PD = PDiag(IsCopyBindingRefToTemp
1664 ? diag::ext_rvalue_to_reference_access_ctor
1665 : diag::err_access_ctor);
1666
1667 break;
1668
1669 case InitializedEntity::EK_Base:
1670 PD = PDiag(diag::err_access_base_ctor);
1671 PD << Entity.isInheritedVirtualBase()
1672 << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
1673 break;
1674
1675 case InitializedEntity::EK_Member:
1676 case InitializedEntity::EK_ParenAggInitMember: {
1677 const FieldDecl *Field = cast<FieldDecl>(Val: Entity.getDecl());
1678 PD = PDiag(diag::err_access_field_ctor);
1679 PD << Field->getType() << getSpecialMember(Constructor);
1680 break;
1681 }
1682
1683 case InitializedEntity::EK_LambdaCapture: {
1684 StringRef VarName = Entity.getCapturedVarName();
1685 PD = PDiag(diag::err_access_lambda_capture);
1686 PD << VarName << Entity.getType() << getSpecialMember(Constructor);
1687 break;
1688 }
1689
1690 }
1691
1692 return CheckConstructorAccess(Loc: UseLoc, D: Constructor, FoundDecl: Found, Entity, PDiag: PD);
1693}
1694
1695Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
1696 CXXConstructorDecl *Constructor,
1697 DeclAccessPair Found,
1698 const InitializedEntity &Entity,
1699 const PartialDiagnostic &PD) {
1700 if (!getLangOpts().AccessControl ||
1701 Found.getAccess() == AS_public)
1702 return AR_accessible;
1703
1704 CXXRecordDecl *NamingClass = Constructor->getParent();
1705
1706 // Initializing a base sub-object is an instance method call on an
1707 // object of the derived class. Otherwise, we have an instance method
1708 // call on an object of the constructed type.
1709 //
1710 // FIXME: If we have a parent, we're initializing the base class subobject
1711 // in aggregate initialization. It's not clear whether the object class
1712 // should be the base class or the derived class in that case.
1713 CXXRecordDecl *ObjectClass;
1714 if ((Entity.getKind() == InitializedEntity::EK_Base ||
1715 Entity.getKind() == InitializedEntity::EK_Delegating) &&
1716 !Entity.getParent()) {
1717 ObjectClass = cast<CXXConstructorDecl>(Val: CurContext)->getParent();
1718 } else if (auto *Shadow =
1719 dyn_cast<ConstructorUsingShadowDecl>(Val: Found.getDecl())) {
1720 // If we're using an inheriting constructor to construct an object,
1721 // the object class is the derived class, not the base class.
1722 ObjectClass = Shadow->getParent();
1723 } else {
1724 ObjectClass = NamingClass;
1725 }
1726
1727 AccessTarget AccessEntity(
1728 Context, AccessTarget::Member, NamingClass,
1729 DeclAccessPair::make(Constructor, Found.getAccess()),
1730 Context.getTypeDeclType(ObjectClass));
1731 AccessEntity.setDiag(PD);
1732
1733 return CheckAccess(S&: *this, Loc: UseLoc, Entity&: AccessEntity);
1734}
1735
1736Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
1737 SourceRange PlacementRange,
1738 CXXRecordDecl *NamingClass,
1739 DeclAccessPair Found,
1740 bool Diagnose) {
1741 if (!getLangOpts().AccessControl ||
1742 !NamingClass ||
1743 Found.getAccess() == AS_public)
1744 return AR_accessible;
1745
1746 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1747 QualType());
1748 if (Diagnose)
1749 Entity.setDiag(diag::err_access)
1750 << PlacementRange;
1751
1752 return CheckAccess(S&: *this, Loc: OpLoc, Entity);
1753}
1754
1755Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc,
1756 CXXRecordDecl *NamingClass,
1757 DeclAccessPair Found) {
1758 if (!getLangOpts().AccessControl ||
1759 !NamingClass ||
1760 Found.getAccess() == AS_public)
1761 return AR_accessible;
1762
1763 AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
1764 Found, QualType());
1765
1766 return CheckAccess(S&: *this, Loc: UseLoc, Entity);
1767}
1768
1769Sema::AccessResult
1770Sema::CheckStructuredBindingMemberAccess(SourceLocation UseLoc,
1771 CXXRecordDecl *DecomposedClass,
1772 DeclAccessPair Field) {
1773 if (!getLangOpts().AccessControl ||
1774 Field.getAccess() == AS_public)
1775 return AR_accessible;
1776
1777 AccessTarget Entity(Context, AccessTarget::Member, DecomposedClass, Field,
1778 Context.getRecordType(DecomposedClass));
1779 Entity.setDiag(diag::err_decomp_decl_inaccessible_field);
1780
1781 return CheckAccess(S&: *this, Loc: UseLoc, Entity);
1782}
1783
1784Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
1785 Expr *ObjectExpr,
1786 const SourceRange &Range,
1787 DeclAccessPair Found) {
1788 if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
1789 return AR_accessible;
1790
1791 const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();
1792 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Val: RT->getDecl());
1793
1794 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1795 ObjectExpr->getType());
1796 Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << Range;
1797
1798 return CheckAccess(S&: *this, Loc: OpLoc, Entity);
1799}
1800
1801Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
1802 Expr *ObjectExpr,
1803 Expr *ArgExpr,
1804 DeclAccessPair Found) {
1805 return CheckMemberOperatorAccess(
1806 OpLoc, ObjectExpr, ArgExpr ? ArgExpr->getSourceRange() : SourceRange(),
1807 Found);
1808}
1809
1810Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
1811 Expr *ObjectExpr,
1812 ArrayRef<Expr *> ArgExprs,
1813 DeclAccessPair FoundDecl) {
1814 SourceRange R;
1815 if (!ArgExprs.empty()) {
1816 R = SourceRange(ArgExprs.front()->getBeginLoc(),
1817 ArgExprs.back()->getEndLoc());
1818 }
1819
1820 return CheckMemberOperatorAccess(OpLoc, ObjectExpr, Range: R, Found: FoundDecl);
1821}
1822
1823Sema::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
1854Sema::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
1872Sema::AccessResult Sema::CheckBaseClassAccess(
1873 SourceLocation AccessLoc, CXXRecordDecl *Base, CXXRecordDecl *Derived,
1874 const CXXBasePath &Path, unsigned DiagID,
1875 llvm::function_ref<void(PartialDiagnostic &)> SetupPDiag, bool ForceCheck,
1876 bool ForceUnprivileged) {
1877 if (!ForceCheck && !getLangOpts().AccessControl)
1878 return AR_accessible;
1879
1880 if (Path.Access == AS_public)
1881 return AR_accessible;
1882
1883 AccessTarget Entity(Context, AccessTarget::Base, Base, Derived, Path.Access);
1884 if (DiagID)
1885 SetupPDiag(Entity.setDiag(DiagID));
1886
1887 if (ForceUnprivileged) {
1888 switch (
1889 CheckEffectiveAccess(S&: *this, EC: EffectiveContext(), Loc: AccessLoc, Entity)) {
1890 case ::AR_accessible:
1891 return Sema::AR_accessible;
1892 case ::AR_inaccessible:
1893 return Sema::AR_inaccessible;
1894 case ::AR_dependent:
1895 return Sema::AR_dependent;
1896 }
1897 llvm_unreachable("unexpected result from CheckEffectiveAccess");
1898 }
1899 return CheckAccess(S&: *this, Loc: AccessLoc, Entity);
1900}
1901
1902Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
1903 QualType Base, QualType Derived,
1904 const CXXBasePath &Path,
1905 unsigned DiagID, bool ForceCheck,
1906 bool ForceUnprivileged) {
1907 return CheckBaseClassAccess(
1908 AccessLoc, Base: Base->getAsCXXRecordDecl(), Derived: Derived->getAsCXXRecordDecl(),
1909 Path, DiagID, SetupPDiag: [&](PartialDiagnostic &PD) { PD << Derived << Base; },
1910 ForceCheck, ForceUnprivileged);
1911}
1912
1913void 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
1929bool Sema::IsSimplyAccessible(NamedDecl *Target, CXXRecordDecl *NamingClass,
1930 QualType BaseType) {
1931 // Perform the C++ accessibility checks first.
1932 if (Target->isCXXClassMember() && NamingClass) {
1933 if (!getLangOpts().CPlusPlus)
1934 return false;
1935 // The unprivileged access is AS_none as we don't know how the member was
1936 // accessed, which is described by the access in DeclAccessPair.
1937 // `IsAccessible` will examine the actual access of Target (i.e.
1938 // Decl->getAccess()) when calculating the access.
1939 AccessTarget Entity(Context, AccessedEntity::Member, NamingClass,
1940 DeclAccessPair::make(D: Target, AS: AS_none), BaseType);
1941 EffectiveContext EC(CurContext);
1942 return ::IsAccessible(S&: *this, EC, Entity) != ::AR_inaccessible;
1943 }
1944
1945 if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Val: Target)) {
1946 // @public and @package ivars are always accessible.
1947 if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||
1948 Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package)
1949 return true;
1950
1951 // If we are inside a class or category implementation, determine the
1952 // interface we're in.
1953 ObjCInterfaceDecl *ClassOfMethodDecl = nullptr;
1954 if (ObjCMethodDecl *MD = getCurMethodDecl())
1955 ClassOfMethodDecl = MD->getClassInterface();
1956 else if (FunctionDecl *FD = getCurFunctionDecl()) {
1957 if (ObjCImplDecl *Impl
1958 = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) {
1959 if (ObjCImplementationDecl *IMPD
1960 = dyn_cast<ObjCImplementationDecl>(Val: Impl))
1961 ClassOfMethodDecl = IMPD->getClassInterface();
1962 else if (ObjCCategoryImplDecl* CatImplClass
1963 = dyn_cast<ObjCCategoryImplDecl>(Val: Impl))
1964 ClassOfMethodDecl = CatImplClass->getClassInterface();
1965 }
1966 }
1967
1968 // If we're not in an interface, this ivar is inaccessible.
1969 if (!ClassOfMethodDecl)
1970 return false;
1971
1972 // If we're inside the same interface that owns the ivar, we're fine.
1973 if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface()))
1974 return true;
1975
1976 // If the ivar is private, it's inaccessible.
1977 if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private)
1978 return false;
1979
1980 return Ivar->getContainingInterface()->isSuperClassOf(I: ClassOfMethodDecl);
1981 }
1982
1983 return true;
1984}
1985

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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