Path: blob/main/contrib/llvm-project/clang/lib/Sema/SemaAccess.cpp
35234 views
//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file provides Sema routines for C++ access control semantics.9//10//===----------------------------------------------------------------------===//1112#include "clang/AST/ASTContext.h"13#include "clang/AST/CXXInheritance.h"14#include "clang/AST/DeclCXX.h"15#include "clang/AST/DeclFriend.h"16#include "clang/AST/DeclObjC.h"17#include "clang/AST/DependentDiagnostic.h"18#include "clang/AST/ExprCXX.h"19#include "clang/Basic/Specifiers.h"20#include "clang/Sema/DelayedDiagnostic.h"21#include "clang/Sema/Initialization.h"22#include "clang/Sema/Lookup.h"23#include "clang/Sema/SemaInternal.h"24#include "llvm/ADT/STLForwardCompat.h"2526using namespace clang;27using namespace sema;2829/// A copy of Sema's enum without AR_delayed.30enum AccessResult {31AR_accessible,32AR_inaccessible,33AR_dependent34};3536bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,37NamedDecl *PrevMemberDecl,38AccessSpecifier LexicalAS) {39if (!PrevMemberDecl) {40// Use the lexical access specifier.41MemberDecl->setAccess(LexicalAS);42return false;43}4445// C++ [class.access.spec]p3: When a member is redeclared its access46// specifier must be same as its initial declaration.47if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {48Diag(MemberDecl->getLocation(),49diag::err_class_redeclared_with_different_access)50<< MemberDecl << LexicalAS;51Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)52<< PrevMemberDecl << PrevMemberDecl->getAccess();5354MemberDecl->setAccess(LexicalAS);55return true;56}5758MemberDecl->setAccess(PrevMemberDecl->getAccess());59return false;60}6162static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {63DeclContext *DC = D->getDeclContext();6465// This can only happen at top: enum decls only "publish" their66// immediate members.67if (isa<EnumDecl>(DC))68DC = cast<EnumDecl>(DC)->getDeclContext();6970CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);71while (DeclaringClass->isAnonymousStructOrUnion())72DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());73return DeclaringClass;74}7576namespace {77struct EffectiveContext {78EffectiveContext() : Inner(nullptr), Dependent(false) {}7980explicit EffectiveContext(DeclContext *DC)81: Inner(DC),82Dependent(DC->isDependentContext()) {8384// An implicit deduction guide is semantically in the context enclosing the85// class template, but for access purposes behaves like the constructor86// from which it was produced.87if (auto *DGD = dyn_cast<CXXDeductionGuideDecl>(DC)) {88if (DGD->isImplicit()) {89DC = DGD->getCorrespondingConstructor();90if (!DC) {91// The copy deduction candidate doesn't have a corresponding92// constructor.93DC = cast<DeclContext>(DGD->getDeducedTemplate()->getTemplatedDecl());94}95}96}9798// C++11 [class.access.nest]p1:99// A nested class is a member and as such has the same access100// rights as any other member.101// C++11 [class.access]p2:102// A member of a class can also access all the names to which103// the class has access. A local class of a member function104// may access the same names that the member function itself105// may access.106// This almost implies that the privileges of nesting are transitive.107// Technically it says nothing about the local classes of non-member108// functions (which can gain privileges through friendship), but we109// take that as an oversight.110while (true) {111// We want to add canonical declarations to the EC lists for112// simplicity of checking, but we need to walk up through the113// actual current DC chain. Otherwise, something like a local114// extern or friend which happens to be the canonical115// declaration will really mess us up.116117if (isa<CXXRecordDecl>(DC)) {118CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);119Records.push_back(Record->getCanonicalDecl());120DC = Record->getDeclContext();121} else if (isa<FunctionDecl>(DC)) {122FunctionDecl *Function = cast<FunctionDecl>(DC);123Functions.push_back(Function->getCanonicalDecl());124if (Function->getFriendObjectKind())125DC = Function->getLexicalDeclContext();126else127DC = Function->getDeclContext();128} else if (DC->isFileContext()) {129break;130} else {131DC = DC->getParent();132}133}134}135136bool isDependent() const { return Dependent; }137138bool includesClass(const CXXRecordDecl *R) const {139R = R->getCanonicalDecl();140return llvm::is_contained(Records, R);141}142143/// Retrieves the innermost "useful" context. Can be null if we're144/// doing access-control without privileges.145DeclContext *getInnerContext() const {146return Inner;147}148149typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;150151DeclContext *Inner;152SmallVector<FunctionDecl*, 4> Functions;153SmallVector<CXXRecordDecl*, 4> Records;154bool Dependent;155};156157/// Like sema::AccessedEntity, but kindly lets us scribble all over158/// it.159struct AccessTarget : public AccessedEntity {160AccessTarget(const AccessedEntity &Entity)161: AccessedEntity(Entity) {162initialize();163}164165AccessTarget(ASTContext &Context,166MemberNonce _,167CXXRecordDecl *NamingClass,168DeclAccessPair FoundDecl,169QualType BaseObjectType)170: AccessedEntity(Context.getDiagAllocator(), Member, NamingClass,171FoundDecl, BaseObjectType) {172initialize();173}174175AccessTarget(ASTContext &Context,176BaseNonce _,177CXXRecordDecl *BaseClass,178CXXRecordDecl *DerivedClass,179AccessSpecifier Access)180: AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass,181Access) {182initialize();183}184185bool isInstanceMember() const {186return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember());187}188189bool hasInstanceContext() const {190return HasInstanceContext;191}192193class SavedInstanceContext {194public:195SavedInstanceContext(SavedInstanceContext &&S)196: Target(S.Target), Has(S.Has) {197S.Target = nullptr;198}199200// The move assignment operator is defined as deleted pending further201// motivation.202SavedInstanceContext &operator=(SavedInstanceContext &&) = delete;203204// The copy constrcutor and copy assignment operator is defined as deleted205// pending further motivation.206SavedInstanceContext(const SavedInstanceContext &) = delete;207SavedInstanceContext &operator=(const SavedInstanceContext &) = delete;208209~SavedInstanceContext() {210if (Target)211Target->HasInstanceContext = Has;212}213214private:215friend struct AccessTarget;216explicit SavedInstanceContext(AccessTarget &Target)217: Target(&Target), Has(Target.HasInstanceContext) {}218AccessTarget *Target;219bool Has;220};221222SavedInstanceContext saveInstanceContext() {223return SavedInstanceContext(*this);224}225226void suppressInstanceContext() {227HasInstanceContext = false;228}229230const CXXRecordDecl *resolveInstanceContext(Sema &S) const {231assert(HasInstanceContext);232if (CalculatedInstanceContext)233return InstanceContext;234235CalculatedInstanceContext = true;236DeclContext *IC = S.computeDeclContext(getBaseObjectType());237InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl()238: nullptr);239return InstanceContext;240}241242const CXXRecordDecl *getDeclaringClass() const {243return DeclaringClass;244}245246/// The "effective" naming class is the canonical non-anonymous247/// class containing the actual naming class.248const CXXRecordDecl *getEffectiveNamingClass() const {249const CXXRecordDecl *namingClass = getNamingClass();250while (namingClass->isAnonymousStructOrUnion())251namingClass = cast<CXXRecordDecl>(namingClass->getParent());252return namingClass->getCanonicalDecl();253}254255private:256void initialize() {257HasInstanceContext = (isMemberAccess() &&258!getBaseObjectType().isNull() &&259getTargetDecl()->isCXXInstanceMember());260CalculatedInstanceContext = false;261InstanceContext = nullptr;262263if (isMemberAccess())264DeclaringClass = FindDeclaringClass(getTargetDecl());265else266DeclaringClass = getBaseClass();267DeclaringClass = DeclaringClass->getCanonicalDecl();268}269270bool HasInstanceContext : 1;271mutable bool CalculatedInstanceContext : 1;272mutable const CXXRecordDecl *InstanceContext;273const CXXRecordDecl *DeclaringClass;274};275276}277278/// Checks whether one class might instantiate to the other.279static bool MightInstantiateTo(const CXXRecordDecl *From,280const CXXRecordDecl *To) {281// Declaration names are always preserved by instantiation.282if (From->getDeclName() != To->getDeclName())283return false;284285const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();286const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();287if (FromDC == ToDC) return true;288if (FromDC->isFileContext() || ToDC->isFileContext()) return false;289290// Be conservative.291return true;292}293294/// Checks whether one class is derived from another, inclusively.295/// Properly indicates when it couldn't be determined due to296/// dependence.297///298/// This should probably be donated to AST or at least Sema.299static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,300const CXXRecordDecl *Target) {301assert(Derived->getCanonicalDecl() == Derived);302assert(Target->getCanonicalDecl() == Target);303304if (Derived == Target) return AR_accessible;305306bool CheckDependent = Derived->isDependentContext();307if (CheckDependent && MightInstantiateTo(Derived, Target))308return AR_dependent;309310AccessResult OnFailure = AR_inaccessible;311SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack312313while (true) {314if (Derived->isDependentContext() && !Derived->hasDefinition() &&315!Derived->isLambda())316return AR_dependent;317318for (const auto &I : Derived->bases()) {319const CXXRecordDecl *RD;320321QualType T = I.getType();322if (const RecordType *RT = T->getAs<RecordType>()) {323RD = cast<CXXRecordDecl>(RT->getDecl());324} else if (const InjectedClassNameType *IT325= T->getAs<InjectedClassNameType>()) {326RD = IT->getDecl();327} else {328assert(T->isDependentType() && "non-dependent base wasn't a record?");329OnFailure = AR_dependent;330continue;331}332333RD = RD->getCanonicalDecl();334if (RD == Target) return AR_accessible;335if (CheckDependent && MightInstantiateTo(RD, Target))336OnFailure = AR_dependent;337338Queue.push_back(RD);339}340341if (Queue.empty()) break;342343Derived = Queue.pop_back_val();344}345346return OnFailure;347}348349350static bool MightInstantiateTo(Sema &S, DeclContext *Context,351DeclContext *Friend) {352if (Friend == Context)353return true;354355assert(!Friend->isDependentContext() &&356"can't handle friends with dependent contexts here");357358if (!Context->isDependentContext())359return false;360361if (Friend->isFileContext())362return false;363364// TODO: this is very conservative365return true;366}367368// Asks whether the type in 'context' can ever instantiate to the type369// in 'friend'.370static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {371if (Friend == Context)372return true;373374if (!Friend->isDependentType() && !Context->isDependentType())375return false;376377// TODO: this is very conservative.378return true;379}380381static bool MightInstantiateTo(Sema &S,382FunctionDecl *Context,383FunctionDecl *Friend) {384if (Context->getDeclName() != Friend->getDeclName())385return false;386387if (!MightInstantiateTo(S,388Context->getDeclContext(),389Friend->getDeclContext()))390return false;391392CanQual<FunctionProtoType> FriendTy393= S.Context.getCanonicalType(Friend->getType())394->getAs<FunctionProtoType>();395CanQual<FunctionProtoType> ContextTy396= S.Context.getCanonicalType(Context->getType())397->getAs<FunctionProtoType>();398399// There isn't any way that I know of to add qualifiers400// during instantiation.401if (FriendTy.getQualifiers() != ContextTy.getQualifiers())402return false;403404if (FriendTy->getNumParams() != ContextTy->getNumParams())405return false;406407if (!MightInstantiateTo(S, ContextTy->getReturnType(),408FriendTy->getReturnType()))409return false;410411for (unsigned I = 0, E = FriendTy->getNumParams(); I != E; ++I)412if (!MightInstantiateTo(S, ContextTy->getParamType(I),413FriendTy->getParamType(I)))414return false;415416return true;417}418419static bool MightInstantiateTo(Sema &S,420FunctionTemplateDecl *Context,421FunctionTemplateDecl *Friend) {422return MightInstantiateTo(S,423Context->getTemplatedDecl(),424Friend->getTemplatedDecl());425}426427static AccessResult MatchesFriend(Sema &S,428const EffectiveContext &EC,429const CXXRecordDecl *Friend) {430if (EC.includesClass(Friend))431return AR_accessible;432433if (EC.isDependent()) {434for (const CXXRecordDecl *Context : EC.Records) {435if (MightInstantiateTo(Context, Friend))436return AR_dependent;437}438}439440return AR_inaccessible;441}442443static AccessResult MatchesFriend(Sema &S,444const EffectiveContext &EC,445CanQualType Friend) {446if (const RecordType *RT = Friend->getAs<RecordType>())447return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));448449// TODO: we can do better than this450if (Friend->isDependentType())451return AR_dependent;452453return AR_inaccessible;454}455456/// Determines whether the given friend class template matches457/// anything in the effective context.458static AccessResult MatchesFriend(Sema &S,459const EffectiveContext &EC,460ClassTemplateDecl *Friend) {461AccessResult OnFailure = AR_inaccessible;462463// Check whether the friend is the template of a class in the464// context chain.465for (SmallVectorImpl<CXXRecordDecl*>::const_iterator466I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {467CXXRecordDecl *Record = *I;468469// Figure out whether the current class has a template:470ClassTemplateDecl *CTD;471472// A specialization of the template...473if (isa<ClassTemplateSpecializationDecl>(Record)) {474CTD = cast<ClassTemplateSpecializationDecl>(Record)475->getSpecializedTemplate();476477// ... or the template pattern itself.478} else {479CTD = Record->getDescribedClassTemplate();480if (!CTD) continue;481}482483// It's a match.484if (Friend == CTD->getCanonicalDecl())485return AR_accessible;486487// If the context isn't dependent, it can't be a dependent match.488if (!EC.isDependent())489continue;490491// If the template names don't match, it can't be a dependent492// match.493if (CTD->getDeclName() != Friend->getDeclName())494continue;495496// If the class's context can't instantiate to the friend's497// context, it can't be a dependent match.498if (!MightInstantiateTo(S, CTD->getDeclContext(),499Friend->getDeclContext()))500continue;501502// Otherwise, it's a dependent match.503OnFailure = AR_dependent;504}505506return OnFailure;507}508509/// Determines whether the given friend function matches anything in510/// the effective context.511static AccessResult MatchesFriend(Sema &S,512const EffectiveContext &EC,513FunctionDecl *Friend) {514AccessResult OnFailure = AR_inaccessible;515516for (SmallVectorImpl<FunctionDecl*>::const_iterator517I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {518if (Friend == *I)519return AR_accessible;520521if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))522OnFailure = AR_dependent;523}524525return OnFailure;526}527528/// Determines whether the given friend function template matches529/// anything in the effective context.530static AccessResult MatchesFriend(Sema &S,531const EffectiveContext &EC,532FunctionTemplateDecl *Friend) {533if (EC.Functions.empty()) return AR_inaccessible;534535AccessResult OnFailure = AR_inaccessible;536537for (SmallVectorImpl<FunctionDecl*>::const_iterator538I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {539540FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();541if (!FTD)542FTD = (*I)->getDescribedFunctionTemplate();543if (!FTD)544continue;545546FTD = FTD->getCanonicalDecl();547548if (Friend == FTD)549return AR_accessible;550551if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))552OnFailure = AR_dependent;553}554555return OnFailure;556}557558/// Determines whether the given friend declaration matches anything559/// in the effective context.560static AccessResult MatchesFriend(Sema &S,561const EffectiveContext &EC,562FriendDecl *FriendD) {563// Whitelist accesses if there's an invalid or unsupported friend564// declaration.565if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend())566return AR_accessible;567568if (TypeSourceInfo *T = FriendD->getFriendType())569return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());570571NamedDecl *Friend572= cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());573574// FIXME: declarations with dependent or templated scope.575576if (isa<ClassTemplateDecl>(Friend))577return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));578579if (isa<FunctionTemplateDecl>(Friend))580return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));581582if (isa<CXXRecordDecl>(Friend))583return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));584585assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");586return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));587}588589static AccessResult GetFriendKind(Sema &S,590const EffectiveContext &EC,591const CXXRecordDecl *Class) {592AccessResult OnFailure = AR_inaccessible;593594// Okay, check friends.595for (auto *Friend : Class->friends()) {596switch (MatchesFriend(S, EC, Friend)) {597case AR_accessible:598return AR_accessible;599600case AR_inaccessible:601continue;602603case AR_dependent:604OnFailure = AR_dependent;605break;606}607}608609// That's it, give up.610return OnFailure;611}612613namespace {614615/// A helper class for checking for a friend which will grant access616/// to a protected instance member.617struct ProtectedFriendContext {618Sema &S;619const EffectiveContext &EC;620const CXXRecordDecl *NamingClass;621bool CheckDependent;622bool EverDependent;623624/// The path down to the current base class.625SmallVector<const CXXRecordDecl*, 20> CurPath;626627ProtectedFriendContext(Sema &S, const EffectiveContext &EC,628const CXXRecordDecl *InstanceContext,629const CXXRecordDecl *NamingClass)630: S(S), EC(EC), NamingClass(NamingClass),631CheckDependent(InstanceContext->isDependentContext() ||632NamingClass->isDependentContext()),633EverDependent(false) {}634635/// Check classes in the current path for friendship, starting at636/// the given index.637bool checkFriendshipAlongPath(unsigned I) {638assert(I < CurPath.size());639for (unsigned E = CurPath.size(); I != E; ++I) {640switch (GetFriendKind(S, EC, CurPath[I])) {641case AR_accessible: return true;642case AR_inaccessible: continue;643case AR_dependent: EverDependent = true; continue;644}645}646return false;647}648649/// Perform a search starting at the given class.650///651/// PrivateDepth is the index of the last (least derived) class652/// along the current path such that a notional public member of653/// the final class in the path would have access in that class.654bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) {655// If we ever reach the naming class, check the current path for656// friendship. We can also stop recursing because we obviously657// won't find the naming class there again.658if (Cur == NamingClass)659return checkFriendshipAlongPath(PrivateDepth);660661if (CheckDependent && MightInstantiateTo(Cur, NamingClass))662EverDependent = true;663664// Recurse into the base classes.665for (const auto &I : Cur->bases()) {666// If this is private inheritance, then a public member of the667// base will not have any access in classes derived from Cur.668unsigned BasePrivateDepth = PrivateDepth;669if (I.getAccessSpecifier() == AS_private)670BasePrivateDepth = CurPath.size() - 1;671672const CXXRecordDecl *RD;673674QualType T = I.getType();675if (const RecordType *RT = T->getAs<RecordType>()) {676RD = cast<CXXRecordDecl>(RT->getDecl());677} else if (const InjectedClassNameType *IT678= T->getAs<InjectedClassNameType>()) {679RD = IT->getDecl();680} else {681assert(T->isDependentType() && "non-dependent base wasn't a record?");682EverDependent = true;683continue;684}685686// Recurse. We don't need to clean up if this returns true.687CurPath.push_back(RD);688if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth))689return true;690CurPath.pop_back();691}692693return false;694}695696bool findFriendship(const CXXRecordDecl *Cur) {697assert(CurPath.empty());698CurPath.push_back(Cur);699return findFriendship(Cur, 0);700}701};702}703704/// Search for a class P that EC is a friend of, under the constraint705/// InstanceContext <= P706/// if InstanceContext exists, or else707/// NamingClass <= P708/// and with the additional restriction that a protected member of709/// NamingClass would have some natural access in P, which implicitly710/// imposes the constraint that P <= NamingClass.711///712/// This isn't quite the condition laid out in the standard.713/// Instead of saying that a notional protected member of NamingClass714/// would have to have some natural access in P, it says the actual715/// target has to have some natural access in P, which opens up the716/// possibility that the target (which is not necessarily a member717/// of NamingClass) might be more accessible along some path not718/// passing through it. That's really a bad idea, though, because it719/// introduces two problems:720/// - Most importantly, it breaks encapsulation because you can721/// access a forbidden base class's members by directly subclassing722/// it elsewhere.723/// - It also makes access substantially harder to compute because it724/// breaks the hill-climbing algorithm: knowing that the target is725/// accessible in some base class would no longer let you change726/// the question solely to whether the base class is accessible,727/// because the original target might have been more accessible728/// because of crazy subclassing.729/// So we don't implement that.730static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC,731const CXXRecordDecl *InstanceContext,732const CXXRecordDecl *NamingClass) {733assert(InstanceContext == nullptr ||734InstanceContext->getCanonicalDecl() == InstanceContext);735assert(NamingClass->getCanonicalDecl() == NamingClass);736737// If we don't have an instance context, our constraints give us738// that NamingClass <= P <= NamingClass, i.e. P == NamingClass.739// This is just the usual friendship check.740if (!InstanceContext) return GetFriendKind(S, EC, NamingClass);741742ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass);743if (PRC.findFriendship(InstanceContext)) return AR_accessible;744if (PRC.EverDependent) return AR_dependent;745return AR_inaccessible;746}747748static AccessResult HasAccess(Sema &S,749const EffectiveContext &EC,750const CXXRecordDecl *NamingClass,751AccessSpecifier Access,752const AccessTarget &Target) {753assert(NamingClass->getCanonicalDecl() == NamingClass &&754"declaration should be canonicalized before being passed here");755756if (Access == AS_public) return AR_accessible;757assert(Access == AS_private || Access == AS_protected);758759AccessResult OnFailure = AR_inaccessible;760761for (EffectiveContext::record_iterator762I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {763// All the declarations in EC have been canonicalized, so pointer764// equality from this point on will work fine.765const CXXRecordDecl *ECRecord = *I;766767// [B2] and [M2]768if (Access == AS_private) {769if (ECRecord == NamingClass)770return AR_accessible;771772if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))773OnFailure = AR_dependent;774775// [B3] and [M3]776} else {777assert(Access == AS_protected);778switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {779case AR_accessible: break;780case AR_inaccessible: continue;781case AR_dependent: OnFailure = AR_dependent; continue;782}783784// C++ [class.protected]p1:785// An additional access check beyond those described earlier in786// [class.access] is applied when a non-static data member or787// non-static member function is a protected member of its naming788// class. As described earlier, access to a protected member is789// granted because the reference occurs in a friend or member of790// some class C. If the access is to form a pointer to member,791// the nested-name-specifier shall name C or a class derived from792// C. All other accesses involve a (possibly implicit) object793// expression. In this case, the class of the object expression794// shall be C or a class derived from C.795//796// We interpret this as a restriction on [M3].797798// In this part of the code, 'C' is just our context class ECRecord.799800// These rules are different if we don't have an instance context.801if (!Target.hasInstanceContext()) {802// If it's not an instance member, these restrictions don't apply.803if (!Target.isInstanceMember()) return AR_accessible;804805// If it's an instance member, use the pointer-to-member rule806// that the naming class has to be derived from the effective807// context.808809// Emulate a MSVC bug where the creation of pointer-to-member810// to protected member of base class is allowed but only from811// static member functions.812if (S.getLangOpts().MSVCCompat && !EC.Functions.empty())813if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front()))814if (MD->isStatic()) return AR_accessible;815816// Despite the standard's confident wording, there is a case817// where you can have an instance member that's neither in a818// pointer-to-member expression nor in a member access: when819// it names a field in an unevaluated context that can't be an820// implicit member. Pending clarification, we just apply the821// same naming-class restriction here.822// FIXME: we're probably not correctly adding the823// protected-member restriction when we retroactively convert824// an expression to being evaluated.825826// We know that ECRecord derives from NamingClass. The827// restriction says to check whether NamingClass derives from828// ECRecord, but that's not really necessary: two distinct829// classes can't be recursively derived from each other. So830// along this path, we just need to check whether the classes831// are equal.832if (NamingClass == ECRecord) return AR_accessible;833834// Otherwise, this context class tells us nothing; on to the next.835continue;836}837838assert(Target.isInstanceMember());839840const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);841if (!InstanceContext) {842OnFailure = AR_dependent;843continue;844}845846switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {847case AR_accessible: return AR_accessible;848case AR_inaccessible: continue;849case AR_dependent: OnFailure = AR_dependent; continue;850}851}852}853854// [M3] and [B3] say that, if the target is protected in N, we grant855// access if the access occurs in a friend or member of some class P856// that's a subclass of N and where the target has some natural857// access in P. The 'member' aspect is easy to handle because P858// would necessarily be one of the effective-context records, and we859// address that above. The 'friend' aspect is completely ridiculous860// to implement because there are no restrictions at all on P861// *unless* the [class.protected] restriction applies. If it does,862// however, we should ignore whether the naming class is a friend,863// and instead rely on whether any potential P is a friend.864if (Access == AS_protected && Target.isInstanceMember()) {865// Compute the instance context if possible.866const CXXRecordDecl *InstanceContext = nullptr;867if (Target.hasInstanceContext()) {868InstanceContext = Target.resolveInstanceContext(S);869if (!InstanceContext) return AR_dependent;870}871872switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) {873case AR_accessible: return AR_accessible;874case AR_inaccessible: return OnFailure;875case AR_dependent: return AR_dependent;876}877llvm_unreachable("impossible friendship kind");878}879880switch (GetFriendKind(S, EC, NamingClass)) {881case AR_accessible: return AR_accessible;882case AR_inaccessible: return OnFailure;883case AR_dependent: return AR_dependent;884}885886// Silence bogus warnings887llvm_unreachable("impossible friendship kind");888}889890/// Finds the best path from the naming class to the declaring class,891/// taking friend declarations into account.892///893/// C++0x [class.access.base]p5:894/// A member m is accessible at the point R when named in class N if895/// [M1] m as a member of N is public, or896/// [M2] m as a member of N is private, and R occurs in a member or897/// friend of class N, or898/// [M3] m as a member of N is protected, and R occurs in a member or899/// friend of class N, or in a member or friend of a class P900/// derived from N, where m as a member of P is public, private,901/// or protected, or902/// [M4] there exists a base class B of N that is accessible at R, and903/// m is accessible at R when named in class B.904///905/// C++0x [class.access.base]p4:906/// A base class B of N is accessible at R, if907/// [B1] an invented public member of B would be a public member of N, or908/// [B2] R occurs in a member or friend of class N, and an invented public909/// member of B would be a private or protected member of N, or910/// [B3] R occurs in a member or friend of a class P derived from N, and an911/// invented public member of B would be a private or protected member912/// of P, or913/// [B4] there exists a class S such that B is a base class of S accessible914/// at R and S is a base class of N accessible at R.915///916/// Along a single inheritance path we can restate both of these917/// iteratively:918///919/// First, we note that M1-4 are equivalent to B1-4 if the member is920/// treated as a notional base of its declaring class with inheritance921/// access equivalent to the member's access. Therefore we need only922/// ask whether a class B is accessible from a class N in context R.923///924/// Let B_1 .. B_n be the inheritance path in question (i.e. where925/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of926/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the927/// closest accessible base in the path:928/// Access(a, b) = (* access on the base specifier from a to b *)929/// Merge(a, forbidden) = forbidden930/// Merge(a, private) = forbidden931/// Merge(a, b) = min(a,b)932/// Accessible(c, forbidden) = false933/// Accessible(c, private) = (R is c) || IsFriend(c, R)934/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R)935/// Accessible(c, public) = true936/// ACAB(n) = public937/// ACAB(i) =938/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in939/// if Accessible(B_i, AccessToBase) then public else AccessToBase940///941/// B is an accessible base of N at R iff ACAB(1) = public.942///943/// \param FinalAccess the access of the "final step", or AS_public if944/// there is no final step.945/// \return null if friendship is dependent946static CXXBasePath *FindBestPath(Sema &S,947const EffectiveContext &EC,948AccessTarget &Target,949AccessSpecifier FinalAccess,950CXXBasePaths &Paths) {951// Derive the paths to the desired base.952const CXXRecordDecl *Derived = Target.getNamingClass();953const CXXRecordDecl *Base = Target.getDeclaringClass();954955// FIXME: fail correctly when there are dependent paths.956bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base),957Paths);958assert(isDerived && "derived class not actually derived from base");959(void) isDerived;960961CXXBasePath *BestPath = nullptr;962963assert(FinalAccess != AS_none && "forbidden access after declaring class");964965bool AnyDependent = false;966967// Derive the friend-modified access along each path.968for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();969PI != PE; ++PI) {970AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext();971972// Walk through the path backwards.973AccessSpecifier PathAccess = FinalAccess;974CXXBasePath::iterator I = PI->end(), E = PI->begin();975while (I != E) {976--I;977978assert(PathAccess != AS_none);979980// If the declaration is a private member of a base class, there981// is no level of friendship in derived classes that can make it982// accessible.983if (PathAccess == AS_private) {984PathAccess = AS_none;985break;986}987988const CXXRecordDecl *NC = I->Class->getCanonicalDecl();989990AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();991PathAccess = std::max(PathAccess, BaseAccess);992993switch (HasAccess(S, EC, NC, PathAccess, Target)) {994case AR_inaccessible: break;995case AR_accessible:996PathAccess = AS_public;997998// Future tests are not against members and so do not have999// instance context.1000Target.suppressInstanceContext();1001break;1002case AR_dependent:1003AnyDependent = true;1004goto Next;1005}1006}10071008// Note that we modify the path's Access field to the1009// friend-modified access.1010if (BestPath == nullptr || PathAccess < BestPath->Access) {1011BestPath = &*PI;1012BestPath->Access = PathAccess;10131014// Short-circuit if we found a public path.1015if (BestPath->Access == AS_public)1016return BestPath;1017}10181019Next: ;1020}10211022assert((!BestPath || BestPath->Access != AS_public) &&1023"fell out of loop with public path");10241025// We didn't find a public path, but at least one path was subject1026// to dependent friendship, so delay the check.1027if (AnyDependent)1028return nullptr;10291030return BestPath;1031}10321033/// Given that an entity has protected natural access, check whether1034/// access might be denied because of the protected member access1035/// restriction.1036///1037/// \return true if a note was emitted1038static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,1039AccessTarget &Target) {1040// Only applies to instance accesses.1041if (!Target.isInstanceMember())1042return false;10431044assert(Target.isMemberAccess());10451046const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass();10471048for (EffectiveContext::record_iterator1049I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {1050const CXXRecordDecl *ECRecord = *I;1051switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {1052case AR_accessible: break;1053case AR_inaccessible: continue;1054case AR_dependent: continue;1055}10561057// The effective context is a subclass of the declaring class.1058// Check whether the [class.protected] restriction is limiting1059// access.10601061// To get this exactly right, this might need to be checked more1062// holistically; it's not necessarily the case that gaining1063// access here would grant us access overall.10641065NamedDecl *D = Target.getTargetDecl();10661067// If we don't have an instance context, [class.protected] says the1068// naming class has to equal the context class.1069if (!Target.hasInstanceContext()) {1070// If it does, the restriction doesn't apply.1071if (NamingClass == ECRecord) continue;10721073// TODO: it would be great to have a fixit here, since this is1074// such an obvious error.1075S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject)1076<< S.Context.getTypeDeclType(ECRecord);1077return true;1078}10791080const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);1081assert(InstanceContext && "diagnosing dependent access");10821083switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {1084case AR_accessible: continue;1085case AR_dependent: continue;1086case AR_inaccessible:1087break;1088}10891090// Okay, the restriction seems to be what's limiting us.10911092// Use a special diagnostic for constructors and destructors.1093if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) ||1094(isa<FunctionTemplateDecl>(D) &&1095isa<CXXConstructorDecl>(1096cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) {1097return S.Diag(D->getLocation(),1098diag::note_access_protected_restricted_ctordtor)1099<< isa<CXXDestructorDecl>(D->getAsFunction());1100}11011102// Otherwise, use the generic diagnostic.1103return S.Diag(D->getLocation(),1104diag::note_access_protected_restricted_object)1105<< S.Context.getTypeDeclType(ECRecord);1106}11071108return false;1109}11101111/// We are unable to access a given declaration due to its direct1112/// access control; diagnose that.1113static void diagnoseBadDirectAccess(Sema &S,1114const EffectiveContext &EC,1115AccessTarget &entity) {1116assert(entity.isMemberAccess());1117NamedDecl *D = entity.getTargetDecl();11181119if (D->getAccess() == AS_protected &&1120TryDiagnoseProtectedAccess(S, EC, entity))1121return;11221123// Find an original declaration.1124while (D->isOutOfLine()) {1125NamedDecl *PrevDecl = nullptr;1126if (VarDecl *VD = dyn_cast<VarDecl>(D))1127PrevDecl = VD->getPreviousDecl();1128else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))1129PrevDecl = FD->getPreviousDecl();1130else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))1131PrevDecl = TND->getPreviousDecl();1132else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {1133if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())1134break;1135PrevDecl = TD->getPreviousDecl();1136}1137if (!PrevDecl) break;1138D = PrevDecl;1139}11401141CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);1142Decl *ImmediateChild;1143if (D->getDeclContext() == DeclaringClass)1144ImmediateChild = D;1145else {1146DeclContext *DC = D->getDeclContext();1147while (DC->getParent() != DeclaringClass)1148DC = DC->getParent();1149ImmediateChild = cast<Decl>(DC);1150}11511152// Check whether there's an AccessSpecDecl preceding this in the1153// chain of the DeclContext.1154bool isImplicit = true;1155for (const auto *I : DeclaringClass->decls()) {1156if (I == ImmediateChild) break;1157if (isa<AccessSpecDecl>(I)) {1158isImplicit = false;1159break;1160}1161}11621163S.Diag(D->getLocation(), diag::note_access_natural)1164<< (unsigned) (D->getAccess() == AS_protected)1165<< isImplicit;1166}11671168/// Diagnose the path which caused the given declaration or base class1169/// to become inaccessible.1170static void DiagnoseAccessPath(Sema &S,1171const EffectiveContext &EC,1172AccessTarget &entity) {1173// Save the instance context to preserve invariants.1174AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext();11751176// This basically repeats the main algorithm but keeps some more1177// information.11781179// The natural access so far.1180AccessSpecifier accessSoFar = AS_public;11811182// Check whether we have special rights to the declaring class.1183if (entity.isMemberAccess()) {1184NamedDecl *D = entity.getTargetDecl();1185accessSoFar = D->getAccess();1186const CXXRecordDecl *declaringClass = entity.getDeclaringClass();11871188switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) {1189// If the declaration is accessible when named in its declaring1190// class, then we must be constrained by the path.1191case AR_accessible:1192accessSoFar = AS_public;1193entity.suppressInstanceContext();1194break;11951196case AR_inaccessible:1197if (accessSoFar == AS_private ||1198declaringClass == entity.getEffectiveNamingClass())1199return diagnoseBadDirectAccess(S, EC, entity);1200break;12011202case AR_dependent:1203llvm_unreachable("cannot diagnose dependent access");1204}1205}12061207CXXBasePaths paths;1208CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths);1209assert(path.Access != AS_public);12101211CXXBasePath::iterator i = path.end(), e = path.begin();1212CXXBasePath::iterator constrainingBase = i;1213while (i != e) {1214--i;12151216assert(accessSoFar != AS_none && accessSoFar != AS_private);12171218// Is the entity accessible when named in the deriving class, as1219// modified by the base specifier?1220const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl();1221const CXXBaseSpecifier *base = i->Base;12221223// If the access to this base is worse than the access we have to1224// the declaration, remember it.1225AccessSpecifier baseAccess = base->getAccessSpecifier();1226if (baseAccess > accessSoFar) {1227constrainingBase = i;1228accessSoFar = baseAccess;1229}12301231switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) {1232case AR_inaccessible: break;1233case AR_accessible:1234accessSoFar = AS_public;1235entity.suppressInstanceContext();1236constrainingBase = nullptr;1237break;1238case AR_dependent:1239llvm_unreachable("cannot diagnose dependent access");1240}12411242// If this was private inheritance, but we don't have access to1243// the deriving class, we're done.1244if (accessSoFar == AS_private) {1245assert(baseAccess == AS_private);1246assert(constrainingBase == i);1247break;1248}1249}12501251// If we don't have a constraining base, the access failure must be1252// due to the original declaration.1253if (constrainingBase == path.end())1254return diagnoseBadDirectAccess(S, EC, entity);12551256// We're constrained by inheritance, but we want to say1257// "declared private here" if we're diagnosing a hierarchy1258// conversion and this is the final step.1259unsigned diagnostic;1260if (entity.isMemberAccess() ||1261constrainingBase + 1 != path.end()) {1262diagnostic = diag::note_access_constrained_by_path;1263} else {1264diagnostic = diag::note_access_natural;1265}12661267const CXXBaseSpecifier *base = constrainingBase->Base;12681269S.Diag(base->getSourceRange().getBegin(), diagnostic)1270<< base->getSourceRange()1271<< (base->getAccessSpecifier() == AS_protected)1272<< (base->getAccessSpecifierAsWritten() == AS_none);12731274if (entity.isMemberAccess())1275S.Diag(entity.getTargetDecl()->getLocation(),1276diag::note_member_declared_at);1277}12781279static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,1280const EffectiveContext &EC,1281AccessTarget &Entity) {1282const CXXRecordDecl *NamingClass = Entity.getNamingClass();1283const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();1284NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : nullptr);12851286S.Diag(Loc, Entity.getDiag())1287<< (Entity.getAccess() == AS_protected)1288<< (D ? D->getDeclName() : DeclarationName())1289<< S.Context.getTypeDeclType(NamingClass)1290<< S.Context.getTypeDeclType(DeclaringClass);1291DiagnoseAccessPath(S, EC, Entity);1292}12931294/// MSVC has a bug where if during an using declaration name lookup,1295/// the declaration found is unaccessible (private) and that declaration1296/// was bring into scope via another using declaration whose target1297/// declaration is accessible (public) then no error is generated.1298/// Example:1299/// class A {1300/// public:1301/// int f();1302/// };1303/// class B : public A {1304/// private:1305/// using A::f;1306/// };1307/// class C : public B {1308/// private:1309/// using B::f;1310/// };1311///1312/// Here, B::f is private so this should fail in Standard C++, but1313/// because B::f refers to A::f which is public MSVC accepts it.1314static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,1315SourceLocation AccessLoc,1316AccessTarget &Entity) {1317if (UsingShadowDecl *Shadow =1318dyn_cast<UsingShadowDecl>(Entity.getTargetDecl()))1319if (UsingDecl *UD = dyn_cast<UsingDecl>(Shadow->getIntroducer())) {1320const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl();1321if (Entity.getTargetDecl()->getAccess() == AS_private &&1322(OrigDecl->getAccess() == AS_public ||1323OrigDecl->getAccess() == AS_protected)) {1324S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible)1325<< UD->getQualifiedNameAsString()1326<< OrigDecl->getQualifiedNameAsString();1327return true;1328}1329}1330return false;1331}13321333/// Determines whether the accessed entity is accessible. Public members1334/// have been weeded out by this point.1335static AccessResult IsAccessible(Sema &S,1336const EffectiveContext &EC,1337AccessTarget &Entity) {1338// Determine the actual naming class.1339const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();13401341AccessSpecifier UnprivilegedAccess = Entity.getAccess();1342assert(UnprivilegedAccess != AS_public && "public access not weeded out");13431344// Before we try to recalculate access paths, try to white-list1345// accesses which just trade in on the final step, i.e. accesses1346// which don't require [M4] or [B4]. These are by far the most1347// common forms of privileged access.1348if (UnprivilegedAccess != AS_none) {1349switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) {1350case AR_dependent:1351// This is actually an interesting policy decision. We don't1352// *have* to delay immediately here: we can do the full access1353// calculation in the hope that friendship on some intermediate1354// class will make the declaration accessible non-dependently.1355// But that's not cheap, and odds are very good (note: assertion1356// made without data) that the friend declaration will determine1357// access.1358return AR_dependent;13591360case AR_accessible: return AR_accessible;1361case AR_inaccessible: break;1362}1363}13641365AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();13661367// We lower member accesses to base accesses by pretending that the1368// member is a base class of its declaring class.1369AccessSpecifier FinalAccess;13701371if (Entity.isMemberAccess()) {1372// Determine if the declaration is accessible from EC when named1373// in its declaring class.1374NamedDecl *Target = Entity.getTargetDecl();1375const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();13761377FinalAccess = Target->getAccess();1378switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {1379case AR_accessible:1380// Target is accessible at EC when named in its declaring class.1381// We can now hill-climb and simply check whether the declaring1382// class is accessible as a base of the naming class. This is1383// equivalent to checking the access of a notional public1384// member with no instance context.1385FinalAccess = AS_public;1386Entity.suppressInstanceContext();1387break;1388case AR_inaccessible: break;1389case AR_dependent: return AR_dependent; // see above1390}13911392if (DeclaringClass == NamingClass)1393return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);1394} else {1395FinalAccess = AS_public;1396}13971398assert(Entity.getDeclaringClass() != NamingClass);13991400// Append the declaration's access if applicable.1401CXXBasePaths Paths;1402CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths);1403if (!Path)1404return AR_dependent;14051406assert(Path->Access <= UnprivilegedAccess &&1407"access along best path worse than direct?");1408if (Path->Access == AS_public)1409return AR_accessible;1410return AR_inaccessible;1411}14121413static void DelayDependentAccess(Sema &S,1414const EffectiveContext &EC,1415SourceLocation Loc,1416const AccessTarget &Entity) {1417assert(EC.isDependent() && "delaying non-dependent access");1418DeclContext *DC = EC.getInnerContext();1419assert(DC->isDependentContext() && "delaying non-dependent access");1420DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,1421Loc,1422Entity.isMemberAccess(),1423Entity.getAccess(),1424Entity.getTargetDecl(),1425Entity.getNamingClass(),1426Entity.getBaseObjectType(),1427Entity.getDiag());1428}14291430/// Checks access to an entity from the given effective context.1431static AccessResult CheckEffectiveAccess(Sema &S,1432const EffectiveContext &EC,1433SourceLocation Loc,1434AccessTarget &Entity) {1435assert(Entity.getAccess() != AS_public && "called for public access!");14361437switch (IsAccessible(S, EC, Entity)) {1438case AR_dependent:1439DelayDependentAccess(S, EC, Loc, Entity);1440return AR_dependent;14411442case AR_inaccessible:1443if (S.getLangOpts().MSVCCompat &&1444IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))1445return AR_accessible;1446if (!Entity.isQuiet())1447DiagnoseBadAccess(S, Loc, EC, Entity);1448return AR_inaccessible;14491450case AR_accessible:1451return AR_accessible;1452}14531454// silence unnecessary warning1455llvm_unreachable("invalid access result");1456}14571458static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,1459AccessTarget &Entity) {1460// If the access path is public, it's accessible everywhere.1461if (Entity.getAccess() == AS_public)1462return Sema::AR_accessible;14631464// If we're currently parsing a declaration, we may need to delay1465// access control checking, because our effective context might be1466// different based on what the declaration comes out as.1467//1468// For example, we might be parsing a declaration with a scope1469// specifier, like this:1470// A::private_type A::foo() { ... }1471//1472// friend declaration should not be delayed because it may lead to incorrect1473// redeclaration chain, such as:1474// class D {1475// class E{1476// class F{};1477// friend void foo(D::E::F& q);1478// };1479// friend void foo(D::E::F& q);1480// };1481if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {1482// [class.friend]p9:1483// A member nominated by a friend declaration shall be accessible in the1484// class containing the friend declaration. The meaning of the friend1485// declaration is the same whether the friend declaration appears in the1486// private, protected, or public ([class.mem]) portion of the class1487// member-specification.1488Scope *TS = S.getCurScope();1489bool IsFriendDeclaration = false;1490while (TS && !IsFriendDeclaration) {1491IsFriendDeclaration = TS->isFriendScope();1492TS = TS->getParent();1493}1494if (!IsFriendDeclaration) {1495S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity));1496return Sema::AR_delayed;1497}1498}14991500EffectiveContext EC(S.CurContext);1501switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {1502case AR_accessible: return Sema::AR_accessible;1503case AR_inaccessible: return Sema::AR_inaccessible;1504case AR_dependent: return Sema::AR_dependent;1505}1506llvm_unreachable("invalid access result");1507}15081509void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {1510// Access control for names used in the declarations of functions1511// and function templates should normally be evaluated in the context1512// of the declaration, just in case it's a friend of something.1513// However, this does not apply to local extern declarations.15141515DeclContext *DC = D->getDeclContext();1516if (D->isLocalExternDecl()) {1517DC = D->getLexicalDeclContext();1518} else if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {1519DC = FN;1520} else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {1521if (isa<DeclContext>(TD->getTemplatedDecl()))1522DC = cast<DeclContext>(TD->getTemplatedDecl());1523} else if (auto *RD = dyn_cast<RequiresExprBodyDecl>(D)) {1524DC = RD;1525}15261527EffectiveContext EC(DC);15281529AccessTarget Target(DD.getAccessData());15301531if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible)1532DD.Triggered = true;1533}15341535void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,1536const MultiLevelTemplateArgumentList &TemplateArgs) {1537SourceLocation Loc = DD.getAccessLoc();1538AccessSpecifier Access = DD.getAccess();15391540Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),1541TemplateArgs);1542if (!NamingD) return;1543Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),1544TemplateArgs);1545if (!TargetD) return;15461547if (DD.isAccessToMember()) {1548CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD);1549NamedDecl *TargetDecl = cast<NamedDecl>(TargetD);1550QualType BaseObjectType = DD.getAccessBaseObjectType();1551if (!BaseObjectType.isNull()) {1552BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc,1553DeclarationName());1554if (BaseObjectType.isNull()) return;1555}15561557AccessTarget Entity(Context,1558AccessTarget::Member,1559NamingClass,1560DeclAccessPair::make(TargetDecl, Access),1561BaseObjectType);1562Entity.setDiag(DD.getDiagnostic());1563CheckAccess(*this, Loc, Entity);1564} else {1565AccessTarget Entity(Context,1566AccessTarget::Base,1567cast<CXXRecordDecl>(TargetD),1568cast<CXXRecordDecl>(NamingD),1569Access);1570Entity.setDiag(DD.getDiagnostic());1571CheckAccess(*this, Loc, Entity);1572}1573}15741575Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,1576DeclAccessPair Found) {1577if (!getLangOpts().AccessControl ||1578!E->getNamingClass() ||1579Found.getAccess() == AS_public)1580return AR_accessible;15811582AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),1583Found, QualType());1584Entity.setDiag(diag::err_access) << E->getSourceRange();15851586return CheckAccess(*this, E->getNameLoc(), Entity);1587}15881589Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,1590DeclAccessPair Found) {1591if (!getLangOpts().AccessControl ||1592Found.getAccess() == AS_public)1593return AR_accessible;15941595QualType BaseType = E->getBaseType();1596if (E->isArrow())1597BaseType = BaseType->castAs<PointerType>()->getPointeeType();15981599AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),1600Found, BaseType);1601Entity.setDiag(diag::err_access) << E->getSourceRange();16021603return CheckAccess(*this, E->getMemberLoc(), Entity);1604}16051606bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass,1607DeclAccessPair Found,1608QualType ObjectType,1609SourceLocation Loc,1610const PartialDiagnostic &Diag) {1611// Fast path.1612if (Found.getAccess() == AS_public || !getLangOpts().AccessControl)1613return true;16141615AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,1616ObjectType);16171618// Suppress diagnostics.1619Entity.setDiag(Diag);16201621switch (CheckAccess(*this, Loc, Entity)) {1622case AR_accessible: return true;1623case AR_inaccessible: return false;1624case AR_dependent: llvm_unreachable("dependent for =delete computation");1625case AR_delayed: llvm_unreachable("cannot delay =delete computation");1626}1627llvm_unreachable("bad access result");1628}16291630Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,1631CXXDestructorDecl *Dtor,1632const PartialDiagnostic &PDiag,1633QualType ObjectTy) {1634if (!getLangOpts().AccessControl)1635return AR_accessible;16361637// There's never a path involved when checking implicit destructor access.1638AccessSpecifier Access = Dtor->getAccess();1639if (Access == AS_public)1640return AR_accessible;16411642CXXRecordDecl *NamingClass = Dtor->getParent();1643if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass);16441645AccessTarget Entity(Context, AccessTarget::Member, NamingClass,1646DeclAccessPair::make(Dtor, Access),1647ObjectTy);1648Entity.setDiag(PDiag); // TODO: avoid copy16491650return CheckAccess(*this, Loc, Entity);1651}16521653Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,1654CXXConstructorDecl *Constructor,1655DeclAccessPair Found,1656const InitializedEntity &Entity,1657bool IsCopyBindingRefToTemp) {1658if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)1659return AR_accessible;16601661PartialDiagnostic PD(PDiag());1662switch (Entity.getKind()) {1663default:1664PD = PDiag(IsCopyBindingRefToTemp1665? diag::ext_rvalue_to_reference_access_ctor1666: diag::err_access_ctor);16671668break;16691670case InitializedEntity::EK_Base:1671PD = PDiag(diag::err_access_base_ctor);1672PD << Entity.isInheritedVirtualBase()1673<< Entity.getBaseSpecifier()->getType()1674<< llvm::to_underlying(getSpecialMember(Constructor));1675break;16761677case InitializedEntity::EK_Member:1678case InitializedEntity::EK_ParenAggInitMember: {1679const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());1680PD = PDiag(diag::err_access_field_ctor);1681PD << Field->getType()1682<< llvm::to_underlying(getSpecialMember(Constructor));1683break;1684}16851686case InitializedEntity::EK_LambdaCapture: {1687StringRef VarName = Entity.getCapturedVarName();1688PD = PDiag(diag::err_access_lambda_capture);1689PD << VarName << Entity.getType()1690<< llvm::to_underlying(getSpecialMember(Constructor));1691break;1692}16931694}16951696return CheckConstructorAccess(UseLoc, Constructor, Found, Entity, PD);1697}16981699Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,1700CXXConstructorDecl *Constructor,1701DeclAccessPair Found,1702const InitializedEntity &Entity,1703const PartialDiagnostic &PD) {1704if (!getLangOpts().AccessControl ||1705Found.getAccess() == AS_public)1706return AR_accessible;17071708CXXRecordDecl *NamingClass = Constructor->getParent();17091710// Initializing a base sub-object is an instance method call on an1711// object of the derived class. Otherwise, we have an instance method1712// call on an object of the constructed type.1713//1714// FIXME: If we have a parent, we're initializing the base class subobject1715// in aggregate initialization. It's not clear whether the object class1716// should be the base class or the derived class in that case.1717CXXRecordDecl *ObjectClass;1718if ((Entity.getKind() == InitializedEntity::EK_Base ||1719Entity.getKind() == InitializedEntity::EK_Delegating) &&1720!Entity.getParent()) {1721ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent();1722} else if (auto *Shadow =1723dyn_cast<ConstructorUsingShadowDecl>(Found.getDecl())) {1724// If we're using an inheriting constructor to construct an object,1725// the object class is the derived class, not the base class.1726ObjectClass = Shadow->getParent();1727} else {1728ObjectClass = NamingClass;1729}17301731AccessTarget AccessEntity(1732Context, AccessTarget::Member, NamingClass,1733DeclAccessPair::make(Constructor, Found.getAccess()),1734Context.getTypeDeclType(ObjectClass));1735AccessEntity.setDiag(PD);17361737return CheckAccess(*this, UseLoc, AccessEntity);1738}17391740Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,1741SourceRange PlacementRange,1742CXXRecordDecl *NamingClass,1743DeclAccessPair Found,1744bool Diagnose) {1745if (!getLangOpts().AccessControl ||1746!NamingClass ||1747Found.getAccess() == AS_public)1748return AR_accessible;17491750AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,1751QualType());1752if (Diagnose)1753Entity.setDiag(diag::err_access)1754<< PlacementRange;17551756return CheckAccess(*this, OpLoc, Entity);1757}17581759Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc,1760CXXRecordDecl *NamingClass,1761DeclAccessPair Found) {1762if (!getLangOpts().AccessControl ||1763!NamingClass ||1764Found.getAccess() == AS_public)1765return AR_accessible;17661767AccessTarget Entity(Context, AccessTarget::Member, NamingClass,1768Found, QualType());17691770return CheckAccess(*this, UseLoc, Entity);1771}17721773Sema::AccessResult1774Sema::CheckStructuredBindingMemberAccess(SourceLocation UseLoc,1775CXXRecordDecl *DecomposedClass,1776DeclAccessPair Field) {1777if (!getLangOpts().AccessControl ||1778Field.getAccess() == AS_public)1779return AR_accessible;17801781AccessTarget Entity(Context, AccessTarget::Member, DecomposedClass, Field,1782Context.getRecordType(DecomposedClass));1783Entity.setDiag(diag::err_decomp_decl_inaccessible_field);17841785return CheckAccess(*this, UseLoc, Entity);1786}17871788Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,1789Expr *ObjectExpr,1790const SourceRange &Range,1791DeclAccessPair Found) {1792if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)1793return AR_accessible;17941795const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();1796CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());17971798AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,1799ObjectExpr->getType());1800Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << Range;18011802return CheckAccess(*this, OpLoc, Entity);1803}18041805Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,1806Expr *ObjectExpr,1807Expr *ArgExpr,1808DeclAccessPair Found) {1809return CheckMemberOperatorAccess(1810OpLoc, ObjectExpr, ArgExpr ? ArgExpr->getSourceRange() : SourceRange(),1811Found);1812}18131814Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,1815Expr *ObjectExpr,1816ArrayRef<Expr *> ArgExprs,1817DeclAccessPair FoundDecl) {1818SourceRange R;1819if (!ArgExprs.empty()) {1820R = SourceRange(ArgExprs.front()->getBeginLoc(),1821ArgExprs.back()->getEndLoc());1822}18231824return CheckMemberOperatorAccess(OpLoc, ObjectExpr, R, FoundDecl);1825}18261827Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {1828assert(isa<CXXMethodDecl>(target->getAsFunction()));18291830// Friendship lookup is a redeclaration lookup, so there's never an1831// inheritance path modifying access.1832AccessSpecifier access = target->getAccess();18331834if (!getLangOpts().AccessControl || access == AS_public)1835return AR_accessible;18361837CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction());18381839AccessTarget entity(Context, AccessTarget::Member,1840cast<CXXRecordDecl>(target->getDeclContext()),1841DeclAccessPair::make(target, access),1842/*no instance context*/ QualType());1843entity.setDiag(diag::err_access_friend_function)1844<< (method->getQualifier() ? method->getQualifierLoc().getSourceRange()1845: method->getNameInfo().getSourceRange());18461847// We need to bypass delayed-diagnostics because we might be called1848// while the ParsingDeclarator is active.1849EffectiveContext EC(CurContext);1850switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) {1851case ::AR_accessible: return Sema::AR_accessible;1852case ::AR_inaccessible: return Sema::AR_inaccessible;1853case ::AR_dependent: return Sema::AR_dependent;1854}1855llvm_unreachable("invalid access result");1856}18571858Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,1859DeclAccessPair Found) {1860if (!getLangOpts().AccessControl ||1861Found.getAccess() == AS_none ||1862Found.getAccess() == AS_public)1863return AR_accessible;18641865OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression;1866CXXRecordDecl *NamingClass = Ovl->getNamingClass();18671868AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,1869/*no instance context*/ QualType());1870Entity.setDiag(diag::err_access)1871<< Ovl->getSourceRange();18721873return CheckAccess(*this, Ovl->getNameLoc(), Entity);1874}18751876Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,1877QualType Base,1878QualType Derived,1879const CXXBasePath &Path,1880unsigned DiagID,1881bool ForceCheck,1882bool ForceUnprivileged) {1883if (!ForceCheck && !getLangOpts().AccessControl)1884return AR_accessible;18851886if (Path.Access == AS_public)1887return AR_accessible;18881889CXXRecordDecl *BaseD, *DerivedD;1890BaseD = cast<CXXRecordDecl>(Base->castAs<RecordType>()->getDecl());1891DerivedD = cast<CXXRecordDecl>(Derived->castAs<RecordType>()->getDecl());18921893AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,1894Path.Access);1895if (DiagID)1896Entity.setDiag(DiagID) << Derived << Base;18971898if (ForceUnprivileged) {1899switch (CheckEffectiveAccess(*this, EffectiveContext(),1900AccessLoc, Entity)) {1901case ::AR_accessible: return Sema::AR_accessible;1902case ::AR_inaccessible: return Sema::AR_inaccessible;1903case ::AR_dependent: return Sema::AR_dependent;1904}1905llvm_unreachable("unexpected result from CheckEffectiveAccess");1906}1907return CheckAccess(*this, AccessLoc, Entity);1908}19091910void Sema::CheckLookupAccess(const LookupResult &R) {1911assert(getLangOpts().AccessControl1912&& "performing access check without access control");1913assert(R.getNamingClass() && "performing access check without naming class");19141915for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {1916if (I.getAccess() != AS_public) {1917AccessTarget Entity(Context, AccessedEntity::Member,1918R.getNamingClass(), I.getPair(),1919R.getBaseObjectType());1920Entity.setDiag(diag::err_access);1921CheckAccess(*this, R.getNameLoc(), Entity);1922}1923}1924}19251926bool Sema::IsSimplyAccessible(NamedDecl *Target, CXXRecordDecl *NamingClass,1927QualType BaseType) {1928// Perform the C++ accessibility checks first.1929if (Target->isCXXClassMember() && NamingClass) {1930if (!getLangOpts().CPlusPlus)1931return false;1932// The unprivileged access is AS_none as we don't know how the member was1933// accessed, which is described by the access in DeclAccessPair.1934// `IsAccessible` will examine the actual access of Target (i.e.1935// Decl->getAccess()) when calculating the access.1936AccessTarget Entity(Context, AccessedEntity::Member, NamingClass,1937DeclAccessPair::make(Target, AS_none), BaseType);1938EffectiveContext EC(CurContext);1939return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;1940}19411942if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Target)) {1943// @public and @package ivars are always accessible.1944if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||1945Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package)1946return true;19471948// If we are inside a class or category implementation, determine the1949// interface we're in.1950ObjCInterfaceDecl *ClassOfMethodDecl = nullptr;1951if (ObjCMethodDecl *MD = getCurMethodDecl())1952ClassOfMethodDecl = MD->getClassInterface();1953else if (FunctionDecl *FD = getCurFunctionDecl()) {1954if (ObjCImplDecl *Impl1955= dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) {1956if (ObjCImplementationDecl *IMPD1957= dyn_cast<ObjCImplementationDecl>(Impl))1958ClassOfMethodDecl = IMPD->getClassInterface();1959else if (ObjCCategoryImplDecl* CatImplClass1960= dyn_cast<ObjCCategoryImplDecl>(Impl))1961ClassOfMethodDecl = CatImplClass->getClassInterface();1962}1963}19641965// If we're not in an interface, this ivar is inaccessible.1966if (!ClassOfMethodDecl)1967return false;19681969// If we're inside the same interface that owns the ivar, we're fine.1970if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface()))1971return true;19721973// If the ivar is private, it's inaccessible.1974if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private)1975return false;19761977return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl);1978}19791980return true;1981}198219831984