SemaAccess.cpp revision 65996191d65b20494b4015b62642b0eff5675617
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 (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) {
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