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