SemaAccess.cpp revision fe6b2d481d91140923f4541f273b253291884214
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 "Lookup.h" 16#include "clang/AST/ASTContext.h" 17#include "clang/AST/CXXInheritance.h" 18#include "clang/AST/DeclCXX.h" 19#include "clang/AST/DeclFriend.h" 20#include "clang/AST/DependentDiagnostic.h" 21#include "clang/AST/ExprCXX.h" 22 23using namespace clang; 24 25/// SetMemberAccessSpecifier - Set the access specifier of a member. 26/// Returns true on error (when the previous member decl access specifier 27/// is different from the new member decl access specifier). 28bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, 29 NamedDecl *PrevMemberDecl, 30 AccessSpecifier LexicalAS) { 31 if (!PrevMemberDecl) { 32 // Use the lexical access specifier. 33 MemberDecl->setAccess(LexicalAS); 34 return false; 35 } 36 37 // C++ [class.access.spec]p3: When a member is redeclared its access 38 // specifier must be same as its initial declaration. 39 if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { 40 Diag(MemberDecl->getLocation(), 41 diag::err_class_redeclared_with_different_access) 42 << MemberDecl << LexicalAS; 43 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) 44 << PrevMemberDecl << PrevMemberDecl->getAccess(); 45 46 MemberDecl->setAccess(LexicalAS); 47 return true; 48 } 49 50 MemberDecl->setAccess(PrevMemberDecl->getAccess()); 51 return false; 52} 53 54namespace { 55struct EffectiveContext { 56 EffectiveContext() : Inner(0), Dependent(false) {} 57 58 explicit EffectiveContext(DeclContext *DC) 59 : Inner(DC), 60 Dependent(DC->isDependentContext()) { 61 62 // C++ [class.access.nest]p1: 63 // A nested class is a member and as such has the same access 64 // rights as any other member. 65 // C++ [class.access]p2: 66 // A member of a class can also access all the names to which 67 // the class has access. A local class of a member function 68 // may access the same names that the member function itself 69 // may access. 70 // This almost implies that the privileges of nesting are transitive. 71 // Technically it says nothing about the local classes of non-member 72 // functions (which can gain privileges through friendship), but we 73 // take that as an oversight. 74 while (true) { 75 if (isa<CXXRecordDecl>(DC)) { 76 CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); 77 Records.push_back(Record); 78 DC = Record->getDeclContext(); 79 } else if (isa<FunctionDecl>(DC)) { 80 FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); 81 Functions.push_back(Function); 82 DC = Function->getDeclContext(); 83 } else if (DC->isFileContext()) { 84 break; 85 } else { 86 DC = DC->getParent(); 87 } 88 } 89 } 90 91 bool isDependent() const { return Dependent; } 92 93 bool includesClass(const CXXRecordDecl *R) const { 94 R = R->getCanonicalDecl(); 95 return std::find(Records.begin(), Records.end(), R) 96 != Records.end(); 97 } 98 99 /// Retrieves the innermost "useful" context. Can be null if we're 100 /// doing access-control without privileges. 101 DeclContext *getInnerContext() const { 102 return Inner; 103 } 104 105 typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; 106 107 DeclContext *Inner; 108 llvm::SmallVector<FunctionDecl*, 4> Functions; 109 llvm::SmallVector<CXXRecordDecl*, 4> Records; 110 bool Dependent; 111}; 112} 113 114static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { 115 DeclContext *DC = D->getDeclContext(); 116 117 // This can only happen at top: enum decls only "publish" their 118 // immediate members. 119 if (isa<EnumDecl>(DC)) 120 DC = cast<EnumDecl>(DC)->getDeclContext(); 121 122 CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); 123 while (DeclaringClass->isAnonymousStructOrUnion()) 124 DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); 125 return DeclaringClass; 126} 127 128static bool MightInstantiateTo(Sema &S, DeclContext *Context, 129 DeclContext *Friend) { 130 if (Friend == Context) 131 return true; 132 133 assert(!Friend->isDependentContext() && 134 "can't handle friends with dependent contexts here"); 135 136 if (!Context->isDependentContext()) 137 return false; 138 139 if (Friend->isFileContext()) 140 return false; 141 142 // TODO: this is very conservative 143 return true; 144} 145 146// Asks whether the type in 'context' can ever instantiate to the type 147// in 'friend'. 148static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) { 149 if (Friend == Context) 150 return true; 151 152 if (!Friend->isDependentType() && !Context->isDependentType()) 153 return false; 154 155 // TODO: this is very conservative. 156 return true; 157} 158 159static bool MightInstantiateTo(Sema &S, 160 FunctionDecl *Context, 161 FunctionDecl *Friend) { 162 if (Context->getDeclName() != Friend->getDeclName()) 163 return false; 164 165 if (!MightInstantiateTo(S, 166 Context->getDeclContext(), 167 Friend->getDeclContext())) 168 return false; 169 170 CanQual<FunctionProtoType> FriendTy 171 = S.Context.getCanonicalType(Friend->getType()) 172 ->getAs<FunctionProtoType>(); 173 CanQual<FunctionProtoType> ContextTy 174 = S.Context.getCanonicalType(Context->getType()) 175 ->getAs<FunctionProtoType>(); 176 177 // There isn't any way that I know of to add qualifiers 178 // during instantiation. 179 if (FriendTy.getQualifiers() != ContextTy.getQualifiers()) 180 return false; 181 182 if (FriendTy->getNumArgs() != ContextTy->getNumArgs()) 183 return false; 184 185 if (!MightInstantiateTo(S, 186 ContextTy->getResultType(), 187 FriendTy->getResultType())) 188 return false; 189 190 for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I) 191 if (!MightInstantiateTo(S, 192 ContextTy->getArgType(I), 193 FriendTy->getArgType(I))) 194 return false; 195 196 return true; 197} 198 199static bool MightInstantiateTo(Sema &S, 200 FunctionTemplateDecl *Context, 201 FunctionTemplateDecl *Friend) { 202 return MightInstantiateTo(S, 203 Context->getTemplatedDecl(), 204 Friend->getTemplatedDecl()); 205} 206 207static Sema::AccessResult MatchesFriend(Sema &S, 208 const EffectiveContext &EC, 209 const CXXRecordDecl *Friend) { 210 if (EC.includesClass(Friend)) 211 return Sema::AR_accessible; 212 213 if (EC.isDependent()) { 214 CanQualType FriendTy 215 = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend)); 216 217 for (EffectiveContext::record_iterator 218 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 219 CanQualType ContextTy 220 = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); 221 if (MightInstantiateTo(S, ContextTy, FriendTy)) 222 return Sema::AR_dependent; 223 } 224 } 225 226 return Sema::AR_inaccessible; 227} 228 229static Sema::AccessResult MatchesFriend(Sema &S, 230 const EffectiveContext &EC, 231 CanQualType Friend) { 232 if (const RecordType *RT = Friend->getAs<RecordType>()) 233 return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); 234 235 // TODO: we can do better than this 236 if (Friend->isDependentType()) 237 return Sema::AR_dependent; 238 239 return Sema::AR_inaccessible; 240} 241 242/// Determines whether the given friend class template matches 243/// anything in the effective context. 244static Sema::AccessResult MatchesFriend(Sema &S, 245 const EffectiveContext &EC, 246 ClassTemplateDecl *Friend) { 247 Sema::AccessResult OnFailure = Sema::AR_inaccessible; 248 249 // Check whether the friend is the template of a class in the 250 // context chain. 251 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator 252 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 253 CXXRecordDecl *Record = *I; 254 255 // Figure out whether the current class has a template: 256 ClassTemplateDecl *CTD; 257 258 // A specialization of the template... 259 if (isa<ClassTemplateSpecializationDecl>(Record)) { 260 CTD = cast<ClassTemplateSpecializationDecl>(Record) 261 ->getSpecializedTemplate(); 262 263 // ... or the template pattern itself. 264 } else { 265 CTD = Record->getDescribedClassTemplate(); 266 if (!CTD) continue; 267 } 268 269 // It's a match. 270 if (Friend == CTD->getCanonicalDecl()) 271 return Sema::AR_accessible; 272 273 // If the context isn't dependent, it can't be a dependent match. 274 if (!EC.isDependent()) 275 continue; 276 277 // If the template names don't match, it can't be a dependent 278 // match. This isn't true in C++0x because of template aliases. 279 if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) 280 continue; 281 282 // If the class's context can't instantiate to the friend's 283 // context, it can't be a dependent match. 284 if (!MightInstantiateTo(S, CTD->getDeclContext(), 285 Friend->getDeclContext())) 286 continue; 287 288 // Otherwise, it's a dependent match. 289 OnFailure = Sema::AR_dependent; 290 } 291 292 return OnFailure; 293} 294 295/// Determines whether the given friend function matches anything in 296/// the effective context. 297static Sema::AccessResult MatchesFriend(Sema &S, 298 const EffectiveContext &EC, 299 FunctionDecl *Friend) { 300 Sema::AccessResult OnFailure = Sema::AR_inaccessible; 301 302 for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator 303 I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { 304 if (Friend == *I) 305 return Sema::AR_accessible; 306 307 if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) 308 OnFailure = Sema::AR_dependent; 309 } 310 311 return OnFailure; 312} 313 314/// Determines whether the given friend function template matches 315/// anything in the effective context. 316static Sema::AccessResult MatchesFriend(Sema &S, 317 const EffectiveContext &EC, 318 FunctionTemplateDecl *Friend) { 319 if (EC.Functions.empty()) return Sema::AR_inaccessible; 320 321 Sema::AccessResult OnFailure = Sema::AR_inaccessible; 322 323 for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator 324 I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { 325 326 FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); 327 if (!FTD) 328 FTD = (*I)->getDescribedFunctionTemplate(); 329 if (!FTD) 330 continue; 331 332 FTD = FTD->getCanonicalDecl(); 333 334 if (Friend == FTD) 335 return Sema::AR_accessible; 336 337 if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) 338 OnFailure = Sema::AR_dependent; 339 } 340 341 return OnFailure; 342} 343 344/// Determines whether the given friend declaration matches anything 345/// in the effective context. 346static Sema::AccessResult MatchesFriend(Sema &S, 347 const EffectiveContext &EC, 348 FriendDecl *FriendD) { 349 if (TypeSourceInfo *T = FriendD->getFriendType()) 350 return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); 351 352 NamedDecl *Friend 353 = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl()); 354 355 // FIXME: declarations with dependent or templated scope. 356 357 if (isa<ClassTemplateDecl>(Friend)) 358 return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend)); 359 360 if (isa<FunctionTemplateDecl>(Friend)) 361 return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend)); 362 363 if (isa<CXXRecordDecl>(Friend)) 364 return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend)); 365 366 assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind"); 367 return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); 368} 369 370static Sema::AccessResult GetFriendKind(Sema &S, 371 const EffectiveContext &EC, 372 const CXXRecordDecl *Class) { 373 // A class always has access to its own members. 374 if (EC.includesClass(Class)) 375 return Sema::AR_accessible; 376 377 Sema::AccessResult OnFailure = Sema::AR_inaccessible; 378 379 // Okay, check friends. 380 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), 381 E = Class->friend_end(); I != E; ++I) { 382 FriendDecl *Friend = *I; 383 384 switch (MatchesFriend(S, EC, Friend)) { 385 case Sema::AR_accessible: 386 return Sema::AR_accessible; 387 388 case Sema::AR_inaccessible: 389 break; 390 391 case Sema::AR_dependent: 392 OnFailure = Sema::AR_dependent; 393 break; 394 395 case Sema::AR_delayed: 396 llvm_unreachable("cannot get delayed answer from MatchesFriend"); 397 } 398 } 399 400 // That's it, give up. 401 return OnFailure; 402} 403 404/// Finds the best path from the naming class to the declaring class, 405/// taking friend declarations into account. 406/// 407/// \param FinalAccess the access of the "final step", or AS_none if 408/// there is no final step. 409/// \return null if friendship is dependent 410static CXXBasePath *FindBestPath(Sema &S, 411 const EffectiveContext &EC, 412 CXXRecordDecl *Derived, 413 CXXRecordDecl *Base, 414 AccessSpecifier FinalAccess, 415 CXXBasePaths &Paths) { 416 // Derive the paths to the desired base. 417 bool isDerived = Derived->isDerivedFrom(Base, Paths); 418 assert(isDerived && "derived class not actually derived from base"); 419 (void) isDerived; 420 421 CXXBasePath *BestPath = 0; 422 423 assert(FinalAccess != AS_none && "forbidden access after declaring class"); 424 425 bool AnyDependent = false; 426 427 // Derive the friend-modified access along each path. 428 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); 429 PI != PE; ++PI) { 430 431 // Walk through the path backwards. 432 AccessSpecifier PathAccess = FinalAccess; 433 CXXBasePath::iterator I = PI->end(), E = PI->begin(); 434 while (I != E) { 435 --I; 436 437 assert(PathAccess != AS_none); 438 439 // If the declaration is a private member of a base class, there 440 // is no level of friendship in derived classes that can make it 441 // accessible. 442 if (PathAccess == AS_private) { 443 PathAccess = AS_none; 444 break; 445 } 446 447 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); 448 if (BaseAccess != AS_public || PathAccess != AS_public) { 449 switch (GetFriendKind(S, EC, I->Class)) { 450 case Sema::AR_inaccessible: 451 PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess); 452 break; 453 case Sema::AR_accessible: 454 PathAccess = AS_public; 455 break; 456 case Sema::AR_dependent: 457 AnyDependent = true; 458 goto Next; 459 case Sema::AR_delayed: 460 llvm_unreachable("friend resolution is never delayed"); break; 461 } 462 } 463 } 464 465 // Note that we modify the path's Access field to the 466 // friend-modified access. 467 if (BestPath == 0 || PathAccess < BestPath->Access) { 468 BestPath = &*PI; 469 BestPath->Access = PathAccess; 470 471 // Short-circuit if we found a public path. 472 if (BestPath->Access == AS_public) 473 return BestPath; 474 } 475 476 Next: ; 477 } 478 479 assert((!BestPath || BestPath->Access != AS_public) && 480 "fell out of loop with public path"); 481 482 // We didn't find a public path, but at least one path was subject 483 // to dependent friendship, so delay the check. 484 if (AnyDependent) 485 return 0; 486 487 return BestPath; 488} 489 490/// Diagnose the path which caused the given declaration or base class 491/// to become inaccessible. 492static void DiagnoseAccessPath(Sema &S, 493 const EffectiveContext &EC, 494 CXXRecordDecl *NamingClass, 495 CXXRecordDecl *DeclaringClass, 496 NamedDecl *D, AccessSpecifier Access) { 497 // Easy case: the decl's natural access determined its path access. 498 // We have to check against AS_private here in case Access is AS_none, 499 // indicating a non-public member of a private base class. 500 // 501 // DependentFriend should be impossible here. 502 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) { 503 switch (GetFriendKind(S, EC, DeclaringClass)) { 504 case Sema::AR_inaccessible: { 505 S.Diag(D->getLocation(), diag::note_access_natural) 506 << (unsigned) (Access == AS_protected) 507 << /*FIXME: not implicitly*/ 0; 508 return; 509 } 510 511 case Sema::AR_accessible: break; 512 513 case Sema::AR_dependent: 514 case Sema::AR_delayed: 515 llvm_unreachable("dependent/delayed not allowed"); 516 return; 517 } 518 } 519 520 CXXBasePaths Paths; 521 CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, 522 AS_public, Paths); 523 524 CXXBasePath::iterator I = Path.end(), E = Path.begin(); 525 while (I != E) { 526 --I; 527 528 const CXXBaseSpecifier *BS = I->Base; 529 AccessSpecifier BaseAccess = BS->getAccessSpecifier(); 530 531 // If this is public inheritance, or the derived class is a friend, 532 // skip this step. 533 if (BaseAccess == AS_public) 534 continue; 535 536 switch (GetFriendKind(S, EC, I->Class)) { 537 case Sema::AR_accessible: continue; 538 case Sema::AR_inaccessible: break; 539 540 case Sema::AR_dependent: 541 case Sema::AR_delayed: 542 llvm_unreachable("dependent friendship, should not be diagnosing"); 543 } 544 545 // Check whether this base specifier is the tighest point 546 // constraining access. We have to check against AS_private for 547 // the same reasons as above. 548 if (BaseAccess == AS_private || BaseAccess >= Access) { 549 550 // We're constrained by inheritance, but we want to say 551 // "declared private here" if we're diagnosing a hierarchy 552 // conversion and this is the final step. 553 unsigned diagnostic; 554 if (D) diagnostic = diag::note_access_constrained_by_path; 555 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural; 556 else diagnostic = diag::note_access_constrained_by_path; 557 558 S.Diag(BS->getSourceRange().getBegin(), diagnostic) 559 << BS->getSourceRange() 560 << (BaseAccess == AS_protected) 561 << (BS->getAccessSpecifierAsWritten() == AS_none); 562 return; 563 } 564 } 565 566 llvm_unreachable("access not apparently constrained by path"); 567} 568 569/// Diagnose an inaccessible class member. 570static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc, 571 const EffectiveContext &EC, 572 CXXRecordDecl *NamingClass, 573 AccessSpecifier Access, 574 const Sema::AccessedEntity &Entity) { 575 NamedDecl *D = Entity.getTargetDecl(); 576 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); 577 578 S.Diag(Loc, Entity.getDiag()) 579 << (Access == AS_protected) 580 << D->getDeclName() 581 << S.Context.getTypeDeclType(NamingClass) 582 << S.Context.getTypeDeclType(DeclaringClass); 583 DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access); 584} 585 586/// Diagnose an inaccessible hierarchy conversion. 587static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc, 588 const EffectiveContext &EC, 589 AccessSpecifier Access, 590 const Sema::AccessedEntity &Entity) { 591 S.Diag(Loc, Entity.getDiag()) 592 << (Access == AS_protected) 593 << DeclarationName() 594 << S.Context.getTypeDeclType(Entity.getDerivedClass()) 595 << S.Context.getTypeDeclType(Entity.getBaseClass()); 596 DiagnoseAccessPath(S, EC, Entity.getDerivedClass(), 597 Entity.getBaseClass(), 0, Access); 598} 599 600static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, 601 const EffectiveContext &EC, 602 CXXRecordDecl *NamingClass, 603 AccessSpecifier Access, 604 const Sema::AccessedEntity &Entity) { 605 if (Entity.isMemberAccess()) 606 DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity); 607 else 608 DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity); 609} 610 611 612/// Try to elevate access using friend declarations. This is 613/// potentially quite expensive. 614/// 615/// \return true if elevation was dependent 616static bool TryElevateAccess(Sema &S, 617 const EffectiveContext &EC, 618 const Sema::AccessedEntity &Entity, 619 AccessSpecifier &Access) { 620 CXXRecordDecl *DeclaringClass; 621 if (Entity.isMemberAccess()) { 622 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl()); 623 } else { 624 DeclaringClass = Entity.getBaseClass(); 625 } 626 CXXRecordDecl *NamingClass = Entity.getNamingClass(); 627 628 // Adjust the declaration of the referred entity. 629 AccessSpecifier DeclAccess = AS_public; 630 if (Entity.isMemberAccess()) { 631 NamedDecl *Target = Entity.getTargetDecl(); 632 633 DeclAccess = Target->getAccess(); 634 if (DeclAccess != AS_public) { 635 switch (GetFriendKind(S, EC, DeclaringClass)) { 636 case Sema::AR_accessible: DeclAccess = AS_public; break; 637 case Sema::AR_inaccessible: break; 638 case Sema::AR_dependent: return true; 639 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed"); 640 } 641 } 642 643 if (DeclaringClass == NamingClass) { 644 Access = DeclAccess; 645 return false; 646 } 647 } 648 649 assert(DeclaringClass != NamingClass); 650 651 // Append the declaration's access if applicable. 652 CXXBasePaths Paths; 653 CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(), 654 DeclaringClass, DeclAccess, Paths); 655 if (!Path) 656 return true; 657 658 // Grab the access along the best path (note that this includes the 659 // final-step access). 660 AccessSpecifier NewAccess = Path->Access; 661 assert(NewAccess <= Access && "access along best path worse than direct?"); 662 Access = NewAccess; 663 return false; 664} 665 666static void DelayAccess(Sema &S, 667 const EffectiveContext &EC, 668 SourceLocation Loc, 669 const Sema::AccessedEntity &Entity) { 670 assert(EC.isDependent() && "delaying non-dependent access"); 671 DeclContext *DC = EC.getInnerContext(); 672 assert(DC->isDependentContext() && "delaying non-dependent access"); 673 DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access, 674 Loc, 675 Entity.isMemberAccess(), 676 Entity.getAccess(), 677 Entity.getTargetDecl(), 678 Entity.getNamingClass(), 679 Entity.getDiag()); 680} 681 682/// Checks access to an entity from the given effective context. 683static Sema::AccessResult CheckEffectiveAccess(Sema &S, 684 const EffectiveContext &EC, 685 SourceLocation Loc, 686 Sema::AccessedEntity const &Entity) { 687 AccessSpecifier Access = Entity.getAccess(); 688 assert(Access != AS_public && "called for public access!"); 689 690 // Find a non-anonymous naming class. For records with access, 691 // there should always be one of these. 692 CXXRecordDecl *NamingClass = Entity.getNamingClass(); 693 while (NamingClass->isAnonymousStructOrUnion()) 694 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); 695 696 // White-list accesses from classes with privileges equivalent to the 697 // naming class --- but only if the access path isn't forbidden 698 // (i.e. an access of a private member from a subclass). 699 if (Access != AS_none && EC.includesClass(NamingClass)) 700 return Sema::AR_accessible; 701 702 // Try to elevate access. 703 // TODO: on some code, it might be better to do the protected check 704 // without trying to elevate first. 705 if (TryElevateAccess(S, EC, Entity, Access)) { 706 DelayAccess(S, EC, Loc, Entity); 707 return Sema::AR_dependent; 708 } 709 710 if (Access == AS_public) return Sema::AR_accessible; 711 712 // Protected access. 713 if (Access == AS_protected) { 714 // FIXME: implement [class.protected]p1 715 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator 716 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) 717 if ((*I)->isDerivedFrom(NamingClass)) 718 return Sema::AR_accessible; 719 720 // FIXME: delay if we can't decide class derivation yet. 721 } 722 723 // Okay, that's it, reject it. 724 if (!Entity.isQuiet()) 725 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); 726 return Sema::AR_inaccessible; 727} 728 729static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, 730 const Sema::AccessedEntity &Entity) { 731 // If the access path is public, it's accessible everywhere. 732 if (Entity.getAccess() == AS_public) 733 return Sema::AR_accessible; 734 735 // If we're currently parsing a top-level declaration, delay 736 // diagnostics. This is the only case where parsing a declaration 737 // can actually change our effective context for the purposes of 738 // access control. 739 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) { 740 S.DelayedDiagnostics.push_back( 741 Sema::DelayedDiagnostic::makeAccess(Loc, Entity)); 742 return Sema::AR_delayed; 743 } 744 745 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext), 746 Loc, Entity); 747} 748 749void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { 750 // Pretend we did this from the context of the newly-parsed 751 // declaration. 752 EffectiveContext EC(Ctx->getDeclContext()); 753 754 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData())) 755 DD.Triggered = true; 756} 757 758void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, 759 const MultiLevelTemplateArgumentList &TemplateArgs) { 760 SourceLocation Loc = DD.getAccessLoc(); 761 AccessSpecifier Access = DD.getAccess(); 762 763 Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(), 764 TemplateArgs); 765 if (!NamingD) return; 766 Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(), 767 TemplateArgs); 768 if (!TargetD) return; 769 770 if (DD.isAccessToMember()) { 771 AccessedEntity Entity(Context, 772 AccessedEntity::Member, 773 cast<CXXRecordDecl>(NamingD), 774 Access, 775 cast<NamedDecl>(TargetD)); 776 Entity.setDiag(DD.getDiagnostic()); 777 CheckAccess(*this, Loc, Entity); 778 } else { 779 AccessedEntity Entity(Context, 780 AccessedEntity::Base, 781 cast<CXXRecordDecl>(TargetD), 782 cast<CXXRecordDecl>(NamingD), 783 Access); 784 Entity.setDiag(DD.getDiagnostic()); 785 CheckAccess(*this, Loc, Entity); 786 } 787} 788 789Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, 790 DeclAccessPair Found) { 791 if (!getLangOptions().AccessControl || 792 !E->getNamingClass() || 793 Found.getAccess() == AS_public) 794 return AR_accessible; 795 796 AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), 797 Found); 798 Entity.setDiag(diag::err_access) << E->getSourceRange(); 799 800 return CheckAccess(*this, E->getNameLoc(), Entity); 801} 802 803/// Perform access-control checking on a previously-unresolved member 804/// access which has now been resolved to a member. 805Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, 806 DeclAccessPair Found) { 807 if (!getLangOptions().AccessControl || 808 Found.getAccess() == AS_public) 809 return AR_accessible; 810 811 AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), 812 Found); 813 Entity.setDiag(diag::err_access) << E->getSourceRange(); 814 815 return CheckAccess(*this, E->getMemberLoc(), Entity); 816} 817 818Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, 819 CXXDestructorDecl *Dtor, 820 const PartialDiagnostic &PDiag) { 821 if (!getLangOptions().AccessControl) 822 return AR_accessible; 823 824 // There's never a path involved when checking implicit destructor access. 825 AccessSpecifier Access = Dtor->getAccess(); 826 if (Access == AS_public) 827 return AR_accessible; 828 829 CXXRecordDecl *NamingClass = Dtor->getParent(); 830 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, 831 DeclAccessPair::make(Dtor, Access)); 832 Entity.setDiag(PDiag); // TODO: avoid copy 833 834 return CheckAccess(*this, Loc, Entity); 835} 836 837/// Checks access to a constructor. 838Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, 839 CXXConstructorDecl *Constructor, 840 AccessSpecifier Access) { 841 if (!getLangOptions().AccessControl || 842 Access == AS_public) 843 return AR_accessible; 844 845 CXXRecordDecl *NamingClass = Constructor->getParent(); 846 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, 847 DeclAccessPair::make(Constructor, Access)); 848 Entity.setDiag(diag::err_access_ctor); 849 850 return CheckAccess(*this, UseLoc, Entity); 851} 852 853/// Checks direct (i.e. non-inherited) access to an arbitrary class 854/// member. 855Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, 856 NamedDecl *Target, 857 const PartialDiagnostic &Diag) { 858 AccessSpecifier Access = Target->getAccess(); 859 if (!getLangOptions().AccessControl || 860 Access == AS_public) 861 return AR_accessible; 862 863 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); 864 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, 865 DeclAccessPair::make(Target, Access)); 866 Entity.setDiag(Diag); 867 return CheckAccess(*this, UseLoc, Entity); 868} 869 870 871/// Checks access to an overloaded operator new or delete. 872Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, 873 SourceRange PlacementRange, 874 CXXRecordDecl *NamingClass, 875 DeclAccessPair Found) { 876 if (!getLangOptions().AccessControl || 877 !NamingClass || 878 Found.getAccess() == AS_public) 879 return AR_accessible; 880 881 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); 882 Entity.setDiag(diag::err_access) 883 << PlacementRange; 884 885 return CheckAccess(*this, OpLoc, Entity); 886} 887 888/// Checks access to an overloaded member operator, including 889/// conversion operators. 890Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, 891 Expr *ObjectExpr, 892 Expr *ArgExpr, 893 DeclAccessPair Found) { 894 if (!getLangOptions().AccessControl || 895 Found.getAccess() == AS_public) 896 return AR_accessible; 897 898 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>(); 899 assert(RT && "found member operator but object expr not of record type"); 900 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); 901 902 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); 903 Entity.setDiag(diag::err_access) 904 << ObjectExpr->getSourceRange() 905 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); 906 907 return CheckAccess(*this, OpLoc, Entity); 908} 909 910/// Checks access for a hierarchy conversion. 911/// 912/// \param IsBaseToDerived whether this is a base-to-derived conversion (true) 913/// or a derived-to-base conversion (false) 914/// \param ForceCheck true if this check should be performed even if access 915/// control is disabled; some things rely on this for semantics 916/// \param ForceUnprivileged true if this check should proceed as if the 917/// context had no special privileges 918/// \param ADK controls the kind of diagnostics that are used 919Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, 920 QualType Base, 921 QualType Derived, 922 const CXXBasePath &Path, 923 unsigned DiagID, 924 bool ForceCheck, 925 bool ForceUnprivileged) { 926 if (!ForceCheck && !getLangOptions().AccessControl) 927 return AR_accessible; 928 929 if (Path.Access == AS_public) 930 return AR_accessible; 931 932 CXXRecordDecl *BaseD, *DerivedD; 933 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); 934 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); 935 936 AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD, 937 Path.Access); 938 if (DiagID) 939 Entity.setDiag(DiagID) << Derived << Base; 940 941 if (ForceUnprivileged) 942 return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity); 943 return CheckAccess(*this, AccessLoc, Entity); 944} 945 946/// Checks access to all the declarations in the given result set. 947void Sema::CheckLookupAccess(const LookupResult &R) { 948 assert(getLangOptions().AccessControl 949 && "performing access check without access control"); 950 assert(R.getNamingClass() && "performing access check without naming class"); 951 952 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { 953 if (I.getAccess() != AS_public) { 954 AccessedEntity Entity(Context, AccessedEntity::Member, 955 R.getNamingClass(), 956 I.getPair()); 957 Entity.setDiag(diag::err_access); 958 959 CheckAccess(*this, R.getNameLoc(), Entity); 960 } 961 } 962} 963