1//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file provides Sema routines for C++ access control semantics.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/ASTContext.h"
14#include "clang/AST/CXXInheritance.h"
15#include "clang/AST/DeclCXX.h"
16#include "clang/AST/DeclFriend.h"
17#include "clang/AST/DeclObjC.h"
18#include "clang/AST/DependentDiagnostic.h"
19#include "clang/AST/ExprCXX.h"
20#include "clang/Basic/Specifiers.h"
21#include "clang/Sema/DelayedDiagnostic.h"
22#include "clang/Sema/Initialization.h"
23#include "clang/Sema/Lookup.h"
24#include "clang/Sema/Template.h"
25#include "clang/Sema/TemplateDeduction.h"
26#include "llvm/ADT/ScopeExit.h"
27
28using namespace clang;
29using namespace sema;
30
31/// A copy of Sema's enum without AR_delayed.
32enum AccessResult {
33 AR_accessible,
34 AR_inaccessible,
35 AR_dependent
36};
37
38bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
39 NamedDecl *PrevMemberDecl,
40 AccessSpecifier LexicalAS) {
41 if (!PrevMemberDecl) {
42 // Use the lexical access specifier.
43 MemberDecl->setAccess(LexicalAS);
44 return false;
45 }
46
47 // C++ [class.access.spec]p3: When a member is redeclared its access
48 // specifier must be same as its initial declaration.
49 if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
50 Diag(Loc: MemberDecl->getLocation(),
51 DiagID: diag::err_class_redeclared_with_different_access)
52 << MemberDecl << LexicalAS;
53 Diag(Loc: PrevMemberDecl->getLocation(), DiagID: diag::note_previous_access_declaration)
54 << PrevMemberDecl << PrevMemberDecl->getAccess();
55
56 MemberDecl->setAccess(LexicalAS);
57 return true;
58 }
59
60 MemberDecl->setAccess(PrevMemberDecl->getAccess());
61 return false;
62}
63
64static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
65 DeclContext *DC = D->getDeclContext();
66
67 // This can only happen at top: enum decls only "publish" their
68 // immediate members.
69 if (isa<EnumDecl>(Val: DC))
70 DC = cast<EnumDecl>(Val: DC)->getDeclContext();
71
72 CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(Val: DC);
73 while (DeclaringClass->isAnonymousStructOrUnion())
74 DeclaringClass = cast<CXXRecordDecl>(Val: DeclaringClass->getDeclContext());
75 return DeclaringClass;
76}
77
78namespace {
79struct EffectiveContext {
80 EffectiveContext() : Inner(nullptr), Dependent(false) {}
81
82 explicit EffectiveContext(DeclContext *DC)
83 : Inner(DC),
84 Dependent(DC->isDependentContext()) {
85
86 // An implicit deduction guide is semantically in the context enclosing the
87 // class template, but for access purposes behaves like the constructor
88 // from which it was produced.
89 if (auto *DGD = dyn_cast<CXXDeductionGuideDecl>(Val: DC)) {
90 if (DGD->isImplicit()) {
91 DC = DGD->getCorrespondingConstructor();
92 if (!DC) {
93 // The copy deduction candidate doesn't have a corresponding
94 // constructor.
95 DC = cast<DeclContext>(Val: DGD->getDeducedTemplate()->getTemplatedDecl());
96 }
97 }
98 }
99
100 // C++11 [class.access.nest]p1:
101 // A nested class is a member and as such has the same access
102 // rights as any other member.
103 // C++11 [class.access]p2:
104 // A member of a class can also access all the names to which
105 // the class has access. A local class of a member function
106 // may access the same names that the member function itself
107 // may access.
108 // This almost implies that the privileges of nesting are transitive.
109 // Technically it says nothing about the local classes of non-member
110 // functions (which can gain privileges through friendship), but we
111 // take that as an oversight.
112 while (true) {
113 // We want to add canonical declarations to the EC lists for
114 // simplicity of checking, but we need to walk up through the
115 // actual current DC chain. Otherwise, something like a local
116 // extern or friend which happens to be the canonical
117 // declaration will really mess us up.
118
119 if (isa<CXXRecordDecl>(Val: DC)) {
120 CXXRecordDecl *Record = cast<CXXRecordDecl>(Val: DC);
121 Records.push_back(Elt: Record->getCanonicalDecl());
122 DC = Record->getDeclContext();
123 } else if (isa<FunctionDecl>(Val: DC)) {
124 FunctionDecl *Function = cast<FunctionDecl>(Val: DC);
125 Functions.push_back(Elt: Function->getCanonicalDecl());
126 if (Function->getFriendObjectKind())
127 DC = Function->getLexicalDeclContext();
128 else
129 DC = Function->getDeclContext();
130 } else if (DC->isFileContext()) {
131 break;
132 } else {
133 DC = DC->getParent();
134 }
135 }
136 }
137
138 bool isDependent() const { return Dependent; }
139
140 bool includesClass(const CXXRecordDecl *R) const {
141 R = R->getCanonicalDecl();
142 return llvm::is_contained(Range: Records, Element: R);
143 }
144
145 /// Retrieves the innermost "useful" context. Can be null if we're
146 /// doing access-control without privileges.
147 DeclContext *getInnerContext() const {
148 return Inner;
149 }
150
151 typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
152
153 DeclContext *Inner;
154 SmallVector<FunctionDecl*, 4> Functions;
155 SmallVector<CXXRecordDecl*, 4> Records;
156 bool Dependent;
157};
158
159/// Like sema::AccessedEntity, but kindly lets us scribble all over
160/// it.
161struct AccessTarget : public AccessedEntity {
162 AccessTarget(const AccessedEntity &Entity)
163 : AccessedEntity(Entity) {
164 initialize();
165 }
166
167 AccessTarget(ASTContext &Context,
168 MemberNonce _,
169 CXXRecordDecl *NamingClass,
170 DeclAccessPair FoundDecl,
171 QualType BaseObjectType)
172 : AccessedEntity(Context.getDiagAllocator(), Member, NamingClass,
173 FoundDecl, BaseObjectType) {
174 initialize();
175 }
176
177 AccessTarget(ASTContext &Context,
178 BaseNonce _,
179 CXXRecordDecl *BaseClass,
180 CXXRecordDecl *DerivedClass,
181 AccessSpecifier Access)
182 : AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass,
183 Access) {
184 initialize();
185 }
186
187 bool isInstanceMember() const {
188 return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember());
189 }
190
191 bool hasInstanceContext() const {
192 return HasInstanceContext;
193 }
194
195 class SavedInstanceContext {
196 public:
197 SavedInstanceContext(SavedInstanceContext &&S)
198 : Target(S.Target), Has(S.Has) {
199 S.Target = nullptr;
200 }
201
202 // The move assignment operator is defined as deleted pending further
203 // motivation.
204 SavedInstanceContext &operator=(SavedInstanceContext &&) = delete;
205
206 // The copy constrcutor and copy assignment operator is defined as deleted
207 // pending further motivation.
208 SavedInstanceContext(const SavedInstanceContext &) = delete;
209 SavedInstanceContext &operator=(const SavedInstanceContext &) = delete;
210
211 ~SavedInstanceContext() {
212 if (Target)
213 Target->HasInstanceContext = Has;
214 }
215
216 private:
217 friend struct AccessTarget;
218 explicit SavedInstanceContext(AccessTarget &Target)
219 : Target(&Target), Has(Target.HasInstanceContext) {}
220 AccessTarget *Target;
221 bool Has;
222 };
223
224 SavedInstanceContext saveInstanceContext() {
225 return SavedInstanceContext(*this);
226 }
227
228 void suppressInstanceContext() {
229 HasInstanceContext = false;
230 }
231
232 const CXXRecordDecl *resolveInstanceContext(Sema &S) const {
233 assert(HasInstanceContext);
234 if (CalculatedInstanceContext)
235 return InstanceContext;
236
237 CalculatedInstanceContext = true;
238 DeclContext *IC = S.computeDeclContext(T: getBaseObjectType());
239 InstanceContext = (IC ? cast<CXXRecordDecl>(Val: IC)->getCanonicalDecl()
240 : nullptr);
241 return InstanceContext;
242 }
243
244 const CXXRecordDecl *getDeclaringClass() const {
245 return DeclaringClass;
246 }
247
248 /// The "effective" naming class is the canonical non-anonymous
249 /// class containing the actual naming class.
250 const CXXRecordDecl *getEffectiveNamingClass() const {
251 const CXXRecordDecl *namingClass = getNamingClass();
252 while (namingClass->isAnonymousStructOrUnion())
253 namingClass = cast<CXXRecordDecl>(Val: namingClass->getParent());
254 return namingClass->getCanonicalDecl();
255 }
256
257private:
258 void initialize() {
259 HasInstanceContext = (isMemberAccess() &&
260 !getBaseObjectType().isNull() &&
261 getTargetDecl()->isCXXInstanceMember());
262 CalculatedInstanceContext = false;
263 InstanceContext = nullptr;
264
265 if (isMemberAccess())
266 DeclaringClass = FindDeclaringClass(D: getTargetDecl());
267 else
268 DeclaringClass = getBaseClass();
269 DeclaringClass = DeclaringClass->getCanonicalDecl();
270 }
271
272 bool HasInstanceContext : 1;
273 mutable bool CalculatedInstanceContext : 1;
274 mutable const CXXRecordDecl *InstanceContext;
275 const CXXRecordDecl *DeclaringClass;
276};
277} // namespace
278
279static CanQual<FunctionProtoType> GetCanonicalFunctionProto(ASTContext &Context,
280 QualType Ty) {
281 return Context.getCanonicalType(T: Ty)->getAs<FunctionProtoType>();
282}
283
284static CanQual<FunctionProtoType>
285GetCanonicalFunctionProto(ASTContext &Context, const FunctionDecl *FD) {
286 return GetCanonicalFunctionProto(Context, Ty: FD->getType());
287}
288
289static const TemplateSpecializationType *
290GetQualifierClassTemplateSpecializationType(ASTContext &Context,
291 NestedNameSpecifier NNS) {
292 if (!NNS || NNS.getKind() != NestedNameSpecifier::Kind::Type)
293 return nullptr;
294
295 QualType Ty(NNS.getAsType(), 0);
296 if (const auto *ICNT = Ty->getAs<InjectedClassNameType>())
297 Ty = ICNT->getDecl()->getCanonicalTemplateSpecializationType(Ctx: Context);
298
299 const auto *TST = Ty->getAsNonAliasTemplateSpecializationType();
300 if (TST && isa_and_nonnull<ClassTemplateDecl>(
301 Val: TST->getTemplateName().getAsTemplateDecl()))
302 return TST;
303
304 return nullptr;
305}
306
307static FunctionTemplateDecl *TryGetFunctionTemplateDecl(FunctionDecl *FD) {
308 if (auto *FTD = FD->getPrimaryTemplate())
309 return FTD->getCanonicalDecl();
310
311 if (auto *FTD = FD->getDescribedFunctionTemplate())
312 return FTD->getCanonicalDecl();
313
314 if (FunctionDecl *Pattern =
315 FD->getTemplateInstantiationPattern(/*ForDefinition=*/false)) {
316 if (auto *FTD = Pattern->getDescribedFunctionTemplate())
317 return FTD->getCanonicalDecl();
318 if (auto *FTD = Pattern->getPrimaryTemplate())
319 return FTD->getCanonicalDecl();
320 }
321
322 return nullptr;
323}
324
325static ClassTemplateDecl *GetClassTemplatePattern(ClassTemplateDecl *CTD) {
326 while (ClassTemplateDecl *Pattern = CTD->getInstantiatedFromMemberTemplate())
327 CTD = Pattern;
328 return CTD;
329}
330
331static ClassTemplateDecl *GetClassTemplateDecl(CXXRecordDecl *RD) {
332 if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Val: RD))
333 return Spec->getSpecializedTemplate();
334 return RD->getDescribedClassTemplate();
335}
336
337static TemplateParameterList *
338SubstTemplateParameterList(Sema &S, TemplateParameterList *TPL, DeclContext *DC,
339 const MultiLevelTemplateArgumentList &Args) {
340 TemplateParameterList *InstTPL =
341 S.SubstTemplateParams(Params: TPL, Owner: DC, TemplateArgs: Args,
342 /*EvaluateConstraints=*/false);
343 if (!InstTPL || !TPL->getRequiresClause())
344 return InstTPL;
345
346 ExprResult InstRequiresClause =
347 S.SubstConstraintExprWithoutSatisfaction(E: TPL->getRequiresClause(), TemplateArgs: Args);
348 if (!InstRequiresClause.isUsable())
349 return nullptr;
350
351 return TemplateParameterList::Create(
352 C: S.Context, TemplateLoc: InstTPL->getTemplateLoc(), LAngleLoc: InstTPL->getLAngleLoc(),
353 Params: InstTPL->asArray(), RAngleLoc: InstTPL->getRAngleLoc(), RequiresClause: InstRequiresClause.get());
354}
355
356static AccessResult
357DeduceTemplateArguments(Sema &S, FriendTemplateDecl *FTD, DeclContext *DC,
358 const TemplateSpecializationType *TST,
359 ArrayRef<TemplateParameterList *> TPLs,
360 TemplateSpecCandidateSet *FailedTSC,
361 MultiLevelTemplateArgumentList &DeducedArgs) {
362 const auto *CandidateRD = dyn_cast<CXXRecordDecl>(Val: DC);
363 if (!CandidateRD)
364 return AR_inaccessible;
365
366 ClassTemplateDecl *CandidateCTD = CandidateRD->getDescribedClassTemplate();
367 ArrayRef<TemplateArgument> CandidateArgs;
368 if (CandidateCTD) {
369 CandidateArgs = CandidateCTD->getInjectedTemplateArgs(Context: S.Context);
370 } else {
371 const auto *CandidateSpec =
372 dyn_cast<ClassTemplateSpecializationDecl>(Val: CandidateRD);
373 if (!CandidateSpec)
374 return AR_inaccessible;
375 CandidateCTD = CandidateSpec->getSpecializedTemplate();
376 CandidateArgs = CandidateSpec->getTemplateArgs().asArray();
377 }
378
379 auto *PatternCTD = dyn_cast_if_present<ClassTemplateDecl>(
380 Val: TST->getTemplateName().getAsTemplateDecl());
381 if (!PatternCTD || !declaresSameEntity(D1: GetClassTemplatePattern(CTD: CandidateCTD),
382 D2: GetClassTemplatePattern(CTD: PatternCTD)))
383 return AR_inaccessible;
384
385 if (S.DeduceTemplateArguments(FTD, PatternCTD, CandidateCTD, TPLs,
386 PatternArgs: TST->template_arguments(), CandidateArgs,
387 Loc: FTD->getLocation(), FailedTSC, DeducedArgs))
388 return AR_accessible;
389
390 return CandidateRD->isDependentContext() ? AR_dependent : AR_inaccessible;
391}
392
393class FriendTemplateMatchContext {
394 Sema &S;
395 FriendTemplateDecl *FTD;
396 Sema::InstantiatingTemplate Inst;
397 TemplateDeductionInfo Info;
398 MultiLevelTemplateArgumentList DeducedArgs;
399 Sema::SFINAETrap Trap;
400 LocalInstantiationScope InstantiationScope;
401 AccessResult Result = AR_inaccessible;
402
403public:
404 FriendTemplateMatchContext(Sema &S, FriendTemplateDecl *FTD)
405 : S(S), FTD(FTD), Inst(S, FTD->getLocation(), FTD),
406 Info(FTD->getLocation()), Trap(S, Info), InstantiationScope(S) {}
407
408 AccessResult deduce(DeclContext *DC, const TemplateSpecializationType *TST,
409 ArrayRef<TemplateParameterList *> TPLs,
410 TemplateSpecCandidateSet *FailedTSC) {
411 if (Inst.isInvalid())
412 return Result = AR_inaccessible;
413 return Result = DeduceTemplateArguments(S, FTD, DC, TST, TPLs, FailedTSC,
414 DeducedArgs);
415 }
416
417 AccessResult getAccessResult() const { return Result; }
418 MultiLevelTemplateArgumentList &getDeducedArgs() { return DeducedArgs; }
419
420 bool hasDeducedArgs() const { return Result == AR_accessible; }
421 bool hasErrorOccurred() const { return Trap.hasErrorOccurred(); }
422};
423
424static bool HasSameFunctionType(Sema &S, QualType FriendType,
425 QualType ContextType, SourceLocation Loc) {
426 if (!S.Context.hasSameFunctionTypeIgnoringExceptionSpec(T: FriendType,
427 U: ContextType))
428 return false;
429
430 const auto *FriendFPT = FriendType->castAs<FunctionProtoType>();
431 const auto *ContextFPT = ContextType->castAs<FunctionProtoType>();
432 return !S.CheckEquivalentExceptionSpec(DiagID: S.PDiag(), NoteID: S.PDiag(), Old: FriendFPT, OldLoc: Loc,
433 New: ContextFPT, NewLoc: Loc);
434}
435
436/// Checks whether one class might instantiate to the other.
437static bool MightInstantiateTo(const CXXRecordDecl *From,
438 const CXXRecordDecl *To) {
439 // Declaration names are always preserved by instantiation.
440 if (From->getDeclName() != To->getDeclName())
441 return false;
442
443 const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();
444 const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();
445
446 if (FromDC == ToDC)
447 return true;
448
449 if (FromDC->isFileContext() || ToDC->isFileContext())
450 return false;
451
452 // Be conservative.
453 return true;
454}
455
456/// Checks whether one class is derived from another, inclusively.
457/// Properly indicates when it couldn't be determined due to
458/// dependence.
459///
460/// This should probably be donated to AST or at least Sema.
461static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
462 const CXXRecordDecl *Target) {
463 assert(Derived->getCanonicalDecl() == Derived);
464 assert(Target->getCanonicalDecl() == Target);
465
466 if (Derived == Target) return AR_accessible;
467
468 bool CheckDependent = Derived->isDependentContext();
469 if (CheckDependent && MightInstantiateTo(From: Derived, To: Target))
470 return AR_dependent;
471
472 AccessResult OnFailure = AR_inaccessible;
473 SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
474
475 while (true) {
476 if (Derived->isDependentContext() && !Derived->hasDefinition() &&
477 !Derived->isLambda())
478 return AR_dependent;
479
480 for (const auto &I : Derived->bases()) {
481 const CXXRecordDecl *RD;
482
483 QualType T = I.getType();
484 if (CXXRecordDecl *Rec = T->getAsCXXRecordDecl()) {
485 RD = Rec;
486 } else {
487 assert(T->isDependentType() && "non-dependent base wasn't a record?");
488 OnFailure = AR_dependent;
489 continue;
490 }
491
492 RD = RD->getCanonicalDecl();
493 if (RD == Target) return AR_accessible;
494 if (CheckDependent && MightInstantiateTo(From: RD, To: Target))
495 OnFailure = AR_dependent;
496
497 Queue.push_back(Elt: RD);
498 }
499
500 if (Queue.empty()) break;
501
502 Derived = Queue.pop_back_val();
503 }
504
505 return OnFailure;
506}
507
508static bool MightInstantiateTo(DeclContext *Context, DeclContext *Friend) {
509 if (Friend == Context)
510 return true;
511
512 assert(!Friend->isDependentContext() &&
513 "can't handle friends with dependent contexts here");
514
515 if (!Context->isDependentContext())
516 return false;
517
518 if (Friend->isFileContext())
519 return false;
520
521 // TODO: this is very conservative
522 return true;
523}
524
525// Asks whether the type in 'context' can ever instantiate to the type
526// in 'friend'.
527static bool MightInstantiateTo(CanQualType Context, CanQualType Friend) {
528 if (Friend == Context)
529 return true;
530
531 if (!Friend->isDependentType() && !Context->isDependentType())
532 return false;
533
534 // TODO: this is very conservative.
535 return true;
536}
537
538static bool MightInstantiateTo(CanQual<FunctionProtoType> Context,
539 CanQual<FunctionProtoType> Friend) {
540 if (Friend.getQualifiers() != Context.getQualifiers())
541 return false;
542
543 if (Friend->getNumParams() != Context->getNumParams())
544 return false;
545
546 if (!MightInstantiateTo(Context: Context->getReturnType(), Friend: Friend->getReturnType()))
547 return false;
548
549 for (unsigned I = 0, E = Friend->getNumParams(); I != E; ++I)
550 if (!MightInstantiateTo(Context: Context->getParamType(i: I), Friend: Friend->getParamType(i: I)))
551 return false;
552
553 return true;
554}
555
556static bool MightInstantiateTo(ASTContext &Ctx, DeclarationName Context,
557 DeclarationName Friend) {
558 if (Context == Friend)
559 return true;
560
561 if (Context.getNameKind() != Friend.getNameKind())
562 return false;
563
564 switch (Context.getNameKind()) {
565 case DeclarationName::CXXConstructorName:
566 case DeclarationName::CXXDestructorName:
567 case DeclarationName::CXXConversionFunctionName:
568 return MightInstantiateTo(Context: Ctx.getCanonicalType(T: Context.getCXXNameType()),
569 Friend: Ctx.getCanonicalType(T: Friend.getCXXNameType()));
570
571 default:
572 return false;
573 }
574}
575
576static bool MightInstantiateTo(ASTContext &Ctx, FunctionDecl *Context,
577 FunctionDecl *Friend) {
578 if (!MightInstantiateTo(Ctx, Context: Context->getDeclName(), Friend: Friend->getDeclName()))
579 return false;
580
581 DeclContext *ContextDC = Context->getDeclContext();
582 DeclContext *FriendDC = Friend->getDeclContext();
583
584 if (!FriendDC->isDependentContext() &&
585 !MightInstantiateTo(Context: ContextDC, Friend: FriendDC))
586 return false;
587
588 CanQual<FunctionProtoType> FriendTy = GetCanonicalFunctionProto(Context&: Ctx, FD: Friend);
589 CanQual<FunctionProtoType> ContextTy =
590 GetCanonicalFunctionProto(Context&: Ctx, FD: Context);
591
592 return MightInstantiateTo(Context: ContextTy, Friend: FriendTy);
593}
594
595static bool MightInstantiateTo(ASTContext &Ctx, FunctionTemplateDecl *Context,
596 FunctionTemplateDecl *Friend) {
597 return MightInstantiateTo(Ctx, Context: Context->getTemplatedDecl(),
598 Friend: Friend->getTemplatedDecl());
599}
600
601static AccessResult MatchesFriend(Sema &S,
602 const EffectiveContext &EC,
603 const CXXRecordDecl *Friend) {
604 if (EC.includesClass(R: Friend))
605 return AR_accessible;
606
607 if (EC.isDependent()) {
608 for (const CXXRecordDecl *Context : EC.Records) {
609 if (MightInstantiateTo(From: Context, To: Friend))
610 return AR_dependent;
611 }
612 }
613
614 return AR_inaccessible;
615}
616
617static AccessResult MatchesFriend(Sema &S,
618 const EffectiveContext &EC,
619 CanQualType Friend) {
620 if (const auto *RD = Friend->getAsCXXRecordDecl())
621 return MatchesFriend(S, EC, Friend: RD);
622
623 // TODO: we can do better than this
624 if (Friend->isDependentType())
625 return AR_dependent;
626
627 return AR_inaccessible;
628}
629
630/// Determines whether the given friend class template matches
631/// anything in the effective context.
632static AccessResult MatchesFriend(Sema &S,
633 const EffectiveContext &EC,
634 ClassTemplateDecl *Friend) {
635 AccessResult OnFailure = AR_inaccessible;
636
637 // Check whether the friend is the template of a class in the
638 // context chain.
639 for (SmallVectorImpl<CXXRecordDecl*>::const_iterator
640 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
641 CXXRecordDecl *Record = *I;
642
643 // Figure out whether the current class has a template:
644 ClassTemplateDecl *CTD;
645
646 // A specialization of the template...
647 if (isa<ClassTemplateSpecializationDecl>(Val: Record)) {
648 CTD = cast<ClassTemplateSpecializationDecl>(Val: Record)
649 ->getSpecializedTemplate();
650
651 // ... or the template pattern itself.
652 } else {
653 CTD = Record->getDescribedClassTemplate();
654 if (!CTD) continue;
655 }
656
657 // It's a match.
658 if (declaresSameEntity(D1: Friend, D2: CTD))
659 return AR_accessible;
660
661 // If the context isn't dependent, it can't be a dependent match.
662 if (!EC.isDependent())
663 continue;
664
665 // If the template names don't match, it can't be a dependent
666 // match.
667 if (CTD->getDeclName() != Friend->getDeclName())
668 continue;
669
670 // If the class's context can't instantiate to the friend's
671 // context, it can't be a dependent match.
672 if (!MightInstantiateTo(Context: CTD->getDeclContext(), Friend: Friend->getDeclContext()))
673 continue;
674
675 // Otherwise, it's a dependent match.
676 OnFailure = AR_dependent;
677 }
678
679 return OnFailure;
680}
681
682/// Determines whether the given friend function matches anything in
683/// the effective context.
684static AccessResult MatchesFriend(Sema &S,
685 const EffectiveContext &EC,
686 FunctionDecl *Friend) {
687 AccessResult OnFailure = AR_inaccessible;
688
689 for (SmallVectorImpl<FunctionDecl*>::const_iterator
690 I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
691 if (Friend == *I)
692 return AR_accessible;
693
694 if (EC.isDependent() && MightInstantiateTo(Ctx&: S.Context, Context: *I, Friend))
695 OnFailure = AR_dependent;
696 }
697
698 return OnFailure;
699}
700
701/// Determines whether the given friend function template matches
702/// anything in the effective context.
703static AccessResult MatchesFriend(Sema &S,
704 const EffectiveContext &EC,
705 FunctionTemplateDecl *Friend) {
706 if (EC.Functions.empty()) return AR_inaccessible;
707
708 AccessResult OnFailure = AR_inaccessible;
709
710 for (SmallVectorImpl<FunctionDecl*>::const_iterator
711 I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
712
713 FunctionTemplateDecl *FTD = TryGetFunctionTemplateDecl(FD: *I);
714 if (!FTD)
715 continue;
716
717 if (Friend == FTD)
718 return AR_accessible;
719
720 if (EC.isDependent() && MightInstantiateTo(Ctx&: S.Context, Context: FTD, Friend))
721 OnFailure = AR_dependent;
722 }
723
724 return OnFailure;
725}
726
727static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
728 NamedDecl *ND) {
729 ND = cast<NamedDecl>(Val: ND->getCanonicalDecl());
730 if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(Val: ND))
731 return MatchesFriend(S, EC, Friend: CTD);
732
733 if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(Val: ND))
734 return MatchesFriend(S, EC, Friend: FTD);
735
736 if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Val: ND))
737 return MatchesFriend(S, EC, Friend: RD);
738
739 assert(isa<FunctionDecl>(ND) && "unknown friend decl kind");
740 return MatchesFriend(S, EC, Friend: cast<FunctionDecl>(Val: ND));
741}
742
743static AccessResult MatchesFriend(Sema &S, FriendTemplateDecl *FTD,
744 DeclarationName FriendName,
745 TagTypeKind FriendTagKind,
746 ClassTemplateDecl *ContextCTD,
747 const TemplateSpecializationType *FriendTST,
748 ArrayRef<TemplateParameterList *> TPLs,
749 TemplateParameterList *MemberTPL,
750 TemplateSpecCandidateSet *FailedTSC) {
751 if (FriendName != ContextCTD->getDeclName())
752 return AR_inaccessible;
753
754 if ((FriendTagKind == TagTypeKind::Union) !=
755 ContextCTD->getTemplatedDecl()->isUnion())
756 return AR_inaccessible;
757
758 DeclContext *ContextDC = ContextCTD->getDeclContext();
759 AccessResult OnFailure =
760 ContextDC->isDependentContext() ? AR_dependent : AR_inaccessible;
761
762 FriendTemplateMatchContext FTMC(S, FTD);
763 AccessResult Result = FTMC.deduce(DC: ContextDC, TST: FriendTST, TPLs, FailedTSC);
764 if (!FTMC.hasDeducedArgs())
765 return Result;
766
767 TemplateParameterList *InstTPL = SubstTemplateParameterList(
768 S, TPL: MemberTPL, DC: ContextDC, Args: FTMC.getDeducedArgs());
769 if (!InstTPL || FTMC.hasErrorOccurred())
770 return OnFailure;
771
772 Sema::TemplateCompareNewDeclInfo FriendInfo(
773 ContextDC, FTD->getLexicalDeclContext(), FTD->getLocation());
774 if (S.TemplateParameterListsAreEqual(
775 NewInstFrom: FriendInfo, New: InstTPL, OldInstFrom: ContextCTD, Old: ContextCTD->getTemplateParameters(),
776 /*Complain=*/false, Kind: Sema::TPL_TemplateMatch))
777 return AR_accessible;
778 return OnFailure;
779}
780
781static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
782 FriendTemplateDecl *FTD,
783 ClassTemplateDecl *FriendCTD,
784 NestedNameSpecifier Qualifier,
785 TemplateSpecCandidateSet *FailedTSC) {
786 const auto *FriendTST =
787 GetQualifierClassTemplateSpecializationType(Context&: S.Context, NNS: Qualifier);
788 if (!FriendTST)
789 return MatchesFriend(S, EC, Friend: FriendCTD);
790
791 ArrayRef<TemplateParameterList *> TPLs = FTD->getTemplateParameterLists();
792
793 AccessResult OnFailure = AR_inaccessible;
794 for (CXXRecordDecl *ContextRD : EC.Records) {
795 ClassTemplateDecl *ContextCTD = GetClassTemplateDecl(RD: ContextRD);
796 if (!ContextCTD)
797 continue;
798
799 AccessResult Result =
800 MatchesFriend(S, FTD, FriendName: FriendCTD->getDeclName(),
801 FriendTagKind: FriendCTD->getTemplatedDecl()->getTagKind(), ContextCTD,
802 FriendTST, TPLs: TPLs.drop_back(), MemberTPL: TPLs.back(), FailedTSC);
803 if (Result == AR_accessible)
804 return AR_accessible;
805 if (Result == AR_dependent)
806 OnFailure = AR_dependent;
807 }
808
809 return OnFailure;
810}
811
812static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
813 FriendTemplateDecl *FTD,
814 TemplateName FriendTemplate,
815 ClassTemplateDecl *FriendCTD,
816 TemplateSpecCandidateSet *FailedTSC) {
817 NestedNameSpecifier Qualifier = FriendTemplate.getQualifier();
818 if (FriendTemplate.getAsUsingShadowDecl())
819 Qualifier = FriendCTD->getTemplatedDecl()->getQualifier();
820 return MatchesFriend(S, EC, FTD, FriendCTD, Qualifier, FailedTSC);
821}
822
823static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
824 FriendTemplateDecl *FTD,
825 ClassTemplateDecl *FriendCTD,
826 TemplateSpecCandidateSet *FailedTSC) {
827 return MatchesFriend(S, EC, FTD, FriendCTD,
828 Qualifier: FriendCTD->getTemplatedDecl()->getQualifier(),
829 FailedTSC);
830}
831
832static AccessResult MatchesFriend(Sema &S, FriendTemplateDecl *FTD,
833 FunctionDecl *FriendFD,
834 FunctionDecl *ContextFD,
835 const TemplateSpecializationType *FriendTST,
836 ArrayRef<TemplateParameterList *> TPLs,
837 TemplateSpecCandidateSet *FailedTSC) {
838 if (!MightInstantiateTo(Ctx&: S.Context, Context: ContextFD->getDeclName(),
839 Friend: FriendFD->getDeclName()))
840 return AR_inaccessible;
841
842 FunctionTemplateDecl *FriendTemplate =
843 FriendFD->getDescribedFunctionTemplate();
844 FunctionTemplateDecl *ContextTemplate = TryGetFunctionTemplateDecl(FD: ContextFD);
845
846 if (FriendTemplate && !ContextTemplate)
847 return AR_inaccessible;
848
849 DeclContext *ContextDC = ContextFD->getDeclContext();
850 AccessResult OnFailure =
851 ContextDC->isDependentContext() ? AR_dependent : AR_inaccessible;
852
853 FriendTemplateMatchContext FTMC(S, FTD);
854 AccessResult Result = FTMC.deduce(DC: ContextDC, TST: FriendTST, TPLs, FailedTSC);
855 if (!FTMC.hasDeducedArgs())
856 return Result;
857
858 Sema::TemplateCompareNewDeclInfo FriendInfo(
859 ContextDC, FTD->getLexicalDeclContext(), FTD->getLocation());
860 if (FriendTemplate) {
861 TemplateParameterList *InstTPL =
862 SubstTemplateParameterList(S, TPL: FriendTemplate->getTemplateParameters(),
863 DC: ContextDC, Args: FTMC.getDeducedArgs());
864 if (!InstTPL || !S.TemplateParameterListsAreEqual(
865 NewInstFrom: FriendInfo, New: InstTPL, OldInstFrom: ContextTemplate,
866 Old: ContextTemplate->getTemplateParameters(),
867 /*Complain=*/false, Kind: Sema::TPL_TemplateMatch))
868 return OnFailure;
869
870 ContextFD = ContextTemplate->getTemplatedDecl();
871 }
872
873 Sema::ContextRAII SavedContext(S, FTD->getDeclContext());
874 QualType InstFriendType =
875 S.SubstType(T: FriendFD->getType(), TemplateArgs: FTMC.getDeducedArgs(),
876 Loc: FriendFD->getLocation(), Entity: FriendFD->getDeclName());
877 SavedContext.pop();
878 if (InstFriendType.isNull() || FTMC.hasErrorOccurred())
879 return OnFailure;
880
881 if (ContextTemplate && !FriendTemplate) {
882 AccessResult OnSpecializationFailure =
883 ContextFD->isDependentContext() ? AR_dependent : OnFailure;
884 const ASTTemplateArgumentListInfo *ArgsWritten =
885 FriendFD->getTemplateSpecializationArgsAsWritten();
886 TemplateArgumentListInfo InstArgs;
887 if (ArgsWritten) {
888 InstArgs.setLAngleLoc(ArgsWritten->getLAngleLoc());
889 InstArgs.setRAngleLoc(ArgsWritten->getRAngleLoc());
890 if (S.SubstTemplateArguments(Args: ArgsWritten->arguments(),
891 TemplateArgs: FTMC.getDeducedArgs(), Outputs&: InstArgs))
892 return OnSpecializationFailure;
893 }
894
895 FunctionDecl *ContextSpecialization = nullptr;
896 TemplateDeductionInfo FunctionInfo(FTD->getLocation());
897 if (S.DeduceTemplateArguments(
898 FunctionTemplate: ContextTemplate, ExplicitTemplateArgs: ArgsWritten ? &InstArgs : nullptr, ArgFunctionType: InstFriendType,
899 Specialization&: ContextSpecialization,
900 Info&: FunctionInfo) != TemplateDeductionResult::Success ||
901 !ContextSpecialization || FTMC.hasErrorOccurred() ||
902 !declaresSameEntity(D1: ContextSpecialization, D2: ContextFD))
903 return OnSpecializationFailure;
904
905 ContextFD = ContextSpecialization;
906 }
907
908 if (!HasSameFunctionType(S, FriendType: InstFriendType, ContextType: ContextFD->getType(),
909 Loc: FTD->getLocation()) ||
910 FTMC.hasErrorOccurred())
911 return OnFailure;
912
913 if (!FriendTemplate)
914 return AR_accessible;
915
916 AssociatedConstraint FriendRequiresClause =
917 FriendFD->getTrailingRequiresClause();
918 AssociatedConstraint ContextRequiresClause =
919 ContextFD->getTrailingRequiresClause();
920 if (FriendRequiresClause.isNull() != ContextRequiresClause.isNull())
921 return AR_inaccessible;
922
923 if (!FriendRequiresClause)
924 return AR_accessible;
925
926 ExprResult InstFriendRequiresClause =
927 S.SubstConstraintExprWithoutSatisfaction(
928 E: const_cast<Expr *>(FriendRequiresClause.ConstraintExpr),
929 TemplateArgs: FTMC.getDeducedArgs());
930
931 if (!InstFriendRequiresClause.isUsable())
932 return OnFailure;
933
934 if (!S.AreConstraintExpressionsEqual(
935 Old: ContextFD, OldConstr: ContextRequiresClause.ConstraintExpr, New: FriendInfo,
936 NewConstr: InstFriendRequiresClause.get()))
937 return OnFailure;
938 return FTMC.hasErrorOccurred() ? AR_inaccessible : AR_accessible;
939}
940
941static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
942 FriendTemplateDecl *FTD,
943 FunctionDecl *FriendFD,
944 TemplateSpecCandidateSet *FailedTSC) {
945 const auto *FriendTST = GetQualifierClassTemplateSpecializationType(
946 Context&: S.Context, NNS: FriendFD->getQualifier());
947 if (!FriendTST)
948 return AR_inaccessible;
949
950 ArrayRef<TemplateParameterList *> TPLs = FTD->getTemplateParameterLists();
951
952 AccessResult OnFailure = AR_inaccessible;
953 for (FunctionDecl *ContextFD : EC.Functions) {
954 AccessResult Result =
955 MatchesFriend(S, FTD, FriendFD, ContextFD, FriendTST, TPLs, FailedTSC);
956 if (Result == AR_accessible)
957 return AR_accessible;
958
959 if (Result == AR_dependent)
960 OnFailure = AR_dependent;
961 }
962 return OnFailure;
963}
964
965static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
966 FriendTemplateDecl *FTD, NamedDecl *Friend,
967 TemplateSpecCandidateSet *FailedTSC) {
968 TemplateName FriendTemplate = FTD->getFriendTemplateName();
969 if (auto *FriendCTD = dyn_cast_if_present<ClassTemplateDecl>(
970 Val: FriendTemplate.getAsTemplateDecl()))
971 return MatchesFriend(S, EC, FTD, FriendTemplate, FriendCTD, FailedTSC);
972 if (auto *FriendCTD = dyn_cast<ClassTemplateDecl>(Val: Friend))
973 return MatchesFriend(S, EC, FTD, FriendCTD, FailedTSC);
974 if (FunctionDecl *FriendFD = Friend->getAsFunction())
975 return MatchesFriend(S, EC, FTD, FriendFD, FailedTSC);
976 return MatchesFriend(S, EC, ND: Friend);
977}
978
979static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
980 FriendTemplateDecl *FTD,
981 TypeSourceInfo *FriendTSI,
982 TemplateSpecCandidateSet *FailedTSC) {
983 QualType FriendType = FriendTSI->getType();
984 if (!FriendType->isDependentType())
985 return MatchesFriend(S, EC, Friend: S.Context.getCanonicalType(T: FriendType));
986
987 AccessResult OnFailure = AR_inaccessible;
988 if (auto FriendTSTL =
989 FriendTSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) {
990 const auto *FriendTST = FriendTSTL.getTypePtr();
991 const auto *FriendQTST = GetQualifierClassTemplateSpecializationType(
992 Context&: S.Context, NNS: FriendTSTL.getQualifierLoc().getNestedNameSpecifier());
993 if (!FriendQTST)
994 return OnFailure;
995
996 ArrayRef<TemplateParameterList *> TPLs = FTD->getTemplateParameterLists();
997
998 TemplateName FriendTemplate = FriendTST->getTemplateName();
999 DeclarationName FriendName;
1000 if (TemplateDecl *TD = FriendTemplate.getAsTemplateDecl())
1001 FriendName = TD->getDeclName();
1002 else if (DependentTemplateName *DTN =
1003 FriendTemplate.getAsDependentTemplateName())
1004 FriendName = DTN->getName().getIdentifier();
1005
1006 TagTypeKind FriendTagKind =
1007 TypeWithKeyword::getTagTypeKindForKeyword(Keyword: FriendTST->getKeyword());
1008
1009 for (CXXRecordDecl *ContextRD : EC.Records) {
1010 ClassTemplateDecl *ContextCTD = GetClassTemplateDecl(RD: ContextRD);
1011 if (!ContextCTD)
1012 continue;
1013
1014 if (FriendName && ContextCTD->getDeclName() != FriendName)
1015 continue;
1016
1017 if ((FriendTagKind == TagTypeKind::Union) !=
1018 ContextCTD->getTemplatedDecl()->isUnion())
1019 continue;
1020
1021 FriendTemplateMatchContext FTMC(S, FTD);
1022 AccessResult Result =
1023 FTMC.deduce(DC: ContextRD->getDeclContext(), TST: FriendQTST, TPLs, FailedTSC);
1024 if (!FTMC.hasDeducedArgs()) {
1025 if (Result == AR_dependent)
1026 OnFailure = AR_dependent;
1027 continue;
1028 }
1029
1030 TypeSourceInfo *InstFriendTSI =
1031 S.SubstFriendType(TSI: FriendTSI, TemplateArgs: FTMC.getDeducedArgs(),
1032 Loc: FTD->getLocation(), Entity: DeclarationName());
1033 if (InstFriendTSI && !FTMC.hasErrorOccurred() &&
1034 S.Context.hasSameType(T1: InstFriendTSI->getType(),
1035 T2: S.Context.getCanonicalTagType(TD: ContextRD)))
1036 return AR_accessible;
1037
1038 if (ContextRD->isDependentContext())
1039 OnFailure = AR_dependent;
1040 }
1041
1042 return OnFailure;
1043 }
1044
1045 const auto *FriendDNT = FriendType->getAs<DependentNameType>();
1046 if (!FriendDNT)
1047 return OnFailure;
1048
1049 const auto *FriendTST = GetQualifierClassTemplateSpecializationType(
1050 Context&: S.Context, NNS: FriendDNT->getQualifier());
1051 if (!FriendTST)
1052 return OnFailure;
1053
1054 ArrayRef<TemplateParameterList *> TPLs = FTD->getTemplateParameterLists();
1055
1056 TagTypeKind FriendTagKind =
1057 TypeWithKeyword::getTagTypeKindForKeyword(Keyword: FriendDNT->getKeyword());
1058 for (CXXRecordDecl *ContextRD : EC.Records) {
1059 if (ContextRD->getDeclName() != FriendDNT->getIdentifier())
1060 continue;
1061
1062 if (ClassTemplateDecl *ContextCTD = GetClassTemplateDecl(RD: ContextRD)) {
1063 if (FTD->getFriendTemplateName().isNull()) {
1064 if (FailedTSC) {
1065 MultiLevelTemplateArgumentList DeducedArgs;
1066 DeduceTemplateArguments(S, FTD, DC: ContextCTD->getDeclContext(),
1067 TST: FriendTST, TPLs, FailedTSC, DeducedArgs);
1068 }
1069 continue;
1070 }
1071
1072 AccessResult Result = MatchesFriend(
1073 S, FTD, FriendName: FriendDNT->getIdentifier(), FriendTagKind, ContextCTD,
1074 FriendTST, TPLs: TPLs.drop_back(), MemberTPL: TPLs.back(), FailedTSC);
1075 if (Result == AR_accessible)
1076 return AR_accessible;
1077 if (Result == AR_dependent)
1078 OnFailure = AR_dependent;
1079 continue;
1080 }
1081
1082 if (!FTD->getFriendTemplateName().isNull())
1083 continue;
1084
1085 if ((FriendTagKind == TagTypeKind::Union) != ContextRD->isUnion())
1086 continue;
1087
1088 MultiLevelTemplateArgumentList DeducedArgs;
1089 AccessResult Result =
1090 DeduceTemplateArguments(S, FTD, DC: ContextRD->getDeclContext(), TST: FriendTST,
1091 TPLs, FailedTSC, DeducedArgs);
1092 if (Result == AR_accessible)
1093 return AR_accessible;
1094 if (Result == AR_dependent)
1095 OnFailure = AR_dependent;
1096 }
1097 return OnFailure;
1098}
1099
1100/// Determines whether the given friend declaration matches anything
1101/// in the effective context.
1102static AccessResult MatchesFriend(Sema &S,
1103 const EffectiveContext &EC,
1104 FriendDecl *FriendD) {
1105 // Whitelist accesses if there's an invalid friend declaration.
1106 if (FriendD->isInvalidDecl())
1107 return AR_accessible;
1108
1109 if (NamedDecl *Friend = FriendD->getFriendDecl())
1110 return MatchesFriend(S, EC, ND: Friend);
1111
1112 if (TypeSourceInfo *T = FriendD->getFriendType())
1113 return MatchesFriend(S, EC, Friend: T->getType()->getCanonicalTypeUnqualified());
1114
1115 return AR_inaccessible;
1116}
1117
1118static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC,
1119 FriendTemplateDecl *FTD,
1120 TemplateSpecCandidateSet *FailedTSC) {
1121 if (FTD->isInvalidDecl())
1122 return AR_accessible;
1123
1124 if (TypeSourceInfo *TSI = FTD->getFriendType())
1125 return MatchesFriend(S, EC, FTD, FriendTSI: TSI, FailedTSC);
1126
1127 NamedDecl *Friend = FTD->getFriendDecl();
1128 assert(Friend && "friend template must name a type or declaration");
1129 return MatchesFriend(S, EC, FTD, Friend, FailedTSC);
1130}
1131
1132static AccessResult GetFriendKind(Sema &S, const EffectiveContext &EC,
1133 const CXXRecordDecl *Class,
1134 TemplateSpecCandidateSet *FailedTSC) {
1135 AccessResult OnFailure = AR_inaccessible;
1136
1137 // Okay, check friends.
1138 for (FriendDecl *Friend : Class->friends()) {
1139 AccessResult AR;
1140 if (auto *FTD = dyn_cast<FriendTemplateDecl>(Val: Friend))
1141 AR = MatchesFriend(S, EC, FTD, FailedTSC);
1142 else
1143 AR = MatchesFriend(S, EC, FriendD: Friend);
1144
1145 switch (AR) {
1146 case AR_accessible:
1147 return AR_accessible;
1148
1149 case AR_inaccessible:
1150 continue;
1151
1152 case AR_dependent:
1153 OnFailure = AR_dependent;
1154 break;
1155 }
1156 }
1157
1158 // That's it, give up.
1159 return OnFailure;
1160}
1161
1162namespace {
1163
1164/// A helper class for checking for a friend which will grant access
1165/// to a protected instance member.
1166struct ProtectedFriendContext {
1167 Sema &S;
1168 const EffectiveContext &EC;
1169 TemplateSpecCandidateSet *FailedTSC;
1170 const CXXRecordDecl *NamingClass;
1171 bool CheckDependent;
1172 bool EverDependent;
1173
1174 /// The path down to the current base class.
1175 SmallVector<const CXXRecordDecl*, 20> CurPath;
1176
1177 ProtectedFriendContext(Sema &S, const EffectiveContext &EC,
1178 const CXXRecordDecl *InstanceContext,
1179 const CXXRecordDecl *NamingClass,
1180 TemplateSpecCandidateSet *FailedTSC)
1181 : S(S), EC(EC), FailedTSC(FailedTSC), NamingClass(NamingClass),
1182 CheckDependent(InstanceContext->isDependentContext() ||
1183 NamingClass->isDependentContext()),
1184 EverDependent(false) {}
1185
1186 /// Check classes in the current path for friendship, starting at
1187 /// the given index.
1188 bool checkFriendshipAlongPath(unsigned I) {
1189 assert(I < CurPath.size());
1190 for (unsigned E = CurPath.size(); I != E; ++I) {
1191 switch (GetFriendKind(S, EC, Class: CurPath[I], FailedTSC)) {
1192 case AR_accessible: return true;
1193 case AR_inaccessible: continue;
1194 case AR_dependent: EverDependent = true; continue;
1195 }
1196 }
1197 return false;
1198 }
1199
1200 /// Perform a search starting at the given class.
1201 ///
1202 /// PrivateDepth is the index of the last (least derived) class
1203 /// along the current path such that a notional public member of
1204 /// the final class in the path would have access in that class.
1205 bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) {
1206 // If we ever reach the naming class, check the current path for
1207 // friendship. We can also stop recursing because we obviously
1208 // won't find the naming class there again.
1209 if (Cur == NamingClass)
1210 return checkFriendshipAlongPath(I: PrivateDepth);
1211
1212 if (CheckDependent && MightInstantiateTo(From: Cur, To: NamingClass))
1213 EverDependent = true;
1214
1215 // Recurse into the base classes.
1216 for (const auto &I : Cur->bases()) {
1217 // If this is private inheritance, then a public member of the
1218 // base will not have any access in classes derived from Cur.
1219 unsigned BasePrivateDepth = PrivateDepth;
1220 if (I.getAccessSpecifier() == AS_private)
1221 BasePrivateDepth = CurPath.size() - 1;
1222
1223 const CXXRecordDecl *RD;
1224
1225 QualType T = I.getType();
1226 if (CXXRecordDecl *Rec = T->getAsCXXRecordDecl()) {
1227 RD = Rec;
1228 } else {
1229 assert(T->isDependentType() && "non-dependent base wasn't a record?");
1230 EverDependent = true;
1231 continue;
1232 }
1233
1234 // Recurse. We don't need to clean up if this returns true.
1235 CurPath.push_back(Elt: RD);
1236 if (findFriendship(Cur: RD->getCanonicalDecl(), PrivateDepth: BasePrivateDepth))
1237 return true;
1238 CurPath.pop_back();
1239 }
1240
1241 return false;
1242 }
1243
1244 bool findFriendship(const CXXRecordDecl *Cur) {
1245 assert(CurPath.empty());
1246 CurPath.push_back(Elt: Cur);
1247 return findFriendship(Cur, PrivateDepth: 0);
1248 }
1249};
1250}
1251
1252/// Search for a class P that EC is a friend of, under the constraint
1253/// InstanceContext <= P
1254/// if InstanceContext exists, or else
1255/// NamingClass <= P
1256/// and with the additional restriction that a protected member of
1257/// NamingClass would have some natural access in P, which implicitly
1258/// imposes the constraint that P <= NamingClass.
1259///
1260/// This isn't quite the condition laid out in the standard.
1261/// Instead of saying that a notional protected member of NamingClass
1262/// would have to have some natural access in P, it says the actual
1263/// target has to have some natural access in P, which opens up the
1264/// possibility that the target (which is not necessarily a member
1265/// of NamingClass) might be more accessible along some path not
1266/// passing through it. That's really a bad idea, though, because it
1267/// introduces two problems:
1268/// - Most importantly, it breaks encapsulation because you can
1269/// access a forbidden base class's members by directly subclassing
1270/// it elsewhere.
1271/// - It also makes access substantially harder to compute because it
1272/// breaks the hill-climbing algorithm: knowing that the target is
1273/// accessible in some base class would no longer let you change
1274/// the question solely to whether the base class is accessible,
1275/// because the original target might have been more accessible
1276/// because of crazy subclassing.
1277/// So we don't implement that.
1278static AccessResult GetProtectedFriendKind(
1279 Sema &S, const EffectiveContext &EC, const CXXRecordDecl *InstanceContext,
1280 const CXXRecordDecl *NamingClass, TemplateSpecCandidateSet *FailedTSC) {
1281 assert(InstanceContext == nullptr ||
1282 InstanceContext->getCanonicalDecl() == InstanceContext);
1283 assert(NamingClass->getCanonicalDecl() == NamingClass);
1284
1285 // If we don't have an instance context, our constraints give us
1286 // that NamingClass <= P <= NamingClass, i.e. P == NamingClass.
1287 // This is just the usual friendship check.
1288 if (!InstanceContext)
1289 return GetFriendKind(S, EC, Class: NamingClass, FailedTSC);
1290
1291 ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass, FailedTSC);
1292 if (PRC.findFriendship(Cur: InstanceContext)) return AR_accessible;
1293 if (PRC.EverDependent) return AR_dependent;
1294 return AR_inaccessible;
1295}
1296
1297static AccessResult HasAccess(Sema &S, const EffectiveContext &EC,
1298 const CXXRecordDecl *NamingClass,
1299 AccessSpecifier Access,
1300 const AccessTarget &Target,
1301 TemplateSpecCandidateSet *FailedTSC) {
1302 assert(NamingClass->getCanonicalDecl() == NamingClass &&
1303 "declaration should be canonicalized before being passed here");
1304
1305 if (Access == AS_public) return AR_accessible;
1306 assert(Access == AS_private || Access == AS_protected);
1307
1308 AccessResult OnFailure = AR_inaccessible;
1309
1310 for (EffectiveContext::record_iterator
1311 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
1312 // All the declarations in EC have been canonicalized, so pointer
1313 // equality from this point on will work fine.
1314 const CXXRecordDecl *ECRecord = *I;
1315
1316 // [B2] and [M2]
1317 if (Access == AS_private) {
1318 if (ECRecord == NamingClass)
1319 return AR_accessible;
1320
1321 if (EC.isDependent() && MightInstantiateTo(From: ECRecord, To: NamingClass))
1322 OnFailure = AR_dependent;
1323
1324 // [B3] and [M3]
1325 } else {
1326 assert(Access == AS_protected);
1327 switch (IsDerivedFromInclusive(Derived: ECRecord, Target: NamingClass)) {
1328 case AR_accessible: break;
1329 case AR_inaccessible: continue;
1330 case AR_dependent: OnFailure = AR_dependent; continue;
1331 }
1332
1333 // C++ [class.protected]p1:
1334 // An additional access check beyond those described earlier in
1335 // [class.access] is applied when a non-static data member or
1336 // non-static member function is a protected member of its naming
1337 // class. As described earlier, access to a protected member is
1338 // granted because the reference occurs in a friend or member of
1339 // some class C. If the access is to form a pointer to member,
1340 // the nested-name-specifier shall name C or a class derived from
1341 // C. All other accesses involve a (possibly implicit) object
1342 // expression. In this case, the class of the object expression
1343 // shall be C or a class derived from C.
1344 //
1345 // We interpret this as a restriction on [M3].
1346
1347 // In this part of the code, 'C' is just our context class ECRecord.
1348
1349 // These rules are different if we don't have an instance context.
1350 if (!Target.hasInstanceContext()) {
1351 // If it's not an instance member, these restrictions don't apply.
1352 if (!Target.isInstanceMember()) return AR_accessible;
1353
1354 // If it's an instance member, use the pointer-to-member rule
1355 // that the naming class has to be derived from the effective
1356 // context.
1357
1358 // Emulate a MSVC bug where the creation of pointer-to-member
1359 // to protected member of base class is allowed but only from
1360 // static member functions.
1361 if (S.getLangOpts().MSVCCompat && !EC.Functions.empty())
1362 if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(Val: EC.Functions.front()))
1363 if (MD->isStatic()) return AR_accessible;
1364
1365 // Despite the standard's confident wording, there is a case
1366 // where you can have an instance member that's neither in a
1367 // pointer-to-member expression nor in a member access: when
1368 // it names a field in an unevaluated context that can't be an
1369 // implicit member. Pending clarification, we just apply the
1370 // same naming-class restriction here.
1371 // FIXME: we're probably not correctly adding the
1372 // protected-member restriction when we retroactively convert
1373 // an expression to being evaluated.
1374
1375 // We know that ECRecord derives from NamingClass. The
1376 // restriction says to check whether NamingClass derives from
1377 // ECRecord, but that's not really necessary: two distinct
1378 // classes can't be recursively derived from each other. So
1379 // along this path, we just need to check whether the classes
1380 // are equal.
1381 if (NamingClass == ECRecord) return AR_accessible;
1382
1383 // Otherwise, this context class tells us nothing; on to the next.
1384 continue;
1385 }
1386
1387 assert(Target.isInstanceMember());
1388
1389 const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
1390 if (!InstanceContext) {
1391 OnFailure = AR_dependent;
1392 continue;
1393 }
1394
1395 switch (IsDerivedFromInclusive(Derived: InstanceContext, Target: ECRecord)) {
1396 case AR_accessible: return AR_accessible;
1397 case AR_inaccessible: continue;
1398 case AR_dependent: OnFailure = AR_dependent; continue;
1399 }
1400 }
1401 }
1402
1403 // [M3] and [B3] say that, if the target is protected in N, we grant
1404 // access if the access occurs in a friend or member of some class P
1405 // that's a subclass of N and where the target has some natural
1406 // access in P. The 'member' aspect is easy to handle because P
1407 // would necessarily be one of the effective-context records, and we
1408 // address that above. The 'friend' aspect is completely ridiculous
1409 // to implement because there are no restrictions at all on P
1410 // *unless* the [class.protected] restriction applies. If it does,
1411 // however, we should ignore whether the naming class is a friend,
1412 // and instead rely on whether any potential P is a friend.
1413 if (Access == AS_protected && Target.isInstanceMember()) {
1414 // Compute the instance context if possible.
1415 const CXXRecordDecl *InstanceContext = nullptr;
1416 if (Target.hasInstanceContext()) {
1417 InstanceContext = Target.resolveInstanceContext(S);
1418 if (!InstanceContext) return AR_dependent;
1419 }
1420
1421 switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass,
1422 FailedTSC)) {
1423 case AR_accessible: return AR_accessible;
1424 case AR_inaccessible: return OnFailure;
1425 case AR_dependent: return AR_dependent;
1426 }
1427 llvm_unreachable("impossible friendship kind");
1428 }
1429
1430 switch (GetFriendKind(S, EC, Class: NamingClass, FailedTSC)) {
1431 case AR_accessible: return AR_accessible;
1432 case AR_inaccessible: return OnFailure;
1433 case AR_dependent: return AR_dependent;
1434 }
1435
1436 // Silence bogus warnings
1437 llvm_unreachable("impossible friendship kind");
1438}
1439
1440/// Finds the best path from the naming class to the declaring class,
1441/// taking friend declarations into account.
1442///
1443/// C++0x [class.access.base]p5:
1444/// A member m is accessible at the point R when named in class N if
1445/// [M1] m as a member of N is public, or
1446/// [M2] m as a member of N is private, and R occurs in a member or
1447/// friend of class N, or
1448/// [M3] m as a member of N is protected, and R occurs in a member or
1449/// friend of class N, or in a member or friend of a class P
1450/// derived from N, where m as a member of P is public, private,
1451/// or protected, or
1452/// [M4] there exists a base class B of N that is accessible at R, and
1453/// m is accessible at R when named in class B.
1454///
1455/// C++0x [class.access.base]p4:
1456/// A base class B of N is accessible at R, if
1457/// [B1] an invented public member of B would be a public member of N, or
1458/// [B2] R occurs in a member or friend of class N, and an invented public
1459/// member of B would be a private or protected member of N, or
1460/// [B3] R occurs in a member or friend of a class P derived from N, and an
1461/// invented public member of B would be a private or protected member
1462/// of P, or
1463/// [B4] there exists a class S such that B is a base class of S accessible
1464/// at R and S is a base class of N accessible at R.
1465///
1466/// Along a single inheritance path we can restate both of these
1467/// iteratively:
1468///
1469/// First, we note that M1-4 are equivalent to B1-4 if the member is
1470/// treated as a notional base of its declaring class with inheritance
1471/// access equivalent to the member's access. Therefore we need only
1472/// ask whether a class B is accessible from a class N in context R.
1473///
1474/// Let B_1 .. B_n be the inheritance path in question (i.e. where
1475/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
1476/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the
1477/// closest accessible base in the path:
1478/// Access(a, b) = (* access on the base specifier from a to b *)
1479/// Merge(a, forbidden) = forbidden
1480/// Merge(a, private) = forbidden
1481/// Merge(a, b) = min(a,b)
1482/// Accessible(c, forbidden) = false
1483/// Accessible(c, private) = (R is c) || IsFriend(c, R)
1484/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
1485/// Accessible(c, public) = true
1486/// ACAB(n) = public
1487/// ACAB(i) =
1488/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
1489/// if Accessible(B_i, AccessToBase) then public else AccessToBase
1490///
1491/// B is an accessible base of N at R iff ACAB(1) = public.
1492///
1493/// \param FinalAccess the access of the "final step", or AS_public if
1494/// there is no final step.
1495/// \return null if friendship is dependent
1496static CXXBasePath *FindBestPath(Sema &S,
1497 const EffectiveContext &EC,
1498 AccessTarget &Target,
1499 AccessSpecifier FinalAccess,
1500 CXXBasePaths &Paths) {
1501 // Derive the paths to the desired base.
1502 const CXXRecordDecl *Derived = Target.getNamingClass();
1503 const CXXRecordDecl *Base = Target.getDeclaringClass();
1504
1505 // FIXME: fail correctly when there are dependent paths.
1506 bool isDerived = Derived->isDerivedFrom(Base: const_cast<CXXRecordDecl*>(Base),
1507 Paths);
1508 assert(isDerived && "derived class not actually derived from base");
1509 (void) isDerived;
1510
1511 CXXBasePath *BestPath = nullptr;
1512
1513 assert(FinalAccess != AS_none && "forbidden access after declaring class");
1514
1515 bool AnyDependent = false;
1516
1517 // Derive the friend-modified access along each path.
1518 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
1519 PI != PE; ++PI) {
1520 AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext();
1521
1522 // Walk through the path backwards.
1523 AccessSpecifier PathAccess = FinalAccess;
1524 CXXBasePath::iterator I = PI->end(), E = PI->begin();
1525 while (I != E) {
1526 --I;
1527
1528 assert(PathAccess != AS_none);
1529
1530 // If the declaration is a private member of a base class, there
1531 // is no level of friendship in derived classes that can make it
1532 // accessible.
1533 if (PathAccess == AS_private) {
1534 PathAccess = AS_none;
1535 break;
1536 }
1537
1538 const CXXRecordDecl *NC = I->Class->getCanonicalDecl();
1539
1540 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
1541 PathAccess = std::max(a: PathAccess, b: BaseAccess);
1542
1543 switch (HasAccess(S, EC, NamingClass: NC, Access: PathAccess, Target,
1544 /*FailedTSC=*/nullptr)) {
1545 case AR_inaccessible: break;
1546 case AR_accessible:
1547 PathAccess = AS_public;
1548
1549 // Future tests are not against members and so do not have
1550 // instance context.
1551 Target.suppressInstanceContext();
1552 break;
1553 case AR_dependent:
1554 AnyDependent = true;
1555 goto Next;
1556 }
1557 }
1558
1559 // Note that we modify the path's Access field to the
1560 // friend-modified access.
1561 if (BestPath == nullptr || PathAccess < BestPath->Access) {
1562 BestPath = &*PI;
1563 BestPath->Access = PathAccess;
1564
1565 // Short-circuit if we found a public path.
1566 if (BestPath->Access == AS_public)
1567 return BestPath;
1568 }
1569
1570 Next: ;
1571 }
1572
1573 assert((!BestPath || BestPath->Access != AS_public) &&
1574 "fell out of loop with public path");
1575
1576 // We didn't find a public path, but at least one path was subject
1577 // to dependent friendship, so delay the check.
1578 if (AnyDependent)
1579 return nullptr;
1580
1581 return BestPath;
1582}
1583
1584/// Given that an entity has protected natural access, check whether
1585/// access might be denied because of the protected member access
1586/// restriction.
1587///
1588/// \return true if a note was emitted
1589static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
1590 AccessTarget &Target) {
1591 // Only applies to instance accesses.
1592 if (!Target.isInstanceMember())
1593 return false;
1594
1595 assert(Target.isMemberAccess());
1596
1597 const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass();
1598
1599 for (EffectiveContext::record_iterator
1600 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
1601 const CXXRecordDecl *ECRecord = *I;
1602 switch (IsDerivedFromInclusive(Derived: ECRecord, Target: NamingClass)) {
1603 case AR_accessible: break;
1604 case AR_inaccessible: continue;
1605 case AR_dependent: continue;
1606 }
1607
1608 // The effective context is a subclass of the declaring class.
1609 // Check whether the [class.protected] restriction is limiting
1610 // access.
1611
1612 // To get this exactly right, this might need to be checked more
1613 // holistically; it's not necessarily the case that gaining
1614 // access here would grant us access overall.
1615
1616 NamedDecl *D = Target.getTargetDecl();
1617
1618 // If we don't have an instance context, [class.protected] says the
1619 // naming class has to equal the context class.
1620 if (!Target.hasInstanceContext()) {
1621 // If it does, the restriction doesn't apply.
1622 if (NamingClass == ECRecord) continue;
1623
1624 // TODO: it would be great to have a fixit here, since this is
1625 // such an obvious error.
1626 S.Diag(Loc: D->getLocation(), DiagID: diag::note_access_protected_restricted_noobject)
1627 << S.Context.getCanonicalTagType(TD: ECRecord);
1628 return true;
1629 }
1630
1631 const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
1632 assert(InstanceContext && "diagnosing dependent access");
1633
1634 switch (IsDerivedFromInclusive(Derived: InstanceContext, Target: ECRecord)) {
1635 case AR_accessible: continue;
1636 case AR_dependent: continue;
1637 case AR_inaccessible:
1638 break;
1639 }
1640
1641 // Okay, the restriction seems to be what's limiting us.
1642
1643 // Use a special diagnostic for constructors and destructors.
1644 if (isa<CXXConstructorDecl>(Val: D) || isa<CXXDestructorDecl>(Val: D) ||
1645 (isa<FunctionTemplateDecl>(Val: D) &&
1646 isa<CXXConstructorDecl>(
1647 Val: cast<FunctionTemplateDecl>(Val: D)->getTemplatedDecl()))) {
1648 return S.Diag(Loc: D->getLocation(),
1649 DiagID: diag::note_access_protected_restricted_ctordtor)
1650 << isa<CXXDestructorDecl>(Val: D->getAsFunction());
1651 }
1652
1653 // Otherwise, use the generic diagnostic.
1654 return S.Diag(Loc: D->getLocation(),
1655 DiagID: diag::note_access_protected_restricted_object)
1656 << S.Context.getCanonicalTagType(TD: ECRecord);
1657 }
1658
1659 return false;
1660}
1661
1662/// We are unable to access a given declaration due to its direct
1663/// access control; diagnose that.
1664static void diagnoseBadDirectAccess(Sema &S,
1665 const EffectiveContext &EC,
1666 AccessTarget &entity) {
1667 assert(entity.isMemberAccess());
1668 NamedDecl *D = entity.getTargetDecl();
1669
1670 if (D->getAccess() == AS_protected &&
1671 TryDiagnoseProtectedAccess(S, EC, Target&: entity))
1672 return;
1673
1674 // Find an original declaration.
1675 while (D->isOutOfLine()) {
1676 NamedDecl *PrevDecl = nullptr;
1677 if (VarDecl *VD = dyn_cast<VarDecl>(Val: D))
1678 PrevDecl = VD->getPreviousDecl();
1679 else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Val: D))
1680 PrevDecl = FD->getPreviousDecl();
1681 else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(Val: D))
1682 PrevDecl = TND->getPreviousDecl();
1683 else if (TagDecl *TD = dyn_cast<TagDecl>(Val: D)) {
1684 if (const auto *RD = dyn_cast<CXXRecordDecl>(Val: TD);
1685 RD && RD->isInjectedClassName())
1686 break;
1687 PrevDecl = TD->getPreviousDecl();
1688 }
1689 if (!PrevDecl) break;
1690 D = PrevDecl;
1691 }
1692
1693 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
1694 Decl *ImmediateChild;
1695 if (D->getDeclContext() == DeclaringClass)
1696 ImmediateChild = D;
1697 else {
1698 DeclContext *DC = D->getDeclContext();
1699 while (DC->getParent() != DeclaringClass)
1700 DC = DC->getParent();
1701 ImmediateChild = cast<Decl>(Val: DC);
1702 }
1703
1704 // Check whether there's an AccessSpecDecl preceding this in the
1705 // chain of the DeclContext.
1706 bool isImplicit = true;
1707 for (const auto *I : DeclaringClass->decls()) {
1708 if (I == ImmediateChild) break;
1709 if (isa<AccessSpecDecl>(Val: I)) {
1710 isImplicit = false;
1711 break;
1712 }
1713 }
1714
1715 S.Diag(Loc: D->getLocation(), DiagID: diag::note_access_natural)
1716 << (unsigned) (D->getAccess() == AS_protected)
1717 << isImplicit;
1718}
1719
1720/// Diagnose the path which caused the given declaration or base class
1721/// to become inaccessible.
1722static void DiagnoseAccessPath(Sema &S,
1723 const EffectiveContext &EC,
1724 AccessTarget &entity) {
1725 // Save the instance context to preserve invariants.
1726 AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext();
1727
1728 // This basically repeats the main algorithm but keeps some more
1729 // information.
1730
1731 // The natural access so far.
1732 AccessSpecifier accessSoFar = AS_public;
1733
1734 // Check whether we have special rights to the declaring class.
1735 if (entity.isMemberAccess()) {
1736 NamedDecl *D = entity.getTargetDecl();
1737 accessSoFar = D->getAccess();
1738 const CXXRecordDecl *declaringClass = entity.getDeclaringClass();
1739
1740 switch (HasAccess(S, EC, NamingClass: declaringClass, Access: accessSoFar, Target: entity,
1741 /*FailedTSC=*/nullptr)) {
1742 // If the declaration is accessible when named in its declaring
1743 // class, then we must be constrained by the path.
1744 case AR_accessible:
1745 accessSoFar = AS_public;
1746 entity.suppressInstanceContext();
1747 break;
1748
1749 case AR_inaccessible:
1750 if (accessSoFar == AS_private ||
1751 declaringClass == entity.getEffectiveNamingClass())
1752 return diagnoseBadDirectAccess(S, EC, entity);
1753 break;
1754
1755 case AR_dependent:
1756 llvm_unreachable("cannot diagnose dependent access");
1757 }
1758 }
1759
1760 CXXBasePaths paths;
1761 CXXBasePath &path = *FindBestPath(S, EC, Target&: entity, FinalAccess: accessSoFar, Paths&: paths);
1762 assert(path.Access != AS_public);
1763
1764 CXXBasePath::iterator i = path.end(), e = path.begin();
1765 CXXBasePath::iterator constrainingBase = i;
1766 while (i != e) {
1767 --i;
1768
1769 assert(accessSoFar != AS_none && accessSoFar != AS_private);
1770
1771 // Is the entity accessible when named in the deriving class, as
1772 // modified by the base specifier?
1773 const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl();
1774 const CXXBaseSpecifier *base = i->Base;
1775
1776 // If the access to this base is worse than the access we have to
1777 // the declaration, remember it.
1778 AccessSpecifier baseAccess = base->getAccessSpecifier();
1779 if (baseAccess > accessSoFar) {
1780 constrainingBase = i;
1781 accessSoFar = baseAccess;
1782 }
1783
1784 switch (HasAccess(S, EC, NamingClass: derivingClass, Access: accessSoFar, Target: entity,
1785 /*FailedTSC=*/nullptr)) {
1786 case AR_inaccessible: break;
1787 case AR_accessible:
1788 accessSoFar = AS_public;
1789 entity.suppressInstanceContext();
1790 constrainingBase = nullptr;
1791 break;
1792 case AR_dependent:
1793 llvm_unreachable("cannot diagnose dependent access");
1794 }
1795
1796 // If this was private inheritance, but we don't have access to
1797 // the deriving class, we're done.
1798 if (accessSoFar == AS_private) {
1799 assert(baseAccess == AS_private);
1800 assert(constrainingBase == i);
1801 break;
1802 }
1803 }
1804
1805 // If we don't have a constraining base, the access failure must be
1806 // due to the original declaration.
1807 if (constrainingBase == path.end())
1808 return diagnoseBadDirectAccess(S, EC, entity);
1809
1810 // We're constrained by inheritance, but we want to say
1811 // "declared private here" if we're diagnosing a hierarchy
1812 // conversion and this is the final step.
1813 unsigned diagnostic;
1814 if (entity.isMemberAccess() ||
1815 constrainingBase + 1 != path.end()) {
1816 diagnostic = diag::note_access_constrained_by_path;
1817 } else {
1818 diagnostic = diag::note_access_natural;
1819 }
1820
1821 const CXXBaseSpecifier *base = constrainingBase->Base;
1822
1823 S.Diag(Loc: base->getSourceRange().getBegin(), DiagID: diagnostic)
1824 << base->getSourceRange()
1825 << (base->getAccessSpecifier() == AS_protected)
1826 << (base->getAccessSpecifierAsWritten() == AS_none);
1827
1828 if (entity.isMemberAccess())
1829 S.Diag(Loc: entity.getTargetDecl()->getLocation(),
1830 DiagID: diag::note_member_declared_at);
1831}
1832
1833static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
1834 const EffectiveContext &EC,
1835 AccessTarget &Entity) {
1836 const CXXRecordDecl *NamingClass = Entity.getNamingClass();
1837 const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
1838 NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : nullptr);
1839
1840 S.Diag(Loc, PD: Entity.getDiag())
1841 << (Entity.getAccess() == AS_protected)
1842 << (D ? D->getDeclName() : DeclarationName())
1843 << S.Context.getCanonicalTagType(TD: NamingClass)
1844 << S.Context.getCanonicalTagType(TD: DeclaringClass);
1845 DiagnoseAccessPath(S, EC, entity&: Entity);
1846}
1847
1848/// MSVC has a bug where if during an using declaration name lookup,
1849/// the declaration found is unaccessible (private) and that declaration
1850/// was bring into scope via another using declaration whose target
1851/// declaration is accessible (public) then no error is generated.
1852/// Example:
1853/// class A {
1854/// public:
1855/// int f();
1856/// };
1857/// class B : public A {
1858/// private:
1859/// using A::f;
1860/// };
1861/// class C : public B {
1862/// private:
1863/// using B::f;
1864/// };
1865///
1866/// Here, B::f is private so this should fail in Standard C++, but
1867/// because B::f refers to A::f which is public MSVC accepts it.
1868static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
1869 SourceLocation AccessLoc,
1870 AccessTarget &Entity) {
1871 if (UsingShadowDecl *Shadow =
1872 dyn_cast<UsingShadowDecl>(Val: Entity.getTargetDecl()))
1873 if (UsingDecl *UD = dyn_cast<UsingDecl>(Val: Shadow->getIntroducer())) {
1874 const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl();
1875 if (Entity.getTargetDecl()->getAccess() == AS_private &&
1876 (OrigDecl->getAccess() == AS_public ||
1877 OrigDecl->getAccess() == AS_protected)) {
1878 S.Diag(Loc: AccessLoc, DiagID: diag::ext_ms_using_declaration_inaccessible)
1879 << UD->getQualifiedNameAsString()
1880 << OrigDecl->getQualifiedNameAsString();
1881 return true;
1882 }
1883 }
1884 return false;
1885}
1886
1887/// Determines whether the accessed entity is accessible. Public members
1888/// have been weeded out by this point.
1889static AccessResult IsAccessible(Sema &S, const EffectiveContext &EC,
1890 AccessTarget &Entity,
1891 TemplateSpecCandidateSet *FailedTSC) {
1892 // Determine the actual naming class.
1893 const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();
1894
1895 AccessSpecifier UnprivilegedAccess = Entity.getAccess();
1896 assert(UnprivilegedAccess != AS_public && "public access not weeded out");
1897
1898 // Before we try to recalculate access paths, try to white-list
1899 // accesses which just trade in on the final step, i.e. accesses
1900 // which don't require [M4] or [B4]. These are by far the most
1901 // common forms of privileged access.
1902 if (UnprivilegedAccess != AS_none) {
1903 switch (
1904 HasAccess(S, EC, NamingClass, Access: UnprivilegedAccess, Target: Entity, FailedTSC)) {
1905 case AR_dependent:
1906 // This is actually an interesting policy decision. We don't
1907 // *have* to delay immediately here: we can do the full access
1908 // calculation in the hope that friendship on some intermediate
1909 // class will make the declaration accessible non-dependently.
1910 // But that's not cheap, and odds are very good (note: assertion
1911 // made without data) that the friend declaration will determine
1912 // access.
1913 return AR_dependent;
1914
1915 case AR_accessible: return AR_accessible;
1916 case AR_inaccessible: break;
1917 }
1918 }
1919
1920 AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();
1921
1922 // We lower member accesses to base accesses by pretending that the
1923 // member is a base class of its declaring class.
1924 AccessSpecifier FinalAccess;
1925
1926 if (Entity.isMemberAccess()) {
1927 // Determine if the declaration is accessible from EC when named
1928 // in its declaring class.
1929 NamedDecl *Target = Entity.getTargetDecl();
1930 const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
1931
1932 FinalAccess = Target->getAccess();
1933 switch (HasAccess(S, EC, NamingClass: DeclaringClass, Access: FinalAccess, Target: Entity, FailedTSC)) {
1934 case AR_accessible:
1935 // Target is accessible at EC when named in its declaring class.
1936 // We can now hill-climb and simply check whether the declaring
1937 // class is accessible as a base of the naming class. This is
1938 // equivalent to checking the access of a notional public
1939 // member with no instance context.
1940 FinalAccess = AS_public;
1941 Entity.suppressInstanceContext();
1942 break;
1943 case AR_inaccessible: break;
1944 case AR_dependent: return AR_dependent; // see above
1945 }
1946
1947 if (DeclaringClass == NamingClass)
1948 return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
1949 } else {
1950 FinalAccess = AS_public;
1951 }
1952
1953 assert(Entity.getDeclaringClass() != NamingClass);
1954
1955 // Append the declaration's access if applicable.
1956 CXXBasePaths Paths;
1957 CXXBasePath *Path = FindBestPath(S, EC, Target&: Entity, FinalAccess, Paths);
1958 if (!Path)
1959 return AR_dependent;
1960
1961 assert(Path->Access <= UnprivilegedAccess &&
1962 "access along best path worse than direct?");
1963 if (Path->Access == AS_public)
1964 return AR_accessible;
1965 return AR_inaccessible;
1966}
1967
1968static void DelayDependentAccess(Sema &S,
1969 const EffectiveContext &EC,
1970 SourceLocation Loc,
1971 const AccessTarget &Entity) {
1972 assert(EC.isDependent() && "delaying non-dependent access");
1973 DeclContext *DC = EC.getInnerContext();
1974 assert(DC->isDependentContext() && "delaying non-dependent access");
1975 DependentDiagnostic::Create(Context&: S.Context, Parent: DC, DependentDiagnostic::Access,
1976 Loc,
1977 IsMemberAccess: Entity.isMemberAccess(),
1978 AS: Entity.getAccess(),
1979 TargetDecl: Entity.getTargetDecl(),
1980 NamingClass: Entity.getNamingClass(),
1981 BaseObjectType: Entity.getBaseObjectType(),
1982 PDiag: Entity.getDiag());
1983}
1984
1985static AccessResult CheckEffectiveAccess(Sema &S, const EffectiveContext &EC,
1986 SourceLocation Loc,
1987 AccessTarget &Entity,
1988 TemplateSpecCandidateSet *FailedTSC) {
1989 assert((Entity.isQuiet() || FailedTSC) &&
1990 "non-quiet access check requires a candidate set");
1991
1992 switch (IsAccessible(S, EC, Entity, FailedTSC)) {
1993 case AR_dependent:
1994 DelayDependentAccess(S, EC, Loc, Entity);
1995 return AR_dependent;
1996
1997 case AR_inaccessible: {
1998 if (S.getLangOpts().MSVCCompat &&
1999 IsMicrosoftUsingDeclarationAccessBug(S, AccessLoc: Loc, Entity))
2000 return AR_accessible;
2001
2002 if (Entity.isQuiet())
2003 return AR_inaccessible;
2004
2005 DiagnoseBadAccess(S, Loc, EC, Entity);
2006 FailedTSC->NoteCandidates(S, Loc);
2007 return AR_inaccessible;
2008 }
2009
2010 case AR_accessible:
2011 return AR_accessible;
2012 }
2013
2014 // silence unnecessary warning
2015 llvm_unreachable("invalid access result");
2016}
2017
2018static AccessResult CheckEffectiveAccess(Sema &S, const EffectiveContext &EC,
2019 SourceLocation Loc,
2020 AccessTarget &Entity) {
2021 assert(Entity.getAccess() != AS_public && "called for public access!");
2022
2023 if (Entity.isQuiet())
2024 return CheckEffectiveAccess(S, EC, Loc, Entity, /*FailedTSC=*/nullptr);
2025
2026 TemplateSpecCandidateSet FailedTSC(
2027 Loc, /*ForTakingAddress=*/false,
2028 TemplateSpecCandidateSetKind::FriendTemplate);
2029 return CheckEffectiveAccess(S, EC, Loc, Entity, FailedTSC: &FailedTSC);
2030}
2031
2032static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
2033 AccessTarget &Entity) {
2034 // If the access path is public, it's accessible everywhere.
2035 if (Entity.getAccess() == AS_public)
2036 return Sema::AR_accessible;
2037
2038 // If we're currently parsing a declaration, we may need to delay
2039 // access control checking, because our effective context might be
2040 // different based on what the declaration comes out as.
2041 //
2042 // For example, we might be parsing a declaration with a scope
2043 // specifier, like this:
2044 // A::private_type A::foo() { ... }
2045 //
2046 // friend declaration should not be delayed because it may lead to incorrect
2047 // redeclaration chain, such as:
2048 // class D {
2049 // class E{
2050 // class F{};
2051 // friend void foo(D::E::F& q);
2052 // };
2053 // friend void foo(D::E::F& q);
2054 // };
2055 if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
2056 // [class.friend]p9:
2057 // A member nominated by a friend declaration shall be accessible in the
2058 // class containing the friend declaration. The meaning of the friend
2059 // declaration is the same whether the friend declaration appears in the
2060 // private, protected, or public ([class.mem]) portion of the class
2061 // member-specification.
2062 Scope *TS = S.getCurScope();
2063 bool IsFriendDeclaration = false;
2064 while (TS && !IsFriendDeclaration) {
2065 IsFriendDeclaration = TS->isFriendScope();
2066 TS = TS->getParent();
2067 }
2068 if (!IsFriendDeclaration) {
2069 S.DelayedDiagnostics.add(diag: DelayedDiagnostic::makeAccess(Loc, Entity));
2070 return Sema::AR_delayed;
2071 }
2072 }
2073
2074 EffectiveContext EC(S.CurContext);
2075 switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
2076 case AR_accessible: return Sema::AR_accessible;
2077 case AR_inaccessible: return Sema::AR_inaccessible;
2078 case AR_dependent: return Sema::AR_dependent;
2079 }
2080 llvm_unreachable("invalid access result");
2081}
2082
2083void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
2084 // Access control for names used in the declarations of functions
2085 // and function templates should normally be evaluated in the context
2086 // of the declaration, just in case it's a friend of something.
2087 // However, this does not apply to local extern declarations.
2088
2089 DeclContext *DC = D->getDeclContext();
2090 if (D->isLocalExternDecl()) {
2091 DC = D->getLexicalDeclContext();
2092 } else if (FunctionDecl *FN = dyn_cast<FunctionDecl>(Val: D)) {
2093 DC = FN;
2094 } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(Val: D)) {
2095 if (auto *D = dyn_cast_if_present<DeclContext>(Val: TD->getTemplatedDecl()))
2096 DC = D;
2097 } else if (auto *RD = dyn_cast<RequiresExprBodyDecl>(Val: D)) {
2098 DC = RD;
2099 }
2100
2101 EffectiveContext EC(DC);
2102
2103 AccessTarget Target(DD.getAccessData());
2104
2105 if (CheckEffectiveAccess(S&: *this, EC, Loc: DD.Loc, Entity&: Target) == ::AR_inaccessible)
2106 DD.Triggered = true;
2107}
2108
2109void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
2110 const MultiLevelTemplateArgumentList &TemplateArgs) {
2111 SourceLocation Loc = DD.getAccessLoc();
2112 AccessSpecifier Access = DD.getAccess();
2113
2114 Decl *NamingD = FindInstantiatedDecl(Loc, D: DD.getAccessNamingClass(),
2115 TemplateArgs);
2116 if (!NamingD) return;
2117 Decl *TargetD = FindInstantiatedDecl(Loc, D: DD.getAccessTarget(),
2118 TemplateArgs);
2119 if (!TargetD) return;
2120
2121 if (DD.isAccessToMember()) {
2122 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Val: NamingD);
2123 NamedDecl *TargetDecl = cast<NamedDecl>(Val: TargetD);
2124 QualType BaseObjectType = DD.getAccessBaseObjectType();
2125 if (!BaseObjectType.isNull()) {
2126 BaseObjectType = SubstType(T: BaseObjectType, TemplateArgs, Loc,
2127 Entity: DeclarationName());
2128 if (BaseObjectType.isNull()) return;
2129 }
2130
2131 AccessTarget Entity(Context,
2132 AccessTarget::Member,
2133 NamingClass,
2134 DeclAccessPair::make(D: TargetDecl, AS: Access),
2135 BaseObjectType);
2136 Entity.setDiag(DD.getDiagnostic());
2137 CheckAccess(S&: *this, Loc, Entity);
2138 } else {
2139 AccessTarget Entity(Context,
2140 AccessTarget::Base,
2141 cast<CXXRecordDecl>(Val: TargetD),
2142 cast<CXXRecordDecl>(Val: NamingD),
2143 Access);
2144 Entity.setDiag(DD.getDiagnostic());
2145 CheckAccess(S&: *this, Loc, Entity);
2146 }
2147}
2148
2149Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
2150 DeclAccessPair Found) {
2151 if (!getLangOpts().AccessControl ||
2152 !E->getNamingClass() ||
2153 Found.getAccess() == AS_public)
2154 return AR_accessible;
2155
2156 AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
2157 Found, QualType());
2158 Entity.setDiag(diag::err_access) << E->getSourceRange();
2159
2160 return CheckAccess(S&: *this, Loc: E->getNameLoc(), Entity);
2161}
2162
2163Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
2164 DeclAccessPair Found) {
2165 if (!getLangOpts().AccessControl ||
2166 Found.getAccess() == AS_public)
2167 return AR_accessible;
2168
2169 QualType BaseType = E->getBaseType();
2170 if (E->isArrow())
2171 BaseType = BaseType->castAs<PointerType>()->getPointeeType();
2172
2173 AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
2174 Found, BaseType);
2175 Entity.setDiag(diag::err_access) << E->getSourceRange();
2176
2177 return CheckAccess(S&: *this, Loc: E->getMemberLoc(), Entity);
2178}
2179
2180bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass,
2181 DeclAccessPair Found,
2182 QualType ObjectType,
2183 SourceLocation Loc,
2184 const PartialDiagnostic &Diag) {
2185 // Fast path.
2186 if (Found.getAccess() == AS_public || !getLangOpts().AccessControl)
2187 return true;
2188
2189 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
2190 ObjectType);
2191
2192 // Suppress diagnostics.
2193 Entity.setDiag(Diag);
2194
2195 // We don't want to delay access checking even we are inside an enclosing
2196 // delayed-diagnostics scope (e.g. when parsing a later declaration whose
2197 // initializer requires explaining why a defaulted comparison operator is
2198 // deleted)
2199 llvm::scope_exit UndelayDiags(
2200 [&, CurrentState(DelayedDiagnostics.pushUndelayed())] {
2201 DelayedDiagnostics.popUndelayed(state: CurrentState);
2202 });
2203
2204 switch (CheckAccess(S&: *this, Loc, Entity)) {
2205 case AR_accessible: return true;
2206 case AR_inaccessible: return false;
2207 case AR_dependent: llvm_unreachable("dependent for =delete computation");
2208 case AR_delayed: llvm_unreachable("cannot delay =delete computation");
2209 }
2210 llvm_unreachable("bad access result");
2211}
2212
2213Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
2214 CXXDestructorDecl *Dtor,
2215 const PartialDiagnostic &PDiag,
2216 QualType ObjectTy) {
2217 if (!getLangOpts().AccessControl)
2218 return AR_accessible;
2219
2220 // There's never a path involved when checking implicit destructor access.
2221 AccessSpecifier Access = Dtor->getAccess();
2222 if (Access == AS_public)
2223 return AR_accessible;
2224
2225 CXXRecordDecl *NamingClass = Dtor->getParent();
2226 if (ObjectTy.isNull())
2227 ObjectTy = Context.getCanonicalTagType(TD: NamingClass);
2228
2229 AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
2230 DeclAccessPair::make(D: Dtor, AS: Access),
2231 ObjectTy);
2232 Entity.setDiag(PDiag); // TODO: avoid copy
2233
2234 return CheckAccess(S&: *this, Loc, Entity);
2235}
2236
2237Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
2238 CXXConstructorDecl *Constructor,
2239 DeclAccessPair Found,
2240 const InitializedEntity &Entity,
2241 bool IsCopyBindingRefToTemp) {
2242 if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
2243 return AR_accessible;
2244
2245 PartialDiagnostic PD(PDiag());
2246 switch (Entity.getKind()) {
2247 default:
2248 PD = PDiag(DiagID: IsCopyBindingRefToTemp
2249 ? diag::ext_rvalue_to_reference_access_ctor
2250 : diag::err_access_ctor);
2251
2252 break;
2253
2254 case InitializedEntity::EK_Base:
2255 PD = PDiag(DiagID: diag::err_access_base_ctor);
2256 PD << Entity.isInheritedVirtualBase()
2257 << Entity.getBaseSpecifier()->getType()
2258 << Constructor->getSpecialMemberKind();
2259 break;
2260
2261 case InitializedEntity::EK_Member:
2262 case InitializedEntity::EK_ParenAggInitMember: {
2263 const FieldDecl *Field = cast<FieldDecl>(Val: Entity.getDecl());
2264 PD = PDiag(DiagID: diag::err_access_field_ctor);
2265 PD << Field->getType() << Constructor->getSpecialMemberKind();
2266 break;
2267 }
2268
2269 case InitializedEntity::EK_LambdaCapture: {
2270 StringRef VarName = Entity.getCapturedVarName();
2271 PD = PDiag(DiagID: diag::err_access_lambda_capture);
2272 PD << VarName << Entity.getType() << Constructor->getSpecialMemberKind();
2273 break;
2274 }
2275
2276 }
2277
2278 return CheckConstructorAccess(Loc: UseLoc, D: Constructor, FoundDecl: Found, Entity, PDiag: PD);
2279}
2280
2281Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
2282 CXXConstructorDecl *Constructor,
2283 DeclAccessPair Found,
2284 const InitializedEntity &Entity,
2285 const PartialDiagnostic &PD) {
2286 if (!getLangOpts().AccessControl ||
2287 Found.getAccess() == AS_public)
2288 return AR_accessible;
2289
2290 CXXRecordDecl *NamingClass = Constructor->getParent();
2291
2292 // Initializing a base sub-object is an instance method call on an
2293 // object of the derived class. Otherwise, we have an instance method
2294 // call on an object of the constructed type.
2295 //
2296 // FIXME: If we have a parent, we're initializing the base class subobject
2297 // in aggregate initialization. It's not clear whether the object class
2298 // should be the base class or the derived class in that case.
2299 CXXRecordDecl *ObjectClass;
2300 if ((Entity.getKind() == InitializedEntity::EK_Base ||
2301 Entity.getKind() == InitializedEntity::EK_Delegating) &&
2302 !Entity.getParent()) {
2303 ObjectClass = cast<CXXConstructorDecl>(Val: CurContext)->getParent();
2304 } else if (auto *Shadow =
2305 dyn_cast<ConstructorUsingShadowDecl>(Val: Found.getDecl())) {
2306 // If we're using an inheriting constructor to construct an object,
2307 // the object class is the derived class, not the base class.
2308 ObjectClass = Shadow->getParent();
2309 } else {
2310 ObjectClass = NamingClass;
2311 }
2312
2313 AccessTarget AccessEntity(
2314 Context, AccessTarget::Member, NamingClass,
2315 DeclAccessPair::make(D: Constructor, AS: Found.getAccess()),
2316 Context.getCanonicalTagType(TD: ObjectClass));
2317 AccessEntity.setDiag(PD);
2318
2319 return CheckAccess(S&: *this, Loc: UseLoc, Entity&: AccessEntity);
2320}
2321
2322Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
2323 SourceRange PlacementRange,
2324 CXXRecordDecl *NamingClass,
2325 DeclAccessPair Found,
2326 bool Diagnose) {
2327 if (!getLangOpts().AccessControl ||
2328 !NamingClass ||
2329 Found.getAccess() == AS_public)
2330 return AR_accessible;
2331
2332 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
2333 QualType());
2334 if (Diagnose)
2335 Entity.setDiag(diag::err_access)
2336 << PlacementRange;
2337
2338 return CheckAccess(S&: *this, Loc: OpLoc, Entity);
2339}
2340
2341Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc,
2342 CXXRecordDecl *NamingClass,
2343 DeclAccessPair Found) {
2344 if (!getLangOpts().AccessControl ||
2345 !NamingClass ||
2346 Found.getAccess() == AS_public)
2347 return AR_accessible;
2348
2349 AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
2350 Found, QualType());
2351
2352 return CheckAccess(S&: *this, Loc: UseLoc, Entity);
2353}
2354
2355Sema::AccessResult
2356Sema::CheckStructuredBindingMemberAccess(SourceLocation UseLoc,
2357 CXXRecordDecl *DecomposedClass,
2358 DeclAccessPair Field) {
2359 if (!getLangOpts().AccessControl ||
2360 Field.getAccess() == AS_public)
2361 return AR_accessible;
2362
2363 AccessTarget Entity(Context, AccessTarget::Member, DecomposedClass, Field,
2364 Context.getCanonicalTagType(TD: DecomposedClass));
2365 Entity.setDiag(diag::err_decomp_decl_inaccessible_field);
2366
2367 return CheckAccess(S&: *this, Loc: UseLoc, Entity);
2368}
2369
2370Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
2371 Expr *ObjectExpr,
2372 const SourceRange &Range,
2373 DeclAccessPair Found) {
2374 if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
2375 return AR_accessible;
2376
2377 auto *NamingClass = ObjectExpr->getType()->castAsCXXRecordDecl();
2378 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
2379 ObjectExpr->getType());
2380 Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << Range;
2381
2382 return CheckAccess(S&: *this, Loc: OpLoc, Entity);
2383}
2384
2385Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
2386 Expr *ObjectExpr,
2387 Expr *ArgExpr,
2388 DeclAccessPair Found) {
2389 return CheckMemberOperatorAccess(
2390 OpLoc, ObjectExpr, Range: ArgExpr ? ArgExpr->getSourceRange() : SourceRange(),
2391 Found);
2392}
2393
2394Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
2395 Expr *ObjectExpr,
2396 ArrayRef<Expr *> ArgExprs,
2397 DeclAccessPair FoundDecl) {
2398 SourceRange R;
2399 if (!ArgExprs.empty()) {
2400 R = SourceRange(ArgExprs.front()->getBeginLoc(),
2401 ArgExprs.back()->getEndLoc());
2402 }
2403
2404 return CheckMemberOperatorAccess(OpLoc, ObjectExpr, Range: R, Found: FoundDecl);
2405}
2406
2407Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
2408 assert(isa<CXXMethodDecl>(target->getAsFunction()));
2409
2410 // Friendship lookup is a redeclaration lookup, so there's never an
2411 // inheritance path modifying access.
2412 AccessSpecifier access = target->getAccess();
2413
2414 if (!getLangOpts().AccessControl || access == AS_public)
2415 return AR_accessible;
2416
2417 CXXMethodDecl *method = cast<CXXMethodDecl>(Val: target->getAsFunction());
2418
2419 AccessTarget entity(Context, AccessTarget::Member,
2420 cast<CXXRecordDecl>(Val: target->getDeclContext()),
2421 DeclAccessPair::make(D: target, AS: access),
2422 /*no instance context*/ QualType());
2423 entity.setDiag(diag::err_access_friend_function)
2424 << (method->getQualifier() ? method->getQualifierLoc().getSourceRange()
2425 : method->getNameInfo().getSourceRange());
2426
2427 // We need to bypass delayed-diagnostics because we might be called
2428 // while the ParsingDeclarator is active.
2429 EffectiveContext EC(CurContext);
2430 switch (CheckEffectiveAccess(S&: *this, EC, Loc: target->getLocation(), Entity&: entity)) {
2431 case ::AR_accessible: return Sema::AR_accessible;
2432 case ::AR_inaccessible: return Sema::AR_inaccessible;
2433 case ::AR_dependent: return Sema::AR_dependent;
2434 }
2435 llvm_unreachable("invalid access result");
2436}
2437
2438Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
2439 DeclAccessPair Found) {
2440 if (!getLangOpts().AccessControl ||
2441 Found.getAccess() == AS_none ||
2442 Found.getAccess() == AS_public)
2443 return AR_accessible;
2444
2445 OverloadExpr *Ovl = OverloadExpr::find(E: OvlExpr).Expression;
2446 CXXRecordDecl *NamingClass = Ovl->getNamingClass();
2447
2448 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
2449 /*no instance context*/ QualType());
2450 Entity.setDiag(diag::err_access)
2451 << Ovl->getSourceRange();
2452
2453 return CheckAccess(S&: *this, Loc: Ovl->getNameLoc(), Entity);
2454}
2455
2456Sema::AccessResult Sema::CheckBaseClassAccess(
2457 SourceLocation AccessLoc, CXXRecordDecl *Base, CXXRecordDecl *Derived,
2458 const CXXBasePath &Path, unsigned DiagID,
2459 llvm::function_ref<void(PartialDiagnostic &)> SetupPDiag, bool ForceCheck,
2460 bool ForceUnprivileged) {
2461 if (!ForceCheck && !getLangOpts().AccessControl)
2462 return AR_accessible;
2463
2464 if (Path.Access == AS_public)
2465 return AR_accessible;
2466
2467 AccessTarget Entity(Context, AccessTarget::Base, Base, Derived, Path.Access);
2468 if (DiagID)
2469 SetupPDiag(Entity.setDiag(DiagID));
2470
2471 if (ForceUnprivileged) {
2472 switch (
2473 CheckEffectiveAccess(S&: *this, EC: EffectiveContext(), Loc: AccessLoc, Entity)) {
2474 case ::AR_accessible:
2475 return Sema::AR_accessible;
2476 case ::AR_inaccessible:
2477 return Sema::AR_inaccessible;
2478 case ::AR_dependent:
2479 return Sema::AR_dependent;
2480 }
2481 llvm_unreachable("unexpected result from CheckEffectiveAccess");
2482 }
2483 return CheckAccess(S&: *this, Loc: AccessLoc, Entity);
2484}
2485
2486Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
2487 QualType Base, QualType Derived,
2488 const CXXBasePath &Path,
2489 unsigned DiagID, bool ForceCheck,
2490 bool ForceUnprivileged) {
2491 return CheckBaseClassAccess(
2492 AccessLoc, Base: Base->getAsCXXRecordDecl(), Derived: Derived->getAsCXXRecordDecl(),
2493 Path, DiagID, SetupPDiag: [&](PartialDiagnostic &PD) { PD << Derived << Base; },
2494 ForceCheck, ForceUnprivileged);
2495}
2496
2497void Sema::CheckLookupAccess(const LookupResult &R) {
2498 assert(getLangOpts().AccessControl
2499 && "performing access check without access control");
2500 assert(R.getNamingClass() && "performing access check without naming class");
2501
2502 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
2503 if (I.getAccess() != AS_public) {
2504 AccessTarget Entity(Context, AccessedEntity::Member,
2505 R.getNamingClass(), I.getPair(),
2506 R.getBaseObjectType());
2507 Entity.setDiag(diag::err_access);
2508 CheckAccess(S&: *this, Loc: R.getNameLoc(), Entity);
2509 }
2510 }
2511}
2512
2513bool Sema::IsSimplyAccessible(NamedDecl *Target, CXXRecordDecl *NamingClass,
2514 QualType BaseType) {
2515 // Perform the C++ accessibility checks first.
2516 if (Target->isCXXClassMember() && NamingClass) {
2517 if (!getLangOpts().CPlusPlus)
2518 return false;
2519 // The unprivileged access is AS_none as we don't know how the member was
2520 // accessed, which is described by the access in DeclAccessPair.
2521 // `IsAccessible` will examine the actual access of Target (i.e.
2522 // Decl->getAccess()) when calculating the access.
2523 AccessTarget Entity(Context, AccessedEntity::Member, NamingClass,
2524 DeclAccessPair::make(D: Target, AS: AS_none), BaseType);
2525 EffectiveContext EC(CurContext);
2526 return ::IsAccessible(S&: *this, EC, Entity, /*FailedTSC=*/nullptr) !=
2527 ::AR_inaccessible;
2528 }
2529
2530 if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Val: Target)) {
2531 // @public and @package ivars are always accessible.
2532 if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||
2533 Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package)
2534 return true;
2535
2536 // If we are inside a class or category implementation, determine the
2537 // interface we're in.
2538 ObjCInterfaceDecl *ClassOfMethodDecl = nullptr;
2539 if (ObjCMethodDecl *MD = getCurMethodDecl())
2540 ClassOfMethodDecl = MD->getClassInterface();
2541 else if (FunctionDecl *FD = getCurFunctionDecl()) {
2542 if (ObjCImplDecl *Impl
2543 = dyn_cast<ObjCImplDecl>(Val: FD->getLexicalDeclContext())) {
2544 if (ObjCImplementationDecl *IMPD
2545 = dyn_cast<ObjCImplementationDecl>(Val: Impl))
2546 ClassOfMethodDecl = IMPD->getClassInterface();
2547 else if (ObjCCategoryImplDecl* CatImplClass
2548 = dyn_cast<ObjCCategoryImplDecl>(Val: Impl))
2549 ClassOfMethodDecl = CatImplClass->getClassInterface();
2550 }
2551 }
2552
2553 // If we're not in an interface, this ivar is inaccessible.
2554 if (!ClassOfMethodDecl)
2555 return false;
2556
2557 // If we're inside the same interface that owns the ivar, we're fine.
2558 if (declaresSameEntity(D1: ClassOfMethodDecl, D2: Ivar->getContainingInterface()))
2559 return true;
2560
2561 // If the ivar is private, it's inaccessible.
2562 if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private)
2563 return false;
2564
2565 return Ivar->getContainingInterface()->isSuperClassOf(I: ClassOfMethodDecl);
2566 }
2567
2568 return true;
2569}
2570