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