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