SemaAccess.cpp revision 00b11d324000c61b8c783663f6d6399514f8a487
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