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