1193326Sed//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// 2193326Sed// 3193326Sed// The LLVM Compiler Infrastructure 4193326Sed// 5193326Sed// This file is distributed under the University of Illinois Open Source 6193326Sed// License. See LICENSE.TXT for details. 7193326Sed// 8193326Sed//===----------------------------------------------------------------------===// 9193326Sed// 10193326Sed// This file provides Sema routines for C++ access control semantics. 11193326Sed// 12193326Sed//===----------------------------------------------------------------------===// 13193326Sed 14212904Sdim#include "clang/Sema/SemaInternal.h" 15193326Sed#include "clang/AST/ASTContext.h" 16198092Srdivacky#include "clang/AST/CXXInheritance.h" 17198092Srdivacky#include "clang/AST/DeclCXX.h" 18205219Srdivacky#include "clang/AST/DeclFriend.h" 19235633Sdim#include "clang/AST/DeclObjC.h" 20206084Srdivacky#include "clang/AST/DependentDiagnostic.h" 21203955Srdivacky#include "clang/AST/ExprCXX.h" 22252723Sdim#include "clang/Sema/DelayedDiagnostic.h" 23252723Sdim#include "clang/Sema/Initialization.h" 24252723Sdim#include "clang/Sema/Lookup.h" 25203955Srdivacky 26193326Sedusing namespace clang; 27212904Sdimusing namespace sema; 28193326Sed 29207619Srdivacky/// A copy of Sema's enum without AR_delayed. 30207619Srdivackyenum AccessResult { 31207619Srdivacky AR_accessible, 32207619Srdivacky AR_inaccessible, 33207619Srdivacky AR_dependent 34207619Srdivacky}; 35207619Srdivacky 36193326Sed/// SetMemberAccessSpecifier - Set the access specifier of a member. 37193326Sed/// Returns true on error (when the previous member decl access specifier 38193326Sed/// is different from the new member decl access specifier). 39198092Srdivackybool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, 40193326Sed NamedDecl *PrevMemberDecl, 41193326Sed AccessSpecifier LexicalAS) { 42193326Sed if (!PrevMemberDecl) { 43193326Sed // Use the lexical access specifier. 44193326Sed MemberDecl->setAccess(LexicalAS); 45193326Sed return false; 46193326Sed } 47198092Srdivacky 48193326Sed // C++ [class.access.spec]p3: When a member is redeclared its access 49193326Sed // specifier must be same as its initial declaration. 50193326Sed if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { 51198092Srdivacky Diag(MemberDecl->getLocation(), 52198092Srdivacky diag::err_class_redeclared_with_different_access) 53193326Sed << MemberDecl << LexicalAS; 54193326Sed Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) 55193326Sed << PrevMemberDecl << PrevMemberDecl->getAccess(); 56201361Srdivacky 57201361Srdivacky MemberDecl->setAccess(LexicalAS); 58193326Sed return true; 59193326Sed } 60198092Srdivacky 61193326Sed MemberDecl->setAccess(PrevMemberDecl->getAccess()); 62193326Sed return false; 63193326Sed} 64193326Sed 65207619Srdivackystatic CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { 66207619Srdivacky DeclContext *DC = D->getDeclContext(); 67207619Srdivacky 68207619Srdivacky // This can only happen at top: enum decls only "publish" their 69207619Srdivacky // immediate members. 70207619Srdivacky if (isa<EnumDecl>(DC)) 71207619Srdivacky DC = cast<EnumDecl>(DC)->getDeclContext(); 72207619Srdivacky 73207619Srdivacky CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); 74207619Srdivacky while (DeclaringClass->isAnonymousStructOrUnion()) 75207619Srdivacky DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); 76207619Srdivacky return DeclaringClass; 77207619Srdivacky} 78207619Srdivacky 79203955Srdivackynamespace { 80203955Srdivackystruct EffectiveContext { 81206084Srdivacky EffectiveContext() : Inner(0), Dependent(false) {} 82193326Sed 83206084Srdivacky explicit EffectiveContext(DeclContext *DC) 84206084Srdivacky : Inner(DC), 85206084Srdivacky Dependent(DC->isDependentContext()) { 86205408Srdivacky 87252723Sdim // C++11 [class.access.nest]p1: 88205408Srdivacky // A nested class is a member and as such has the same access 89205408Srdivacky // rights as any other member. 90252723Sdim // C++11 [class.access]p2: 91205408Srdivacky // A member of a class can also access all the names to which 92206084Srdivacky // the class has access. A local class of a member function 93206084Srdivacky // may access the same names that the member function itself 94206084Srdivacky // may access. 95206084Srdivacky // This almost implies that the privileges of nesting are transitive. 96206084Srdivacky // Technically it says nothing about the local classes of non-member 97206084Srdivacky // functions (which can gain privileges through friendship), but we 98206084Srdivacky // take that as an oversight. 99206084Srdivacky while (true) { 100245431Sdim // We want to add canonical declarations to the EC lists for 101245431Sdim // simplicity of checking, but we need to walk up through the 102245431Sdim // actual current DC chain. Otherwise, something like a local 103245431Sdim // extern or friend which happens to be the canonical 104245431Sdim // declaration will really mess us up. 105245431Sdim 106206084Srdivacky if (isa<CXXRecordDecl>(DC)) { 107245431Sdim CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); 108245431Sdim Records.push_back(Record->getCanonicalDecl()); 109206084Srdivacky DC = Record->getDeclContext(); 110206084Srdivacky } else if (isa<FunctionDecl>(DC)) { 111245431Sdim FunctionDecl *Function = cast<FunctionDecl>(DC); 112245431Sdim Functions.push_back(Function->getCanonicalDecl()); 113226890Sdim if (Function->getFriendObjectKind()) 114226890Sdim DC = Function->getLexicalDeclContext(); 115226890Sdim else 116226890Sdim DC = Function->getDeclContext(); 117206084Srdivacky } else if (DC->isFileContext()) { 118206084Srdivacky break; 119206084Srdivacky } else { 120206084Srdivacky DC = DC->getParent(); 121206084Srdivacky } 122205408Srdivacky } 123203955Srdivacky } 124198092Srdivacky 125206084Srdivacky bool isDependent() const { return Dependent; } 126206084Srdivacky 127205408Srdivacky bool includesClass(const CXXRecordDecl *R) const { 128205408Srdivacky R = R->getCanonicalDecl(); 129205408Srdivacky return std::find(Records.begin(), Records.end(), R) 130205408Srdivacky != Records.end(); 131203955Srdivacky } 132198092Srdivacky 133206084Srdivacky /// Retrieves the innermost "useful" context. Can be null if we're 134206084Srdivacky /// doing access-control without privileges. 135206084Srdivacky DeclContext *getInnerContext() const { 136206084Srdivacky return Inner; 137206084Srdivacky } 138206084Srdivacky 139226890Sdim typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; 140206084Srdivacky 141206084Srdivacky DeclContext *Inner; 142226890Sdim SmallVector<FunctionDecl*, 4> Functions; 143226890Sdim SmallVector<CXXRecordDecl*, 4> Records; 144206084Srdivacky bool Dependent; 145203955Srdivacky}; 146207619Srdivacky 147218893Sdim/// Like sema::AccessedEntity, but kindly lets us scribble all over 148207619Srdivacky/// it. 149212904Sdimstruct AccessTarget : public AccessedEntity { 150212904Sdim AccessTarget(const AccessedEntity &Entity) 151207619Srdivacky : AccessedEntity(Entity) { 152207619Srdivacky initialize(); 153207619Srdivacky } 154207619Srdivacky 155207619Srdivacky AccessTarget(ASTContext &Context, 156207619Srdivacky MemberNonce _, 157207619Srdivacky CXXRecordDecl *NamingClass, 158207619Srdivacky DeclAccessPair FoundDecl, 159226890Sdim QualType BaseObjectType) 160245431Sdim : AccessedEntity(Context.getDiagAllocator(), Member, NamingClass, 161245431Sdim FoundDecl, BaseObjectType) { 162207619Srdivacky initialize(); 163207619Srdivacky } 164207619Srdivacky 165207619Srdivacky AccessTarget(ASTContext &Context, 166207619Srdivacky BaseNonce _, 167207619Srdivacky CXXRecordDecl *BaseClass, 168207619Srdivacky CXXRecordDecl *DerivedClass, 169207619Srdivacky AccessSpecifier Access) 170245431Sdim : AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass, 171245431Sdim Access) { 172207619Srdivacky initialize(); 173207619Srdivacky } 174207619Srdivacky 175235633Sdim bool isInstanceMember() const { 176235633Sdim return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember()); 177235633Sdim } 178235633Sdim 179207619Srdivacky bool hasInstanceContext() const { 180207619Srdivacky return HasInstanceContext; 181207619Srdivacky } 182207619Srdivacky 183207619Srdivacky class SavedInstanceContext { 184207619Srdivacky public: 185207619Srdivacky ~SavedInstanceContext() { 186207619Srdivacky Target.HasInstanceContext = Has; 187207619Srdivacky } 188207619Srdivacky 189207619Srdivacky private: 190207619Srdivacky friend struct AccessTarget; 191207619Srdivacky explicit SavedInstanceContext(AccessTarget &Target) 192207619Srdivacky : Target(Target), Has(Target.HasInstanceContext) {} 193207619Srdivacky AccessTarget &Target; 194207619Srdivacky bool Has; 195207619Srdivacky }; 196207619Srdivacky 197207619Srdivacky SavedInstanceContext saveInstanceContext() { 198207619Srdivacky return SavedInstanceContext(*this); 199207619Srdivacky } 200207619Srdivacky 201207619Srdivacky void suppressInstanceContext() { 202207619Srdivacky HasInstanceContext = false; 203207619Srdivacky } 204207619Srdivacky 205207619Srdivacky const CXXRecordDecl *resolveInstanceContext(Sema &S) const { 206207619Srdivacky assert(HasInstanceContext); 207207619Srdivacky if (CalculatedInstanceContext) 208207619Srdivacky return InstanceContext; 209207619Srdivacky 210207619Srdivacky CalculatedInstanceContext = true; 211207619Srdivacky DeclContext *IC = S.computeDeclContext(getBaseObjectType()); 212207619Srdivacky InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0); 213207619Srdivacky return InstanceContext; 214207619Srdivacky } 215207619Srdivacky 216207619Srdivacky const CXXRecordDecl *getDeclaringClass() const { 217207619Srdivacky return DeclaringClass; 218207619Srdivacky } 219207619Srdivacky 220252723Sdim /// The "effective" naming class is the canonical non-anonymous 221252723Sdim /// class containing the actual naming class. 222252723Sdim const CXXRecordDecl *getEffectiveNamingClass() const { 223252723Sdim const CXXRecordDecl *namingClass = getNamingClass(); 224252723Sdim while (namingClass->isAnonymousStructOrUnion()) 225252723Sdim namingClass = cast<CXXRecordDecl>(namingClass->getParent()); 226252723Sdim return namingClass->getCanonicalDecl(); 227252723Sdim } 228252723Sdim 229207619Srdivackyprivate: 230207619Srdivacky void initialize() { 231207619Srdivacky HasInstanceContext = (isMemberAccess() && 232207619Srdivacky !getBaseObjectType().isNull() && 233207619Srdivacky getTargetDecl()->isCXXInstanceMember()); 234207619Srdivacky CalculatedInstanceContext = false; 235207619Srdivacky InstanceContext = 0; 236207619Srdivacky 237207619Srdivacky if (isMemberAccess()) 238207619Srdivacky DeclaringClass = FindDeclaringClass(getTargetDecl()); 239207619Srdivacky else 240207619Srdivacky DeclaringClass = getBaseClass(); 241207619Srdivacky DeclaringClass = DeclaringClass->getCanonicalDecl(); 242207619Srdivacky } 243207619Srdivacky 244207619Srdivacky bool HasInstanceContext : 1; 245207619Srdivacky mutable bool CalculatedInstanceContext : 1; 246207619Srdivacky mutable const CXXRecordDecl *InstanceContext; 247207619Srdivacky const CXXRecordDecl *DeclaringClass; 248207619Srdivacky}; 249207619Srdivacky 250203955Srdivacky} 251193326Sed 252207619Srdivacky/// Checks whether one class might instantiate to the other. 253207619Srdivackystatic bool MightInstantiateTo(const CXXRecordDecl *From, 254207619Srdivacky const CXXRecordDecl *To) { 255207619Srdivacky // Declaration names are always preserved by instantiation. 256207619Srdivacky if (From->getDeclName() != To->getDeclName()) 257207619Srdivacky return false; 258206084Srdivacky 259207619Srdivacky const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext(); 260207619Srdivacky const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext(); 261207619Srdivacky if (FromDC == ToDC) return true; 262207619Srdivacky if (FromDC->isFileContext() || ToDC->isFileContext()) return false; 263206084Srdivacky 264207619Srdivacky // Be conservative. 265207619Srdivacky return true; 266203955Srdivacky} 267198092Srdivacky 268207619Srdivacky/// Checks whether one class is derived from another, inclusively. 269207619Srdivacky/// Properly indicates when it couldn't be determined due to 270207619Srdivacky/// dependence. 271207619Srdivacky/// 272207619Srdivacky/// This should probably be donated to AST or at least Sema. 273207619Srdivackystatic AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, 274207619Srdivacky const CXXRecordDecl *Target) { 275207619Srdivacky assert(Derived->getCanonicalDecl() == Derived); 276207619Srdivacky assert(Target->getCanonicalDecl() == Target); 277207619Srdivacky 278207619Srdivacky if (Derived == Target) return AR_accessible; 279207619Srdivacky 280207619Srdivacky bool CheckDependent = Derived->isDependentContext(); 281207619Srdivacky if (CheckDependent && MightInstantiateTo(Derived, Target)) 282207619Srdivacky return AR_dependent; 283207619Srdivacky 284207619Srdivacky AccessResult OnFailure = AR_inaccessible; 285226890Sdim SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack 286207619Srdivacky 287207619Srdivacky while (true) { 288235633Sdim if (Derived->isDependentContext() && !Derived->hasDefinition()) 289235633Sdim return AR_dependent; 290235633Sdim 291207619Srdivacky for (CXXRecordDecl::base_class_const_iterator 292207619Srdivacky I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) { 293207619Srdivacky 294207619Srdivacky const CXXRecordDecl *RD; 295207619Srdivacky 296207619Srdivacky QualType T = I->getType(); 297207619Srdivacky if (const RecordType *RT = T->getAs<RecordType>()) { 298207619Srdivacky RD = cast<CXXRecordDecl>(RT->getDecl()); 299207619Srdivacky } else if (const InjectedClassNameType *IT 300207619Srdivacky = T->getAs<InjectedClassNameType>()) { 301207619Srdivacky RD = IT->getDecl(); 302207619Srdivacky } else { 303207619Srdivacky assert(T->isDependentType() && "non-dependent base wasn't a record?"); 304207619Srdivacky OnFailure = AR_dependent; 305207619Srdivacky continue; 306207619Srdivacky } 307207619Srdivacky 308207619Srdivacky RD = RD->getCanonicalDecl(); 309207619Srdivacky if (RD == Target) return AR_accessible; 310207619Srdivacky if (CheckDependent && MightInstantiateTo(RD, Target)) 311207619Srdivacky OnFailure = AR_dependent; 312207619Srdivacky 313207619Srdivacky Queue.push_back(RD); 314207619Srdivacky } 315207619Srdivacky 316207619Srdivacky if (Queue.empty()) break; 317207619Srdivacky 318263509Sdim Derived = Queue.pop_back_val(); 319207619Srdivacky } 320207619Srdivacky 321207619Srdivacky return OnFailure; 322207619Srdivacky} 323207619Srdivacky 324207619Srdivacky 325206084Srdivackystatic bool MightInstantiateTo(Sema &S, DeclContext *Context, 326206084Srdivacky DeclContext *Friend) { 327206084Srdivacky if (Friend == Context) 328206084Srdivacky return true; 329206084Srdivacky 330206084Srdivacky assert(!Friend->isDependentContext() && 331206084Srdivacky "can't handle friends with dependent contexts here"); 332206084Srdivacky 333206084Srdivacky if (!Context->isDependentContext()) 334206084Srdivacky return false; 335206084Srdivacky 336206084Srdivacky if (Friend->isFileContext()) 337206084Srdivacky return false; 338206084Srdivacky 339206084Srdivacky // TODO: this is very conservative 340206084Srdivacky return true; 341206084Srdivacky} 342206084Srdivacky 343206084Srdivacky// Asks whether the type in 'context' can ever instantiate to the type 344206084Srdivacky// in 'friend'. 345206084Srdivackystatic bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) { 346206084Srdivacky if (Friend == Context) 347206084Srdivacky return true; 348206084Srdivacky 349206084Srdivacky if (!Friend->isDependentType() && !Context->isDependentType()) 350206084Srdivacky return false; 351206084Srdivacky 352206084Srdivacky // TODO: this is very conservative. 353206084Srdivacky return true; 354206084Srdivacky} 355206084Srdivacky 356206084Srdivackystatic bool MightInstantiateTo(Sema &S, 357206084Srdivacky FunctionDecl *Context, 358206084Srdivacky FunctionDecl *Friend) { 359206084Srdivacky if (Context->getDeclName() != Friend->getDeclName()) 360206084Srdivacky return false; 361206084Srdivacky 362206084Srdivacky if (!MightInstantiateTo(S, 363206084Srdivacky Context->getDeclContext(), 364206084Srdivacky Friend->getDeclContext())) 365206084Srdivacky return false; 366206084Srdivacky 367206084Srdivacky CanQual<FunctionProtoType> FriendTy 368206084Srdivacky = S.Context.getCanonicalType(Friend->getType()) 369206084Srdivacky ->getAs<FunctionProtoType>(); 370206084Srdivacky CanQual<FunctionProtoType> ContextTy 371206084Srdivacky = S.Context.getCanonicalType(Context->getType()) 372206084Srdivacky ->getAs<FunctionProtoType>(); 373206084Srdivacky 374206084Srdivacky // There isn't any way that I know of to add qualifiers 375206084Srdivacky // during instantiation. 376206084Srdivacky if (FriendTy.getQualifiers() != ContextTy.getQualifiers()) 377206084Srdivacky return false; 378206084Srdivacky 379206084Srdivacky if (FriendTy->getNumArgs() != ContextTy->getNumArgs()) 380206084Srdivacky return false; 381206084Srdivacky 382206084Srdivacky if (!MightInstantiateTo(S, 383206084Srdivacky ContextTy->getResultType(), 384206084Srdivacky FriendTy->getResultType())) 385206084Srdivacky return false; 386206084Srdivacky 387206084Srdivacky for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I) 388206084Srdivacky if (!MightInstantiateTo(S, 389206084Srdivacky ContextTy->getArgType(I), 390206084Srdivacky FriendTy->getArgType(I))) 391206084Srdivacky return false; 392206084Srdivacky 393206084Srdivacky return true; 394206084Srdivacky} 395206084Srdivacky 396206084Srdivackystatic bool MightInstantiateTo(Sema &S, 397206084Srdivacky FunctionTemplateDecl *Context, 398206084Srdivacky FunctionTemplateDecl *Friend) { 399206084Srdivacky return MightInstantiateTo(S, 400206084Srdivacky Context->getTemplatedDecl(), 401206084Srdivacky Friend->getTemplatedDecl()); 402206084Srdivacky} 403206084Srdivacky 404207619Srdivackystatic AccessResult MatchesFriend(Sema &S, 405207619Srdivacky const EffectiveContext &EC, 406207619Srdivacky const CXXRecordDecl *Friend) { 407205408Srdivacky if (EC.includesClass(Friend)) 408207619Srdivacky return AR_accessible; 409205408Srdivacky 410206084Srdivacky if (EC.isDependent()) { 411206084Srdivacky CanQualType FriendTy 412206084Srdivacky = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend)); 413206084Srdivacky 414206084Srdivacky for (EffectiveContext::record_iterator 415206084Srdivacky I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 416206084Srdivacky CanQualType ContextTy 417206084Srdivacky = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); 418206084Srdivacky if (MightInstantiateTo(S, ContextTy, FriendTy)) 419207619Srdivacky return AR_dependent; 420206084Srdivacky } 421206084Srdivacky } 422206084Srdivacky 423207619Srdivacky return AR_inaccessible; 424205408Srdivacky} 425205408Srdivacky 426207619Srdivackystatic AccessResult MatchesFriend(Sema &S, 427207619Srdivacky const EffectiveContext &EC, 428207619Srdivacky CanQualType Friend) { 429206084Srdivacky if (const RecordType *RT = Friend->getAs<RecordType>()) 430206084Srdivacky return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); 431205408Srdivacky 432206084Srdivacky // TODO: we can do better than this 433206084Srdivacky if (Friend->isDependentType()) 434207619Srdivacky return AR_dependent; 435205408Srdivacky 436207619Srdivacky return AR_inaccessible; 437206084Srdivacky} 438205408Srdivacky 439206084Srdivacky/// Determines whether the given friend class template matches 440206084Srdivacky/// anything in the effective context. 441207619Srdivackystatic AccessResult MatchesFriend(Sema &S, 442207619Srdivacky const EffectiveContext &EC, 443207619Srdivacky ClassTemplateDecl *Friend) { 444207619Srdivacky AccessResult OnFailure = AR_inaccessible; 445205408Srdivacky 446206084Srdivacky // Check whether the friend is the template of a class in the 447206084Srdivacky // context chain. 448226890Sdim for (SmallVectorImpl<CXXRecordDecl*>::const_iterator 449206084Srdivacky I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 450206084Srdivacky CXXRecordDecl *Record = *I; 451205408Srdivacky 452206084Srdivacky // Figure out whether the current class has a template: 453206084Srdivacky ClassTemplateDecl *CTD; 454205408Srdivacky 455206084Srdivacky // A specialization of the template... 456206084Srdivacky if (isa<ClassTemplateSpecializationDecl>(Record)) { 457206084Srdivacky CTD = cast<ClassTemplateSpecializationDecl>(Record) 458206084Srdivacky ->getSpecializedTemplate(); 459205408Srdivacky 460206084Srdivacky // ... or the template pattern itself. 461206084Srdivacky } else { 462206084Srdivacky CTD = Record->getDescribedClassTemplate(); 463206084Srdivacky if (!CTD) continue; 464205408Srdivacky } 465205408Srdivacky 466206084Srdivacky // It's a match. 467206084Srdivacky if (Friend == CTD->getCanonicalDecl()) 468207619Srdivacky return AR_accessible; 469206084Srdivacky 470206084Srdivacky // If the context isn't dependent, it can't be a dependent match. 471206084Srdivacky if (!EC.isDependent()) 472206084Srdivacky continue; 473206084Srdivacky 474206084Srdivacky // If the template names don't match, it can't be a dependent 475223017Sdim // match. 476223017Sdim if (CTD->getDeclName() != Friend->getDeclName()) 477206084Srdivacky continue; 478206084Srdivacky 479206084Srdivacky // If the class's context can't instantiate to the friend's 480206084Srdivacky // context, it can't be a dependent match. 481206084Srdivacky if (!MightInstantiateTo(S, CTD->getDeclContext(), 482206084Srdivacky Friend->getDeclContext())) 483206084Srdivacky continue; 484206084Srdivacky 485206084Srdivacky // Otherwise, it's a dependent match. 486207619Srdivacky OnFailure = AR_dependent; 487205408Srdivacky } 488205408Srdivacky 489206084Srdivacky return OnFailure; 490206084Srdivacky} 491205408Srdivacky 492206084Srdivacky/// Determines whether the given friend function matches anything in 493206084Srdivacky/// the effective context. 494207619Srdivackystatic AccessResult MatchesFriend(Sema &S, 495207619Srdivacky const EffectiveContext &EC, 496207619Srdivacky FunctionDecl *Friend) { 497207619Srdivacky AccessResult OnFailure = AR_inaccessible; 498206084Srdivacky 499226890Sdim for (SmallVectorImpl<FunctionDecl*>::const_iterator 500206084Srdivacky I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { 501206084Srdivacky if (Friend == *I) 502207619Srdivacky return AR_accessible; 503206084Srdivacky 504206084Srdivacky if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) 505207619Srdivacky OnFailure = AR_dependent; 506206084Srdivacky } 507206084Srdivacky 508206084Srdivacky return OnFailure; 509206084Srdivacky} 510206084Srdivacky 511206084Srdivacky/// Determines whether the given friend function template matches 512206084Srdivacky/// anything in the effective context. 513207619Srdivackystatic AccessResult MatchesFriend(Sema &S, 514207619Srdivacky const EffectiveContext &EC, 515207619Srdivacky FunctionTemplateDecl *Friend) { 516207619Srdivacky if (EC.Functions.empty()) return AR_inaccessible; 517206084Srdivacky 518207619Srdivacky AccessResult OnFailure = AR_inaccessible; 519206084Srdivacky 520226890Sdim for (SmallVectorImpl<FunctionDecl*>::const_iterator 521206084Srdivacky I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { 522206084Srdivacky 523206084Srdivacky FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); 524205408Srdivacky if (!FTD) 525206084Srdivacky FTD = (*I)->getDescribedFunctionTemplate(); 526206084Srdivacky if (!FTD) 527206084Srdivacky continue; 528205408Srdivacky 529206084Srdivacky FTD = FTD->getCanonicalDecl(); 530206084Srdivacky 531206084Srdivacky if (Friend == FTD) 532207619Srdivacky return AR_accessible; 533206084Srdivacky 534206084Srdivacky if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) 535207619Srdivacky OnFailure = AR_dependent; 536205408Srdivacky } 537205408Srdivacky 538206084Srdivacky return OnFailure; 539206084Srdivacky} 540205408Srdivacky 541206084Srdivacky/// Determines whether the given friend declaration matches anything 542206084Srdivacky/// in the effective context. 543207619Srdivackystatic AccessResult MatchesFriend(Sema &S, 544207619Srdivacky const EffectiveContext &EC, 545207619Srdivacky FriendDecl *FriendD) { 546218893Sdim // Whitelist accesses if there's an invalid or unsupported friend 547218893Sdim // declaration. 548218893Sdim if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend()) 549218893Sdim return AR_accessible; 550218893Sdim 551206084Srdivacky if (TypeSourceInfo *T = FriendD->getFriendType()) 552206084Srdivacky return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); 553205408Srdivacky 554206084Srdivacky NamedDecl *Friend 555206084Srdivacky = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl()); 556206084Srdivacky 557206084Srdivacky // FIXME: declarations with dependent or templated scope. 558206084Srdivacky 559206084Srdivacky if (isa<ClassTemplateDecl>(Friend)) 560206084Srdivacky return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend)); 561206084Srdivacky 562206084Srdivacky if (isa<FunctionTemplateDecl>(Friend)) 563206084Srdivacky return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend)); 564206084Srdivacky 565206084Srdivacky if (isa<CXXRecordDecl>(Friend)) 566206084Srdivacky return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend)); 567206084Srdivacky 568206084Srdivacky assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind"); 569206084Srdivacky return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); 570205408Srdivacky} 571205408Srdivacky 572207619Srdivackystatic AccessResult GetFriendKind(Sema &S, 573207619Srdivacky const EffectiveContext &EC, 574207619Srdivacky const CXXRecordDecl *Class) { 575207619Srdivacky AccessResult OnFailure = AR_inaccessible; 576205408Srdivacky 577205219Srdivacky // Okay, check friends. 578205219Srdivacky for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), 579205219Srdivacky E = Class->friend_end(); I != E; ++I) { 580205219Srdivacky FriendDecl *Friend = *I; 581205219Srdivacky 582205408Srdivacky switch (MatchesFriend(S, EC, Friend)) { 583207619Srdivacky case AR_accessible: 584207619Srdivacky return AR_accessible; 585205219Srdivacky 586207619Srdivacky case AR_inaccessible: 587207619Srdivacky continue; 588205408Srdivacky 589207619Srdivacky case AR_dependent: 590207619Srdivacky OnFailure = AR_dependent; 591205408Srdivacky break; 592205219Srdivacky } 593205219Srdivacky } 594205219Srdivacky 595205219Srdivacky // That's it, give up. 596205408Srdivacky return OnFailure; 597203955Srdivacky} 598198092Srdivacky 599212904Sdimnamespace { 600212904Sdim 601212904Sdim/// A helper class for checking for a friend which will grant access 602212904Sdim/// to a protected instance member. 603212904Sdimstruct ProtectedFriendContext { 604212904Sdim Sema &S; 605212904Sdim const EffectiveContext &EC; 606212904Sdim const CXXRecordDecl *NamingClass; 607212904Sdim bool CheckDependent; 608212904Sdim bool EverDependent; 609212904Sdim 610212904Sdim /// The path down to the current base class. 611226890Sdim SmallVector<const CXXRecordDecl*, 20> CurPath; 612212904Sdim 613212904Sdim ProtectedFriendContext(Sema &S, const EffectiveContext &EC, 614212904Sdim const CXXRecordDecl *InstanceContext, 615212904Sdim const CXXRecordDecl *NamingClass) 616212904Sdim : S(S), EC(EC), NamingClass(NamingClass), 617212904Sdim CheckDependent(InstanceContext->isDependentContext() || 618212904Sdim NamingClass->isDependentContext()), 619212904Sdim EverDependent(false) {} 620212904Sdim 621212904Sdim /// Check classes in the current path for friendship, starting at 622212904Sdim /// the given index. 623212904Sdim bool checkFriendshipAlongPath(unsigned I) { 624212904Sdim assert(I < CurPath.size()); 625212904Sdim for (unsigned E = CurPath.size(); I != E; ++I) { 626212904Sdim switch (GetFriendKind(S, EC, CurPath[I])) { 627212904Sdim case AR_accessible: return true; 628212904Sdim case AR_inaccessible: continue; 629212904Sdim case AR_dependent: EverDependent = true; continue; 630212904Sdim } 631212904Sdim } 632212904Sdim return false; 633212904Sdim } 634212904Sdim 635212904Sdim /// Perform a search starting at the given class. 636212904Sdim /// 637212904Sdim /// PrivateDepth is the index of the last (least derived) class 638212904Sdim /// along the current path such that a notional public member of 639212904Sdim /// the final class in the path would have access in that class. 640212904Sdim bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) { 641212904Sdim // If we ever reach the naming class, check the current path for 642212904Sdim // friendship. We can also stop recursing because we obviously 643212904Sdim // won't find the naming class there again. 644212904Sdim if (Cur == NamingClass) 645212904Sdim return checkFriendshipAlongPath(PrivateDepth); 646212904Sdim 647212904Sdim if (CheckDependent && MightInstantiateTo(Cur, NamingClass)) 648212904Sdim EverDependent = true; 649212904Sdim 650212904Sdim // Recurse into the base classes. 651212904Sdim for (CXXRecordDecl::base_class_const_iterator 652212904Sdim I = Cur->bases_begin(), E = Cur->bases_end(); I != E; ++I) { 653212904Sdim 654212904Sdim // If this is private inheritance, then a public member of the 655212904Sdim // base will not have any access in classes derived from Cur. 656212904Sdim unsigned BasePrivateDepth = PrivateDepth; 657212904Sdim if (I->getAccessSpecifier() == AS_private) 658212904Sdim BasePrivateDepth = CurPath.size() - 1; 659212904Sdim 660212904Sdim const CXXRecordDecl *RD; 661212904Sdim 662212904Sdim QualType T = I->getType(); 663212904Sdim if (const RecordType *RT = T->getAs<RecordType>()) { 664212904Sdim RD = cast<CXXRecordDecl>(RT->getDecl()); 665212904Sdim } else if (const InjectedClassNameType *IT 666212904Sdim = T->getAs<InjectedClassNameType>()) { 667212904Sdim RD = IT->getDecl(); 668212904Sdim } else { 669212904Sdim assert(T->isDependentType() && "non-dependent base wasn't a record?"); 670212904Sdim EverDependent = true; 671212904Sdim continue; 672212904Sdim } 673212904Sdim 674212904Sdim // Recurse. We don't need to clean up if this returns true. 675212904Sdim CurPath.push_back(RD); 676212904Sdim if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth)) 677212904Sdim return true; 678212904Sdim CurPath.pop_back(); 679212904Sdim } 680212904Sdim 681212904Sdim return false; 682212904Sdim } 683212904Sdim 684212904Sdim bool findFriendship(const CXXRecordDecl *Cur) { 685212904Sdim assert(CurPath.empty()); 686212904Sdim CurPath.push_back(Cur); 687212904Sdim return findFriendship(Cur, 0); 688212904Sdim } 689212904Sdim}; 690212904Sdim} 691212904Sdim 692212904Sdim/// Search for a class P that EC is a friend of, under the constraint 693235633Sdim/// InstanceContext <= P 694235633Sdim/// if InstanceContext exists, or else 695235633Sdim/// NamingClass <= P 696212904Sdim/// and with the additional restriction that a protected member of 697235633Sdim/// NamingClass would have some natural access in P, which implicitly 698235633Sdim/// imposes the constraint that P <= NamingClass. 699212904Sdim/// 700235633Sdim/// This isn't quite the condition laid out in the standard. 701235633Sdim/// Instead of saying that a notional protected member of NamingClass 702235633Sdim/// would have to have some natural access in P, it says the actual 703235633Sdim/// target has to have some natural access in P, which opens up the 704235633Sdim/// possibility that the target (which is not necessarily a member 705235633Sdim/// of NamingClass) might be more accessible along some path not 706235633Sdim/// passing through it. That's really a bad idea, though, because it 707212904Sdim/// introduces two problems: 708235633Sdim/// - Most importantly, it breaks encapsulation because you can 709235633Sdim/// access a forbidden base class's members by directly subclassing 710235633Sdim/// it elsewhere. 711235633Sdim/// - It also makes access substantially harder to compute because it 712212904Sdim/// breaks the hill-climbing algorithm: knowing that the target is 713212904Sdim/// accessible in some base class would no longer let you change 714212904Sdim/// the question solely to whether the base class is accessible, 715212904Sdim/// because the original target might have been more accessible 716212904Sdim/// because of crazy subclassing. 717212904Sdim/// So we don't implement that. 718212904Sdimstatic AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC, 719212904Sdim const CXXRecordDecl *InstanceContext, 720212904Sdim const CXXRecordDecl *NamingClass) { 721235633Sdim assert(InstanceContext == 0 || 722235633Sdim InstanceContext->getCanonicalDecl() == InstanceContext); 723212904Sdim assert(NamingClass->getCanonicalDecl() == NamingClass); 724212904Sdim 725235633Sdim // If we don't have an instance context, our constraints give us 726235633Sdim // that NamingClass <= P <= NamingClass, i.e. P == NamingClass. 727235633Sdim // This is just the usual friendship check. 728235633Sdim if (!InstanceContext) return GetFriendKind(S, EC, NamingClass); 729235633Sdim 730212904Sdim ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass); 731212904Sdim if (PRC.findFriendship(InstanceContext)) return AR_accessible; 732212904Sdim if (PRC.EverDependent) return AR_dependent; 733212904Sdim return AR_inaccessible; 734212904Sdim} 735212904Sdim 736207619Srdivackystatic AccessResult HasAccess(Sema &S, 737207619Srdivacky const EffectiveContext &EC, 738207619Srdivacky const CXXRecordDecl *NamingClass, 739207619Srdivacky AccessSpecifier Access, 740207619Srdivacky const AccessTarget &Target) { 741206084Srdivacky assert(NamingClass->getCanonicalDecl() == NamingClass && 742206084Srdivacky "declaration should be canonicalized before being passed here"); 743206084Srdivacky 744207619Srdivacky if (Access == AS_public) return AR_accessible; 745206084Srdivacky assert(Access == AS_private || Access == AS_protected); 746206084Srdivacky 747207619Srdivacky AccessResult OnFailure = AR_inaccessible; 748207619Srdivacky 749206084Srdivacky for (EffectiveContext::record_iterator 750206084Srdivacky I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 751206084Srdivacky // All the declarations in EC have been canonicalized, so pointer 752206084Srdivacky // equality from this point on will work fine. 753206084Srdivacky const CXXRecordDecl *ECRecord = *I; 754206084Srdivacky 755206084Srdivacky // [B2] and [M2] 756207619Srdivacky if (Access == AS_private) { 757207619Srdivacky if (ECRecord == NamingClass) 758207619Srdivacky return AR_accessible; 759206084Srdivacky 760207619Srdivacky if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass)) 761207619Srdivacky OnFailure = AR_dependent; 762207619Srdivacky 763206084Srdivacky // [B3] and [M3] 764207619Srdivacky } else { 765207619Srdivacky assert(Access == AS_protected); 766207619Srdivacky switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { 767207619Srdivacky case AR_accessible: break; 768207619Srdivacky case AR_inaccessible: continue; 769207619Srdivacky case AR_dependent: OnFailure = AR_dependent; continue; 770207619Srdivacky } 771207619Srdivacky 772207619Srdivacky // C++ [class.protected]p1: 773207619Srdivacky // An additional access check beyond those described earlier in 774207619Srdivacky // [class.access] is applied when a non-static data member or 775207619Srdivacky // non-static member function is a protected member of its naming 776207619Srdivacky // class. As described earlier, access to a protected member is 777207619Srdivacky // granted because the reference occurs in a friend or member of 778207619Srdivacky // some class C. If the access is to form a pointer to member, 779207619Srdivacky // the nested-name-specifier shall name C or a class derived from 780207619Srdivacky // C. All other accesses involve a (possibly implicit) object 781207619Srdivacky // expression. In this case, the class of the object expression 782207619Srdivacky // shall be C or a class derived from C. 783207619Srdivacky // 784235633Sdim // We interpret this as a restriction on [M3]. 785235633Sdim 786235633Sdim // In this part of the code, 'C' is just our context class ECRecord. 787235633Sdim 788235633Sdim // These rules are different if we don't have an instance context. 789235633Sdim if (!Target.hasInstanceContext()) { 790235633Sdim // If it's not an instance member, these restrictions don't apply. 791235633Sdim if (!Target.isInstanceMember()) return AR_accessible; 792235633Sdim 793235633Sdim // If it's an instance member, use the pointer-to-member rule 794235633Sdim // that the naming class has to be derived from the effective 795235633Sdim // context. 796235633Sdim 797235633Sdim // Emulate a MSVC bug where the creation of pointer-to-member 798235633Sdim // to protected member of base class is allowed but only from 799245431Sdim // static member functions. 800235633Sdim if (S.getLangOpts().MicrosoftMode && !EC.Functions.empty()) 801235633Sdim if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front())) 802235633Sdim if (MD->isStatic()) return AR_accessible; 803235633Sdim 804235633Sdim // Despite the standard's confident wording, there is a case 805235633Sdim // where you can have an instance member that's neither in a 806235633Sdim // pointer-to-member expression nor in a member access: when 807235633Sdim // it names a field in an unevaluated context that can't be an 808235633Sdim // implicit member. Pending clarification, we just apply the 809235633Sdim // same naming-class restriction here. 810235633Sdim // FIXME: we're probably not correctly adding the 811235633Sdim // protected-member restriction when we retroactively convert 812235633Sdim // an expression to being evaluated. 813235633Sdim 814235633Sdim // We know that ECRecord derives from NamingClass. The 815235633Sdim // restriction says to check whether NamingClass derives from 816235633Sdim // ECRecord, but that's not really necessary: two distinct 817235633Sdim // classes can't be recursively derived from each other. So 818235633Sdim // along this path, we just need to check whether the classes 819235633Sdim // are equal. 820235633Sdim if (NamingClass == ECRecord) return AR_accessible; 821235633Sdim 822235633Sdim // Otherwise, this context class tells us nothing; on to the next. 823235633Sdim continue; 824235633Sdim } 825235633Sdim 826235633Sdim assert(Target.isInstanceMember()); 827235633Sdim 828235633Sdim const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); 829235633Sdim if (!InstanceContext) { 830235633Sdim OnFailure = AR_dependent; 831235633Sdim continue; 832235633Sdim } 833235633Sdim 834207619Srdivacky switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { 835207619Srdivacky case AR_accessible: return AR_accessible; 836207619Srdivacky case AR_inaccessible: continue; 837207619Srdivacky case AR_dependent: OnFailure = AR_dependent; continue; 838207619Srdivacky } 839207619Srdivacky } 840206084Srdivacky } 841206084Srdivacky 842212904Sdim // [M3] and [B3] say that, if the target is protected in N, we grant 843212904Sdim // access if the access occurs in a friend or member of some class P 844212904Sdim // that's a subclass of N and where the target has some natural 845212904Sdim // access in P. The 'member' aspect is easy to handle because P 846212904Sdim // would necessarily be one of the effective-context records, and we 847212904Sdim // address that above. The 'friend' aspect is completely ridiculous 848212904Sdim // to implement because there are no restrictions at all on P 849212904Sdim // *unless* the [class.protected] restriction applies. If it does, 850212904Sdim // however, we should ignore whether the naming class is a friend, 851212904Sdim // and instead rely on whether any potential P is a friend. 852235633Sdim if (Access == AS_protected && Target.isInstanceMember()) { 853235633Sdim // Compute the instance context if possible. 854235633Sdim const CXXRecordDecl *InstanceContext = 0; 855235633Sdim if (Target.hasInstanceContext()) { 856235633Sdim InstanceContext = Target.resolveInstanceContext(S); 857235633Sdim if (!InstanceContext) return AR_dependent; 858235633Sdim } 859235633Sdim 860212904Sdim switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) { 861212904Sdim case AR_accessible: return AR_accessible; 862207619Srdivacky case AR_inaccessible: return OnFailure; 863207619Srdivacky case AR_dependent: return AR_dependent; 864207619Srdivacky } 865212904Sdim llvm_unreachable("impossible friendship kind"); 866207619Srdivacky } 867207619Srdivacky 868207619Srdivacky switch (GetFriendKind(S, EC, NamingClass)) { 869207619Srdivacky case AR_accessible: return AR_accessible; 870207619Srdivacky case AR_inaccessible: return OnFailure; 871207619Srdivacky case AR_dependent: return AR_dependent; 872207619Srdivacky } 873207619Srdivacky 874207619Srdivacky // Silence bogus warnings 875207619Srdivacky llvm_unreachable("impossible friendship kind"); 876206084Srdivacky} 877206084Srdivacky 878203955Srdivacky/// Finds the best path from the naming class to the declaring class, 879203955Srdivacky/// taking friend declarations into account. 880203955Srdivacky/// 881206084Srdivacky/// C++0x [class.access.base]p5: 882206084Srdivacky/// A member m is accessible at the point R when named in class N if 883206084Srdivacky/// [M1] m as a member of N is public, or 884206084Srdivacky/// [M2] m as a member of N is private, and R occurs in a member or 885206084Srdivacky/// friend of class N, or 886206084Srdivacky/// [M3] m as a member of N is protected, and R occurs in a member or 887206084Srdivacky/// friend of class N, or in a member or friend of a class P 888206084Srdivacky/// derived from N, where m as a member of P is public, private, 889206084Srdivacky/// or protected, or 890206084Srdivacky/// [M4] there exists a base class B of N that is accessible at R, and 891206084Srdivacky/// m is accessible at R when named in class B. 892206084Srdivacky/// 893206084Srdivacky/// C++0x [class.access.base]p4: 894206084Srdivacky/// A base class B of N is accessible at R, if 895206084Srdivacky/// [B1] an invented public member of B would be a public member of N, or 896206084Srdivacky/// [B2] R occurs in a member or friend of class N, and an invented public 897206084Srdivacky/// member of B would be a private or protected member of N, or 898206084Srdivacky/// [B3] R occurs in a member or friend of a class P derived from N, and an 899206084Srdivacky/// invented public member of B would be a private or protected member 900206084Srdivacky/// of P, or 901206084Srdivacky/// [B4] there exists a class S such that B is a base class of S accessible 902206084Srdivacky/// at R and S is a base class of N accessible at R. 903206084Srdivacky/// 904206084Srdivacky/// Along a single inheritance path we can restate both of these 905206084Srdivacky/// iteratively: 906206084Srdivacky/// 907206084Srdivacky/// First, we note that M1-4 are equivalent to B1-4 if the member is 908206084Srdivacky/// treated as a notional base of its declaring class with inheritance 909206084Srdivacky/// access equivalent to the member's access. Therefore we need only 910206084Srdivacky/// ask whether a class B is accessible from a class N in context R. 911206084Srdivacky/// 912206084Srdivacky/// Let B_1 .. B_n be the inheritance path in question (i.e. where 913206084Srdivacky/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of 914206084Srdivacky/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the 915206084Srdivacky/// closest accessible base in the path: 916206084Srdivacky/// Access(a, b) = (* access on the base specifier from a to b *) 917206084Srdivacky/// Merge(a, forbidden) = forbidden 918206084Srdivacky/// Merge(a, private) = forbidden 919206084Srdivacky/// Merge(a, b) = min(a,b) 920206084Srdivacky/// Accessible(c, forbidden) = false 921206084Srdivacky/// Accessible(c, private) = (R is c) || IsFriend(c, R) 922206084Srdivacky/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R) 923206084Srdivacky/// Accessible(c, public) = true 924206084Srdivacky/// ACAB(n) = public 925206084Srdivacky/// ACAB(i) = 926206084Srdivacky/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in 927206084Srdivacky/// if Accessible(B_i, AccessToBase) then public else AccessToBase 928206084Srdivacky/// 929206084Srdivacky/// B is an accessible base of N at R iff ACAB(1) = public. 930206084Srdivacky/// 931207619Srdivacky/// \param FinalAccess the access of the "final step", or AS_public if 932205408Srdivacky/// there is no final step. 933203955Srdivacky/// \return null if friendship is dependent 934203955Srdivackystatic CXXBasePath *FindBestPath(Sema &S, 935203955Srdivacky const EffectiveContext &EC, 936207619Srdivacky AccessTarget &Target, 937205408Srdivacky AccessSpecifier FinalAccess, 938203955Srdivacky CXXBasePaths &Paths) { 939203955Srdivacky // Derive the paths to the desired base. 940207619Srdivacky const CXXRecordDecl *Derived = Target.getNamingClass(); 941207619Srdivacky const CXXRecordDecl *Base = Target.getDeclaringClass(); 942207619Srdivacky 943207619Srdivacky // FIXME: fail correctly when there are dependent paths. 944207619Srdivacky bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base), 945207619Srdivacky Paths); 946203955Srdivacky assert(isDerived && "derived class not actually derived from base"); 947203955Srdivacky (void) isDerived; 948203955Srdivacky 949203955Srdivacky CXXBasePath *BestPath = 0; 950203955Srdivacky 951205408Srdivacky assert(FinalAccess != AS_none && "forbidden access after declaring class"); 952205408Srdivacky 953206084Srdivacky bool AnyDependent = false; 954206084Srdivacky 955203955Srdivacky // Derive the friend-modified access along each path. 956203955Srdivacky for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); 957203955Srdivacky PI != PE; ++PI) { 958207619Srdivacky AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext(); 959203955Srdivacky 960203955Srdivacky // Walk through the path backwards. 961205408Srdivacky AccessSpecifier PathAccess = FinalAccess; 962203955Srdivacky CXXBasePath::iterator I = PI->end(), E = PI->begin(); 963203955Srdivacky while (I != E) { 964203955Srdivacky --I; 965203955Srdivacky 966205408Srdivacky assert(PathAccess != AS_none); 967205408Srdivacky 968205408Srdivacky // If the declaration is a private member of a base class, there 969205408Srdivacky // is no level of friendship in derived classes that can make it 970205408Srdivacky // accessible. 971205408Srdivacky if (PathAccess == AS_private) { 972205408Srdivacky PathAccess = AS_none; 973205408Srdivacky break; 974205408Srdivacky } 975205408Srdivacky 976207619Srdivacky const CXXRecordDecl *NC = I->Class->getCanonicalDecl(); 977207619Srdivacky 978203955Srdivacky AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); 979206084Srdivacky PathAccess = std::max(PathAccess, BaseAccess); 980207619Srdivacky 981207619Srdivacky switch (HasAccess(S, EC, NC, PathAccess, Target)) { 982207619Srdivacky case AR_inaccessible: break; 983207619Srdivacky case AR_accessible: 984207619Srdivacky PathAccess = AS_public; 985207619Srdivacky 986207619Srdivacky // Future tests are not against members and so do not have 987207619Srdivacky // instance context. 988207619Srdivacky Target.suppressInstanceContext(); 989207619Srdivacky break; 990207619Srdivacky case AR_dependent: 991206084Srdivacky AnyDependent = true; 992206084Srdivacky goto Next; 993193326Sed } 994193326Sed } 995198092Srdivacky 996203955Srdivacky // Note that we modify the path's Access field to the 997203955Srdivacky // friend-modified access. 998203955Srdivacky if (BestPath == 0 || PathAccess < BestPath->Access) { 999203955Srdivacky BestPath = &*PI; 1000203955Srdivacky BestPath->Access = PathAccess; 1001206084Srdivacky 1002206084Srdivacky // Short-circuit if we found a public path. 1003206084Srdivacky if (BestPath->Access == AS_public) 1004206084Srdivacky return BestPath; 1005193326Sed } 1006206084Srdivacky 1007206084Srdivacky Next: ; 1008193326Sed } 1009193326Sed 1010206084Srdivacky assert((!BestPath || BestPath->Access != AS_public) && 1011206084Srdivacky "fell out of loop with public path"); 1012206084Srdivacky 1013206084Srdivacky // We didn't find a public path, but at least one path was subject 1014206084Srdivacky // to dependent friendship, so delay the check. 1015206084Srdivacky if (AnyDependent) 1016206084Srdivacky return 0; 1017206084Srdivacky 1018203955Srdivacky return BestPath; 1019198092Srdivacky} 1020198092Srdivacky 1021212904Sdim/// Given that an entity has protected natural access, check whether 1022212904Sdim/// access might be denied because of the protected member access 1023212904Sdim/// restriction. 1024212904Sdim/// 1025212904Sdim/// \return true if a note was emitted 1026212904Sdimstatic bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC, 1027212904Sdim AccessTarget &Target) { 1028212904Sdim // Only applies to instance accesses. 1029235633Sdim if (!Target.isInstanceMember()) 1030212904Sdim return false; 1031235633Sdim 1032212904Sdim assert(Target.isMemberAccess()); 1033212904Sdim 1034252723Sdim const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass(); 1035212904Sdim 1036212904Sdim for (EffectiveContext::record_iterator 1037212904Sdim I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 1038212904Sdim const CXXRecordDecl *ECRecord = *I; 1039235633Sdim switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { 1040212904Sdim case AR_accessible: break; 1041212904Sdim case AR_inaccessible: continue; 1042212904Sdim case AR_dependent: continue; 1043212904Sdim } 1044212904Sdim 1045212904Sdim // The effective context is a subclass of the declaring class. 1046235633Sdim // Check whether the [class.protected] restriction is limiting 1047235633Sdim // access. 1048212904Sdim 1049212904Sdim // To get this exactly right, this might need to be checked more 1050212904Sdim // holistically; it's not necessarily the case that gaining 1051212904Sdim // access here would grant us access overall. 1052212904Sdim 1053235633Sdim NamedDecl *D = Target.getTargetDecl(); 1054235633Sdim 1055235633Sdim // If we don't have an instance context, [class.protected] says the 1056235633Sdim // naming class has to equal the context class. 1057235633Sdim if (!Target.hasInstanceContext()) { 1058235633Sdim // If it does, the restriction doesn't apply. 1059235633Sdim if (NamingClass == ECRecord) continue; 1060235633Sdim 1061235633Sdim // TODO: it would be great to have a fixit here, since this is 1062235633Sdim // such an obvious error. 1063235633Sdim S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject) 1064235633Sdim << S.Context.getTypeDeclType(ECRecord); 1065235633Sdim return true; 1066235633Sdim } 1067235633Sdim 1068212904Sdim const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); 1069212904Sdim assert(InstanceContext && "diagnosing dependent access"); 1070212904Sdim 1071212904Sdim switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { 1072212904Sdim case AR_accessible: continue; 1073212904Sdim case AR_dependent: continue; 1074212904Sdim case AR_inaccessible: 1075235633Sdim break; 1076235633Sdim } 1077235633Sdim 1078235633Sdim // Okay, the restriction seems to be what's limiting us. 1079235633Sdim 1080235633Sdim // Use a special diagnostic for constructors and destructors. 1081235633Sdim if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) || 1082235633Sdim (isa<FunctionTemplateDecl>(D) && 1083235633Sdim isa<CXXConstructorDecl>( 1084235633Sdim cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) { 1085235633Sdim S.Diag(D->getLocation(), diag::note_access_protected_restricted_ctordtor) 1086235633Sdim << isa<CXXDestructorDecl>(D); 1087212904Sdim return true; 1088212904Sdim } 1089235633Sdim 1090235633Sdim // Otherwise, use the generic diagnostic. 1091235633Sdim S.Diag(D->getLocation(), diag::note_access_protected_restricted_object) 1092235633Sdim << S.Context.getTypeDeclType(ECRecord); 1093235633Sdim return true; 1094212904Sdim } 1095212904Sdim 1096212904Sdim return false; 1097212904Sdim} 1098212904Sdim 1099252723Sdim/// We are unable to access a given declaration due to its direct 1100252723Sdim/// access control; diagnose that. 1101252723Sdimstatic void diagnoseBadDirectAccess(Sema &S, 1102252723Sdim const EffectiveContext &EC, 1103252723Sdim AccessTarget &entity) { 1104252723Sdim assert(entity.isMemberAccess()); 1105252723Sdim NamedDecl *D = entity.getTargetDecl(); 1106252723Sdim 1107252723Sdim if (D->getAccess() == AS_protected && 1108252723Sdim TryDiagnoseProtectedAccess(S, EC, entity)) 1109252723Sdim return; 1110252723Sdim 1111252723Sdim // Find an original declaration. 1112252723Sdim while (D->isOutOfLine()) { 1113252723Sdim NamedDecl *PrevDecl = 0; 1114252723Sdim if (VarDecl *VD = dyn_cast<VarDecl>(D)) 1115252723Sdim PrevDecl = VD->getPreviousDecl(); 1116252723Sdim else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 1117252723Sdim PrevDecl = FD->getPreviousDecl(); 1118252723Sdim else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D)) 1119252723Sdim PrevDecl = TND->getPreviousDecl(); 1120252723Sdim else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { 1121252723Sdim if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName()) 1122252723Sdim break; 1123252723Sdim PrevDecl = TD->getPreviousDecl(); 1124252723Sdim } 1125252723Sdim if (!PrevDecl) break; 1126252723Sdim D = PrevDecl; 1127252723Sdim } 1128252723Sdim 1129252723Sdim CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); 1130252723Sdim Decl *ImmediateChild; 1131252723Sdim if (D->getDeclContext() == DeclaringClass) 1132252723Sdim ImmediateChild = D; 1133252723Sdim else { 1134252723Sdim DeclContext *DC = D->getDeclContext(); 1135252723Sdim while (DC->getParent() != DeclaringClass) 1136252723Sdim DC = DC->getParent(); 1137252723Sdim ImmediateChild = cast<Decl>(DC); 1138252723Sdim } 1139252723Sdim 1140252723Sdim // Check whether there's an AccessSpecDecl preceding this in the 1141252723Sdim // chain of the DeclContext. 1142252723Sdim bool isImplicit = true; 1143252723Sdim for (CXXRecordDecl::decl_iterator 1144252723Sdim I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end(); 1145252723Sdim I != E; ++I) { 1146252723Sdim if (*I == ImmediateChild) break; 1147252723Sdim if (isa<AccessSpecDecl>(*I)) { 1148252723Sdim isImplicit = false; 1149252723Sdim break; 1150252723Sdim } 1151252723Sdim } 1152252723Sdim 1153252723Sdim S.Diag(D->getLocation(), diag::note_access_natural) 1154252723Sdim << (unsigned) (D->getAccess() == AS_protected) 1155252723Sdim << isImplicit; 1156252723Sdim} 1157252723Sdim 1158203955Srdivacky/// Diagnose the path which caused the given declaration or base class 1159203955Srdivacky/// to become inaccessible. 1160203955Srdivackystatic void DiagnoseAccessPath(Sema &S, 1161203955Srdivacky const EffectiveContext &EC, 1162252723Sdim AccessTarget &entity) { 1163252723Sdim // Save the instance context to preserve invariants. 1164252723Sdim AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext(); 1165206084Srdivacky 1166252723Sdim // This basically repeats the main algorithm but keeps some more 1167252723Sdim // information. 1168206084Srdivacky 1169252723Sdim // The natural access so far. 1170252723Sdim AccessSpecifier accessSoFar = AS_public; 1171212904Sdim 1172252723Sdim // Check whether we have special rights to the declaring class. 1173252723Sdim if (entity.isMemberAccess()) { 1174252723Sdim NamedDecl *D = entity.getTargetDecl(); 1175252723Sdim accessSoFar = D->getAccess(); 1176252723Sdim const CXXRecordDecl *declaringClass = entity.getDeclaringClass(); 1177218893Sdim 1178252723Sdim switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) { 1179252723Sdim // If the declaration is accessible when named in its declaring 1180252723Sdim // class, then we must be constrained by the path. 1181252723Sdim case AR_accessible: 1182252723Sdim accessSoFar = AS_public; 1183252723Sdim entity.suppressInstanceContext(); 1184252723Sdim break; 1185218893Sdim 1186252723Sdim case AR_inaccessible: 1187252723Sdim if (accessSoFar == AS_private || 1188252723Sdim declaringClass == entity.getEffectiveNamingClass()) 1189252723Sdim return diagnoseBadDirectAccess(S, EC, entity); 1190252723Sdim break; 1191198092Srdivacky 1192207619Srdivacky case AR_dependent: 1193252723Sdim llvm_unreachable("cannot diagnose dependent access"); 1194203955Srdivacky } 1195203955Srdivacky } 1196193326Sed 1197252723Sdim CXXBasePaths paths; 1198252723Sdim CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths); 1199252723Sdim assert(path.Access != AS_public); 1200198092Srdivacky 1201252723Sdim CXXBasePath::iterator i = path.end(), e = path.begin(); 1202252723Sdim CXXBasePath::iterator constrainingBase = i; 1203252723Sdim while (i != e) { 1204252723Sdim --i; 1205193326Sed 1206252723Sdim assert(accessSoFar != AS_none && accessSoFar != AS_private); 1207203955Srdivacky 1208252723Sdim // Is the entity accessible when named in the deriving class, as 1209252723Sdim // modified by the base specifier? 1210252723Sdim const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl(); 1211252723Sdim const CXXBaseSpecifier *base = i->Base; 1212203955Srdivacky 1213252723Sdim // If the access to this base is worse than the access we have to 1214252723Sdim // the declaration, remember it. 1215252723Sdim AccessSpecifier baseAccess = base->getAccessSpecifier(); 1216252723Sdim if (baseAccess > accessSoFar) { 1217252723Sdim constrainingBase = i; 1218252723Sdim accessSoFar = baseAccess; 1219252723Sdim } 1220252723Sdim 1221252723Sdim switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) { 1222207619Srdivacky case AR_inaccessible: break; 1223252723Sdim case AR_accessible: 1224252723Sdim accessSoFar = AS_public; 1225252723Sdim entity.suppressInstanceContext(); 1226252723Sdim constrainingBase = 0; 1227252723Sdim break; 1228207619Srdivacky case AR_dependent: 1229252723Sdim llvm_unreachable("cannot diagnose dependent access"); 1230203955Srdivacky } 1231203955Srdivacky 1232252723Sdim // If this was private inheritance, but we don't have access to 1233252723Sdim // the deriving class, we're done. 1234252723Sdim if (accessSoFar == AS_private) { 1235252723Sdim assert(baseAccess == AS_private); 1236252723Sdim assert(constrainingBase == i); 1237252723Sdim break; 1238252723Sdim } 1239252723Sdim } 1240203955Srdivacky 1241252723Sdim // If we don't have a constraining base, the access failure must be 1242252723Sdim // due to the original declaration. 1243252723Sdim if (constrainingBase == path.end()) 1244252723Sdim return diagnoseBadDirectAccess(S, EC, entity); 1245203955Srdivacky 1246252723Sdim // We're constrained by inheritance, but we want to say 1247252723Sdim // "declared private here" if we're diagnosing a hierarchy 1248252723Sdim // conversion and this is the final step. 1249252723Sdim unsigned diagnostic; 1250252723Sdim if (entity.isMemberAccess() || 1251252723Sdim constrainingBase + 1 != path.end()) { 1252252723Sdim diagnostic = diag::note_access_constrained_by_path; 1253252723Sdim } else { 1254252723Sdim diagnostic = diag::note_access_natural; 1255193326Sed } 1256198092Srdivacky 1257252723Sdim const CXXBaseSpecifier *base = constrainingBase->Base; 1258252723Sdim 1259252723Sdim S.Diag(base->getSourceRange().getBegin(), diagnostic) 1260252723Sdim << base->getSourceRange() 1261252723Sdim << (base->getAccessSpecifier() == AS_protected) 1262252723Sdim << (base->getAccessSpecifierAsWritten() == AS_none); 1263252723Sdim 1264252723Sdim if (entity.isMemberAccess()) 1265252723Sdim S.Diag(entity.getTargetDecl()->getLocation(), diag::note_field_decl); 1266193326Sed} 1267202879Srdivacky 1268206084Srdivackystatic void DiagnoseBadAccess(Sema &S, SourceLocation Loc, 1269206084Srdivacky const EffectiveContext &EC, 1270207619Srdivacky AccessTarget &Entity) { 1271206084Srdivacky const CXXRecordDecl *NamingClass = Entity.getNamingClass(); 1272207619Srdivacky const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); 1273207619Srdivacky NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); 1274203955Srdivacky 1275205219Srdivacky S.Diag(Loc, Entity.getDiag()) 1276206084Srdivacky << (Entity.getAccess() == AS_protected) 1277206084Srdivacky << (D ? D->getDeclName() : DeclarationName()) 1278205219Srdivacky << S.Context.getTypeDeclType(NamingClass) 1279205219Srdivacky << S.Context.getTypeDeclType(DeclaringClass); 1280206084Srdivacky DiagnoseAccessPath(S, EC, Entity); 1281203955Srdivacky} 1282202879Srdivacky 1283223017Sdim/// MSVC has a bug where if during an using declaration name lookup, 1284223017Sdim/// the declaration found is unaccessible (private) and that declaration 1285223017Sdim/// was bring into scope via another using declaration whose target 1286223017Sdim/// declaration is accessible (public) then no error is generated. 1287223017Sdim/// Example: 1288223017Sdim/// class A { 1289223017Sdim/// public: 1290223017Sdim/// int f(); 1291223017Sdim/// }; 1292223017Sdim/// class B : public A { 1293223017Sdim/// private: 1294223017Sdim/// using A::f; 1295223017Sdim/// }; 1296223017Sdim/// class C : public B { 1297223017Sdim/// private: 1298223017Sdim/// using B::f; 1299223017Sdim/// }; 1300223017Sdim/// 1301223017Sdim/// Here, B::f is private so this should fail in Standard C++, but 1302223017Sdim/// because B::f refers to A::f which is public MSVC accepts it. 1303223017Sdimstatic bool IsMicrosoftUsingDeclarationAccessBug(Sema& S, 1304223017Sdim SourceLocation AccessLoc, 1305223017Sdim AccessTarget &Entity) { 1306223017Sdim if (UsingShadowDecl *Shadow = 1307223017Sdim dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) { 1308223017Sdim const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl(); 1309223017Sdim if (Entity.getTargetDecl()->getAccess() == AS_private && 1310223017Sdim (OrigDecl->getAccess() == AS_public || 1311223017Sdim OrigDecl->getAccess() == AS_protected)) { 1312235633Sdim S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible) 1313223017Sdim << Shadow->getUsingDecl()->getQualifiedNameAsString() 1314223017Sdim << OrigDecl->getQualifiedNameAsString(); 1315223017Sdim return true; 1316223017Sdim } 1317223017Sdim } 1318223017Sdim return false; 1319223017Sdim} 1320223017Sdim 1321206084Srdivacky/// Determines whether the accessed entity is accessible. Public members 1322206084Srdivacky/// have been weeded out by this point. 1323207619Srdivackystatic AccessResult IsAccessible(Sema &S, 1324207619Srdivacky const EffectiveContext &EC, 1325207619Srdivacky AccessTarget &Entity) { 1326206084Srdivacky // Determine the actual naming class. 1327252723Sdim const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass(); 1328202879Srdivacky 1329206084Srdivacky AccessSpecifier UnprivilegedAccess = Entity.getAccess(); 1330206084Srdivacky assert(UnprivilegedAccess != AS_public && "public access not weeded out"); 1331202879Srdivacky 1332206084Srdivacky // Before we try to recalculate access paths, try to white-list 1333206084Srdivacky // accesses which just trade in on the final step, i.e. accesses 1334206084Srdivacky // which don't require [M4] or [B4]. These are by far the most 1335207619Srdivacky // common forms of privileged access. 1336206084Srdivacky if (UnprivilegedAccess != AS_none) { 1337207619Srdivacky switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) { 1338207619Srdivacky case AR_dependent: 1339206084Srdivacky // This is actually an interesting policy decision. We don't 1340206084Srdivacky // *have* to delay immediately here: we can do the full access 1341206084Srdivacky // calculation in the hope that friendship on some intermediate 1342206084Srdivacky // class will make the declaration accessible non-dependently. 1343206084Srdivacky // But that's not cheap, and odds are very good (note: assertion 1344206084Srdivacky // made without data) that the friend declaration will determine 1345206084Srdivacky // access. 1346207619Srdivacky return AR_dependent; 1347202879Srdivacky 1348207619Srdivacky case AR_accessible: return AR_accessible; 1349207619Srdivacky case AR_inaccessible: break; 1350206084Srdivacky } 1351206084Srdivacky } 1352206084Srdivacky 1353207619Srdivacky AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext(); 1354202879Srdivacky 1355206084Srdivacky // We lower member accesses to base accesses by pretending that the 1356206084Srdivacky // member is a base class of its declaring class. 1357206084Srdivacky AccessSpecifier FinalAccess; 1358206084Srdivacky 1359203955Srdivacky if (Entity.isMemberAccess()) { 1360206084Srdivacky // Determine if the declaration is accessible from EC when named 1361206084Srdivacky // in its declaring class. 1362203955Srdivacky NamedDecl *Target = Entity.getTargetDecl(); 1363207619Srdivacky const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); 1364203955Srdivacky 1365206084Srdivacky FinalAccess = Target->getAccess(); 1366207619Srdivacky switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) { 1367207619Srdivacky case AR_accessible: 1368252723Sdim // Target is accessible at EC when named in its declaring class. 1369252723Sdim // We can now hill-climb and simply check whether the declaring 1370252723Sdim // class is accessible as a base of the naming class. This is 1371252723Sdim // equivalent to checking the access of a notional public 1372252723Sdim // member with no instance context. 1373207619Srdivacky FinalAccess = AS_public; 1374252723Sdim Entity.suppressInstanceContext(); 1375207619Srdivacky break; 1376207619Srdivacky case AR_inaccessible: break; 1377207619Srdivacky case AR_dependent: return AR_dependent; // see above 1378203955Srdivacky } 1379203955Srdivacky 1380206084Srdivacky if (DeclaringClass == NamingClass) 1381207619Srdivacky return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible); 1382206084Srdivacky } else { 1383206084Srdivacky FinalAccess = AS_public; 1384202879Srdivacky } 1385202879Srdivacky 1386207619Srdivacky assert(Entity.getDeclaringClass() != NamingClass); 1387203955Srdivacky 1388203955Srdivacky // Append the declaration's access if applicable. 1389203955Srdivacky CXXBasePaths Paths; 1390207619Srdivacky CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); 1391206084Srdivacky if (!Path) 1392207619Srdivacky return AR_dependent; 1393203955Srdivacky 1394206084Srdivacky assert(Path->Access <= UnprivilegedAccess && 1395206084Srdivacky "access along best path worse than direct?"); 1396206084Srdivacky if (Path->Access == AS_public) 1397207619Srdivacky return AR_accessible; 1398207619Srdivacky return AR_inaccessible; 1399203955Srdivacky} 1400203955Srdivacky 1401207619Srdivackystatic void DelayDependentAccess(Sema &S, 1402207619Srdivacky const EffectiveContext &EC, 1403207619Srdivacky SourceLocation Loc, 1404207619Srdivacky const AccessTarget &Entity) { 1405206084Srdivacky assert(EC.isDependent() && "delaying non-dependent access"); 1406206084Srdivacky DeclContext *DC = EC.getInnerContext(); 1407206084Srdivacky assert(DC->isDependentContext() && "delaying non-dependent access"); 1408206084Srdivacky DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access, 1409206084Srdivacky Loc, 1410206084Srdivacky Entity.isMemberAccess(), 1411206084Srdivacky Entity.getAccess(), 1412206084Srdivacky Entity.getTargetDecl(), 1413206084Srdivacky Entity.getNamingClass(), 1414207619Srdivacky Entity.getBaseObjectType(), 1415206084Srdivacky Entity.getDiag()); 1416206084Srdivacky} 1417206084Srdivacky 1418203955Srdivacky/// Checks access to an entity from the given effective context. 1419207619Srdivackystatic AccessResult CheckEffectiveAccess(Sema &S, 1420207619Srdivacky const EffectiveContext &EC, 1421207619Srdivacky SourceLocation Loc, 1422207619Srdivacky AccessTarget &Entity) { 1423206084Srdivacky assert(Entity.getAccess() != AS_public && "called for public access!"); 1424203955Srdivacky 1425235633Sdim if (S.getLangOpts().MicrosoftMode && 1426223017Sdim IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) 1427223017Sdim return AR_accessible; 1428223017Sdim 1429206084Srdivacky switch (IsAccessible(S, EC, Entity)) { 1430207619Srdivacky case AR_dependent: 1431207619Srdivacky DelayDependentAccess(S, EC, Loc, Entity); 1432207619Srdivacky return AR_dependent; 1433202879Srdivacky 1434207619Srdivacky case AR_inaccessible: 1435206084Srdivacky if (!Entity.isQuiet()) 1436206084Srdivacky DiagnoseBadAccess(S, Loc, EC, Entity); 1437207619Srdivacky return AR_inaccessible; 1438203955Srdivacky 1439207619Srdivacky case AR_accessible: 1440207619Srdivacky return AR_accessible; 1441206084Srdivacky } 1442202879Srdivacky 1443207619Srdivacky // silence unnecessary warning 1444207619Srdivacky llvm_unreachable("invalid access result"); 1445203955Srdivacky} 1446202879Srdivacky 1447203955Srdivackystatic Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, 1448207619Srdivacky AccessTarget &Entity) { 1449203955Srdivacky // If the access path is public, it's accessible everywhere. 1450203955Srdivacky if (Entity.getAccess() == AS_public) 1451203955Srdivacky return Sema::AR_accessible; 1452202879Srdivacky 1453218893Sdim // If we're currently parsing a declaration, we may need to delay 1454218893Sdim // access control checking, because our effective context might be 1455218893Sdim // different based on what the declaration comes out as. 1456218893Sdim // 1457218893Sdim // For example, we might be parsing a declaration with a scope 1458218893Sdim // specifier, like this: 1459218893Sdim // A::private_type A::foo() { ... } 1460218893Sdim // 1461218893Sdim // Or we might be parsing something that will turn out to be a friend: 1462218893Sdim // void foo(A::private_type); 1463218893Sdim // void B::foo(A::private_type); 1464218893Sdim if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { 1465218893Sdim S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity)); 1466203955Srdivacky return Sema::AR_delayed; 1467202879Srdivacky } 1468202879Srdivacky 1469207619Srdivacky EffectiveContext EC(S.CurContext); 1470207619Srdivacky switch (CheckEffectiveAccess(S, EC, Loc, Entity)) { 1471207619Srdivacky case AR_accessible: return Sema::AR_accessible; 1472207619Srdivacky case AR_inaccessible: return Sema::AR_inaccessible; 1473207619Srdivacky case AR_dependent: return Sema::AR_dependent; 1474207619Srdivacky } 1475207619Srdivacky llvm_unreachable("falling off end"); 1476202879Srdivacky} 1477202879Srdivacky 1478252723Sdimvoid Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) { 1479218893Sdim // Access control for names used in the declarations of functions 1480218893Sdim // and function templates should normally be evaluated in the context 1481218893Sdim // of the declaration, just in case it's a friend of something. 1482218893Sdim // However, this does not apply to local extern declarations. 1483218893Sdim 1484252723Sdim DeclContext *DC = D->getDeclContext(); 1485252723Sdim if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) { 1486263509Sdim if (D->getLexicalDeclContext()->isFunctionOrMethod()) 1487263509Sdim DC = D->getLexicalDeclContext(); 1488263509Sdim else 1489252723Sdim DC = FN; 1490252723Sdim } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) { 1491252723Sdim DC = cast<DeclContext>(TD->getTemplatedDecl()); 1492218893Sdim } 1493218893Sdim 1494207619Srdivacky EffectiveContext EC(DC); 1495203955Srdivacky 1496207619Srdivacky AccessTarget Target(DD.getAccessData()); 1497207619Srdivacky 1498207619Srdivacky if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible) 1499203955Srdivacky DD.Triggered = true; 1500203955Srdivacky} 1501203955Srdivacky 1502206084Srdivackyvoid Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, 1503206084Srdivacky const MultiLevelTemplateArgumentList &TemplateArgs) { 1504206084Srdivacky SourceLocation Loc = DD.getAccessLoc(); 1505206084Srdivacky AccessSpecifier Access = DD.getAccess(); 1506206084Srdivacky 1507206084Srdivacky Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(), 1508206084Srdivacky TemplateArgs); 1509206084Srdivacky if (!NamingD) return; 1510206084Srdivacky Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(), 1511206084Srdivacky TemplateArgs); 1512206084Srdivacky if (!TargetD) return; 1513206084Srdivacky 1514206084Srdivacky if (DD.isAccessToMember()) { 1515207619Srdivacky CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD); 1516207619Srdivacky NamedDecl *TargetDecl = cast<NamedDecl>(TargetD); 1517207619Srdivacky QualType BaseObjectType = DD.getAccessBaseObjectType(); 1518207619Srdivacky if (!BaseObjectType.isNull()) { 1519207619Srdivacky BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc, 1520207619Srdivacky DeclarationName()); 1521207619Srdivacky if (BaseObjectType.isNull()) return; 1522207619Srdivacky } 1523207619Srdivacky 1524207619Srdivacky AccessTarget Entity(Context, 1525207619Srdivacky AccessTarget::Member, 1526207619Srdivacky NamingClass, 1527207619Srdivacky DeclAccessPair::make(TargetDecl, Access), 1528207619Srdivacky BaseObjectType); 1529206084Srdivacky Entity.setDiag(DD.getDiagnostic()); 1530206084Srdivacky CheckAccess(*this, Loc, Entity); 1531206084Srdivacky } else { 1532207619Srdivacky AccessTarget Entity(Context, 1533207619Srdivacky AccessTarget::Base, 1534207619Srdivacky cast<CXXRecordDecl>(TargetD), 1535207619Srdivacky cast<CXXRecordDecl>(NamingD), 1536207619Srdivacky Access); 1537206084Srdivacky Entity.setDiag(DD.getDiagnostic()); 1538206084Srdivacky CheckAccess(*this, Loc, Entity); 1539206084Srdivacky } 1540206084Srdivacky} 1541206084Srdivacky 1542203955SrdivackySema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, 1543205408Srdivacky DeclAccessPair Found) { 1544235633Sdim if (!getLangOpts().AccessControl || 1545205219Srdivacky !E->getNamingClass() || 1546205408Srdivacky Found.getAccess() == AS_public) 1547203955Srdivacky return AR_accessible; 1548203955Srdivacky 1549207619Srdivacky AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), 1550207619Srdivacky Found, QualType()); 1551205219Srdivacky Entity.setDiag(diag::err_access) << E->getSourceRange(); 1552205219Srdivacky 1553205219Srdivacky return CheckAccess(*this, E->getNameLoc(), Entity); 1554203955Srdivacky} 1555203955Srdivacky 1556203955Srdivacky/// Perform access-control checking on a previously-unresolved member 1557203955Srdivacky/// access which has now been resolved to a member. 1558203955SrdivackySema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, 1559205408Srdivacky DeclAccessPair Found) { 1560235633Sdim if (!getLangOpts().AccessControl || 1561205408Srdivacky Found.getAccess() == AS_public) 1562203955Srdivacky return AR_accessible; 1563203955Srdivacky 1564207619Srdivacky QualType BaseType = E->getBaseType(); 1565207619Srdivacky if (E->isArrow()) 1566207619Srdivacky BaseType = BaseType->getAs<PointerType>()->getPointeeType(); 1567207619Srdivacky 1568207619Srdivacky AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), 1569207619Srdivacky Found, BaseType); 1570205219Srdivacky Entity.setDiag(diag::err_access) << E->getSourceRange(); 1571205219Srdivacky 1572205219Srdivacky return CheckAccess(*this, E->getMemberLoc(), Entity); 1573203955Srdivacky} 1574203955Srdivacky 1575235633Sdim/// Is the given special member function accessible for the purposes of 1576235633Sdim/// deciding whether to define a special member function as deleted? 1577235633Sdimbool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, 1578235633Sdim AccessSpecifier access, 1579235633Sdim QualType objectType) { 1580235633Sdim // Fast path. 1581235633Sdim if (access == AS_public || !getLangOpts().AccessControl) return true; 1582235633Sdim 1583235633Sdim AccessTarget entity(Context, AccessTarget::Member, decl->getParent(), 1584235633Sdim DeclAccessPair::make(decl, access), objectType); 1585235633Sdim 1586235633Sdim // Suppress diagnostics. 1587235633Sdim entity.setDiag(PDiag()); 1588235633Sdim 1589235633Sdim switch (CheckAccess(*this, SourceLocation(), entity)) { 1590235633Sdim case AR_accessible: return true; 1591235633Sdim case AR_inaccessible: return false; 1592235633Sdim case AR_dependent: llvm_unreachable("dependent for =delete computation"); 1593235633Sdim case AR_delayed: llvm_unreachable("cannot delay =delete computation"); 1594235633Sdim } 1595235633Sdim llvm_unreachable("bad access result"); 1596235633Sdim} 1597235633Sdim 1598203955SrdivackySema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, 1599205219Srdivacky CXXDestructorDecl *Dtor, 1600235633Sdim const PartialDiagnostic &PDiag, 1601235633Sdim QualType ObjectTy) { 1602235633Sdim if (!getLangOpts().AccessControl) 1603203955Srdivacky return AR_accessible; 1604203955Srdivacky 1605205219Srdivacky // There's never a path involved when checking implicit destructor access. 1606203955Srdivacky AccessSpecifier Access = Dtor->getAccess(); 1607203955Srdivacky if (Access == AS_public) 1608203955Srdivacky return AR_accessible; 1609203955Srdivacky 1610205219Srdivacky CXXRecordDecl *NamingClass = Dtor->getParent(); 1611235633Sdim if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass); 1612235633Sdim 1613207619Srdivacky AccessTarget Entity(Context, AccessTarget::Member, NamingClass, 1614207619Srdivacky DeclAccessPair::make(Dtor, Access), 1615235633Sdim ObjectTy); 1616205219Srdivacky Entity.setDiag(PDiag); // TODO: avoid copy 1617205219Srdivacky 1618205219Srdivacky return CheckAccess(*this, Loc, Entity); 1619203955Srdivacky} 1620203955Srdivacky 1621203955Srdivacky/// Checks access to a constructor. 1622203955SrdivackySema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, 1623210299Sed CXXConstructorDecl *Constructor, 1624210299Sed const InitializedEntity &Entity, 1625210299Sed AccessSpecifier Access, 1626210299Sed bool IsCopyBindingRefToTemp) { 1627235633Sdim if (!getLangOpts().AccessControl || Access == AS_public) 1628203955Srdivacky return AR_accessible; 1629203955Srdivacky 1630223017Sdim PartialDiagnostic PD(PDiag()); 1631207619Srdivacky switch (Entity.getKind()) { 1632207619Srdivacky default: 1633223017Sdim PD = PDiag(IsCopyBindingRefToTemp 1634223017Sdim ? diag::ext_rvalue_to_reference_access_ctor 1635223017Sdim : diag::err_access_ctor); 1636223017Sdim 1637207619Srdivacky break; 1638205219Srdivacky 1639207619Srdivacky case InitializedEntity::EK_Base: 1640223017Sdim PD = PDiag(diag::err_access_base_ctor); 1641223017Sdim PD << Entity.isInheritedVirtualBase() 1642223017Sdim << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor); 1643207619Srdivacky break; 1644207619Srdivacky 1645207619Srdivacky case InitializedEntity::EK_Member: { 1646207619Srdivacky const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); 1647223017Sdim PD = PDiag(diag::err_access_field_ctor); 1648223017Sdim PD << Field->getType() << getSpecialMember(Constructor); 1649207619Srdivacky break; 1650207619Srdivacky } 1651207619Srdivacky 1652235633Sdim case InitializedEntity::EK_LambdaCapture: { 1653263509Sdim StringRef VarName = Entity.getCapturedVarName(); 1654235633Sdim PD = PDiag(diag::err_access_lambda_capture); 1655263509Sdim PD << VarName << Entity.getType() << getSpecialMember(Constructor); 1656235633Sdim break; 1657207619Srdivacky } 1658207619Srdivacky 1659235633Sdim } 1660235633Sdim 1661235633Sdim return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD); 1662223017Sdim} 1663223017Sdim 1664223017Sdim/// Checks access to a constructor. 1665223017SdimSema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, 1666223017Sdim CXXConstructorDecl *Constructor, 1667235633Sdim const InitializedEntity &Entity, 1668223017Sdim AccessSpecifier Access, 1669235633Sdim const PartialDiagnostic &PD) { 1670235633Sdim if (!getLangOpts().AccessControl || 1671223017Sdim Access == AS_public) 1672223017Sdim return AR_accessible; 1673223017Sdim 1674223017Sdim CXXRecordDecl *NamingClass = Constructor->getParent(); 1675235633Sdim 1676235633Sdim // Initializing a base sub-object is an instance method call on an 1677235633Sdim // object of the derived class. Otherwise, we have an instance method 1678235633Sdim // call on an object of the constructed type. 1679235633Sdim CXXRecordDecl *ObjectClass; 1680235633Sdim if (Entity.getKind() == InitializedEntity::EK_Base) { 1681235633Sdim ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent(); 1682235633Sdim } else { 1683235633Sdim ObjectClass = NamingClass; 1684235633Sdim } 1685235633Sdim 1686223017Sdim AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, 1687223017Sdim DeclAccessPair::make(Constructor, Access), 1688235633Sdim Context.getTypeDeclType(ObjectClass)); 1689223017Sdim AccessEntity.setDiag(PD); 1690223017Sdim 1691207619Srdivacky return CheckAccess(*this, UseLoc, AccessEntity); 1692235633Sdim} 1693203955Srdivacky 1694205408Srdivacky/// Checks access to an overloaded operator new or delete. 1695205408SrdivackySema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, 1696205408Srdivacky SourceRange PlacementRange, 1697205408Srdivacky CXXRecordDecl *NamingClass, 1698223017Sdim DeclAccessPair Found, 1699223017Sdim bool Diagnose) { 1700235633Sdim if (!getLangOpts().AccessControl || 1701205408Srdivacky !NamingClass || 1702205408Srdivacky Found.getAccess() == AS_public) 1703205408Srdivacky return AR_accessible; 1704205408Srdivacky 1705207619Srdivacky AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 1706207619Srdivacky QualType()); 1707223017Sdim if (Diagnose) 1708223017Sdim Entity.setDiag(diag::err_access) 1709223017Sdim << PlacementRange; 1710205408Srdivacky 1711205408Srdivacky return CheckAccess(*this, OpLoc, Entity); 1712205408Srdivacky} 1713205408Srdivacky 1714263509Sdim/// \brief Checks access to a member. 1715263509SdimSema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc, 1716263509Sdim CXXRecordDecl *NamingClass, 1717263509Sdim DeclAccessPair Found) { 1718263509Sdim if (!getLangOpts().AccessControl || 1719263509Sdim !NamingClass || 1720263509Sdim Found.getAccess() == AS_public) 1721263509Sdim return AR_accessible; 1722263509Sdim 1723263509Sdim AccessTarget Entity(Context, AccessTarget::Member, NamingClass, 1724263509Sdim Found, QualType()); 1725263509Sdim 1726263509Sdim return CheckAccess(*this, UseLoc, Entity); 1727263509Sdim} 1728263509Sdim 1729203955Srdivacky/// Checks access to an overloaded member operator, including 1730203955Srdivacky/// conversion operators. 1731203955SrdivackySema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, 1732203955Srdivacky Expr *ObjectExpr, 1733205219Srdivacky Expr *ArgExpr, 1734205408Srdivacky DeclAccessPair Found) { 1735235633Sdim if (!getLangOpts().AccessControl || 1736205408Srdivacky Found.getAccess() == AS_public) 1737203955Srdivacky return AR_accessible; 1738203955Srdivacky 1739226890Sdim const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>(); 1740203955Srdivacky CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); 1741203955Srdivacky 1742207619Srdivacky AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 1743207619Srdivacky ObjectExpr->getType()); 1744205219Srdivacky Entity.setDiag(diag::err_access) 1745205219Srdivacky << ObjectExpr->getSourceRange() 1746205219Srdivacky << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); 1747205219Srdivacky 1748205219Srdivacky return CheckAccess(*this, OpLoc, Entity); 1749203955Srdivacky} 1750203955Srdivacky 1751245431Sdim/// Checks access to the target of a friend declaration. 1752245431SdimSema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) { 1753245431Sdim assert(isa<CXXMethodDecl>(target) || 1754245431Sdim (isa<FunctionTemplateDecl>(target) && 1755245431Sdim isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(target) 1756245431Sdim ->getTemplatedDecl()))); 1757245431Sdim 1758245431Sdim // Friendship lookup is a redeclaration lookup, so there's never an 1759245431Sdim // inheritance path modifying access. 1760245431Sdim AccessSpecifier access = target->getAccess(); 1761245431Sdim 1762245431Sdim if (!getLangOpts().AccessControl || access == AS_public) 1763245431Sdim return AR_accessible; 1764245431Sdim 1765245431Sdim CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(target); 1766245431Sdim if (!method) 1767245431Sdim method = cast<CXXMethodDecl>( 1768245431Sdim cast<FunctionTemplateDecl>(target)->getTemplatedDecl()); 1769245431Sdim assert(method->getQualifier()); 1770245431Sdim 1771245431Sdim AccessTarget entity(Context, AccessTarget::Member, 1772245431Sdim cast<CXXRecordDecl>(target->getDeclContext()), 1773245431Sdim DeclAccessPair::make(target, access), 1774245431Sdim /*no instance context*/ QualType()); 1775245431Sdim entity.setDiag(diag::err_access_friend_function) 1776245431Sdim << method->getQualifierLoc().getSourceRange(); 1777245431Sdim 1778245431Sdim // We need to bypass delayed-diagnostics because we might be called 1779245431Sdim // while the ParsingDeclarator is active. 1780245431Sdim EffectiveContext EC(CurContext); 1781245431Sdim switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) { 1782245431Sdim case AR_accessible: return Sema::AR_accessible; 1783245431Sdim case AR_inaccessible: return Sema::AR_inaccessible; 1784245431Sdim case AR_dependent: return Sema::AR_dependent; 1785245431Sdim } 1786245431Sdim llvm_unreachable("falling off end"); 1787245431Sdim} 1788245431Sdim 1789206084SrdivackySema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, 1790206084Srdivacky DeclAccessPair Found) { 1791235633Sdim if (!getLangOpts().AccessControl || 1792206084Srdivacky Found.getAccess() == AS_none || 1793206084Srdivacky Found.getAccess() == AS_public) 1794206084Srdivacky return AR_accessible; 1795206084Srdivacky 1796212904Sdim OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression; 1797207619Srdivacky CXXRecordDecl *NamingClass = Ovl->getNamingClass(); 1798206084Srdivacky 1799207619Srdivacky AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 1800235633Sdim /*no instance context*/ QualType()); 1801206084Srdivacky Entity.setDiag(diag::err_access) 1802206084Srdivacky << Ovl->getSourceRange(); 1803206084Srdivacky 1804206084Srdivacky return CheckAccess(*this, Ovl->getNameLoc(), Entity); 1805206084Srdivacky} 1806206084Srdivacky 1807203955Srdivacky/// Checks access for a hierarchy conversion. 1808203955Srdivacky/// 1809203955Srdivacky/// \param ForceCheck true if this check should be performed even if access 1810203955Srdivacky/// control is disabled; some things rely on this for semantics 1811203955Srdivacky/// \param ForceUnprivileged true if this check should proceed as if the 1812203955Srdivacky/// context had no special privileges 1813203955SrdivackySema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, 1814203955Srdivacky QualType Base, 1815203955Srdivacky QualType Derived, 1816203955Srdivacky const CXXBasePath &Path, 1817205219Srdivacky unsigned DiagID, 1818203955Srdivacky bool ForceCheck, 1819205219Srdivacky bool ForceUnprivileged) { 1820235633Sdim if (!ForceCheck && !getLangOpts().AccessControl) 1821203955Srdivacky return AR_accessible; 1822203955Srdivacky 1823203955Srdivacky if (Path.Access == AS_public) 1824203955Srdivacky return AR_accessible; 1825203955Srdivacky 1826203955Srdivacky CXXRecordDecl *BaseD, *DerivedD; 1827203955Srdivacky BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); 1828203955Srdivacky DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); 1829203955Srdivacky 1830207619Srdivacky AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD, 1831207619Srdivacky Path.Access); 1832205219Srdivacky if (DiagID) 1833205219Srdivacky Entity.setDiag(DiagID) << Derived << Base; 1834205219Srdivacky 1835207619Srdivacky if (ForceUnprivileged) { 1836207619Srdivacky switch (CheckEffectiveAccess(*this, EffectiveContext(), 1837207619Srdivacky AccessLoc, Entity)) { 1838207619Srdivacky case ::AR_accessible: return Sema::AR_accessible; 1839207619Srdivacky case ::AR_inaccessible: return Sema::AR_inaccessible; 1840207619Srdivacky case ::AR_dependent: return Sema::AR_dependent; 1841207619Srdivacky } 1842207619Srdivacky llvm_unreachable("unexpected result from CheckEffectiveAccess"); 1843207619Srdivacky } 1844205219Srdivacky return CheckAccess(*this, AccessLoc, Entity); 1845203955Srdivacky} 1846203955Srdivacky 1847202879Srdivacky/// Checks access to all the declarations in the given result set. 1848203955Srdivackyvoid Sema::CheckLookupAccess(const LookupResult &R) { 1849235633Sdim assert(getLangOpts().AccessControl 1850203955Srdivacky && "performing access check without access control"); 1851203955Srdivacky assert(R.getNamingClass() && "performing access check without naming class"); 1852203955Srdivacky 1853205219Srdivacky for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { 1854205219Srdivacky if (I.getAccess() != AS_public) { 1855207619Srdivacky AccessTarget Entity(Context, AccessedEntity::Member, 1856207619Srdivacky R.getNamingClass(), I.getPair(), 1857226890Sdim R.getBaseObjectType()); 1858205219Srdivacky Entity.setDiag(diag::err_access); 1859205219Srdivacky CheckAccess(*this, R.getNameLoc(), Entity); 1860205219Srdivacky } 1861205219Srdivacky } 1862202879Srdivacky} 1863210299Sed 1864226890Sdim/// Checks access to Decl from the given class. The check will take access 1865226890Sdim/// specifiers into account, but no member access expressions and such. 1866226890Sdim/// 1867226890Sdim/// \param Decl the declaration to check if it can be accessed 1868245431Sdim/// \param Ctx the class/context from which to start the search 1869226890Sdim/// \return true if the Decl is accessible from the Class, false otherwise. 1870235633Sdimbool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) { 1871235633Sdim if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) { 1872235633Sdim if (!Decl->isCXXClassMember()) 1873235633Sdim return true; 1874226890Sdim 1875235633Sdim QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal(); 1876235633Sdim AccessTarget Entity(Context, AccessedEntity::Member, Class, 1877235633Sdim DeclAccessPair::make(Decl, Decl->getAccess()), 1878235633Sdim qType); 1879235633Sdim if (Entity.getAccess() == AS_public) 1880235633Sdim return true; 1881226890Sdim 1882235633Sdim EffectiveContext EC(CurContext); 1883235633Sdim return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; 1884235633Sdim } 1885235633Sdim 1886235633Sdim if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) { 1887235633Sdim // @public and @package ivars are always accessible. 1888235633Sdim if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public || 1889235633Sdim Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package) 1890235633Sdim return true; 1891263509Sdim 1892235633Sdim // If we are inside a class or category implementation, determine the 1893235633Sdim // interface we're in. 1894235633Sdim ObjCInterfaceDecl *ClassOfMethodDecl = 0; 1895235633Sdim if (ObjCMethodDecl *MD = getCurMethodDecl()) 1896235633Sdim ClassOfMethodDecl = MD->getClassInterface(); 1897235633Sdim else if (FunctionDecl *FD = getCurFunctionDecl()) { 1898235633Sdim if (ObjCImplDecl *Impl 1899235633Sdim = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) { 1900235633Sdim if (ObjCImplementationDecl *IMPD 1901235633Sdim = dyn_cast<ObjCImplementationDecl>(Impl)) 1902235633Sdim ClassOfMethodDecl = IMPD->getClassInterface(); 1903235633Sdim else if (ObjCCategoryImplDecl* CatImplClass 1904235633Sdim = dyn_cast<ObjCCategoryImplDecl>(Impl)) 1905235633Sdim ClassOfMethodDecl = CatImplClass->getClassInterface(); 1906235633Sdim } 1907235633Sdim } 1908235633Sdim 1909235633Sdim // If we're not in an interface, this ivar is inaccessible. 1910235633Sdim if (!ClassOfMethodDecl) 1911235633Sdim return false; 1912235633Sdim 1913235633Sdim // If we're inside the same interface that owns the ivar, we're fine. 1914235633Sdim if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface())) 1915235633Sdim return true; 1916235633Sdim 1917235633Sdim // If the ivar is private, it's inaccessible. 1918235633Sdim if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private) 1919235633Sdim return false; 1920235633Sdim 1921235633Sdim return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl); 1922235633Sdim } 1923235633Sdim 1924235633Sdim return true; 1925226890Sdim} 1926