SemaAccess.cpp revision 7aceaf8cee77c98478e8934dc283910292711a7e
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/ExprCXX.h" 21 22using namespace clang; 23 24/// SetMemberAccessSpecifier - Set the access specifier of a member. 25/// Returns true on error (when the previous member decl access specifier 26/// is different from the new member decl access specifier). 27bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, 28 NamedDecl *PrevMemberDecl, 29 AccessSpecifier LexicalAS) { 30 if (!PrevMemberDecl) { 31 // Use the lexical access specifier. 32 MemberDecl->setAccess(LexicalAS); 33 return false; 34 } 35 36 // C++ [class.access.spec]p3: When a member is redeclared its access 37 // specifier must be same as its initial declaration. 38 if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { 39 Diag(MemberDecl->getLocation(), 40 diag::err_class_redeclared_with_different_access) 41 << MemberDecl << LexicalAS; 42 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) 43 << PrevMemberDecl << PrevMemberDecl->getAccess(); 44 45 MemberDecl->setAccess(LexicalAS); 46 return true; 47 } 48 49 MemberDecl->setAccess(PrevMemberDecl->getAccess()); 50 return false; 51} 52 53namespace { 54struct EffectiveContext { 55 EffectiveContext() : Function(0) {} 56 57 explicit EffectiveContext(DeclContext *DC) { 58 if (isa<FunctionDecl>(DC)) { 59 Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); 60 DC = Function->getDeclContext(); 61 } else 62 Function = 0; 63 64 // C++ [class.access.nest]p1: 65 // A nested class is a member and as such has the same access 66 // rights as any other member. 67 // C++ [class.access]p2: 68 // A member of a class can also access all the names to which 69 // the class has access. 70 // This implies that the privileges of nesting are transitive. 71 while (isa<CXXRecordDecl>(DC)) { 72 CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); 73 Records.push_back(Record); 74 DC = Record->getDeclContext(); 75 } 76 } 77 78 bool includesClass(const CXXRecordDecl *R) const { 79 R = R->getCanonicalDecl(); 80 return std::find(Records.begin(), Records.end(), R) 81 != Records.end(); 82 } 83 84 llvm::SmallVector<CXXRecordDecl*, 4> Records; 85 FunctionDecl *Function; 86}; 87} 88 89static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { 90 CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext()); 91 while (DeclaringClass->isAnonymousStructOrUnion()) 92 DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); 93 return DeclaringClass; 94} 95 96static Sema::AccessResult MatchesFriend(Sema &S, 97 const EffectiveContext &EC, 98 const CXXRecordDecl *Friend) { 99 // FIXME: close matches becuse of dependency 100 if (EC.includesClass(Friend)) 101 return Sema::AR_accessible; 102 103 return Sema::AR_inaccessible; 104} 105 106static Sema::AccessResult MatchesFriend(Sema &S, 107 const EffectiveContext &EC, 108 FriendDecl *Friend) { 109 if (Type *T = Friend->getFriendType()) { 110 CanQualType CT = T->getCanonicalTypeUnqualified(); 111 if (const RecordType *RT = CT->getAs<RecordType>()) 112 return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); 113 114 // TODO: we can fail early for a lot of type classes. 115 if (T->isDependentType()) 116 return Sema::AR_dependent; 117 118 return Sema::AR_inaccessible; 119 } 120 121 NamedDecl *D 122 = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl()); 123 124 // FIXME: declarations with dependent or templated scope. 125 126 // For class templates, we want to check whether any of the records 127 // are possible specializations of the template. 128 if (isa<ClassTemplateDecl>(D)) { 129 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator 130 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { 131 CXXRecordDecl *Record = *I; 132 ClassTemplateDecl *CTD; 133 134 // A specialization of the template... 135 if (isa<ClassTemplateSpecializationDecl>(Record)) { 136 CTD = cast<ClassTemplateSpecializationDecl>(Record) 137 ->getSpecializedTemplate(); 138 139 // ... or the template pattern itself. 140 } else { 141 CTD = Record->getDescribedClassTemplate(); 142 } 143 144 if (CTD && D == CTD->getCanonicalDecl()) 145 return Sema::AR_accessible; 146 } 147 148 return Sema::AR_inaccessible; 149 } 150 151 // Same thing for function templates. 152 if (isa<FunctionTemplateDecl>(D)) { 153 if (!EC.Function) return Sema::AR_inaccessible; 154 155 FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate(); 156 if (!FTD) 157 FTD = EC.Function->getDescribedFunctionTemplate(); 158 159 if (FTD && D == FTD->getCanonicalDecl()) 160 return Sema::AR_accessible; 161 162 return Sema::AR_inaccessible; 163 } 164 165 // Friend functions. FIXME: close matches due to dependency. 166 // 167 // The decl pointers in EC have been canonicalized, so pointer 168 // equality is sufficient. 169 if (D == EC.Function) 170 return Sema::AR_accessible; 171 172 if (isa<CXXRecordDecl>(D)) 173 return MatchesFriend(S, EC, cast<CXXRecordDecl>(D)); 174 175 return Sema::AR_inaccessible; 176} 177 178static Sema::AccessResult GetFriendKind(Sema &S, 179 const EffectiveContext &EC, 180 const CXXRecordDecl *Class) { 181 // A class always has access to its own members. 182 if (EC.includesClass(Class)) 183 return Sema::AR_accessible; 184 185 Sema::AccessResult OnFailure = Sema::AR_inaccessible; 186 187 // Okay, check friends. 188 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), 189 E = Class->friend_end(); I != E; ++I) { 190 FriendDecl *Friend = *I; 191 192 switch (MatchesFriend(S, EC, Friend)) { 193 case Sema::AR_accessible: 194 return Sema::AR_accessible; 195 196 case Sema::AR_inaccessible: 197 break; 198 199 case Sema::AR_dependent: 200 OnFailure = Sema::AR_dependent; 201 break; 202 203 case Sema::AR_delayed: 204 llvm_unreachable("cannot get delayed answer from MatchesFriend"); 205 } 206 } 207 208 // That's it, give up. 209 return OnFailure; 210} 211 212/// Finds the best path from the naming class to the declaring class, 213/// taking friend declarations into account. 214/// 215/// \param FinalAccess the access of the "final step", or AS_none if 216/// there is no final step. 217/// \return null if friendship is dependent 218static CXXBasePath *FindBestPath(Sema &S, 219 const EffectiveContext &EC, 220 CXXRecordDecl *Derived, 221 CXXRecordDecl *Base, 222 AccessSpecifier FinalAccess, 223 CXXBasePaths &Paths) { 224 // Derive the paths to the desired base. 225 bool isDerived = Derived->isDerivedFrom(Base, Paths); 226 assert(isDerived && "derived class not actually derived from base"); 227 (void) isDerived; 228 229 CXXBasePath *BestPath = 0; 230 231 assert(FinalAccess != AS_none && "forbidden access after declaring class"); 232 233 // Derive the friend-modified access along each path. 234 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); 235 PI != PE; ++PI) { 236 237 // Walk through the path backwards. 238 AccessSpecifier PathAccess = FinalAccess; 239 CXXBasePath::iterator I = PI->end(), E = PI->begin(); 240 while (I != E) { 241 --I; 242 243 assert(PathAccess != AS_none); 244 245 // If the declaration is a private member of a base class, there 246 // is no level of friendship in derived classes that can make it 247 // accessible. 248 if (PathAccess == AS_private) { 249 PathAccess = AS_none; 250 break; 251 } 252 253 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); 254 if (BaseAccess != AS_public) { 255 switch (GetFriendKind(S, EC, I->Class)) { 256 case Sema::AR_inaccessible: 257 PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess); 258 break; 259 case Sema::AR_accessible: 260 PathAccess = AS_public; 261 break; 262 case Sema::AR_dependent: 263 return 0; 264 case Sema::AR_delayed: 265 llvm_unreachable("friend resolution is never delayed"); break; 266 } 267 } 268 } 269 270 // Note that we modify the path's Access field to the 271 // friend-modified access. 272 if (BestPath == 0 || PathAccess < BestPath->Access) { 273 BestPath = &*PI; 274 BestPath->Access = PathAccess; 275 } 276 } 277 278 return BestPath; 279} 280 281/// Diagnose the path which caused the given declaration or base class 282/// to become inaccessible. 283static void DiagnoseAccessPath(Sema &S, 284 const EffectiveContext &EC, 285 CXXRecordDecl *NamingClass, 286 CXXRecordDecl *DeclaringClass, 287 NamedDecl *D, AccessSpecifier Access) { 288 // Easy case: the decl's natural access determined its path access. 289 // We have to check against AS_private here in case Access is AS_none, 290 // indicating a non-public member of a private base class. 291 // 292 // DependentFriend should be impossible here. 293 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) { 294 switch (GetFriendKind(S, EC, DeclaringClass)) { 295 case Sema::AR_inaccessible: { 296 S.Diag(D->getLocation(), diag::note_access_natural) 297 << (unsigned) (Access == AS_protected) 298 << /*FIXME: not implicitly*/ 0; 299 return; 300 } 301 302 case Sema::AR_accessible: break; 303 304 case Sema::AR_dependent: 305 case Sema::AR_delayed: 306 llvm_unreachable("dependent/delayed not allowed"); 307 return; 308 } 309 } 310 311 CXXBasePaths Paths; 312 CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, 313 AS_public, Paths); 314 315 CXXBasePath::iterator I = Path.end(), E = Path.begin(); 316 while (I != E) { 317 --I; 318 319 const CXXBaseSpecifier *BS = I->Base; 320 AccessSpecifier BaseAccess = BS->getAccessSpecifier(); 321 322 // If this is public inheritance, or the derived class is a friend, 323 // skip this step. 324 if (BaseAccess == AS_public) 325 continue; 326 327 switch (GetFriendKind(S, EC, I->Class)) { 328 case Sema::AR_accessible: continue; 329 case Sema::AR_inaccessible: break; 330 331 case Sema::AR_dependent: 332 case Sema::AR_delayed: 333 llvm_unreachable("dependent friendship, should not be diagnosing"); 334 } 335 336 // Check whether this base specifier is the tighest point 337 // constraining access. We have to check against AS_private for 338 // the same reasons as above. 339 if (BaseAccess == AS_private || BaseAccess >= Access) { 340 341 // We're constrained by inheritance, but we want to say 342 // "declared private here" if we're diagnosing a hierarchy 343 // conversion and this is the final step. 344 unsigned diagnostic; 345 if (D) diagnostic = diag::note_access_constrained_by_path; 346 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural; 347 else diagnostic = diag::note_access_constrained_by_path; 348 349 S.Diag(BS->getSourceRange().getBegin(), diagnostic) 350 << BS->getSourceRange() 351 << (BaseAccess == AS_protected) 352 << (BS->getAccessSpecifierAsWritten() == AS_none); 353 return; 354 } 355 } 356 357 llvm_unreachable("access not apparently constrained by path"); 358} 359 360/// Diagnose an inaccessible class member. 361static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc, 362 const EffectiveContext &EC, 363 CXXRecordDecl *NamingClass, 364 AccessSpecifier Access, 365 const Sema::AccessedEntity &Entity) { 366 NamedDecl *D = Entity.getTargetDecl(); 367 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); 368 369 S.Diag(Loc, Entity.getDiag()) 370 << (Access == AS_protected) 371 << D->getDeclName() 372 << S.Context.getTypeDeclType(NamingClass) 373 << S.Context.getTypeDeclType(DeclaringClass); 374 DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access); 375} 376 377/// Diagnose an inaccessible hierarchy conversion. 378static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc, 379 const EffectiveContext &EC, 380 AccessSpecifier Access, 381 const Sema::AccessedEntity &Entity) { 382 S.Diag(Loc, Entity.getDiag()) 383 << (Access == AS_protected) 384 << DeclarationName() 385 << S.Context.getTypeDeclType(Entity.getDerivedClass()) 386 << S.Context.getTypeDeclType(Entity.getBaseClass()); 387 DiagnoseAccessPath(S, EC, Entity.getDerivedClass(), 388 Entity.getBaseClass(), 0, Access); 389} 390 391static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, 392 const EffectiveContext &EC, 393 CXXRecordDecl *NamingClass, 394 AccessSpecifier Access, 395 const Sema::AccessedEntity &Entity) { 396 if (Entity.isMemberAccess()) 397 DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity); 398 else 399 DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity); 400} 401 402 403/// Try to elevate access using friend declarations. This is 404/// potentially quite expensive. 405static void TryElevateAccess(Sema &S, 406 const EffectiveContext &EC, 407 const Sema::AccessedEntity &Entity, 408 AccessSpecifier &Access) { 409 CXXRecordDecl *DeclaringClass; 410 if (Entity.isMemberAccess()) { 411 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl()); 412 } else { 413 DeclaringClass = Entity.getBaseClass(); 414 } 415 CXXRecordDecl *NamingClass = Entity.getNamingClass(); 416 417 // Adjust the declaration of the referred entity. 418 AccessSpecifier DeclAccess = AS_public; 419 if (Entity.isMemberAccess()) { 420 NamedDecl *Target = Entity.getTargetDecl(); 421 422 DeclAccess = Target->getAccess(); 423 if (DeclAccess != AS_public) { 424 switch (GetFriendKind(S, EC, DeclaringClass)) { 425 case Sema::AR_accessible: DeclAccess = AS_public; break; 426 case Sema::AR_inaccessible: break; 427 case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return; 428 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed"); 429 } 430 } 431 432 if (DeclaringClass == NamingClass) { 433 Access = DeclAccess; 434 return; 435 } 436 } 437 438 assert(DeclaringClass != NamingClass); 439 440 // Append the declaration's access if applicable. 441 CXXBasePaths Paths; 442 CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(), 443 DeclaringClass, DeclAccess, Paths); 444 if (!Path) { 445 // FIXME: delay dependent friendship 446 return; 447 } 448 449 // Grab the access along the best path (note that this includes the 450 // final-step access). 451 AccessSpecifier NewAccess = Path->Access; 452 assert(NewAccess <= Access && "access along best path worse than direct?"); 453 Access = NewAccess; 454} 455 456/// Checks access to an entity from the given effective context. 457static Sema::AccessResult CheckEffectiveAccess(Sema &S, 458 const EffectiveContext &EC, 459 SourceLocation Loc, 460 Sema::AccessedEntity const &Entity) { 461 AccessSpecifier Access = Entity.getAccess(); 462 assert(Access != AS_public && "called for public access!"); 463 464 // Find a non-anonymous naming class. For records with access, 465 // there should always be one of these. 466 CXXRecordDecl *NamingClass = Entity.getNamingClass(); 467 while (NamingClass->isAnonymousStructOrUnion()) 468 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); 469 470 // White-list accesses from classes with privileges equivalent to the 471 // naming class --- but only if the access path isn't forbidden 472 // (i.e. an access of a private member from a subclass). 473 if (Access != AS_none && EC.includesClass(NamingClass)) 474 return Sema::AR_accessible; 475 476 // Try to elevate access. 477 // FIXME: delay if elevation was dependent? 478 // TODO: on some code, it might be better to do the protected check 479 // without trying to elevate first. 480 TryElevateAccess(S, EC, Entity, Access); 481 if (Access == AS_public) return Sema::AR_accessible; 482 483 // Protected access. 484 if (Access == AS_protected) { 485 // FIXME: implement [class.protected]p1 486 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator 487 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) 488 if ((*I)->isDerivedFrom(NamingClass)) 489 return Sema::AR_accessible; 490 491 // FIXME: delay if we can't decide class derivation yet. 492 } 493 494 // Okay, that's it, reject it. 495 if (!Entity.isQuiet()) 496 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); 497 return Sema::AR_inaccessible; 498} 499 500static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, 501 const Sema::AccessedEntity &Entity) { 502 // If the access path is public, it's accessible everywhere. 503 if (Entity.getAccess() == AS_public) 504 return Sema::AR_accessible; 505 506 // If we're currently parsing a top-level declaration, delay 507 // diagnostics. This is the only case where parsing a declaration 508 // can actually change our effective context for the purposes of 509 // access control. 510 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) { 511 S.DelayedDiagnostics.push_back( 512 Sema::DelayedDiagnostic::makeAccess(Loc, Entity)); 513 return Sema::AR_delayed; 514 } 515 516 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext), 517 Loc, Entity); 518} 519 520void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { 521 // Pretend we did this from the context of the newly-parsed 522 // declaration. 523 EffectiveContext EC(Ctx->getDeclContext()); 524 525 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData())) 526 DD.Triggered = true; 527} 528 529Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, 530 NamedDecl *D, 531 AccessSpecifier Access) { 532 if (!getLangOptions().AccessControl || 533 !E->getNamingClass() || 534 Access == AS_public) 535 return AR_accessible; 536 537 AccessedEntity Entity(AccessedEntity::Member, 538 E->getNamingClass(), Access, D); 539 Entity.setDiag(diag::err_access) << E->getSourceRange(); 540 541 return CheckAccess(*this, E->getNameLoc(), Entity); 542} 543 544/// Perform access-control checking on a previously-unresolved member 545/// access which has now been resolved to a member. 546Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, 547 NamedDecl *D, 548 AccessSpecifier Access) { 549 if (!getLangOptions().AccessControl || 550 Access == AS_public) 551 return AR_accessible; 552 553 AccessedEntity Entity(AccessedEntity::Member, 554 E->getNamingClass(), Access, D); 555 Entity.setDiag(diag::err_access) << E->getSourceRange(); 556 557 return CheckAccess(*this, E->getMemberLoc(), Entity); 558} 559 560Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, 561 CXXDestructorDecl *Dtor, 562 const PartialDiagnostic &PDiag) { 563 if (!getLangOptions().AccessControl) 564 return AR_accessible; 565 566 // There's never a path involved when checking implicit destructor access. 567 AccessSpecifier Access = Dtor->getAccess(); 568 if (Access == AS_public) 569 return AR_accessible; 570 571 CXXRecordDecl *NamingClass = Dtor->getParent(); 572 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor); 573 Entity.setDiag(PDiag); // TODO: avoid copy 574 575 return CheckAccess(*this, Loc, Entity); 576} 577 578/// Checks access to a constructor. 579Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, 580 CXXConstructorDecl *Constructor, 581 AccessSpecifier Access) { 582 if (!getLangOptions().AccessControl || 583 Access == AS_public) 584 return AR_accessible; 585 586 CXXRecordDecl *NamingClass = Constructor->getParent(); 587 AccessedEntity Entity(AccessedEntity::Member, 588 NamingClass, Access, Constructor); 589 Entity.setDiag(diag::err_access_ctor); 590 591 return CheckAccess(*this, UseLoc, Entity); 592} 593 594/// Checks direct (i.e. non-inherited) access to an arbitrary class 595/// member. 596Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, 597 NamedDecl *Target, 598 const PartialDiagnostic &Diag) { 599 AccessSpecifier Access = Target->getAccess(); 600 if (!getLangOptions().AccessControl || 601 Access == AS_public) 602 return AR_accessible; 603 604 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); 605 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target); 606 Entity.setDiag(Diag); 607 return CheckAccess(*this, UseLoc, Entity); 608} 609 610 611/// Checks access to an overloaded operator new or delete. 612Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, 613 SourceRange PlacementRange, 614 CXXRecordDecl *NamingClass, 615 NamedDecl *Fn, 616 AccessSpecifier Access) { 617 if (!getLangOptions().AccessControl || 618 !NamingClass || 619 Access == AS_public) 620 return AR_accessible; 621 622 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Fn); 623 Entity.setDiag(diag::err_access) 624 << PlacementRange; 625 626 return CheckAccess(*this, OpLoc, Entity); 627} 628 629/// Checks access to an overloaded member operator, including 630/// conversion operators. 631Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, 632 Expr *ObjectExpr, 633 Expr *ArgExpr, 634 NamedDecl *MemberOperator, 635 AccessSpecifier Access) { 636 if (!getLangOptions().AccessControl || 637 Access == AS_public) 638 return AR_accessible; 639 640 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>(); 641 assert(RT && "found member operator but object expr not of record type"); 642 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); 643 644 AccessedEntity Entity(AccessedEntity::Member, 645 NamingClass, Access, MemberOperator); 646 Entity.setDiag(diag::err_access) 647 << ObjectExpr->getSourceRange() 648 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); 649 650 return CheckAccess(*this, OpLoc, Entity); 651} 652 653/// Checks access for a hierarchy conversion. 654/// 655/// \param IsBaseToDerived whether this is a base-to-derived conversion (true) 656/// or a derived-to-base conversion (false) 657/// \param ForceCheck true if this check should be performed even if access 658/// control is disabled; some things rely on this for semantics 659/// \param ForceUnprivileged true if this check should proceed as if the 660/// context had no special privileges 661/// \param ADK controls the kind of diagnostics that are used 662Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, 663 QualType Base, 664 QualType Derived, 665 const CXXBasePath &Path, 666 unsigned DiagID, 667 bool ForceCheck, 668 bool ForceUnprivileged) { 669 if (!ForceCheck && !getLangOptions().AccessControl) 670 return AR_accessible; 671 672 if (Path.Access == AS_public) 673 return AR_accessible; 674 675 CXXRecordDecl *BaseD, *DerivedD; 676 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); 677 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); 678 679 AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access); 680 if (DiagID) 681 Entity.setDiag(DiagID) << Derived << Base; 682 683 if (ForceUnprivileged) 684 return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity); 685 return CheckAccess(*this, AccessLoc, Entity); 686} 687 688/// Checks access to all the declarations in the given result set. 689void Sema::CheckLookupAccess(const LookupResult &R) { 690 assert(getLangOptions().AccessControl 691 && "performing access check without access control"); 692 assert(R.getNamingClass() && "performing access check without naming class"); 693 694 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { 695 if (I.getAccess() != AS_public) { 696 AccessedEntity Entity(AccessedEntity::Member, 697 R.getNamingClass(), I.getAccess(), *I); 698 Entity.setDiag(diag::err_access); 699 700 CheckAccess(*this, R.getNameLoc(), Entity); 701 } 702 } 703} 704