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