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