SemaAccess.cpp revision 3b8c53b619c1c3d77632734d227566071459b9f5
1//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file provides Sema routines for C++ access control semantics. 11// 12//===----------------------------------------------------------------------===// 13 14#include "Sema.h" 15#include "SemaInit.h" 16#include "Lookup.h" 17#include "clang/AST/ASTContext.h" 18#include "clang/AST/CXXInheritance.h" 19#include "clang/AST/DeclCXX.h" 20#include "clang/AST/DeclFriend.h" 21#include "clang/AST/DependentDiagnostic.h" 22#include "clang/AST/ExprCXX.h" 23 24using namespace clang; 25 26/// A copy of Sema's enum without AR_delayed. 27enum AccessResult { 28 AR_accessible, 29 AR_inaccessible, 30 AR_dependent 31}; 32 33/// SetMemberAccessSpecifier - Set the access specifier of a member. 34/// Returns true on error (when the previous member decl access specifier 35/// is different from the new member decl access specifier). 36bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, 37 NamedDecl *PrevMemberDecl, 38 AccessSpecifier LexicalAS) { 39 if (!PrevMemberDecl) { 40 // Use the lexical access specifier. 41 MemberDecl->setAccess(LexicalAS); 42 return false; 43 } 44 45 // C++ [class.access.spec]p3: When a member is redeclared its access 46 // specifier must be same as its initial declaration. 47 if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { 48 Diag(MemberDecl->getLocation(), 49 diag::err_class_redeclared_with_different_access) 50 << MemberDecl << LexicalAS; 51 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) 52 << PrevMemberDecl << PrevMemberDecl->getAccess(); 53 54 MemberDecl->setAccess(LexicalAS); 55 return true; 56 } 57 58 MemberDecl->setAccess(PrevMemberDecl->getAccess()); 59 return false; 60} 61 62static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { 63 DeclContext *DC = D->getDeclContext(); 64 65 // This can only happen at top: enum decls only "publish" their 66 // immediate members. 67 if (isa<EnumDecl>(DC)) 68 DC = cast<EnumDecl>(DC)->getDeclContext(); 69 70 CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); 71 while (DeclaringClass->isAnonymousStructOrUnion()) 72 DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); 73 return DeclaringClass; 74} 75 76namespace { 77struct EffectiveContext { 78 EffectiveContext() : Inner(0), Dependent(false) {} 79 80 explicit EffectiveContext(DeclContext *DC) 81 : Inner(DC), 82 Dependent(DC->isDependentContext()) { 83 84 // C++ [class.access.nest]p1: 85 // A nested class is a member and as such has the same access 86 // rights as any other member. 87 // C++ [class.access]p2: 88 // A member of a class can also access all the names to which 89 // the class has access. A local class of a member function 90 // may access the same names that the member function itself 91 // may access. 92 // This almost implies that the privileges of nesting are transitive. 93 // Technically it says nothing about the local classes of non-member 94 // functions (which can gain privileges through friendship), but we 95 // take that as an oversight. 96 while (true) { 97 if (isa<CXXRecordDecl>(DC)) { 98 CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); 99 Records.push_back(Record); 100 DC = Record->getDeclContext(); 101 } else if (isa<FunctionDecl>(DC)) { 102 FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); 103 Functions.push_back(Function); 104 DC = Function->getDeclContext(); 105 } else if (DC->isFileContext()) { 106 break; 107 } else { 108 DC = DC->getParent(); 109 } 110 } 111 } 112 113 bool isDependent() const { return Dependent; } 114 115 bool includesClass(const CXXRecordDecl *R) const { 116 R = R->getCanonicalDecl(); 117 return std::find(Records.begin(), Records.end(), R) 118 != Records.end(); 119 } 120 121 /// Retrieves the innermost "useful" context. Can be null if we're 122 /// doing access-control without privileges. 123 DeclContext *getInnerContext() const { 124 return Inner; 125 } 126 127 typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; 128 129 DeclContext *Inner; 130 llvm::SmallVector<FunctionDecl*, 4> Functions; 131 llvm::SmallVector<CXXRecordDecl*, 4> Records; 132 bool Dependent; 133}; 134 135/// Like Sema's AccessedEntity, but kindly lets us scribble all over 136/// it. 137struct AccessTarget : public Sema::AccessedEntity { 138 AccessTarget(const Sema::AccessedEntity &Entity) 139 : AccessedEntity(Entity) { 140 initialize(); 141 } 142 143 AccessTarget(ASTContext &Context, 144 MemberNonce _, 145 CXXRecordDecl *NamingClass, 146 DeclAccessPair FoundDecl, 147 QualType BaseObjectType) 148 : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) { 149 initialize(); 150 } 151 152 AccessTarget(ASTContext &Context, 153 BaseNonce _, 154 CXXRecordDecl *BaseClass, 155 CXXRecordDecl *DerivedClass, 156 AccessSpecifier Access) 157 : AccessedEntity(Context, Base, BaseClass, DerivedClass, Access) { 158 initialize(); 159 } 160 161 bool hasInstanceContext() const { 162 return HasInstanceContext; 163 } 164 165 class SavedInstanceContext { 166 public: 167 ~SavedInstanceContext() { 168 Target.HasInstanceContext = Has; 169 } 170 171 private: 172 friend struct AccessTarget; 173 explicit SavedInstanceContext(AccessTarget &Target) 174 : Target(Target), Has(Target.HasInstanceContext) {} 175 AccessTarget &Target; 176 bool Has; 177 }; 178 179 SavedInstanceContext saveInstanceContext() { 180 return SavedInstanceContext(*this); 181 } 182 183 void suppressInstanceContext() { 184 HasInstanceContext = false; 185 } 186 187 const CXXRecordDecl *resolveInstanceContext(Sema &S) const { 188 assert(HasInstanceContext); 189 if (CalculatedInstanceContext) 190 return InstanceContext; 191 192 CalculatedInstanceContext = true; 193 DeclContext *IC = S.computeDeclContext(getBaseObjectType()); 194 InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0); 195 return InstanceContext; 196 } 197 198 const CXXRecordDecl *getDeclaringClass() const { 199 return DeclaringClass; 200 } 201 202private: 203 void initialize() { 204 HasInstanceContext = (isMemberAccess() && 205 !getBaseObjectType().isNull() && 206 getTargetDecl()->isCXXInstanceMember()); 207 CalculatedInstanceContext = false; 208 InstanceContext = 0; 209 210 if (isMemberAccess()) 211 DeclaringClass = FindDeclaringClass(getTargetDecl()); 212 else 213 DeclaringClass = getBaseClass(); 214 DeclaringClass = DeclaringClass->getCanonicalDecl(); 215 } 216 217 bool HasInstanceContext : 1; 218 mutable bool CalculatedInstanceContext : 1; 219 mutable const CXXRecordDecl *InstanceContext; 220 const CXXRecordDecl *DeclaringClass; 221}; 222 223} 224 225/// Checks whether one class is derived from another, inclusively. 226/// Properly indicates when it couldn't be determined due to 227/// dependence. 228/// 229/// This should probably be donated to AST or at least Sema. 230static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, 231 const CXXRecordDecl *Target) { 232 assert(Derived->getCanonicalDecl() == Derived); 233 assert(Target->getCanonicalDecl() == Target); 234 235 if (Derived == Target) return AR_accessible; 236 237 AccessResult OnFailure = AR_inaccessible; 238 llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack 239 240 while (true) { 241 for (CXXRecordDecl::base_class_const_iterator 242 I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) { 243 244 const CXXRecordDecl *RD; 245 246 QualType T = I->getType(); 247 if (const RecordType *RT = T->getAs<RecordType>()) { 248 RD = cast<CXXRecordDecl>(RT->getDecl()); 249 } else { 250 // It's possible for a base class to be the current 251 // instantiation of some enclosing template, but I'm guessing 252 // nobody will ever care that we just dependently delay here. 253 assert(T->isDependentType() && "non-dependent base wasn't a record?"); 254 OnFailure = AR_dependent; 255 continue; 256 } 257 258 RD = RD->getCanonicalDecl(); 259 if (RD == Target) return AR_accessible; 260 Queue.push_back(RD); 261 } 262 263 if (Queue.empty()) break; 264 265 Derived = Queue.back(); 266 Queue.pop_back(); 267 } 268 269 return OnFailure; 270} 271 272 273static bool MightInstantiateTo(Sema &S, DeclContext *Context, 274 DeclContext *Friend) { 275 if (Friend == Context) 276 return true; 277 278 assert(!Friend->isDependentContext() && 279 "can't handle friends with dependent contexts here"); 280 281 if (!Context->isDependentContext()) 282 return false; 283 284 if (Friend->isFileContext()) 285 return false; 286 287 // TODO: this is very conservative 288 return true; 289} 290 291// Asks whether the type in 'context' can ever instantiate to the type 292// in 'friend'. 293static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) { 294 if (Friend == Context) 295 return true; 296 297 if (!Friend->isDependentType() && !Context->isDependentType()) 298 return false; 299 300 // TODO: this is very conservative. 301 return true; 302} 303 304static bool MightInstantiateTo(Sema &S, 305 FunctionDecl *Context, 306 FunctionDecl *Friend) { 307 if (Context->getDeclName() != Friend->getDeclName()) 308 return false; 309 310 if (!MightInstantiateTo(S, 311 Context->getDeclContext(), 312 Friend->getDeclContext())) 313 return false; 314 315 CanQual<FunctionProtoType> FriendTy 316 = S.Context.getCanonicalType(Friend->getType()) 317 ->getAs<FunctionProtoType>(); 318 CanQual<FunctionProtoType> ContextTy 319 = S.Context.getCanonicalType(Context->getType()) 320 ->getAs<FunctionProtoType>(); 321 322 // There isn't any way that I know of to add qualifiers 323 // during instantiation. 324 if (FriendTy.getQualifiers() != ContextTy.getQualifiers()) 325 return false; 326 327 if (FriendTy->getNumArgs() != ContextTy->getNumArgs()) 328 return false; 329 330 if (!MightInstantiateTo(S, 331 ContextTy->getResultType(), 332 FriendTy->getResultType())) 333 return false; 334 335 for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I) 336 if (!MightInstantiateTo(S, 337 ContextTy->getArgType(I), 338 FriendTy->getArgType(I))) 339 return false; 340 341 return true; 342} 343 344static bool MightInstantiateTo(Sema &S, 345 FunctionTemplateDecl *Context, 346 FunctionTemplateDecl *Friend) { 347 return MightInstantiateTo(S, 348 Context->getTemplatedDecl(), 349 Friend->getTemplatedDecl()); 350} 351 352static AccessResult MatchesFriend(Sema &S, 353 const EffectiveContext &EC, 354 const CXXRecordDecl *Friend) { 355 if (EC.includesClass(Friend)) 356 return AR_accessible; 357 358 if (EC.isDependent()) { 359 CanQualType FriendTy 360 = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend)); 361 362 for (EffectiveContext::record_iterator 363 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 364 CanQualType ContextTy 365 = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); 366 if (MightInstantiateTo(S, ContextTy, FriendTy)) 367 return AR_dependent; 368 } 369 } 370 371 return AR_inaccessible; 372} 373 374static AccessResult MatchesFriend(Sema &S, 375 const EffectiveContext &EC, 376 CanQualType Friend) { 377 if (const RecordType *RT = Friend->getAs<RecordType>()) 378 return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); 379 380 // TODO: we can do better than this 381 if (Friend->isDependentType()) 382 return AR_dependent; 383 384 return AR_inaccessible; 385} 386 387/// Determines whether the given friend class template matches 388/// anything in the effective context. 389static AccessResult MatchesFriend(Sema &S, 390 const EffectiveContext &EC, 391 ClassTemplateDecl *Friend) { 392 AccessResult OnFailure = AR_inaccessible; 393 394 // Check whether the friend is the template of a class in the 395 // context chain. 396 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator 397 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 398 CXXRecordDecl *Record = *I; 399 400 // Figure out whether the current class has a template: 401 ClassTemplateDecl *CTD; 402 403 // A specialization of the template... 404 if (isa<ClassTemplateSpecializationDecl>(Record)) { 405 CTD = cast<ClassTemplateSpecializationDecl>(Record) 406 ->getSpecializedTemplate(); 407 408 // ... or the template pattern itself. 409 } else { 410 CTD = Record->getDescribedClassTemplate(); 411 if (!CTD) continue; 412 } 413 414 // It's a match. 415 if (Friend == CTD->getCanonicalDecl()) 416 return AR_accessible; 417 418 // If the context isn't dependent, it can't be a dependent match. 419 if (!EC.isDependent()) 420 continue; 421 422 // If the template names don't match, it can't be a dependent 423 // match. This isn't true in C++0x because of template aliases. 424 if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) 425 continue; 426 427 // If the class's context can't instantiate to the friend's 428 // context, it can't be a dependent match. 429 if (!MightInstantiateTo(S, CTD->getDeclContext(), 430 Friend->getDeclContext())) 431 continue; 432 433 // Otherwise, it's a dependent match. 434 OnFailure = AR_dependent; 435 } 436 437 return OnFailure; 438} 439 440/// Determines whether the given friend function matches anything in 441/// the effective context. 442static AccessResult MatchesFriend(Sema &S, 443 const EffectiveContext &EC, 444 FunctionDecl *Friend) { 445 AccessResult OnFailure = AR_inaccessible; 446 447 for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator 448 I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { 449 if (Friend == *I) 450 return AR_accessible; 451 452 if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) 453 OnFailure = AR_dependent; 454 } 455 456 return OnFailure; 457} 458 459/// Determines whether the given friend function template matches 460/// anything in the effective context. 461static AccessResult MatchesFriend(Sema &S, 462 const EffectiveContext &EC, 463 FunctionTemplateDecl *Friend) { 464 if (EC.Functions.empty()) return AR_inaccessible; 465 466 AccessResult OnFailure = AR_inaccessible; 467 468 for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator 469 I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { 470 471 FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); 472 if (!FTD) 473 FTD = (*I)->getDescribedFunctionTemplate(); 474 if (!FTD) 475 continue; 476 477 FTD = FTD->getCanonicalDecl(); 478 479 if (Friend == FTD) 480 return AR_accessible; 481 482 if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) 483 OnFailure = AR_dependent; 484 } 485 486 return OnFailure; 487} 488 489/// Determines whether the given friend declaration matches anything 490/// in the effective context. 491static AccessResult MatchesFriend(Sema &S, 492 const EffectiveContext &EC, 493 FriendDecl *FriendD) { 494 if (TypeSourceInfo *T = FriendD->getFriendType()) 495 return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); 496 497 NamedDecl *Friend 498 = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl()); 499 500 // FIXME: declarations with dependent or templated scope. 501 502 if (isa<ClassTemplateDecl>(Friend)) 503 return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend)); 504 505 if (isa<FunctionTemplateDecl>(Friend)) 506 return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend)); 507 508 if (isa<CXXRecordDecl>(Friend)) 509 return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend)); 510 511 assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind"); 512 return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); 513} 514 515static AccessResult GetFriendKind(Sema &S, 516 const EffectiveContext &EC, 517 const CXXRecordDecl *Class) { 518 AccessResult OnFailure = AR_inaccessible; 519 520 // Okay, check friends. 521 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), 522 E = Class->friend_end(); I != E; ++I) { 523 FriendDecl *Friend = *I; 524 525 switch (MatchesFriend(S, EC, Friend)) { 526 case AR_accessible: 527 return AR_accessible; 528 529 case AR_inaccessible: 530 continue; 531 532 case AR_dependent: 533 OnFailure = AR_dependent; 534 break; 535 } 536 } 537 538 // That's it, give up. 539 return OnFailure; 540} 541 542static AccessResult HasAccess(Sema &S, 543 const EffectiveContext &EC, 544 const CXXRecordDecl *NamingClass, 545 AccessSpecifier Access, 546 const AccessTarget &Target) { 547 assert(NamingClass->getCanonicalDecl() == NamingClass && 548 "declaration should be canonicalized before being passed here"); 549 550 if (Access == AS_public) return AR_accessible; 551 assert(Access == AS_private || Access == AS_protected); 552 553 AccessResult OnFailure = AR_inaccessible; 554 555 for (EffectiveContext::record_iterator 556 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 557 // All the declarations in EC have been canonicalized, so pointer 558 // equality from this point on will work fine. 559 const CXXRecordDecl *ECRecord = *I; 560 561 // [B2] and [M2] 562 if (Access == AS_private) { 563 if (ECRecord == NamingClass) 564 return AR_accessible; 565 566 // [B3] and [M3] 567 } else { 568 assert(Access == AS_protected); 569 switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { 570 case AR_accessible: break; 571 case AR_inaccessible: continue; 572 case AR_dependent: OnFailure = AR_dependent; continue; 573 } 574 575 if (!Target.hasInstanceContext()) 576 return AR_accessible; 577 578 const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); 579 if (!InstanceContext) { 580 OnFailure = AR_dependent; 581 continue; 582 } 583 584 // C++ [class.protected]p1: 585 // An additional access check beyond those described earlier in 586 // [class.access] is applied when a non-static data member or 587 // non-static member function is a protected member of its naming 588 // class. As described earlier, access to a protected member is 589 // granted because the reference occurs in a friend or member of 590 // some class C. If the access is to form a pointer to member, 591 // the nested-name-specifier shall name C or a class derived from 592 // C. All other accesses involve a (possibly implicit) object 593 // expression. In this case, the class of the object expression 594 // shall be C or a class derived from C. 595 // 596 // We interpret this as a restriction on [M3]. Most of the 597 // conditions are encoded by not having any instance context. 598 switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { 599 case AR_accessible: return AR_accessible; 600 case AR_inaccessible: continue; 601 case AR_dependent: OnFailure = AR_dependent; continue; 602 } 603 } 604 } 605 606 if (!NamingClass->hasFriends()) 607 return OnFailure; 608 609 // Don't consider friends if we're under the [class.protected] 610 // restriction, above. 611 if (Access == AS_protected && Target.hasInstanceContext()) { 612 const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); 613 if (!InstanceContext) return AR_dependent; 614 615 switch (IsDerivedFromInclusive(InstanceContext, NamingClass)) { 616 case AR_accessible: break; 617 case AR_inaccessible: return OnFailure; 618 case AR_dependent: return AR_dependent; 619 } 620 } 621 622 switch (GetFriendKind(S, EC, NamingClass)) { 623 case AR_accessible: return AR_accessible; 624 case AR_inaccessible: return OnFailure; 625 case AR_dependent: return AR_dependent; 626 } 627 628 // Silence bogus warnings 629 llvm_unreachable("impossible friendship kind"); 630 return OnFailure; 631} 632 633/// Finds the best path from the naming class to the declaring class, 634/// taking friend declarations into account. 635/// 636/// C++0x [class.access.base]p5: 637/// A member m is accessible at the point R when named in class N if 638/// [M1] m as a member of N is public, or 639/// [M2] m as a member of N is private, and R occurs in a member or 640/// friend of class N, or 641/// [M3] m as a member of N is protected, and R occurs in a member or 642/// friend of class N, or in a member or friend of a class P 643/// derived from N, where m as a member of P is public, private, 644/// or protected, or 645/// [M4] there exists a base class B of N that is accessible at R, and 646/// m is accessible at R when named in class B. 647/// 648/// C++0x [class.access.base]p4: 649/// A base class B of N is accessible at R, if 650/// [B1] an invented public member of B would be a public member of N, or 651/// [B2] R occurs in a member or friend of class N, and an invented public 652/// member of B would be a private or protected member of N, or 653/// [B3] R occurs in a member or friend of a class P derived from N, and an 654/// invented public member of B would be a private or protected member 655/// of P, or 656/// [B4] there exists a class S such that B is a base class of S accessible 657/// at R and S is a base class of N accessible at R. 658/// 659/// Along a single inheritance path we can restate both of these 660/// iteratively: 661/// 662/// First, we note that M1-4 are equivalent to B1-4 if the member is 663/// treated as a notional base of its declaring class with inheritance 664/// access equivalent to the member's access. Therefore we need only 665/// ask whether a class B is accessible from a class N in context R. 666/// 667/// Let B_1 .. B_n be the inheritance path in question (i.e. where 668/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of 669/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the 670/// closest accessible base in the path: 671/// Access(a, b) = (* access on the base specifier from a to b *) 672/// Merge(a, forbidden) = forbidden 673/// Merge(a, private) = forbidden 674/// Merge(a, b) = min(a,b) 675/// Accessible(c, forbidden) = false 676/// Accessible(c, private) = (R is c) || IsFriend(c, R) 677/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R) 678/// Accessible(c, public) = true 679/// ACAB(n) = public 680/// ACAB(i) = 681/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in 682/// if Accessible(B_i, AccessToBase) then public else AccessToBase 683/// 684/// B is an accessible base of N at R iff ACAB(1) = public. 685/// 686/// \param FinalAccess the access of the "final step", or AS_public if 687/// there is no final step. 688/// \return null if friendship is dependent 689static CXXBasePath *FindBestPath(Sema &S, 690 const EffectiveContext &EC, 691 AccessTarget &Target, 692 AccessSpecifier FinalAccess, 693 CXXBasePaths &Paths) { 694 // Derive the paths to the desired base. 695 const CXXRecordDecl *Derived = Target.getNamingClass(); 696 const CXXRecordDecl *Base = Target.getDeclaringClass(); 697 698 // FIXME: fail correctly when there are dependent paths. 699 bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base), 700 Paths); 701 assert(isDerived && "derived class not actually derived from base"); 702 (void) isDerived; 703 704 CXXBasePath *BestPath = 0; 705 706 assert(FinalAccess != AS_none && "forbidden access after declaring class"); 707 708 bool AnyDependent = false; 709 710 // Derive the friend-modified access along each path. 711 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); 712 PI != PE; ++PI) { 713 AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext(); 714 715 // Walk through the path backwards. 716 AccessSpecifier PathAccess = FinalAccess; 717 CXXBasePath::iterator I = PI->end(), E = PI->begin(); 718 while (I != E) { 719 --I; 720 721 assert(PathAccess != AS_none); 722 723 // If the declaration is a private member of a base class, there 724 // is no level of friendship in derived classes that can make it 725 // accessible. 726 if (PathAccess == AS_private) { 727 PathAccess = AS_none; 728 break; 729 } 730 731 const CXXRecordDecl *NC = I->Class->getCanonicalDecl(); 732 733 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); 734 PathAccess = std::max(PathAccess, BaseAccess); 735 736 switch (HasAccess(S, EC, NC, PathAccess, Target)) { 737 case AR_inaccessible: break; 738 case AR_accessible: 739 PathAccess = AS_public; 740 741 // Future tests are not against members and so do not have 742 // instance context. 743 Target.suppressInstanceContext(); 744 break; 745 case AR_dependent: 746 AnyDependent = true; 747 goto Next; 748 } 749 } 750 751 // Note that we modify the path's Access field to the 752 // friend-modified access. 753 if (BestPath == 0 || PathAccess < BestPath->Access) { 754 BestPath = &*PI; 755 BestPath->Access = PathAccess; 756 757 // Short-circuit if we found a public path. 758 if (BestPath->Access == AS_public) 759 return BestPath; 760 } 761 762 Next: ; 763 } 764 765 assert((!BestPath || BestPath->Access != AS_public) && 766 "fell out of loop with public path"); 767 768 // We didn't find a public path, but at least one path was subject 769 // to dependent friendship, so delay the check. 770 if (AnyDependent) 771 return 0; 772 773 return BestPath; 774} 775 776/// Diagnose the path which caused the given declaration or base class 777/// to become inaccessible. 778static void DiagnoseAccessPath(Sema &S, 779 const EffectiveContext &EC, 780 AccessTarget &Entity) { 781 AccessSpecifier Access = Entity.getAccess(); 782 const CXXRecordDecl *NamingClass = Entity.getNamingClass(); 783 NamingClass = NamingClass->getCanonicalDecl(); 784 785 NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); 786 const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); 787 788 // Easy case: the decl's natural access determined its path access. 789 // We have to check against AS_private here in case Access is AS_none, 790 // indicating a non-public member of a private base class. 791 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) { 792 switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) { 793 case AR_inaccessible: { 794 S.Diag(D->getLocation(), diag::note_access_natural) 795 << (unsigned) (Access == AS_protected) 796 << /*FIXME: not implicitly*/ 0; 797 return; 798 } 799 800 case AR_accessible: break; 801 802 case AR_dependent: 803 llvm_unreachable("can't diagnose dependent access failures"); 804 return; 805 } 806 } 807 808 CXXBasePaths Paths; 809 CXXBasePath &Path = *FindBestPath(S, EC, Entity, AS_public, Paths); 810 811 CXXBasePath::iterator I = Path.end(), E = Path.begin(); 812 while (I != E) { 813 --I; 814 815 const CXXBaseSpecifier *BS = I->Base; 816 AccessSpecifier BaseAccess = BS->getAccessSpecifier(); 817 818 // If this is public inheritance, or the derived class is a friend, 819 // skip this step. 820 if (BaseAccess == AS_public) 821 continue; 822 823 switch (GetFriendKind(S, EC, I->Class)) { 824 case AR_accessible: continue; 825 case AR_inaccessible: break; 826 case AR_dependent: 827 llvm_unreachable("can't diagnose dependent access failures"); 828 } 829 830 // Check whether this base specifier is the tighest point 831 // constraining access. We have to check against AS_private for 832 // the same reasons as above. 833 if (BaseAccess == AS_private || BaseAccess >= Access) { 834 835 // We're constrained by inheritance, but we want to say 836 // "declared private here" if we're diagnosing a hierarchy 837 // conversion and this is the final step. 838 unsigned diagnostic; 839 if (D) diagnostic = diag::note_access_constrained_by_path; 840 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural; 841 else diagnostic = diag::note_access_constrained_by_path; 842 843 S.Diag(BS->getSourceRange().getBegin(), diagnostic) 844 << BS->getSourceRange() 845 << (BaseAccess == AS_protected) 846 << (BS->getAccessSpecifierAsWritten() == AS_none); 847 return; 848 } 849 } 850 851 llvm_unreachable("access not apparently constrained by path"); 852} 853 854static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, 855 const EffectiveContext &EC, 856 AccessTarget &Entity) { 857 const CXXRecordDecl *NamingClass = Entity.getNamingClass(); 858 const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); 859 NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); 860 861 S.Diag(Loc, Entity.getDiag()) 862 << (Entity.getAccess() == AS_protected) 863 << (D ? D->getDeclName() : DeclarationName()) 864 << S.Context.getTypeDeclType(NamingClass) 865 << S.Context.getTypeDeclType(DeclaringClass); 866 DiagnoseAccessPath(S, EC, Entity); 867} 868 869/// Determines whether the accessed entity is accessible. Public members 870/// have been weeded out by this point. 871static AccessResult IsAccessible(Sema &S, 872 const EffectiveContext &EC, 873 AccessTarget &Entity) { 874 // Determine the actual naming class. 875 CXXRecordDecl *NamingClass = Entity.getNamingClass(); 876 while (NamingClass->isAnonymousStructOrUnion()) 877 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); 878 NamingClass = NamingClass->getCanonicalDecl(); 879 880 AccessSpecifier UnprivilegedAccess = Entity.getAccess(); 881 assert(UnprivilegedAccess != AS_public && "public access not weeded out"); 882 883 // Before we try to recalculate access paths, try to white-list 884 // accesses which just trade in on the final step, i.e. accesses 885 // which don't require [M4] or [B4]. These are by far the most 886 // common forms of privileged access. 887 if (UnprivilegedAccess != AS_none) { 888 switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) { 889 case AR_dependent: 890 // This is actually an interesting policy decision. We don't 891 // *have* to delay immediately here: we can do the full access 892 // calculation in the hope that friendship on some intermediate 893 // class will make the declaration accessible non-dependently. 894 // But that's not cheap, and odds are very good (note: assertion 895 // made without data) that the friend declaration will determine 896 // access. 897 return AR_dependent; 898 899 case AR_accessible: return AR_accessible; 900 case AR_inaccessible: break; 901 } 902 } 903 904 AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext(); 905 906 // We lower member accesses to base accesses by pretending that the 907 // member is a base class of its declaring class. 908 AccessSpecifier FinalAccess; 909 910 if (Entity.isMemberAccess()) { 911 // Determine if the declaration is accessible from EC when named 912 // in its declaring class. 913 NamedDecl *Target = Entity.getTargetDecl(); 914 const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); 915 916 FinalAccess = Target->getAccess(); 917 switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) { 918 case AR_accessible: 919 FinalAccess = AS_public; 920 break; 921 case AR_inaccessible: break; 922 case AR_dependent: return AR_dependent; // see above 923 } 924 925 if (DeclaringClass == NamingClass) 926 return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible); 927 928 Entity.suppressInstanceContext(); 929 } else { 930 FinalAccess = AS_public; 931 } 932 933 assert(Entity.getDeclaringClass() != NamingClass); 934 935 // Append the declaration's access if applicable. 936 CXXBasePaths Paths; 937 CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); 938 if (!Path) 939 return AR_dependent; 940 941 assert(Path->Access <= UnprivilegedAccess && 942 "access along best path worse than direct?"); 943 if (Path->Access == AS_public) 944 return AR_accessible; 945 return AR_inaccessible; 946} 947 948static void DelayDependentAccess(Sema &S, 949 const EffectiveContext &EC, 950 SourceLocation Loc, 951 const AccessTarget &Entity) { 952 assert(EC.isDependent() && "delaying non-dependent access"); 953 DeclContext *DC = EC.getInnerContext(); 954 assert(DC->isDependentContext() && "delaying non-dependent access"); 955 DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access, 956 Loc, 957 Entity.isMemberAccess(), 958 Entity.getAccess(), 959 Entity.getTargetDecl(), 960 Entity.getNamingClass(), 961 Entity.getBaseObjectType(), 962 Entity.getDiag()); 963} 964 965/// Checks access to an entity from the given effective context. 966static AccessResult CheckEffectiveAccess(Sema &S, 967 const EffectiveContext &EC, 968 SourceLocation Loc, 969 AccessTarget &Entity) { 970 assert(Entity.getAccess() != AS_public && "called for public access!"); 971 972 switch (IsAccessible(S, EC, Entity)) { 973 case AR_dependent: 974 DelayDependentAccess(S, EC, Loc, Entity); 975 return AR_dependent; 976 977 case AR_inaccessible: 978 if (!Entity.isQuiet()) 979 DiagnoseBadAccess(S, Loc, EC, Entity); 980 return AR_inaccessible; 981 982 case AR_accessible: 983 return AR_accessible; 984 } 985 986 // silence unnecessary warning 987 llvm_unreachable("invalid access result"); 988 return AR_accessible; 989} 990 991static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, 992 AccessTarget &Entity) { 993 // If the access path is public, it's accessible everywhere. 994 if (Entity.getAccess() == AS_public) 995 return Sema::AR_accessible; 996 997 // If we're currently parsing a top-level declaration, delay 998 // diagnostics. This is the only case where parsing a declaration 999 // can actually change our effective context for the purposes of 1000 // access control. 1001 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) { 1002 S.DelayedDiagnostics.push_back( 1003 Sema::DelayedDiagnostic::makeAccess(Loc, Entity)); 1004 return Sema::AR_delayed; 1005 } 1006 1007 EffectiveContext EC(S.CurContext); 1008 switch (CheckEffectiveAccess(S, EC, Loc, Entity)) { 1009 case AR_accessible: return Sema::AR_accessible; 1010 case AR_inaccessible: return Sema::AR_inaccessible; 1011 case AR_dependent: return Sema::AR_dependent; 1012 } 1013 llvm_unreachable("falling off end"); 1014 return Sema::AR_accessible; 1015} 1016 1017void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { 1018 // Pretend we did this from the context of the newly-parsed 1019 // declaration. If that declaration itself forms a declaration context, 1020 // include it in the effective context so that parameters and return types of 1021 // befriended functions have that function's access priveledges. 1022 DeclContext *DC = Ctx->getDeclContext(); 1023 if (isa<FunctionDecl>(Ctx)) 1024 DC = cast<DeclContext>(Ctx); 1025 else if (FunctionTemplateDecl *FnTpl = dyn_cast<FunctionTemplateDecl>(Ctx)) 1026 DC = cast<DeclContext>(FnTpl->getTemplatedDecl()); 1027 EffectiveContext EC(DC); 1028 1029 AccessTarget Target(DD.getAccessData()); 1030 1031 if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible) 1032 DD.Triggered = true; 1033} 1034 1035void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, 1036 const MultiLevelTemplateArgumentList &TemplateArgs) { 1037 SourceLocation Loc = DD.getAccessLoc(); 1038 AccessSpecifier Access = DD.getAccess(); 1039 1040 Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(), 1041 TemplateArgs); 1042 if (!NamingD) return; 1043 Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(), 1044 TemplateArgs); 1045 if (!TargetD) return; 1046 1047 if (DD.isAccessToMember()) { 1048 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD); 1049 NamedDecl *TargetDecl = cast<NamedDecl>(TargetD); 1050 QualType BaseObjectType = DD.getAccessBaseObjectType(); 1051 if (!BaseObjectType.isNull()) { 1052 BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc, 1053 DeclarationName()); 1054 if (BaseObjectType.isNull()) return; 1055 } 1056 1057 AccessTarget Entity(Context, 1058 AccessTarget::Member, 1059 NamingClass, 1060 DeclAccessPair::make(TargetDecl, Access), 1061 BaseObjectType); 1062 Entity.setDiag(DD.getDiagnostic()); 1063 CheckAccess(*this, Loc, Entity); 1064 } else { 1065 AccessTarget Entity(Context, 1066 AccessTarget::Base, 1067 cast<CXXRecordDecl>(TargetD), 1068 cast<CXXRecordDecl>(NamingD), 1069 Access); 1070 Entity.setDiag(DD.getDiagnostic()); 1071 CheckAccess(*this, Loc, Entity); 1072 } 1073} 1074 1075Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, 1076 DeclAccessPair Found) { 1077 if (!getLangOptions().AccessControl || 1078 !E->getNamingClass() || 1079 Found.getAccess() == AS_public) 1080 return AR_accessible; 1081 1082 AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), 1083 Found, QualType()); 1084 Entity.setDiag(diag::err_access) << E->getSourceRange(); 1085 1086 return CheckAccess(*this, E->getNameLoc(), Entity); 1087} 1088 1089/// Perform access-control checking on a previously-unresolved member 1090/// access which has now been resolved to a member. 1091Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, 1092 DeclAccessPair Found) { 1093 if (!getLangOptions().AccessControl || 1094 Found.getAccess() == AS_public) 1095 return AR_accessible; 1096 1097 QualType BaseType = E->getBaseType(); 1098 if (E->isArrow()) 1099 BaseType = BaseType->getAs<PointerType>()->getPointeeType(); 1100 1101 AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), 1102 Found, BaseType); 1103 Entity.setDiag(diag::err_access) << E->getSourceRange(); 1104 1105 return CheckAccess(*this, E->getMemberLoc(), Entity); 1106} 1107 1108Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, 1109 CXXDestructorDecl *Dtor, 1110 const PartialDiagnostic &PDiag) { 1111 if (!getLangOptions().AccessControl) 1112 return AR_accessible; 1113 1114 // There's never a path involved when checking implicit destructor access. 1115 AccessSpecifier Access = Dtor->getAccess(); 1116 if (Access == AS_public) 1117 return AR_accessible; 1118 1119 CXXRecordDecl *NamingClass = Dtor->getParent(); 1120 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, 1121 DeclAccessPair::make(Dtor, Access), 1122 QualType()); 1123 Entity.setDiag(PDiag); // TODO: avoid copy 1124 1125 return CheckAccess(*this, Loc, Entity); 1126} 1127 1128/// Checks access to a constructor. 1129Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, 1130 CXXConstructorDecl *Constructor, 1131 const InitializedEntity &Entity, 1132 AccessSpecifier Access) { 1133 if (!getLangOptions().AccessControl || 1134 Access == AS_public) 1135 return AR_accessible; 1136 1137 CXXRecordDecl *NamingClass = Constructor->getParent(); 1138 AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, 1139 DeclAccessPair::make(Constructor, Access), 1140 QualType()); 1141 switch (Entity.getKind()) { 1142 default: 1143 AccessEntity.setDiag(diag::err_access_ctor); 1144 break; 1145 1146 case InitializedEntity::EK_Base: 1147 AccessEntity.setDiag(PDiag(diag::err_access_base) 1148 << Entity.isInheritedVirtualBase() 1149 << Entity.getBaseSpecifier()->getType() 1150 << getSpecialMember(Constructor)); 1151 break; 1152 1153 case InitializedEntity::EK_Member: { 1154 const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); 1155 AccessEntity.setDiag(PDiag(diag::err_access_ctor_field) 1156 << Field->getDeclName() << Field->getType()); 1157 break; 1158 } 1159 1160 } 1161 1162 return CheckAccess(*this, UseLoc, AccessEntity); 1163} 1164 1165/// Checks direct (i.e. non-inherited) access to an arbitrary class 1166/// member. 1167Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, 1168 NamedDecl *Target, 1169 const PartialDiagnostic &Diag) { 1170 AccessSpecifier Access = Target->getAccess(); 1171 if (!getLangOptions().AccessControl || 1172 Access == AS_public) 1173 return AR_accessible; 1174 1175 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); 1176 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, 1177 DeclAccessPair::make(Target, Access), 1178 QualType()); 1179 Entity.setDiag(Diag); 1180 return CheckAccess(*this, UseLoc, Entity); 1181} 1182 1183 1184/// Checks access to an overloaded operator new or delete. 1185Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, 1186 SourceRange PlacementRange, 1187 CXXRecordDecl *NamingClass, 1188 DeclAccessPair Found) { 1189 if (!getLangOptions().AccessControl || 1190 !NamingClass || 1191 Found.getAccess() == AS_public) 1192 return AR_accessible; 1193 1194 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 1195 QualType()); 1196 Entity.setDiag(diag::err_access) 1197 << PlacementRange; 1198 1199 return CheckAccess(*this, OpLoc, Entity); 1200} 1201 1202/// Checks access to an overloaded member operator, including 1203/// conversion operators. 1204Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, 1205 Expr *ObjectExpr, 1206 Expr *ArgExpr, 1207 DeclAccessPair Found) { 1208 if (!getLangOptions().AccessControl || 1209 Found.getAccess() == AS_public) 1210 return AR_accessible; 1211 1212 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>(); 1213 assert(RT && "found member operator but object expr not of record type"); 1214 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); 1215 1216 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 1217 ObjectExpr->getType()); 1218 Entity.setDiag(diag::err_access) 1219 << ObjectExpr->getSourceRange() 1220 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); 1221 1222 return CheckAccess(*this, OpLoc, Entity); 1223} 1224 1225Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, 1226 DeclAccessPair Found) { 1227 if (!getLangOptions().AccessControl || 1228 Found.getAccess() == AS_none || 1229 Found.getAccess() == AS_public) 1230 return AR_accessible; 1231 1232 OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer(); 1233 NestedNameSpecifier *Qualifier = Ovl->getQualifier(); 1234 assert(Qualifier && "address of overloaded member without qualifier"); 1235 1236 CXXScopeSpec SS; 1237 SS.setScopeRep(Qualifier); 1238 SS.setRange(Ovl->getQualifierRange()); 1239 DeclContext *DC = computeDeclContext(SS); 1240 assert(DC && DC->isRecord() && "scope did not resolve to record"); 1241 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(DC); 1242 1243 AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, 1244 Context.getTypeDeclType(NamingClass)); 1245 Entity.setDiag(diag::err_access) 1246 << Ovl->getSourceRange(); 1247 1248 return CheckAccess(*this, Ovl->getNameLoc(), Entity); 1249} 1250 1251/// Checks access for a hierarchy conversion. 1252/// 1253/// \param IsBaseToDerived whether this is a base-to-derived conversion (true) 1254/// or a derived-to-base conversion (false) 1255/// \param ForceCheck true if this check should be performed even if access 1256/// control is disabled; some things rely on this for semantics 1257/// \param ForceUnprivileged true if this check should proceed as if the 1258/// context had no special privileges 1259/// \param ADK controls the kind of diagnostics that are used 1260Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, 1261 QualType Base, 1262 QualType Derived, 1263 const CXXBasePath &Path, 1264 unsigned DiagID, 1265 bool ForceCheck, 1266 bool ForceUnprivileged) { 1267 if (!ForceCheck && !getLangOptions().AccessControl) 1268 return AR_accessible; 1269 1270 if (Path.Access == AS_public) 1271 return AR_accessible; 1272 1273 CXXRecordDecl *BaseD, *DerivedD; 1274 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); 1275 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); 1276 1277 AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD, 1278 Path.Access); 1279 if (DiagID) 1280 Entity.setDiag(DiagID) << Derived << Base; 1281 1282 if (ForceUnprivileged) { 1283 switch (CheckEffectiveAccess(*this, EffectiveContext(), 1284 AccessLoc, Entity)) { 1285 case ::AR_accessible: return Sema::AR_accessible; 1286 case ::AR_inaccessible: return Sema::AR_inaccessible; 1287 case ::AR_dependent: return Sema::AR_dependent; 1288 } 1289 llvm_unreachable("unexpected result from CheckEffectiveAccess"); 1290 } 1291 return CheckAccess(*this, AccessLoc, Entity); 1292} 1293 1294/// Checks access to all the declarations in the given result set. 1295void Sema::CheckLookupAccess(const LookupResult &R) { 1296 assert(getLangOptions().AccessControl 1297 && "performing access check without access control"); 1298 assert(R.getNamingClass() && "performing access check without naming class"); 1299 1300 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { 1301 if (I.getAccess() != AS_public) { 1302 AccessTarget Entity(Context, AccessedEntity::Member, 1303 R.getNamingClass(), I.getPair(), 1304 R.getBaseObjectType()); 1305 Entity.setDiag(diag::err_access); 1306 1307 CheckAccess(*this, R.getNameLoc(), Entity); 1308 } 1309 } 1310} 1311