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