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