1193326Sed//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
2193326Sed//
3193326Sed//                     The LLVM Compiler Infrastructure
4193326Sed//
5193326Sed// This file is distributed under the University of Illinois Open Source
6193326Sed// License. See LICENSE.TXT for details.
7193326Sed//
8193326Sed//===----------------------------------------------------------------------===//
9193326Sed//
10193326Sed// This file provides Sema routines for C++ access control semantics.
11193326Sed//
12193326Sed//===----------------------------------------------------------------------===//
13193326Sed
14212904Sdim#include "clang/Sema/SemaInternal.h"
15193326Sed#include "clang/AST/ASTContext.h"
16198092Srdivacky#include "clang/AST/CXXInheritance.h"
17198092Srdivacky#include "clang/AST/DeclCXX.h"
18205219Srdivacky#include "clang/AST/DeclFriend.h"
19235633Sdim#include "clang/AST/DeclObjC.h"
20206084Srdivacky#include "clang/AST/DependentDiagnostic.h"
21203955Srdivacky#include "clang/AST/ExprCXX.h"
22252723Sdim#include "clang/Sema/DelayedDiagnostic.h"
23252723Sdim#include "clang/Sema/Initialization.h"
24252723Sdim#include "clang/Sema/Lookup.h"
25203955Srdivacky
26193326Sedusing namespace clang;
27212904Sdimusing namespace sema;
28193326Sed
29207619Srdivacky/// A copy of Sema's enum without AR_delayed.
30207619Srdivackyenum AccessResult {
31207619Srdivacky  AR_accessible,
32207619Srdivacky  AR_inaccessible,
33207619Srdivacky  AR_dependent
34207619Srdivacky};
35207619Srdivacky
36193326Sed/// SetMemberAccessSpecifier - Set the access specifier of a member.
37193326Sed/// Returns true on error (when the previous member decl access specifier
38193326Sed/// is different from the new member decl access specifier).
39198092Srdivackybool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
40193326Sed                                    NamedDecl *PrevMemberDecl,
41193326Sed                                    AccessSpecifier LexicalAS) {
42193326Sed  if (!PrevMemberDecl) {
43193326Sed    // Use the lexical access specifier.
44193326Sed    MemberDecl->setAccess(LexicalAS);
45193326Sed    return false;
46193326Sed  }
47198092Srdivacky
48193326Sed  // C++ [class.access.spec]p3: When a member is redeclared its access
49193326Sed  // specifier must be same as its initial declaration.
50193326Sed  if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
51198092Srdivacky    Diag(MemberDecl->getLocation(),
52198092Srdivacky         diag::err_class_redeclared_with_different_access)
53193326Sed      << MemberDecl << LexicalAS;
54193326Sed    Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
55193326Sed      << PrevMemberDecl << PrevMemberDecl->getAccess();
56201361Srdivacky
57201361Srdivacky    MemberDecl->setAccess(LexicalAS);
58193326Sed    return true;
59193326Sed  }
60198092Srdivacky
61193326Sed  MemberDecl->setAccess(PrevMemberDecl->getAccess());
62193326Sed  return false;
63193326Sed}
64193326Sed
65207619Srdivackystatic CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
66207619Srdivacky  DeclContext *DC = D->getDeclContext();
67207619Srdivacky
68207619Srdivacky  // This can only happen at top: enum decls only "publish" their
69207619Srdivacky  // immediate members.
70207619Srdivacky  if (isa<EnumDecl>(DC))
71207619Srdivacky    DC = cast<EnumDecl>(DC)->getDeclContext();
72207619Srdivacky
73207619Srdivacky  CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
74207619Srdivacky  while (DeclaringClass->isAnonymousStructOrUnion())
75207619Srdivacky    DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
76207619Srdivacky  return DeclaringClass;
77207619Srdivacky}
78207619Srdivacky
79203955Srdivackynamespace {
80203955Srdivackystruct EffectiveContext {
81206084Srdivacky  EffectiveContext() : Inner(0), Dependent(false) {}
82193326Sed
83206084Srdivacky  explicit EffectiveContext(DeclContext *DC)
84206084Srdivacky    : Inner(DC),
85206084Srdivacky      Dependent(DC->isDependentContext()) {
86205408Srdivacky
87252723Sdim    // C++11 [class.access.nest]p1:
88205408Srdivacky    //   A nested class is a member and as such has the same access
89205408Srdivacky    //   rights as any other member.
90252723Sdim    // C++11 [class.access]p2:
91205408Srdivacky    //   A member of a class can also access all the names to which
92206084Srdivacky    //   the class has access.  A local class of a member function
93206084Srdivacky    //   may access the same names that the member function itself
94206084Srdivacky    //   may access.
95206084Srdivacky    // This almost implies that the privileges of nesting are transitive.
96206084Srdivacky    // Technically it says nothing about the local classes of non-member
97206084Srdivacky    // functions (which can gain privileges through friendship), but we
98206084Srdivacky    // take that as an oversight.
99206084Srdivacky    while (true) {
100245431Sdim      // We want to add canonical declarations to the EC lists for
101245431Sdim      // simplicity of checking, but we need to walk up through the
102245431Sdim      // actual current DC chain.  Otherwise, something like a local
103245431Sdim      // extern or friend which happens to be the canonical
104245431Sdim      // declaration will really mess us up.
105245431Sdim
106206084Srdivacky      if (isa<CXXRecordDecl>(DC)) {
107245431Sdim        CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
108245431Sdim        Records.push_back(Record->getCanonicalDecl());
109206084Srdivacky        DC = Record->getDeclContext();
110206084Srdivacky      } else if (isa<FunctionDecl>(DC)) {
111245431Sdim        FunctionDecl *Function = cast<FunctionDecl>(DC);
112245431Sdim        Functions.push_back(Function->getCanonicalDecl());
113226890Sdim        if (Function->getFriendObjectKind())
114226890Sdim          DC = Function->getLexicalDeclContext();
115226890Sdim        else
116226890Sdim          DC = Function->getDeclContext();
117206084Srdivacky      } else if (DC->isFileContext()) {
118206084Srdivacky        break;
119206084Srdivacky      } else {
120206084Srdivacky        DC = DC->getParent();
121206084Srdivacky      }
122205408Srdivacky    }
123203955Srdivacky  }
124198092Srdivacky
125206084Srdivacky  bool isDependent() const { return Dependent; }
126206084Srdivacky
127205408Srdivacky  bool includesClass(const CXXRecordDecl *R) const {
128205408Srdivacky    R = R->getCanonicalDecl();
129205408Srdivacky    return std::find(Records.begin(), Records.end(), R)
130205408Srdivacky             != Records.end();
131203955Srdivacky  }
132198092Srdivacky
133206084Srdivacky  /// Retrieves the innermost "useful" context.  Can be null if we're
134206084Srdivacky  /// doing access-control without privileges.
135206084Srdivacky  DeclContext *getInnerContext() const {
136206084Srdivacky    return Inner;
137206084Srdivacky  }
138206084Srdivacky
139226890Sdim  typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
140206084Srdivacky
141206084Srdivacky  DeclContext *Inner;
142226890Sdim  SmallVector<FunctionDecl*, 4> Functions;
143226890Sdim  SmallVector<CXXRecordDecl*, 4> Records;
144206084Srdivacky  bool Dependent;
145203955Srdivacky};
146207619Srdivacky
147218893Sdim/// Like sema::AccessedEntity, but kindly lets us scribble all over
148207619Srdivacky/// it.
149212904Sdimstruct AccessTarget : public AccessedEntity {
150212904Sdim  AccessTarget(const AccessedEntity &Entity)
151207619Srdivacky    : AccessedEntity(Entity) {
152207619Srdivacky    initialize();
153207619Srdivacky  }
154207619Srdivacky
155207619Srdivacky  AccessTarget(ASTContext &Context,
156207619Srdivacky               MemberNonce _,
157207619Srdivacky               CXXRecordDecl *NamingClass,
158207619Srdivacky               DeclAccessPair FoundDecl,
159226890Sdim               QualType BaseObjectType)
160245431Sdim    : AccessedEntity(Context.getDiagAllocator(), Member, NamingClass,
161245431Sdim                     FoundDecl, BaseObjectType) {
162207619Srdivacky    initialize();
163207619Srdivacky  }
164207619Srdivacky
165207619Srdivacky  AccessTarget(ASTContext &Context,
166207619Srdivacky               BaseNonce _,
167207619Srdivacky               CXXRecordDecl *BaseClass,
168207619Srdivacky               CXXRecordDecl *DerivedClass,
169207619Srdivacky               AccessSpecifier Access)
170245431Sdim    : AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass,
171245431Sdim                     Access) {
172207619Srdivacky    initialize();
173207619Srdivacky  }
174207619Srdivacky
175235633Sdim  bool isInstanceMember() const {
176235633Sdim    return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember());
177235633Sdim  }
178235633Sdim
179207619Srdivacky  bool hasInstanceContext() const {
180207619Srdivacky    return HasInstanceContext;
181207619Srdivacky  }
182207619Srdivacky
183207619Srdivacky  class SavedInstanceContext {
184207619Srdivacky  public:
185207619Srdivacky    ~SavedInstanceContext() {
186207619Srdivacky      Target.HasInstanceContext = Has;
187207619Srdivacky    }
188207619Srdivacky
189207619Srdivacky  private:
190207619Srdivacky    friend struct AccessTarget;
191207619Srdivacky    explicit SavedInstanceContext(AccessTarget &Target)
192207619Srdivacky      : Target(Target), Has(Target.HasInstanceContext) {}
193207619Srdivacky    AccessTarget &Target;
194207619Srdivacky    bool Has;
195207619Srdivacky  };
196207619Srdivacky
197207619Srdivacky  SavedInstanceContext saveInstanceContext() {
198207619Srdivacky    return SavedInstanceContext(*this);
199207619Srdivacky  }
200207619Srdivacky
201207619Srdivacky  void suppressInstanceContext() {
202207619Srdivacky    HasInstanceContext = false;
203207619Srdivacky  }
204207619Srdivacky
205207619Srdivacky  const CXXRecordDecl *resolveInstanceContext(Sema &S) const {
206207619Srdivacky    assert(HasInstanceContext);
207207619Srdivacky    if (CalculatedInstanceContext)
208207619Srdivacky      return InstanceContext;
209207619Srdivacky
210207619Srdivacky    CalculatedInstanceContext = true;
211207619Srdivacky    DeclContext *IC = S.computeDeclContext(getBaseObjectType());
212207619Srdivacky    InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0);
213207619Srdivacky    return InstanceContext;
214207619Srdivacky  }
215207619Srdivacky
216207619Srdivacky  const CXXRecordDecl *getDeclaringClass() const {
217207619Srdivacky    return DeclaringClass;
218207619Srdivacky  }
219207619Srdivacky
220252723Sdim  /// The "effective" naming class is the canonical non-anonymous
221252723Sdim  /// class containing the actual naming class.
222252723Sdim  const CXXRecordDecl *getEffectiveNamingClass() const {
223252723Sdim    const CXXRecordDecl *namingClass = getNamingClass();
224252723Sdim    while (namingClass->isAnonymousStructOrUnion())
225252723Sdim      namingClass = cast<CXXRecordDecl>(namingClass->getParent());
226252723Sdim    return namingClass->getCanonicalDecl();
227252723Sdim  }
228252723Sdim
229207619Srdivackyprivate:
230207619Srdivacky  void initialize() {
231207619Srdivacky    HasInstanceContext = (isMemberAccess() &&
232207619Srdivacky                          !getBaseObjectType().isNull() &&
233207619Srdivacky                          getTargetDecl()->isCXXInstanceMember());
234207619Srdivacky    CalculatedInstanceContext = false;
235207619Srdivacky    InstanceContext = 0;
236207619Srdivacky
237207619Srdivacky    if (isMemberAccess())
238207619Srdivacky      DeclaringClass = FindDeclaringClass(getTargetDecl());
239207619Srdivacky    else
240207619Srdivacky      DeclaringClass = getBaseClass();
241207619Srdivacky    DeclaringClass = DeclaringClass->getCanonicalDecl();
242207619Srdivacky  }
243207619Srdivacky
244207619Srdivacky  bool HasInstanceContext : 1;
245207619Srdivacky  mutable bool CalculatedInstanceContext : 1;
246207619Srdivacky  mutable const CXXRecordDecl *InstanceContext;
247207619Srdivacky  const CXXRecordDecl *DeclaringClass;
248207619Srdivacky};
249207619Srdivacky
250203955Srdivacky}
251193326Sed
252207619Srdivacky/// Checks whether one class might instantiate to the other.
253207619Srdivackystatic bool MightInstantiateTo(const CXXRecordDecl *From,
254207619Srdivacky                               const CXXRecordDecl *To) {
255207619Srdivacky  // Declaration names are always preserved by instantiation.
256207619Srdivacky  if (From->getDeclName() != To->getDeclName())
257207619Srdivacky    return false;
258206084Srdivacky
259207619Srdivacky  const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();
260207619Srdivacky  const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();
261207619Srdivacky  if (FromDC == ToDC) return true;
262207619Srdivacky  if (FromDC->isFileContext() || ToDC->isFileContext()) return false;
263206084Srdivacky
264207619Srdivacky  // Be conservative.
265207619Srdivacky  return true;
266203955Srdivacky}
267198092Srdivacky
268207619Srdivacky/// Checks whether one class is derived from another, inclusively.
269207619Srdivacky/// Properly indicates when it couldn't be determined due to
270207619Srdivacky/// dependence.
271207619Srdivacky///
272207619Srdivacky/// This should probably be donated to AST or at least Sema.
273207619Srdivackystatic AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
274207619Srdivacky                                           const CXXRecordDecl *Target) {
275207619Srdivacky  assert(Derived->getCanonicalDecl() == Derived);
276207619Srdivacky  assert(Target->getCanonicalDecl() == Target);
277207619Srdivacky
278207619Srdivacky  if (Derived == Target) return AR_accessible;
279207619Srdivacky
280207619Srdivacky  bool CheckDependent = Derived->isDependentContext();
281207619Srdivacky  if (CheckDependent && MightInstantiateTo(Derived, Target))
282207619Srdivacky    return AR_dependent;
283207619Srdivacky
284207619Srdivacky  AccessResult OnFailure = AR_inaccessible;
285226890Sdim  SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
286207619Srdivacky
287207619Srdivacky  while (true) {
288235633Sdim    if (Derived->isDependentContext() && !Derived->hasDefinition())
289235633Sdim      return AR_dependent;
290235633Sdim
291207619Srdivacky    for (CXXRecordDecl::base_class_const_iterator
292207619Srdivacky           I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) {
293207619Srdivacky
294207619Srdivacky      const CXXRecordDecl *RD;
295207619Srdivacky
296207619Srdivacky      QualType T = I->getType();
297207619Srdivacky      if (const RecordType *RT = T->getAs<RecordType>()) {
298207619Srdivacky        RD = cast<CXXRecordDecl>(RT->getDecl());
299207619Srdivacky      } else if (const InjectedClassNameType *IT
300207619Srdivacky                   = T->getAs<InjectedClassNameType>()) {
301207619Srdivacky        RD = IT->getDecl();
302207619Srdivacky      } else {
303207619Srdivacky        assert(T->isDependentType() && "non-dependent base wasn't a record?");
304207619Srdivacky        OnFailure = AR_dependent;
305207619Srdivacky        continue;
306207619Srdivacky      }
307207619Srdivacky
308207619Srdivacky      RD = RD->getCanonicalDecl();
309207619Srdivacky      if (RD == Target) return AR_accessible;
310207619Srdivacky      if (CheckDependent && MightInstantiateTo(RD, Target))
311207619Srdivacky        OnFailure = AR_dependent;
312207619Srdivacky
313207619Srdivacky      Queue.push_back(RD);
314207619Srdivacky    }
315207619Srdivacky
316207619Srdivacky    if (Queue.empty()) break;
317207619Srdivacky
318263509Sdim    Derived = Queue.pop_back_val();
319207619Srdivacky  }
320207619Srdivacky
321207619Srdivacky  return OnFailure;
322207619Srdivacky}
323207619Srdivacky
324207619Srdivacky
325206084Srdivackystatic bool MightInstantiateTo(Sema &S, DeclContext *Context,
326206084Srdivacky                               DeclContext *Friend) {
327206084Srdivacky  if (Friend == Context)
328206084Srdivacky    return true;
329206084Srdivacky
330206084Srdivacky  assert(!Friend->isDependentContext() &&
331206084Srdivacky         "can't handle friends with dependent contexts here");
332206084Srdivacky
333206084Srdivacky  if (!Context->isDependentContext())
334206084Srdivacky    return false;
335206084Srdivacky
336206084Srdivacky  if (Friend->isFileContext())
337206084Srdivacky    return false;
338206084Srdivacky
339206084Srdivacky  // TODO: this is very conservative
340206084Srdivacky  return true;
341206084Srdivacky}
342206084Srdivacky
343206084Srdivacky// Asks whether the type in 'context' can ever instantiate to the type
344206084Srdivacky// in 'friend'.
345206084Srdivackystatic bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
346206084Srdivacky  if (Friend == Context)
347206084Srdivacky    return true;
348206084Srdivacky
349206084Srdivacky  if (!Friend->isDependentType() && !Context->isDependentType())
350206084Srdivacky    return false;
351206084Srdivacky
352206084Srdivacky  // TODO: this is very conservative.
353206084Srdivacky  return true;
354206084Srdivacky}
355206084Srdivacky
356206084Srdivackystatic bool MightInstantiateTo(Sema &S,
357206084Srdivacky                               FunctionDecl *Context,
358206084Srdivacky                               FunctionDecl *Friend) {
359206084Srdivacky  if (Context->getDeclName() != Friend->getDeclName())
360206084Srdivacky    return false;
361206084Srdivacky
362206084Srdivacky  if (!MightInstantiateTo(S,
363206084Srdivacky                          Context->getDeclContext(),
364206084Srdivacky                          Friend->getDeclContext()))
365206084Srdivacky    return false;
366206084Srdivacky
367206084Srdivacky  CanQual<FunctionProtoType> FriendTy
368206084Srdivacky    = S.Context.getCanonicalType(Friend->getType())
369206084Srdivacky         ->getAs<FunctionProtoType>();
370206084Srdivacky  CanQual<FunctionProtoType> ContextTy
371206084Srdivacky    = S.Context.getCanonicalType(Context->getType())
372206084Srdivacky         ->getAs<FunctionProtoType>();
373206084Srdivacky
374206084Srdivacky  // There isn't any way that I know of to add qualifiers
375206084Srdivacky  // during instantiation.
376206084Srdivacky  if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
377206084Srdivacky    return false;
378206084Srdivacky
379206084Srdivacky  if (FriendTy->getNumArgs() != ContextTy->getNumArgs())
380206084Srdivacky    return false;
381206084Srdivacky
382206084Srdivacky  if (!MightInstantiateTo(S,
383206084Srdivacky                          ContextTy->getResultType(),
384206084Srdivacky                          FriendTy->getResultType()))
385206084Srdivacky    return false;
386206084Srdivacky
387206084Srdivacky  for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I)
388206084Srdivacky    if (!MightInstantiateTo(S,
389206084Srdivacky                            ContextTy->getArgType(I),
390206084Srdivacky                            FriendTy->getArgType(I)))
391206084Srdivacky      return false;
392206084Srdivacky
393206084Srdivacky  return true;
394206084Srdivacky}
395206084Srdivacky
396206084Srdivackystatic bool MightInstantiateTo(Sema &S,
397206084Srdivacky                               FunctionTemplateDecl *Context,
398206084Srdivacky                               FunctionTemplateDecl *Friend) {
399206084Srdivacky  return MightInstantiateTo(S,
400206084Srdivacky                            Context->getTemplatedDecl(),
401206084Srdivacky                            Friend->getTemplatedDecl());
402206084Srdivacky}
403206084Srdivacky
404207619Srdivackystatic AccessResult MatchesFriend(Sema &S,
405207619Srdivacky                                  const EffectiveContext &EC,
406207619Srdivacky                                  const CXXRecordDecl *Friend) {
407205408Srdivacky  if (EC.includesClass(Friend))
408207619Srdivacky    return AR_accessible;
409205408Srdivacky
410206084Srdivacky  if (EC.isDependent()) {
411206084Srdivacky    CanQualType FriendTy
412206084Srdivacky      = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend));
413206084Srdivacky
414206084Srdivacky    for (EffectiveContext::record_iterator
415206084Srdivacky           I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
416206084Srdivacky      CanQualType ContextTy
417206084Srdivacky        = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
418206084Srdivacky      if (MightInstantiateTo(S, ContextTy, FriendTy))
419207619Srdivacky        return AR_dependent;
420206084Srdivacky    }
421206084Srdivacky  }
422206084Srdivacky
423207619Srdivacky  return AR_inaccessible;
424205408Srdivacky}
425205408Srdivacky
426207619Srdivackystatic AccessResult MatchesFriend(Sema &S,
427207619Srdivacky                                  const EffectiveContext &EC,
428207619Srdivacky                                  CanQualType Friend) {
429206084Srdivacky  if (const RecordType *RT = Friend->getAs<RecordType>())
430206084Srdivacky    return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
431205408Srdivacky
432206084Srdivacky  // TODO: we can do better than this
433206084Srdivacky  if (Friend->isDependentType())
434207619Srdivacky    return AR_dependent;
435205408Srdivacky
436207619Srdivacky  return AR_inaccessible;
437206084Srdivacky}
438205408Srdivacky
439206084Srdivacky/// Determines whether the given friend class template matches
440206084Srdivacky/// anything in the effective context.
441207619Srdivackystatic AccessResult MatchesFriend(Sema &S,
442207619Srdivacky                                  const EffectiveContext &EC,
443207619Srdivacky                                  ClassTemplateDecl *Friend) {
444207619Srdivacky  AccessResult OnFailure = AR_inaccessible;
445205408Srdivacky
446206084Srdivacky  // Check whether the friend is the template of a class in the
447206084Srdivacky  // context chain.
448226890Sdim  for (SmallVectorImpl<CXXRecordDecl*>::const_iterator
449206084Srdivacky         I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
450206084Srdivacky    CXXRecordDecl *Record = *I;
451205408Srdivacky
452206084Srdivacky    // Figure out whether the current class has a template:
453206084Srdivacky    ClassTemplateDecl *CTD;
454205408Srdivacky
455206084Srdivacky    // A specialization of the template...
456206084Srdivacky    if (isa<ClassTemplateSpecializationDecl>(Record)) {
457206084Srdivacky      CTD = cast<ClassTemplateSpecializationDecl>(Record)
458206084Srdivacky        ->getSpecializedTemplate();
459205408Srdivacky
460206084Srdivacky    // ... or the template pattern itself.
461206084Srdivacky    } else {
462206084Srdivacky      CTD = Record->getDescribedClassTemplate();
463206084Srdivacky      if (!CTD) continue;
464205408Srdivacky    }
465205408Srdivacky
466206084Srdivacky    // It's a match.
467206084Srdivacky    if (Friend == CTD->getCanonicalDecl())
468207619Srdivacky      return AR_accessible;
469206084Srdivacky
470206084Srdivacky    // If the context isn't dependent, it can't be a dependent match.
471206084Srdivacky    if (!EC.isDependent())
472206084Srdivacky      continue;
473206084Srdivacky
474206084Srdivacky    // If the template names don't match, it can't be a dependent
475223017Sdim    // match.
476223017Sdim    if (CTD->getDeclName() != Friend->getDeclName())
477206084Srdivacky      continue;
478206084Srdivacky
479206084Srdivacky    // If the class's context can't instantiate to the friend's
480206084Srdivacky    // context, it can't be a dependent match.
481206084Srdivacky    if (!MightInstantiateTo(S, CTD->getDeclContext(),
482206084Srdivacky                            Friend->getDeclContext()))
483206084Srdivacky      continue;
484206084Srdivacky
485206084Srdivacky    // Otherwise, it's a dependent match.
486207619Srdivacky    OnFailure = AR_dependent;
487205408Srdivacky  }
488205408Srdivacky
489206084Srdivacky  return OnFailure;
490206084Srdivacky}
491205408Srdivacky
492206084Srdivacky/// Determines whether the given friend function matches anything in
493206084Srdivacky/// the effective context.
494207619Srdivackystatic AccessResult MatchesFriend(Sema &S,
495207619Srdivacky                                  const EffectiveContext &EC,
496207619Srdivacky                                  FunctionDecl *Friend) {
497207619Srdivacky  AccessResult OnFailure = AR_inaccessible;
498206084Srdivacky
499226890Sdim  for (SmallVectorImpl<FunctionDecl*>::const_iterator
500206084Srdivacky         I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
501206084Srdivacky    if (Friend == *I)
502207619Srdivacky      return AR_accessible;
503206084Srdivacky
504206084Srdivacky    if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
505207619Srdivacky      OnFailure = AR_dependent;
506206084Srdivacky  }
507206084Srdivacky
508206084Srdivacky  return OnFailure;
509206084Srdivacky}
510206084Srdivacky
511206084Srdivacky/// Determines whether the given friend function template matches
512206084Srdivacky/// anything in the effective context.
513207619Srdivackystatic AccessResult MatchesFriend(Sema &S,
514207619Srdivacky                                  const EffectiveContext &EC,
515207619Srdivacky                                  FunctionTemplateDecl *Friend) {
516207619Srdivacky  if (EC.Functions.empty()) return AR_inaccessible;
517206084Srdivacky
518207619Srdivacky  AccessResult OnFailure = AR_inaccessible;
519206084Srdivacky
520226890Sdim  for (SmallVectorImpl<FunctionDecl*>::const_iterator
521206084Srdivacky         I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
522206084Srdivacky
523206084Srdivacky    FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
524205408Srdivacky    if (!FTD)
525206084Srdivacky      FTD = (*I)->getDescribedFunctionTemplate();
526206084Srdivacky    if (!FTD)
527206084Srdivacky      continue;
528205408Srdivacky
529206084Srdivacky    FTD = FTD->getCanonicalDecl();
530206084Srdivacky
531206084Srdivacky    if (Friend == FTD)
532207619Srdivacky      return AR_accessible;
533206084Srdivacky
534206084Srdivacky    if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
535207619Srdivacky      OnFailure = AR_dependent;
536205408Srdivacky  }
537205408Srdivacky
538206084Srdivacky  return OnFailure;
539206084Srdivacky}
540205408Srdivacky
541206084Srdivacky/// Determines whether the given friend declaration matches anything
542206084Srdivacky/// in the effective context.
543207619Srdivackystatic AccessResult MatchesFriend(Sema &S,
544207619Srdivacky                                  const EffectiveContext &EC,
545207619Srdivacky                                  FriendDecl *FriendD) {
546218893Sdim  // Whitelist accesses if there's an invalid or unsupported friend
547218893Sdim  // declaration.
548218893Sdim  if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend())
549218893Sdim    return AR_accessible;
550218893Sdim
551206084Srdivacky  if (TypeSourceInfo *T = FriendD->getFriendType())
552206084Srdivacky    return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
553205408Srdivacky
554206084Srdivacky  NamedDecl *Friend
555206084Srdivacky    = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
556206084Srdivacky
557206084Srdivacky  // FIXME: declarations with dependent or templated scope.
558206084Srdivacky
559206084Srdivacky  if (isa<ClassTemplateDecl>(Friend))
560206084Srdivacky    return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
561206084Srdivacky
562206084Srdivacky  if (isa<FunctionTemplateDecl>(Friend))
563206084Srdivacky    return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
564206084Srdivacky
565206084Srdivacky  if (isa<CXXRecordDecl>(Friend))
566206084Srdivacky    return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
567206084Srdivacky
568206084Srdivacky  assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
569206084Srdivacky  return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
570205408Srdivacky}
571205408Srdivacky
572207619Srdivackystatic AccessResult GetFriendKind(Sema &S,
573207619Srdivacky                                  const EffectiveContext &EC,
574207619Srdivacky                                  const CXXRecordDecl *Class) {
575207619Srdivacky  AccessResult OnFailure = AR_inaccessible;
576205408Srdivacky
577205219Srdivacky  // Okay, check friends.
578205219Srdivacky  for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
579205219Srdivacky         E = Class->friend_end(); I != E; ++I) {
580205219Srdivacky    FriendDecl *Friend = *I;
581205219Srdivacky
582205408Srdivacky    switch (MatchesFriend(S, EC, Friend)) {
583207619Srdivacky    case AR_accessible:
584207619Srdivacky      return AR_accessible;
585205219Srdivacky
586207619Srdivacky    case AR_inaccessible:
587207619Srdivacky      continue;
588205408Srdivacky
589207619Srdivacky    case AR_dependent:
590207619Srdivacky      OnFailure = AR_dependent;
591205408Srdivacky      break;
592205219Srdivacky    }
593205219Srdivacky  }
594205219Srdivacky
595205219Srdivacky  // That's it, give up.
596205408Srdivacky  return OnFailure;
597203955Srdivacky}
598198092Srdivacky
599212904Sdimnamespace {
600212904Sdim
601212904Sdim/// A helper class for checking for a friend which will grant access
602212904Sdim/// to a protected instance member.
603212904Sdimstruct ProtectedFriendContext {
604212904Sdim  Sema &S;
605212904Sdim  const EffectiveContext &EC;
606212904Sdim  const CXXRecordDecl *NamingClass;
607212904Sdim  bool CheckDependent;
608212904Sdim  bool EverDependent;
609212904Sdim
610212904Sdim  /// The path down to the current base class.
611226890Sdim  SmallVector<const CXXRecordDecl*, 20> CurPath;
612212904Sdim
613212904Sdim  ProtectedFriendContext(Sema &S, const EffectiveContext &EC,
614212904Sdim                         const CXXRecordDecl *InstanceContext,
615212904Sdim                         const CXXRecordDecl *NamingClass)
616212904Sdim    : S(S), EC(EC), NamingClass(NamingClass),
617212904Sdim      CheckDependent(InstanceContext->isDependentContext() ||
618212904Sdim                     NamingClass->isDependentContext()),
619212904Sdim      EverDependent(false) {}
620212904Sdim
621212904Sdim  /// Check classes in the current path for friendship, starting at
622212904Sdim  /// the given index.
623212904Sdim  bool checkFriendshipAlongPath(unsigned I) {
624212904Sdim    assert(I < CurPath.size());
625212904Sdim    for (unsigned E = CurPath.size(); I != E; ++I) {
626212904Sdim      switch (GetFriendKind(S, EC, CurPath[I])) {
627212904Sdim      case AR_accessible:   return true;
628212904Sdim      case AR_inaccessible: continue;
629212904Sdim      case AR_dependent:    EverDependent = true; continue;
630212904Sdim      }
631212904Sdim    }
632212904Sdim    return false;
633212904Sdim  }
634212904Sdim
635212904Sdim  /// Perform a search starting at the given class.
636212904Sdim  ///
637212904Sdim  /// PrivateDepth is the index of the last (least derived) class
638212904Sdim  /// along the current path such that a notional public member of
639212904Sdim  /// the final class in the path would have access in that class.
640212904Sdim  bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) {
641212904Sdim    // If we ever reach the naming class, check the current path for
642212904Sdim    // friendship.  We can also stop recursing because we obviously
643212904Sdim    // won't find the naming class there again.
644212904Sdim    if (Cur == NamingClass)
645212904Sdim      return checkFriendshipAlongPath(PrivateDepth);
646212904Sdim
647212904Sdim    if (CheckDependent && MightInstantiateTo(Cur, NamingClass))
648212904Sdim      EverDependent = true;
649212904Sdim
650212904Sdim    // Recurse into the base classes.
651212904Sdim    for (CXXRecordDecl::base_class_const_iterator
652212904Sdim           I = Cur->bases_begin(), E = Cur->bases_end(); I != E; ++I) {
653212904Sdim
654212904Sdim      // If this is private inheritance, then a public member of the
655212904Sdim      // base will not have any access in classes derived from Cur.
656212904Sdim      unsigned BasePrivateDepth = PrivateDepth;
657212904Sdim      if (I->getAccessSpecifier() == AS_private)
658212904Sdim        BasePrivateDepth = CurPath.size() - 1;
659212904Sdim
660212904Sdim      const CXXRecordDecl *RD;
661212904Sdim
662212904Sdim      QualType T = I->getType();
663212904Sdim      if (const RecordType *RT = T->getAs<RecordType>()) {
664212904Sdim        RD = cast<CXXRecordDecl>(RT->getDecl());
665212904Sdim      } else if (const InjectedClassNameType *IT
666212904Sdim                   = T->getAs<InjectedClassNameType>()) {
667212904Sdim        RD = IT->getDecl();
668212904Sdim      } else {
669212904Sdim        assert(T->isDependentType() && "non-dependent base wasn't a record?");
670212904Sdim        EverDependent = true;
671212904Sdim        continue;
672212904Sdim      }
673212904Sdim
674212904Sdim      // Recurse.  We don't need to clean up if this returns true.
675212904Sdim      CurPath.push_back(RD);
676212904Sdim      if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth))
677212904Sdim        return true;
678212904Sdim      CurPath.pop_back();
679212904Sdim    }
680212904Sdim
681212904Sdim    return false;
682212904Sdim  }
683212904Sdim
684212904Sdim  bool findFriendship(const CXXRecordDecl *Cur) {
685212904Sdim    assert(CurPath.empty());
686212904Sdim    CurPath.push_back(Cur);
687212904Sdim    return findFriendship(Cur, 0);
688212904Sdim  }
689212904Sdim};
690212904Sdim}
691212904Sdim
692212904Sdim/// Search for a class P that EC is a friend of, under the constraint
693235633Sdim///   InstanceContext <= P
694235633Sdim/// if InstanceContext exists, or else
695235633Sdim///   NamingClass <= P
696212904Sdim/// and with the additional restriction that a protected member of
697235633Sdim/// NamingClass would have some natural access in P, which implicitly
698235633Sdim/// imposes the constraint that P <= NamingClass.
699212904Sdim///
700235633Sdim/// This isn't quite the condition laid out in the standard.
701235633Sdim/// Instead of saying that a notional protected member of NamingClass
702235633Sdim/// would have to have some natural access in P, it says the actual
703235633Sdim/// target has to have some natural access in P, which opens up the
704235633Sdim/// possibility that the target (which is not necessarily a member
705235633Sdim/// of NamingClass) might be more accessible along some path not
706235633Sdim/// passing through it.  That's really a bad idea, though, because it
707212904Sdim/// introduces two problems:
708235633Sdim///   - Most importantly, it breaks encapsulation because you can
709235633Sdim///     access a forbidden base class's members by directly subclassing
710235633Sdim///     it elsewhere.
711235633Sdim///   - It also makes access substantially harder to compute because it
712212904Sdim///     breaks the hill-climbing algorithm: knowing that the target is
713212904Sdim///     accessible in some base class would no longer let you change
714212904Sdim///     the question solely to whether the base class is accessible,
715212904Sdim///     because the original target might have been more accessible
716212904Sdim///     because of crazy subclassing.
717212904Sdim/// So we don't implement that.
718212904Sdimstatic AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC,
719212904Sdim                                           const CXXRecordDecl *InstanceContext,
720212904Sdim                                           const CXXRecordDecl *NamingClass) {
721235633Sdim  assert(InstanceContext == 0 ||
722235633Sdim         InstanceContext->getCanonicalDecl() == InstanceContext);
723212904Sdim  assert(NamingClass->getCanonicalDecl() == NamingClass);
724212904Sdim
725235633Sdim  // If we don't have an instance context, our constraints give us
726235633Sdim  // that NamingClass <= P <= NamingClass, i.e. P == NamingClass.
727235633Sdim  // This is just the usual friendship check.
728235633Sdim  if (!InstanceContext) return GetFriendKind(S, EC, NamingClass);
729235633Sdim
730212904Sdim  ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass);
731212904Sdim  if (PRC.findFriendship(InstanceContext)) return AR_accessible;
732212904Sdim  if (PRC.EverDependent) return AR_dependent;
733212904Sdim  return AR_inaccessible;
734212904Sdim}
735212904Sdim
736207619Srdivackystatic AccessResult HasAccess(Sema &S,
737207619Srdivacky                              const EffectiveContext &EC,
738207619Srdivacky                              const CXXRecordDecl *NamingClass,
739207619Srdivacky                              AccessSpecifier Access,
740207619Srdivacky                              const AccessTarget &Target) {
741206084Srdivacky  assert(NamingClass->getCanonicalDecl() == NamingClass &&
742206084Srdivacky         "declaration should be canonicalized before being passed here");
743206084Srdivacky
744207619Srdivacky  if (Access == AS_public) return AR_accessible;
745206084Srdivacky  assert(Access == AS_private || Access == AS_protected);
746206084Srdivacky
747207619Srdivacky  AccessResult OnFailure = AR_inaccessible;
748207619Srdivacky
749206084Srdivacky  for (EffectiveContext::record_iterator
750206084Srdivacky         I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
751206084Srdivacky    // All the declarations in EC have been canonicalized, so pointer
752206084Srdivacky    // equality from this point on will work fine.
753206084Srdivacky    const CXXRecordDecl *ECRecord = *I;
754206084Srdivacky
755206084Srdivacky    // [B2] and [M2]
756207619Srdivacky    if (Access == AS_private) {
757207619Srdivacky      if (ECRecord == NamingClass)
758207619Srdivacky        return AR_accessible;
759206084Srdivacky
760207619Srdivacky      if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))
761207619Srdivacky        OnFailure = AR_dependent;
762207619Srdivacky
763206084Srdivacky    // [B3] and [M3]
764207619Srdivacky    } else {
765207619Srdivacky      assert(Access == AS_protected);
766207619Srdivacky      switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
767207619Srdivacky      case AR_accessible: break;
768207619Srdivacky      case AR_inaccessible: continue;
769207619Srdivacky      case AR_dependent: OnFailure = AR_dependent; continue;
770207619Srdivacky      }
771207619Srdivacky
772207619Srdivacky      // C++ [class.protected]p1:
773207619Srdivacky      //   An additional access check beyond those described earlier in
774207619Srdivacky      //   [class.access] is applied when a non-static data member or
775207619Srdivacky      //   non-static member function is a protected member of its naming
776207619Srdivacky      //   class.  As described earlier, access to a protected member is
777207619Srdivacky      //   granted because the reference occurs in a friend or member of
778207619Srdivacky      //   some class C.  If the access is to form a pointer to member,
779207619Srdivacky      //   the nested-name-specifier shall name C or a class derived from
780207619Srdivacky      //   C. All other accesses involve a (possibly implicit) object
781207619Srdivacky      //   expression. In this case, the class of the object expression
782207619Srdivacky      //   shall be C or a class derived from C.
783207619Srdivacky      //
784235633Sdim      // We interpret this as a restriction on [M3].
785235633Sdim
786235633Sdim      // In this part of the code, 'C' is just our context class ECRecord.
787235633Sdim
788235633Sdim      // These rules are different if we don't have an instance context.
789235633Sdim      if (!Target.hasInstanceContext()) {
790235633Sdim        // If it's not an instance member, these restrictions don't apply.
791235633Sdim        if (!Target.isInstanceMember()) return AR_accessible;
792235633Sdim
793235633Sdim        // If it's an instance member, use the pointer-to-member rule
794235633Sdim        // that the naming class has to be derived from the effective
795235633Sdim        // context.
796235633Sdim
797235633Sdim        // Emulate a MSVC bug where the creation of pointer-to-member
798235633Sdim        // to protected member of base class is allowed but only from
799245431Sdim        // static member functions.
800235633Sdim        if (S.getLangOpts().MicrosoftMode && !EC.Functions.empty())
801235633Sdim          if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front()))
802235633Sdim            if (MD->isStatic()) return AR_accessible;
803235633Sdim
804235633Sdim        // Despite the standard's confident wording, there is a case
805235633Sdim        // where you can have an instance member that's neither in a
806235633Sdim        // pointer-to-member expression nor in a member access:  when
807235633Sdim        // it names a field in an unevaluated context that can't be an
808235633Sdim        // implicit member.  Pending clarification, we just apply the
809235633Sdim        // same naming-class restriction here.
810235633Sdim        //   FIXME: we're probably not correctly adding the
811235633Sdim        //   protected-member restriction when we retroactively convert
812235633Sdim        //   an expression to being evaluated.
813235633Sdim
814235633Sdim        // We know that ECRecord derives from NamingClass.  The
815235633Sdim        // restriction says to check whether NamingClass derives from
816235633Sdim        // ECRecord, but that's not really necessary: two distinct
817235633Sdim        // classes can't be recursively derived from each other.  So
818235633Sdim        // along this path, we just need to check whether the classes
819235633Sdim        // are equal.
820235633Sdim        if (NamingClass == ECRecord) return AR_accessible;
821235633Sdim
822235633Sdim        // Otherwise, this context class tells us nothing;  on to the next.
823235633Sdim        continue;
824235633Sdim      }
825235633Sdim
826235633Sdim      assert(Target.isInstanceMember());
827235633Sdim
828235633Sdim      const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
829235633Sdim      if (!InstanceContext) {
830235633Sdim        OnFailure = AR_dependent;
831235633Sdim        continue;
832235633Sdim      }
833235633Sdim
834207619Srdivacky      switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
835207619Srdivacky      case AR_accessible: return AR_accessible;
836207619Srdivacky      case AR_inaccessible: continue;
837207619Srdivacky      case AR_dependent: OnFailure = AR_dependent; continue;
838207619Srdivacky      }
839207619Srdivacky    }
840206084Srdivacky  }
841206084Srdivacky
842212904Sdim  // [M3] and [B3] say that, if the target is protected in N, we grant
843212904Sdim  // access if the access occurs in a friend or member of some class P
844212904Sdim  // that's a subclass of N and where the target has some natural
845212904Sdim  // access in P.  The 'member' aspect is easy to handle because P
846212904Sdim  // would necessarily be one of the effective-context records, and we
847212904Sdim  // address that above.  The 'friend' aspect is completely ridiculous
848212904Sdim  // to implement because there are no restrictions at all on P
849212904Sdim  // *unless* the [class.protected] restriction applies.  If it does,
850212904Sdim  // however, we should ignore whether the naming class is a friend,
851212904Sdim  // and instead rely on whether any potential P is a friend.
852235633Sdim  if (Access == AS_protected && Target.isInstanceMember()) {
853235633Sdim    // Compute the instance context if possible.
854235633Sdim    const CXXRecordDecl *InstanceContext = 0;
855235633Sdim    if (Target.hasInstanceContext()) {
856235633Sdim      InstanceContext = Target.resolveInstanceContext(S);
857235633Sdim      if (!InstanceContext) return AR_dependent;
858235633Sdim    }
859235633Sdim
860212904Sdim    switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) {
861212904Sdim    case AR_accessible: return AR_accessible;
862207619Srdivacky    case AR_inaccessible: return OnFailure;
863207619Srdivacky    case AR_dependent: return AR_dependent;
864207619Srdivacky    }
865212904Sdim    llvm_unreachable("impossible friendship kind");
866207619Srdivacky  }
867207619Srdivacky
868207619Srdivacky  switch (GetFriendKind(S, EC, NamingClass)) {
869207619Srdivacky  case AR_accessible: return AR_accessible;
870207619Srdivacky  case AR_inaccessible: return OnFailure;
871207619Srdivacky  case AR_dependent: return AR_dependent;
872207619Srdivacky  }
873207619Srdivacky
874207619Srdivacky  // Silence bogus warnings
875207619Srdivacky  llvm_unreachable("impossible friendship kind");
876206084Srdivacky}
877206084Srdivacky
878203955Srdivacky/// Finds the best path from the naming class to the declaring class,
879203955Srdivacky/// taking friend declarations into account.
880203955Srdivacky///
881206084Srdivacky/// C++0x [class.access.base]p5:
882206084Srdivacky///   A member m is accessible at the point R when named in class N if
883206084Srdivacky///   [M1] m as a member of N is public, or
884206084Srdivacky///   [M2] m as a member of N is private, and R occurs in a member or
885206084Srdivacky///        friend of class N, or
886206084Srdivacky///   [M3] m as a member of N is protected, and R occurs in a member or
887206084Srdivacky///        friend of class N, or in a member or friend of a class P
888206084Srdivacky///        derived from N, where m as a member of P is public, private,
889206084Srdivacky///        or protected, or
890206084Srdivacky///   [M4] there exists a base class B of N that is accessible at R, and
891206084Srdivacky///        m is accessible at R when named in class B.
892206084Srdivacky///
893206084Srdivacky/// C++0x [class.access.base]p4:
894206084Srdivacky///   A base class B of N is accessible at R, if
895206084Srdivacky///   [B1] an invented public member of B would be a public member of N, or
896206084Srdivacky///   [B2] R occurs in a member or friend of class N, and an invented public
897206084Srdivacky///        member of B would be a private or protected member of N, or
898206084Srdivacky///   [B3] R occurs in a member or friend of a class P derived from N, and an
899206084Srdivacky///        invented public member of B would be a private or protected member
900206084Srdivacky///        of P, or
901206084Srdivacky///   [B4] there exists a class S such that B is a base class of S accessible
902206084Srdivacky///        at R and S is a base class of N accessible at R.
903206084Srdivacky///
904206084Srdivacky/// Along a single inheritance path we can restate both of these
905206084Srdivacky/// iteratively:
906206084Srdivacky///
907206084Srdivacky/// First, we note that M1-4 are equivalent to B1-4 if the member is
908206084Srdivacky/// treated as a notional base of its declaring class with inheritance
909206084Srdivacky/// access equivalent to the member's access.  Therefore we need only
910206084Srdivacky/// ask whether a class B is accessible from a class N in context R.
911206084Srdivacky///
912206084Srdivacky/// Let B_1 .. B_n be the inheritance path in question (i.e. where
913206084Srdivacky/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
914206084Srdivacky/// B_i).  For i in 1..n, we will calculate ACAB(i), the access to the
915206084Srdivacky/// closest accessible base in the path:
916206084Srdivacky///   Access(a, b) = (* access on the base specifier from a to b *)
917206084Srdivacky///   Merge(a, forbidden) = forbidden
918206084Srdivacky///   Merge(a, private) = forbidden
919206084Srdivacky///   Merge(a, b) = min(a,b)
920206084Srdivacky///   Accessible(c, forbidden) = false
921206084Srdivacky///   Accessible(c, private) = (R is c) || IsFriend(c, R)
922206084Srdivacky///   Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
923206084Srdivacky///   Accessible(c, public) = true
924206084Srdivacky///   ACAB(n) = public
925206084Srdivacky///   ACAB(i) =
926206084Srdivacky///     let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
927206084Srdivacky///     if Accessible(B_i, AccessToBase) then public else AccessToBase
928206084Srdivacky///
929206084Srdivacky/// B is an accessible base of N at R iff ACAB(1) = public.
930206084Srdivacky///
931207619Srdivacky/// \param FinalAccess the access of the "final step", or AS_public if
932205408Srdivacky///   there is no final step.
933203955Srdivacky/// \return null if friendship is dependent
934203955Srdivackystatic CXXBasePath *FindBestPath(Sema &S,
935203955Srdivacky                                 const EffectiveContext &EC,
936207619Srdivacky                                 AccessTarget &Target,
937205408Srdivacky                                 AccessSpecifier FinalAccess,
938203955Srdivacky                                 CXXBasePaths &Paths) {
939203955Srdivacky  // Derive the paths to the desired base.
940207619Srdivacky  const CXXRecordDecl *Derived = Target.getNamingClass();
941207619Srdivacky  const CXXRecordDecl *Base = Target.getDeclaringClass();
942207619Srdivacky
943207619Srdivacky  // FIXME: fail correctly when there are dependent paths.
944207619Srdivacky  bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base),
945207619Srdivacky                                          Paths);
946203955Srdivacky  assert(isDerived && "derived class not actually derived from base");
947203955Srdivacky  (void) isDerived;
948203955Srdivacky
949203955Srdivacky  CXXBasePath *BestPath = 0;
950203955Srdivacky
951205408Srdivacky  assert(FinalAccess != AS_none && "forbidden access after declaring class");
952205408Srdivacky
953206084Srdivacky  bool AnyDependent = false;
954206084Srdivacky
955203955Srdivacky  // Derive the friend-modified access along each path.
956203955Srdivacky  for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
957203955Srdivacky         PI != PE; ++PI) {
958207619Srdivacky    AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext();
959203955Srdivacky
960203955Srdivacky    // Walk through the path backwards.
961205408Srdivacky    AccessSpecifier PathAccess = FinalAccess;
962203955Srdivacky    CXXBasePath::iterator I = PI->end(), E = PI->begin();
963203955Srdivacky    while (I != E) {
964203955Srdivacky      --I;
965203955Srdivacky
966205408Srdivacky      assert(PathAccess != AS_none);
967205408Srdivacky
968205408Srdivacky      // If the declaration is a private member of a base class, there
969205408Srdivacky      // is no level of friendship in derived classes that can make it
970205408Srdivacky      // accessible.
971205408Srdivacky      if (PathAccess == AS_private) {
972205408Srdivacky        PathAccess = AS_none;
973205408Srdivacky        break;
974205408Srdivacky      }
975205408Srdivacky
976207619Srdivacky      const CXXRecordDecl *NC = I->Class->getCanonicalDecl();
977207619Srdivacky
978203955Srdivacky      AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
979206084Srdivacky      PathAccess = std::max(PathAccess, BaseAccess);
980207619Srdivacky
981207619Srdivacky      switch (HasAccess(S, EC, NC, PathAccess, Target)) {
982207619Srdivacky      case AR_inaccessible: break;
983207619Srdivacky      case AR_accessible:
984207619Srdivacky        PathAccess = AS_public;
985207619Srdivacky
986207619Srdivacky        // Future tests are not against members and so do not have
987207619Srdivacky        // instance context.
988207619Srdivacky        Target.suppressInstanceContext();
989207619Srdivacky        break;
990207619Srdivacky      case AR_dependent:
991206084Srdivacky        AnyDependent = true;
992206084Srdivacky        goto Next;
993193326Sed      }
994193326Sed    }
995198092Srdivacky
996203955Srdivacky    // Note that we modify the path's Access field to the
997203955Srdivacky    // friend-modified access.
998203955Srdivacky    if (BestPath == 0 || PathAccess < BestPath->Access) {
999203955Srdivacky      BestPath = &*PI;
1000203955Srdivacky      BestPath->Access = PathAccess;
1001206084Srdivacky
1002206084Srdivacky      // Short-circuit if we found a public path.
1003206084Srdivacky      if (BestPath->Access == AS_public)
1004206084Srdivacky        return BestPath;
1005193326Sed    }
1006206084Srdivacky
1007206084Srdivacky  Next: ;
1008193326Sed  }
1009193326Sed
1010206084Srdivacky  assert((!BestPath || BestPath->Access != AS_public) &&
1011206084Srdivacky         "fell out of loop with public path");
1012206084Srdivacky
1013206084Srdivacky  // We didn't find a public path, but at least one path was subject
1014206084Srdivacky  // to dependent friendship, so delay the check.
1015206084Srdivacky  if (AnyDependent)
1016206084Srdivacky    return 0;
1017206084Srdivacky
1018203955Srdivacky  return BestPath;
1019198092Srdivacky}
1020198092Srdivacky
1021212904Sdim/// Given that an entity has protected natural access, check whether
1022212904Sdim/// access might be denied because of the protected member access
1023212904Sdim/// restriction.
1024212904Sdim///
1025212904Sdim/// \return true if a note was emitted
1026212904Sdimstatic bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
1027212904Sdim                                       AccessTarget &Target) {
1028212904Sdim  // Only applies to instance accesses.
1029235633Sdim  if (!Target.isInstanceMember())
1030212904Sdim    return false;
1031235633Sdim
1032212904Sdim  assert(Target.isMemberAccess());
1033212904Sdim
1034252723Sdim  const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass();
1035212904Sdim
1036212904Sdim  for (EffectiveContext::record_iterator
1037212904Sdim         I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
1038212904Sdim    const CXXRecordDecl *ECRecord = *I;
1039235633Sdim    switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
1040212904Sdim    case AR_accessible: break;
1041212904Sdim    case AR_inaccessible: continue;
1042212904Sdim    case AR_dependent: continue;
1043212904Sdim    }
1044212904Sdim
1045212904Sdim    // The effective context is a subclass of the declaring class.
1046235633Sdim    // Check whether the [class.protected] restriction is limiting
1047235633Sdim    // access.
1048212904Sdim
1049212904Sdim    // To get this exactly right, this might need to be checked more
1050212904Sdim    // holistically;  it's not necessarily the case that gaining
1051212904Sdim    // access here would grant us access overall.
1052212904Sdim
1053235633Sdim    NamedDecl *D = Target.getTargetDecl();
1054235633Sdim
1055235633Sdim    // If we don't have an instance context, [class.protected] says the
1056235633Sdim    // naming class has to equal the context class.
1057235633Sdim    if (!Target.hasInstanceContext()) {
1058235633Sdim      // If it does, the restriction doesn't apply.
1059235633Sdim      if (NamingClass == ECRecord) continue;
1060235633Sdim
1061235633Sdim      // TODO: it would be great to have a fixit here, since this is
1062235633Sdim      // such an obvious error.
1063235633Sdim      S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject)
1064235633Sdim        << S.Context.getTypeDeclType(ECRecord);
1065235633Sdim      return true;
1066235633Sdim    }
1067235633Sdim
1068212904Sdim    const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
1069212904Sdim    assert(InstanceContext && "diagnosing dependent access");
1070212904Sdim
1071212904Sdim    switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
1072212904Sdim    case AR_accessible: continue;
1073212904Sdim    case AR_dependent: continue;
1074212904Sdim    case AR_inaccessible:
1075235633Sdim      break;
1076235633Sdim    }
1077235633Sdim
1078235633Sdim    // Okay, the restriction seems to be what's limiting us.
1079235633Sdim
1080235633Sdim    // Use a special diagnostic for constructors and destructors.
1081235633Sdim    if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) ||
1082235633Sdim        (isa<FunctionTemplateDecl>(D) &&
1083235633Sdim         isa<CXXConstructorDecl>(
1084235633Sdim                cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) {
1085235633Sdim      S.Diag(D->getLocation(), diag::note_access_protected_restricted_ctordtor)
1086235633Sdim        << isa<CXXDestructorDecl>(D);
1087212904Sdim      return true;
1088212904Sdim    }
1089235633Sdim
1090235633Sdim    // Otherwise, use the generic diagnostic.
1091235633Sdim    S.Diag(D->getLocation(), diag::note_access_protected_restricted_object)
1092235633Sdim      << S.Context.getTypeDeclType(ECRecord);
1093235633Sdim    return true;
1094212904Sdim  }
1095212904Sdim
1096212904Sdim  return false;
1097212904Sdim}
1098212904Sdim
1099252723Sdim/// We are unable to access a given declaration due to its direct
1100252723Sdim/// access control;  diagnose that.
1101252723Sdimstatic void diagnoseBadDirectAccess(Sema &S,
1102252723Sdim                                    const EffectiveContext &EC,
1103252723Sdim                                    AccessTarget &entity) {
1104252723Sdim  assert(entity.isMemberAccess());
1105252723Sdim  NamedDecl *D = entity.getTargetDecl();
1106252723Sdim
1107252723Sdim  if (D->getAccess() == AS_protected &&
1108252723Sdim      TryDiagnoseProtectedAccess(S, EC, entity))
1109252723Sdim    return;
1110252723Sdim
1111252723Sdim  // Find an original declaration.
1112252723Sdim  while (D->isOutOfLine()) {
1113252723Sdim    NamedDecl *PrevDecl = 0;
1114252723Sdim    if (VarDecl *VD = dyn_cast<VarDecl>(D))
1115252723Sdim      PrevDecl = VD->getPreviousDecl();
1116252723Sdim    else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
1117252723Sdim      PrevDecl = FD->getPreviousDecl();
1118252723Sdim    else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
1119252723Sdim      PrevDecl = TND->getPreviousDecl();
1120252723Sdim    else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
1121252723Sdim      if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
1122252723Sdim        break;
1123252723Sdim      PrevDecl = TD->getPreviousDecl();
1124252723Sdim    }
1125252723Sdim    if (!PrevDecl) break;
1126252723Sdim    D = PrevDecl;
1127252723Sdim  }
1128252723Sdim
1129252723Sdim  CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
1130252723Sdim  Decl *ImmediateChild;
1131252723Sdim  if (D->getDeclContext() == DeclaringClass)
1132252723Sdim    ImmediateChild = D;
1133252723Sdim  else {
1134252723Sdim    DeclContext *DC = D->getDeclContext();
1135252723Sdim    while (DC->getParent() != DeclaringClass)
1136252723Sdim      DC = DC->getParent();
1137252723Sdim    ImmediateChild = cast<Decl>(DC);
1138252723Sdim  }
1139252723Sdim
1140252723Sdim  // Check whether there's an AccessSpecDecl preceding this in the
1141252723Sdim  // chain of the DeclContext.
1142252723Sdim  bool isImplicit = true;
1143252723Sdim  for (CXXRecordDecl::decl_iterator
1144252723Sdim         I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end();
1145252723Sdim       I != E; ++I) {
1146252723Sdim    if (*I == ImmediateChild) break;
1147252723Sdim    if (isa<AccessSpecDecl>(*I)) {
1148252723Sdim      isImplicit = false;
1149252723Sdim      break;
1150252723Sdim    }
1151252723Sdim  }
1152252723Sdim
1153252723Sdim  S.Diag(D->getLocation(), diag::note_access_natural)
1154252723Sdim    << (unsigned) (D->getAccess() == AS_protected)
1155252723Sdim    << isImplicit;
1156252723Sdim}
1157252723Sdim
1158203955Srdivacky/// Diagnose the path which caused the given declaration or base class
1159203955Srdivacky/// to become inaccessible.
1160203955Srdivackystatic void DiagnoseAccessPath(Sema &S,
1161203955Srdivacky                               const EffectiveContext &EC,
1162252723Sdim                               AccessTarget &entity) {
1163252723Sdim  // Save the instance context to preserve invariants.
1164252723Sdim  AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext();
1165206084Srdivacky
1166252723Sdim  // This basically repeats the main algorithm but keeps some more
1167252723Sdim  // information.
1168206084Srdivacky
1169252723Sdim  // The natural access so far.
1170252723Sdim  AccessSpecifier accessSoFar = AS_public;
1171212904Sdim
1172252723Sdim  // Check whether we have special rights to the declaring class.
1173252723Sdim  if (entity.isMemberAccess()) {
1174252723Sdim    NamedDecl *D = entity.getTargetDecl();
1175252723Sdim    accessSoFar = D->getAccess();
1176252723Sdim    const CXXRecordDecl *declaringClass = entity.getDeclaringClass();
1177218893Sdim
1178252723Sdim    switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) {
1179252723Sdim    // If the declaration is accessible when named in its declaring
1180252723Sdim    // class, then we must be constrained by the path.
1181252723Sdim    case AR_accessible:
1182252723Sdim      accessSoFar = AS_public;
1183252723Sdim      entity.suppressInstanceContext();
1184252723Sdim      break;
1185218893Sdim
1186252723Sdim    case AR_inaccessible:
1187252723Sdim      if (accessSoFar == AS_private ||
1188252723Sdim          declaringClass == entity.getEffectiveNamingClass())
1189252723Sdim        return diagnoseBadDirectAccess(S, EC, entity);
1190252723Sdim      break;
1191198092Srdivacky
1192207619Srdivacky    case AR_dependent:
1193252723Sdim      llvm_unreachable("cannot diagnose dependent access");
1194203955Srdivacky    }
1195203955Srdivacky  }
1196193326Sed
1197252723Sdim  CXXBasePaths paths;
1198252723Sdim  CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths);
1199252723Sdim  assert(path.Access != AS_public);
1200198092Srdivacky
1201252723Sdim  CXXBasePath::iterator i = path.end(), e = path.begin();
1202252723Sdim  CXXBasePath::iterator constrainingBase = i;
1203252723Sdim  while (i != e) {
1204252723Sdim    --i;
1205193326Sed
1206252723Sdim    assert(accessSoFar != AS_none && accessSoFar != AS_private);
1207203955Srdivacky
1208252723Sdim    // Is the entity accessible when named in the deriving class, as
1209252723Sdim    // modified by the base specifier?
1210252723Sdim    const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl();
1211252723Sdim    const CXXBaseSpecifier *base = i->Base;
1212203955Srdivacky
1213252723Sdim    // If the access to this base is worse than the access we have to
1214252723Sdim    // the declaration, remember it.
1215252723Sdim    AccessSpecifier baseAccess = base->getAccessSpecifier();
1216252723Sdim    if (baseAccess > accessSoFar) {
1217252723Sdim      constrainingBase = i;
1218252723Sdim      accessSoFar = baseAccess;
1219252723Sdim    }
1220252723Sdim
1221252723Sdim    switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) {
1222207619Srdivacky    case AR_inaccessible: break;
1223252723Sdim    case AR_accessible:
1224252723Sdim      accessSoFar = AS_public;
1225252723Sdim      entity.suppressInstanceContext();
1226252723Sdim      constrainingBase = 0;
1227252723Sdim      break;
1228207619Srdivacky    case AR_dependent:
1229252723Sdim      llvm_unreachable("cannot diagnose dependent access");
1230203955Srdivacky    }
1231203955Srdivacky
1232252723Sdim    // If this was private inheritance, but we don't have access to
1233252723Sdim    // the deriving class, we're done.
1234252723Sdim    if (accessSoFar == AS_private) {
1235252723Sdim      assert(baseAccess == AS_private);
1236252723Sdim      assert(constrainingBase == i);
1237252723Sdim      break;
1238252723Sdim    }
1239252723Sdim  }
1240203955Srdivacky
1241252723Sdim  // If we don't have a constraining base, the access failure must be
1242252723Sdim  // due to the original declaration.
1243252723Sdim  if (constrainingBase == path.end())
1244252723Sdim    return diagnoseBadDirectAccess(S, EC, entity);
1245203955Srdivacky
1246252723Sdim  // We're constrained by inheritance, but we want to say
1247252723Sdim  // "declared private here" if we're diagnosing a hierarchy
1248252723Sdim  // conversion and this is the final step.
1249252723Sdim  unsigned diagnostic;
1250252723Sdim  if (entity.isMemberAccess() ||
1251252723Sdim      constrainingBase + 1 != path.end()) {
1252252723Sdim    diagnostic = diag::note_access_constrained_by_path;
1253252723Sdim  } else {
1254252723Sdim    diagnostic = diag::note_access_natural;
1255193326Sed  }
1256198092Srdivacky
1257252723Sdim  const CXXBaseSpecifier *base = constrainingBase->Base;
1258252723Sdim
1259252723Sdim  S.Diag(base->getSourceRange().getBegin(), diagnostic)
1260252723Sdim    << base->getSourceRange()
1261252723Sdim    << (base->getAccessSpecifier() == AS_protected)
1262252723Sdim    << (base->getAccessSpecifierAsWritten() == AS_none);
1263252723Sdim
1264252723Sdim  if (entity.isMemberAccess())
1265252723Sdim    S.Diag(entity.getTargetDecl()->getLocation(), diag::note_field_decl);
1266193326Sed}
1267202879Srdivacky
1268206084Srdivackystatic void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
1269206084Srdivacky                              const EffectiveContext &EC,
1270207619Srdivacky                              AccessTarget &Entity) {
1271206084Srdivacky  const CXXRecordDecl *NamingClass = Entity.getNamingClass();
1272207619Srdivacky  const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
1273207619Srdivacky  NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
1274203955Srdivacky
1275205219Srdivacky  S.Diag(Loc, Entity.getDiag())
1276206084Srdivacky    << (Entity.getAccess() == AS_protected)
1277206084Srdivacky    << (D ? D->getDeclName() : DeclarationName())
1278205219Srdivacky    << S.Context.getTypeDeclType(NamingClass)
1279205219Srdivacky    << S.Context.getTypeDeclType(DeclaringClass);
1280206084Srdivacky  DiagnoseAccessPath(S, EC, Entity);
1281203955Srdivacky}
1282202879Srdivacky
1283223017Sdim/// MSVC has a bug where if during an using declaration name lookup,
1284223017Sdim/// the declaration found is unaccessible (private) and that declaration
1285223017Sdim/// was bring into scope via another using declaration whose target
1286223017Sdim/// declaration is accessible (public) then no error is generated.
1287223017Sdim/// Example:
1288223017Sdim///   class A {
1289223017Sdim///   public:
1290223017Sdim///     int f();
1291223017Sdim///   };
1292223017Sdim///   class B : public A {
1293223017Sdim///   private:
1294223017Sdim///     using A::f;
1295223017Sdim///   };
1296223017Sdim///   class C : public B {
1297223017Sdim///   private:
1298223017Sdim///     using B::f;
1299223017Sdim///   };
1300223017Sdim///
1301223017Sdim/// Here, B::f is private so this should fail in Standard C++, but
1302223017Sdim/// because B::f refers to A::f which is public MSVC accepts it.
1303223017Sdimstatic bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
1304223017Sdim                                                 SourceLocation AccessLoc,
1305223017Sdim                                                 AccessTarget &Entity) {
1306223017Sdim  if (UsingShadowDecl *Shadow =
1307223017Sdim                         dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) {
1308223017Sdim    const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl();
1309223017Sdim    if (Entity.getTargetDecl()->getAccess() == AS_private &&
1310223017Sdim        (OrigDecl->getAccess() == AS_public ||
1311223017Sdim         OrigDecl->getAccess() == AS_protected)) {
1312235633Sdim      S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible)
1313223017Sdim        << Shadow->getUsingDecl()->getQualifiedNameAsString()
1314223017Sdim        << OrigDecl->getQualifiedNameAsString();
1315223017Sdim      return true;
1316223017Sdim    }
1317223017Sdim  }
1318223017Sdim  return false;
1319223017Sdim}
1320223017Sdim
1321206084Srdivacky/// Determines whether the accessed entity is accessible.  Public members
1322206084Srdivacky/// have been weeded out by this point.
1323207619Srdivackystatic AccessResult IsAccessible(Sema &S,
1324207619Srdivacky                                 const EffectiveContext &EC,
1325207619Srdivacky                                 AccessTarget &Entity) {
1326206084Srdivacky  // Determine the actual naming class.
1327252723Sdim  const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();
1328202879Srdivacky
1329206084Srdivacky  AccessSpecifier UnprivilegedAccess = Entity.getAccess();
1330206084Srdivacky  assert(UnprivilegedAccess != AS_public && "public access not weeded out");
1331202879Srdivacky
1332206084Srdivacky  // Before we try to recalculate access paths, try to white-list
1333206084Srdivacky  // accesses which just trade in on the final step, i.e. accesses
1334206084Srdivacky  // which don't require [M4] or [B4]. These are by far the most
1335207619Srdivacky  // common forms of privileged access.
1336206084Srdivacky  if (UnprivilegedAccess != AS_none) {
1337207619Srdivacky    switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) {
1338207619Srdivacky    case AR_dependent:
1339206084Srdivacky      // This is actually an interesting policy decision.  We don't
1340206084Srdivacky      // *have* to delay immediately here: we can do the full access
1341206084Srdivacky      // calculation in the hope that friendship on some intermediate
1342206084Srdivacky      // class will make the declaration accessible non-dependently.
1343206084Srdivacky      // But that's not cheap, and odds are very good (note: assertion
1344206084Srdivacky      // made without data) that the friend declaration will determine
1345206084Srdivacky      // access.
1346207619Srdivacky      return AR_dependent;
1347202879Srdivacky
1348207619Srdivacky    case AR_accessible: return AR_accessible;
1349207619Srdivacky    case AR_inaccessible: break;
1350206084Srdivacky    }
1351206084Srdivacky  }
1352206084Srdivacky
1353207619Srdivacky  AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();
1354202879Srdivacky
1355206084Srdivacky  // We lower member accesses to base accesses by pretending that the
1356206084Srdivacky  // member is a base class of its declaring class.
1357206084Srdivacky  AccessSpecifier FinalAccess;
1358206084Srdivacky
1359203955Srdivacky  if (Entity.isMemberAccess()) {
1360206084Srdivacky    // Determine if the declaration is accessible from EC when named
1361206084Srdivacky    // in its declaring class.
1362203955Srdivacky    NamedDecl *Target = Entity.getTargetDecl();
1363207619Srdivacky    const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
1364203955Srdivacky
1365206084Srdivacky    FinalAccess = Target->getAccess();
1366207619Srdivacky    switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
1367207619Srdivacky    case AR_accessible:
1368252723Sdim      // Target is accessible at EC when named in its declaring class.
1369252723Sdim      // We can now hill-climb and simply check whether the declaring
1370252723Sdim      // class is accessible as a base of the naming class.  This is
1371252723Sdim      // equivalent to checking the access of a notional public
1372252723Sdim      // member with no instance context.
1373207619Srdivacky      FinalAccess = AS_public;
1374252723Sdim      Entity.suppressInstanceContext();
1375207619Srdivacky      break;
1376207619Srdivacky    case AR_inaccessible: break;
1377207619Srdivacky    case AR_dependent: return AR_dependent; // see above
1378203955Srdivacky    }
1379203955Srdivacky
1380206084Srdivacky    if (DeclaringClass == NamingClass)
1381207619Srdivacky      return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
1382206084Srdivacky  } else {
1383206084Srdivacky    FinalAccess = AS_public;
1384202879Srdivacky  }
1385202879Srdivacky
1386207619Srdivacky  assert(Entity.getDeclaringClass() != NamingClass);
1387203955Srdivacky
1388203955Srdivacky  // Append the declaration's access if applicable.
1389203955Srdivacky  CXXBasePaths Paths;
1390207619Srdivacky  CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths);
1391206084Srdivacky  if (!Path)
1392207619Srdivacky    return AR_dependent;
1393203955Srdivacky
1394206084Srdivacky  assert(Path->Access <= UnprivilegedAccess &&
1395206084Srdivacky         "access along best path worse than direct?");
1396206084Srdivacky  if (Path->Access == AS_public)
1397207619Srdivacky    return AR_accessible;
1398207619Srdivacky  return AR_inaccessible;
1399203955Srdivacky}
1400203955Srdivacky
1401207619Srdivackystatic void DelayDependentAccess(Sema &S,
1402207619Srdivacky                                 const EffectiveContext &EC,
1403207619Srdivacky                                 SourceLocation Loc,
1404207619Srdivacky                                 const AccessTarget &Entity) {
1405206084Srdivacky  assert(EC.isDependent() && "delaying non-dependent access");
1406206084Srdivacky  DeclContext *DC = EC.getInnerContext();
1407206084Srdivacky  assert(DC->isDependentContext() && "delaying non-dependent access");
1408206084Srdivacky  DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
1409206084Srdivacky                              Loc,
1410206084Srdivacky                              Entity.isMemberAccess(),
1411206084Srdivacky                              Entity.getAccess(),
1412206084Srdivacky                              Entity.getTargetDecl(),
1413206084Srdivacky                              Entity.getNamingClass(),
1414207619Srdivacky                              Entity.getBaseObjectType(),
1415206084Srdivacky                              Entity.getDiag());
1416206084Srdivacky}
1417206084Srdivacky
1418203955Srdivacky/// Checks access to an entity from the given effective context.
1419207619Srdivackystatic AccessResult CheckEffectiveAccess(Sema &S,
1420207619Srdivacky                                         const EffectiveContext &EC,
1421207619Srdivacky                                         SourceLocation Loc,
1422207619Srdivacky                                         AccessTarget &Entity) {
1423206084Srdivacky  assert(Entity.getAccess() != AS_public && "called for public access!");
1424203955Srdivacky
1425235633Sdim  if (S.getLangOpts().MicrosoftMode &&
1426223017Sdim      IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
1427223017Sdim    return AR_accessible;
1428223017Sdim
1429206084Srdivacky  switch (IsAccessible(S, EC, Entity)) {
1430207619Srdivacky  case AR_dependent:
1431207619Srdivacky    DelayDependentAccess(S, EC, Loc, Entity);
1432207619Srdivacky    return AR_dependent;
1433202879Srdivacky
1434207619Srdivacky  case AR_inaccessible:
1435206084Srdivacky    if (!Entity.isQuiet())
1436206084Srdivacky      DiagnoseBadAccess(S, Loc, EC, Entity);
1437207619Srdivacky    return AR_inaccessible;
1438203955Srdivacky
1439207619Srdivacky  case AR_accessible:
1440207619Srdivacky    return AR_accessible;
1441206084Srdivacky  }
1442202879Srdivacky
1443207619Srdivacky  // silence unnecessary warning
1444207619Srdivacky  llvm_unreachable("invalid access result");
1445203955Srdivacky}
1446202879Srdivacky
1447203955Srdivackystatic Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
1448207619Srdivacky                                      AccessTarget &Entity) {
1449203955Srdivacky  // If the access path is public, it's accessible everywhere.
1450203955Srdivacky  if (Entity.getAccess() == AS_public)
1451203955Srdivacky    return Sema::AR_accessible;
1452202879Srdivacky
1453218893Sdim  // If we're currently parsing a declaration, we may need to delay
1454218893Sdim  // access control checking, because our effective context might be
1455218893Sdim  // different based on what the declaration comes out as.
1456218893Sdim  //
1457218893Sdim  // For example, we might be parsing a declaration with a scope
1458218893Sdim  // specifier, like this:
1459218893Sdim  //   A::private_type A::foo() { ... }
1460218893Sdim  //
1461218893Sdim  // Or we might be parsing something that will turn out to be a friend:
1462218893Sdim  //   void foo(A::private_type);
1463218893Sdim  //   void B::foo(A::private_type);
1464218893Sdim  if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
1465218893Sdim    S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity));
1466203955Srdivacky    return Sema::AR_delayed;
1467202879Srdivacky  }
1468202879Srdivacky
1469207619Srdivacky  EffectiveContext EC(S.CurContext);
1470207619Srdivacky  switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
1471207619Srdivacky  case AR_accessible: return Sema::AR_accessible;
1472207619Srdivacky  case AR_inaccessible: return Sema::AR_inaccessible;
1473207619Srdivacky  case AR_dependent: return Sema::AR_dependent;
1474207619Srdivacky  }
1475207619Srdivacky  llvm_unreachable("falling off end");
1476202879Srdivacky}
1477202879Srdivacky
1478252723Sdimvoid Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
1479218893Sdim  // Access control for names used in the declarations of functions
1480218893Sdim  // and function templates should normally be evaluated in the context
1481218893Sdim  // of the declaration, just in case it's a friend of something.
1482218893Sdim  // However, this does not apply to local extern declarations.
1483218893Sdim
1484252723Sdim  DeclContext *DC = D->getDeclContext();
1485252723Sdim  if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {
1486263509Sdim    if (D->getLexicalDeclContext()->isFunctionOrMethod())
1487263509Sdim      DC = D->getLexicalDeclContext();
1488263509Sdim    else
1489252723Sdim      DC = FN;
1490252723Sdim  } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
1491252723Sdim    DC = cast<DeclContext>(TD->getTemplatedDecl());
1492218893Sdim  }
1493218893Sdim
1494207619Srdivacky  EffectiveContext EC(DC);
1495203955Srdivacky
1496207619Srdivacky  AccessTarget Target(DD.getAccessData());
1497207619Srdivacky
1498207619Srdivacky  if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible)
1499203955Srdivacky    DD.Triggered = true;
1500203955Srdivacky}
1501203955Srdivacky
1502206084Srdivackyvoid Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
1503206084Srdivacky                        const MultiLevelTemplateArgumentList &TemplateArgs) {
1504206084Srdivacky  SourceLocation Loc = DD.getAccessLoc();
1505206084Srdivacky  AccessSpecifier Access = DD.getAccess();
1506206084Srdivacky
1507206084Srdivacky  Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
1508206084Srdivacky                                       TemplateArgs);
1509206084Srdivacky  if (!NamingD) return;
1510206084Srdivacky  Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
1511206084Srdivacky                                       TemplateArgs);
1512206084Srdivacky  if (!TargetD) return;
1513206084Srdivacky
1514206084Srdivacky  if (DD.isAccessToMember()) {
1515207619Srdivacky    CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD);
1516207619Srdivacky    NamedDecl *TargetDecl = cast<NamedDecl>(TargetD);
1517207619Srdivacky    QualType BaseObjectType = DD.getAccessBaseObjectType();
1518207619Srdivacky    if (!BaseObjectType.isNull()) {
1519207619Srdivacky      BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc,
1520207619Srdivacky                                 DeclarationName());
1521207619Srdivacky      if (BaseObjectType.isNull()) return;
1522207619Srdivacky    }
1523207619Srdivacky
1524207619Srdivacky    AccessTarget Entity(Context,
1525207619Srdivacky                        AccessTarget::Member,
1526207619Srdivacky                        NamingClass,
1527207619Srdivacky                        DeclAccessPair::make(TargetDecl, Access),
1528207619Srdivacky                        BaseObjectType);
1529206084Srdivacky    Entity.setDiag(DD.getDiagnostic());
1530206084Srdivacky    CheckAccess(*this, Loc, Entity);
1531206084Srdivacky  } else {
1532207619Srdivacky    AccessTarget Entity(Context,
1533207619Srdivacky                        AccessTarget::Base,
1534207619Srdivacky                        cast<CXXRecordDecl>(TargetD),
1535207619Srdivacky                        cast<CXXRecordDecl>(NamingD),
1536207619Srdivacky                        Access);
1537206084Srdivacky    Entity.setDiag(DD.getDiagnostic());
1538206084Srdivacky    CheckAccess(*this, Loc, Entity);
1539206084Srdivacky  }
1540206084Srdivacky}
1541206084Srdivacky
1542203955SrdivackySema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
1543205408Srdivacky                                                     DeclAccessPair Found) {
1544235633Sdim  if (!getLangOpts().AccessControl ||
1545205219Srdivacky      !E->getNamingClass() ||
1546205408Srdivacky      Found.getAccess() == AS_public)
1547203955Srdivacky    return AR_accessible;
1548203955Srdivacky
1549207619Srdivacky  AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
1550207619Srdivacky                      Found, QualType());
1551205219Srdivacky  Entity.setDiag(diag::err_access) << E->getSourceRange();
1552205219Srdivacky
1553205219Srdivacky  return CheckAccess(*this, E->getNameLoc(), Entity);
1554203955Srdivacky}
1555203955Srdivacky
1556203955Srdivacky/// Perform access-control checking on a previously-unresolved member
1557203955Srdivacky/// access which has now been resolved to a member.
1558203955SrdivackySema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
1559205408Srdivacky                                                     DeclAccessPair Found) {
1560235633Sdim  if (!getLangOpts().AccessControl ||
1561205408Srdivacky      Found.getAccess() == AS_public)
1562203955Srdivacky    return AR_accessible;
1563203955Srdivacky
1564207619Srdivacky  QualType BaseType = E->getBaseType();
1565207619Srdivacky  if (E->isArrow())
1566207619Srdivacky    BaseType = BaseType->getAs<PointerType>()->getPointeeType();
1567207619Srdivacky
1568207619Srdivacky  AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
1569207619Srdivacky                      Found, BaseType);
1570205219Srdivacky  Entity.setDiag(diag::err_access) << E->getSourceRange();
1571205219Srdivacky
1572205219Srdivacky  return CheckAccess(*this, E->getMemberLoc(), Entity);
1573203955Srdivacky}
1574203955Srdivacky
1575235633Sdim/// Is the given special member function accessible for the purposes of
1576235633Sdim/// deciding whether to define a special member function as deleted?
1577235633Sdimbool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl,
1578235633Sdim                                                AccessSpecifier access,
1579235633Sdim                                                QualType objectType) {
1580235633Sdim  // Fast path.
1581235633Sdim  if (access == AS_public || !getLangOpts().AccessControl) return true;
1582235633Sdim
1583235633Sdim  AccessTarget entity(Context, AccessTarget::Member, decl->getParent(),
1584235633Sdim                      DeclAccessPair::make(decl, access), objectType);
1585235633Sdim
1586235633Sdim  // Suppress diagnostics.
1587235633Sdim  entity.setDiag(PDiag());
1588235633Sdim
1589235633Sdim  switch (CheckAccess(*this, SourceLocation(), entity)) {
1590235633Sdim  case AR_accessible: return true;
1591235633Sdim  case AR_inaccessible: return false;
1592235633Sdim  case AR_dependent: llvm_unreachable("dependent for =delete computation");
1593235633Sdim  case AR_delayed: llvm_unreachable("cannot delay =delete computation");
1594235633Sdim  }
1595235633Sdim  llvm_unreachable("bad access result");
1596235633Sdim}
1597235633Sdim
1598203955SrdivackySema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
1599205219Srdivacky                                               CXXDestructorDecl *Dtor,
1600235633Sdim                                               const PartialDiagnostic &PDiag,
1601235633Sdim                                               QualType ObjectTy) {
1602235633Sdim  if (!getLangOpts().AccessControl)
1603203955Srdivacky    return AR_accessible;
1604203955Srdivacky
1605205219Srdivacky  // There's never a path involved when checking implicit destructor access.
1606203955Srdivacky  AccessSpecifier Access = Dtor->getAccess();
1607203955Srdivacky  if (Access == AS_public)
1608203955Srdivacky    return AR_accessible;
1609203955Srdivacky
1610205219Srdivacky  CXXRecordDecl *NamingClass = Dtor->getParent();
1611235633Sdim  if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass);
1612235633Sdim
1613207619Srdivacky  AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
1614207619Srdivacky                      DeclAccessPair::make(Dtor, Access),
1615235633Sdim                      ObjectTy);
1616205219Srdivacky  Entity.setDiag(PDiag); // TODO: avoid copy
1617205219Srdivacky
1618205219Srdivacky  return CheckAccess(*this, Loc, Entity);
1619203955Srdivacky}
1620203955Srdivacky
1621203955Srdivacky/// Checks access to a constructor.
1622203955SrdivackySema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
1623210299Sed                                                CXXConstructorDecl *Constructor,
1624210299Sed                                                const InitializedEntity &Entity,
1625210299Sed                                                AccessSpecifier Access,
1626210299Sed                                                bool IsCopyBindingRefToTemp) {
1627235633Sdim  if (!getLangOpts().AccessControl || Access == AS_public)
1628203955Srdivacky    return AR_accessible;
1629203955Srdivacky
1630223017Sdim  PartialDiagnostic PD(PDiag());
1631207619Srdivacky  switch (Entity.getKind()) {
1632207619Srdivacky  default:
1633223017Sdim    PD = PDiag(IsCopyBindingRefToTemp
1634223017Sdim                 ? diag::ext_rvalue_to_reference_access_ctor
1635223017Sdim                 : diag::err_access_ctor);
1636223017Sdim
1637207619Srdivacky    break;
1638205219Srdivacky
1639207619Srdivacky  case InitializedEntity::EK_Base:
1640223017Sdim    PD = PDiag(diag::err_access_base_ctor);
1641223017Sdim    PD << Entity.isInheritedVirtualBase()
1642223017Sdim       << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
1643207619Srdivacky    break;
1644207619Srdivacky
1645207619Srdivacky  case InitializedEntity::EK_Member: {
1646207619Srdivacky    const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
1647223017Sdim    PD = PDiag(diag::err_access_field_ctor);
1648223017Sdim    PD << Field->getType() << getSpecialMember(Constructor);
1649207619Srdivacky    break;
1650207619Srdivacky  }
1651207619Srdivacky
1652235633Sdim  case InitializedEntity::EK_LambdaCapture: {
1653263509Sdim    StringRef VarName = Entity.getCapturedVarName();
1654235633Sdim    PD = PDiag(diag::err_access_lambda_capture);
1655263509Sdim    PD << VarName << Entity.getType() << getSpecialMember(Constructor);
1656235633Sdim    break;
1657207619Srdivacky  }
1658207619Srdivacky
1659235633Sdim  }
1660235633Sdim
1661235633Sdim  return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD);
1662223017Sdim}
1663223017Sdim
1664223017Sdim/// Checks access to a constructor.
1665223017SdimSema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
1666223017Sdim                                                CXXConstructorDecl *Constructor,
1667235633Sdim                                                const InitializedEntity &Entity,
1668223017Sdim                                                AccessSpecifier Access,
1669235633Sdim                                                const PartialDiagnostic &PD) {
1670235633Sdim  if (!getLangOpts().AccessControl ||
1671223017Sdim      Access == AS_public)
1672223017Sdim    return AR_accessible;
1673223017Sdim
1674223017Sdim  CXXRecordDecl *NamingClass = Constructor->getParent();
1675235633Sdim
1676235633Sdim  // Initializing a base sub-object is an instance method call on an
1677235633Sdim  // object of the derived class.  Otherwise, we have an instance method
1678235633Sdim  // call on an object of the constructed type.
1679235633Sdim  CXXRecordDecl *ObjectClass;
1680235633Sdim  if (Entity.getKind() == InitializedEntity::EK_Base) {
1681235633Sdim    ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent();
1682235633Sdim  } else {
1683235633Sdim    ObjectClass = NamingClass;
1684235633Sdim  }
1685235633Sdim
1686223017Sdim  AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
1687223017Sdim                            DeclAccessPair::make(Constructor, Access),
1688235633Sdim                            Context.getTypeDeclType(ObjectClass));
1689223017Sdim  AccessEntity.setDiag(PD);
1690223017Sdim
1691207619Srdivacky  return CheckAccess(*this, UseLoc, AccessEntity);
1692235633Sdim}
1693203955Srdivacky
1694205408Srdivacky/// Checks access to an overloaded operator new or delete.
1695205408SrdivackySema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
1696205408Srdivacky                                               SourceRange PlacementRange,
1697205408Srdivacky                                               CXXRecordDecl *NamingClass,
1698223017Sdim                                               DeclAccessPair Found,
1699223017Sdim                                               bool Diagnose) {
1700235633Sdim  if (!getLangOpts().AccessControl ||
1701205408Srdivacky      !NamingClass ||
1702205408Srdivacky      Found.getAccess() == AS_public)
1703205408Srdivacky    return AR_accessible;
1704205408Srdivacky
1705207619Srdivacky  AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1706207619Srdivacky                      QualType());
1707223017Sdim  if (Diagnose)
1708223017Sdim    Entity.setDiag(diag::err_access)
1709223017Sdim      << PlacementRange;
1710205408Srdivacky
1711205408Srdivacky  return CheckAccess(*this, OpLoc, Entity);
1712205408Srdivacky}
1713205408Srdivacky
1714263509Sdim/// \brief Checks access to a member.
1715263509SdimSema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc,
1716263509Sdim                                           CXXRecordDecl *NamingClass,
1717263509Sdim                                           DeclAccessPair Found) {
1718263509Sdim  if (!getLangOpts().AccessControl ||
1719263509Sdim      !NamingClass ||
1720263509Sdim      Found.getAccess() == AS_public)
1721263509Sdim    return AR_accessible;
1722263509Sdim
1723263509Sdim  AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
1724263509Sdim                      Found, QualType());
1725263509Sdim
1726263509Sdim  return CheckAccess(*this, UseLoc, Entity);
1727263509Sdim}
1728263509Sdim
1729203955Srdivacky/// Checks access to an overloaded member operator, including
1730203955Srdivacky/// conversion operators.
1731203955SrdivackySema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
1732203955Srdivacky                                                   Expr *ObjectExpr,
1733205219Srdivacky                                                   Expr *ArgExpr,
1734205408Srdivacky                                                   DeclAccessPair Found) {
1735235633Sdim  if (!getLangOpts().AccessControl ||
1736205408Srdivacky      Found.getAccess() == AS_public)
1737203955Srdivacky    return AR_accessible;
1738203955Srdivacky
1739226890Sdim  const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();
1740203955Srdivacky  CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
1741203955Srdivacky
1742207619Srdivacky  AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1743207619Srdivacky                      ObjectExpr->getType());
1744205219Srdivacky  Entity.setDiag(diag::err_access)
1745205219Srdivacky    << ObjectExpr->getSourceRange()
1746205219Srdivacky    << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
1747205219Srdivacky
1748205219Srdivacky  return CheckAccess(*this, OpLoc, Entity);
1749203955Srdivacky}
1750203955Srdivacky
1751245431Sdim/// Checks access to the target of a friend declaration.
1752245431SdimSema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
1753245431Sdim  assert(isa<CXXMethodDecl>(target) ||
1754245431Sdim         (isa<FunctionTemplateDecl>(target) &&
1755245431Sdim          isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(target)
1756245431Sdim                               ->getTemplatedDecl())));
1757245431Sdim
1758245431Sdim  // Friendship lookup is a redeclaration lookup, so there's never an
1759245431Sdim  // inheritance path modifying access.
1760245431Sdim  AccessSpecifier access = target->getAccess();
1761245431Sdim
1762245431Sdim  if (!getLangOpts().AccessControl || access == AS_public)
1763245431Sdim    return AR_accessible;
1764245431Sdim
1765245431Sdim  CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(target);
1766245431Sdim  if (!method)
1767245431Sdim    method = cast<CXXMethodDecl>(
1768245431Sdim                     cast<FunctionTemplateDecl>(target)->getTemplatedDecl());
1769245431Sdim  assert(method->getQualifier());
1770245431Sdim
1771245431Sdim  AccessTarget entity(Context, AccessTarget::Member,
1772245431Sdim                      cast<CXXRecordDecl>(target->getDeclContext()),
1773245431Sdim                      DeclAccessPair::make(target, access),
1774245431Sdim                      /*no instance context*/ QualType());
1775245431Sdim  entity.setDiag(diag::err_access_friend_function)
1776245431Sdim    << method->getQualifierLoc().getSourceRange();
1777245431Sdim
1778245431Sdim  // We need to bypass delayed-diagnostics because we might be called
1779245431Sdim  // while the ParsingDeclarator is active.
1780245431Sdim  EffectiveContext EC(CurContext);
1781245431Sdim  switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) {
1782245431Sdim  case AR_accessible: return Sema::AR_accessible;
1783245431Sdim  case AR_inaccessible: return Sema::AR_inaccessible;
1784245431Sdim  case AR_dependent: return Sema::AR_dependent;
1785245431Sdim  }
1786245431Sdim  llvm_unreachable("falling off end");
1787245431Sdim}
1788245431Sdim
1789206084SrdivackySema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
1790206084Srdivacky                                                    DeclAccessPair Found) {
1791235633Sdim  if (!getLangOpts().AccessControl ||
1792206084Srdivacky      Found.getAccess() == AS_none ||
1793206084Srdivacky      Found.getAccess() == AS_public)
1794206084Srdivacky    return AR_accessible;
1795206084Srdivacky
1796212904Sdim  OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression;
1797207619Srdivacky  CXXRecordDecl *NamingClass = Ovl->getNamingClass();
1798206084Srdivacky
1799207619Srdivacky  AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
1800235633Sdim                      /*no instance context*/ QualType());
1801206084Srdivacky  Entity.setDiag(diag::err_access)
1802206084Srdivacky    << Ovl->getSourceRange();
1803206084Srdivacky
1804206084Srdivacky  return CheckAccess(*this, Ovl->getNameLoc(), Entity);
1805206084Srdivacky}
1806206084Srdivacky
1807203955Srdivacky/// Checks access for a hierarchy conversion.
1808203955Srdivacky///
1809203955Srdivacky/// \param ForceCheck true if this check should be performed even if access
1810203955Srdivacky///     control is disabled;  some things rely on this for semantics
1811203955Srdivacky/// \param ForceUnprivileged true if this check should proceed as if the
1812203955Srdivacky///     context had no special privileges
1813203955SrdivackySema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
1814203955Srdivacky                                              QualType Base,
1815203955Srdivacky                                              QualType Derived,
1816203955Srdivacky                                              const CXXBasePath &Path,
1817205219Srdivacky                                              unsigned DiagID,
1818203955Srdivacky                                              bool ForceCheck,
1819205219Srdivacky                                              bool ForceUnprivileged) {
1820235633Sdim  if (!ForceCheck && !getLangOpts().AccessControl)
1821203955Srdivacky    return AR_accessible;
1822203955Srdivacky
1823203955Srdivacky  if (Path.Access == AS_public)
1824203955Srdivacky    return AR_accessible;
1825203955Srdivacky
1826203955Srdivacky  CXXRecordDecl *BaseD, *DerivedD;
1827203955Srdivacky  BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
1828203955Srdivacky  DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
1829203955Srdivacky
1830207619Srdivacky  AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,
1831207619Srdivacky                      Path.Access);
1832205219Srdivacky  if (DiagID)
1833205219Srdivacky    Entity.setDiag(DiagID) << Derived << Base;
1834205219Srdivacky
1835207619Srdivacky  if (ForceUnprivileged) {
1836207619Srdivacky    switch (CheckEffectiveAccess(*this, EffectiveContext(),
1837207619Srdivacky                                 AccessLoc, Entity)) {
1838207619Srdivacky    case ::AR_accessible: return Sema::AR_accessible;
1839207619Srdivacky    case ::AR_inaccessible: return Sema::AR_inaccessible;
1840207619Srdivacky    case ::AR_dependent: return Sema::AR_dependent;
1841207619Srdivacky    }
1842207619Srdivacky    llvm_unreachable("unexpected result from CheckEffectiveAccess");
1843207619Srdivacky  }
1844205219Srdivacky  return CheckAccess(*this, AccessLoc, Entity);
1845203955Srdivacky}
1846203955Srdivacky
1847202879Srdivacky/// Checks access to all the declarations in the given result set.
1848203955Srdivackyvoid Sema::CheckLookupAccess(const LookupResult &R) {
1849235633Sdim  assert(getLangOpts().AccessControl
1850203955Srdivacky         && "performing access check without access control");
1851203955Srdivacky  assert(R.getNamingClass() && "performing access check without naming class");
1852203955Srdivacky
1853205219Srdivacky  for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
1854205219Srdivacky    if (I.getAccess() != AS_public) {
1855207619Srdivacky      AccessTarget Entity(Context, AccessedEntity::Member,
1856207619Srdivacky                          R.getNamingClass(), I.getPair(),
1857226890Sdim                          R.getBaseObjectType());
1858205219Srdivacky      Entity.setDiag(diag::err_access);
1859205219Srdivacky      CheckAccess(*this, R.getNameLoc(), Entity);
1860205219Srdivacky    }
1861205219Srdivacky  }
1862202879Srdivacky}
1863210299Sed
1864226890Sdim/// Checks access to Decl from the given class. The check will take access
1865226890Sdim/// specifiers into account, but no member access expressions and such.
1866226890Sdim///
1867226890Sdim/// \param Decl the declaration to check if it can be accessed
1868245431Sdim/// \param Ctx the class/context from which to start the search
1869226890Sdim/// \return true if the Decl is accessible from the Class, false otherwise.
1870235633Sdimbool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) {
1871235633Sdim  if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) {
1872235633Sdim    if (!Decl->isCXXClassMember())
1873235633Sdim      return true;
1874226890Sdim
1875235633Sdim    QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal();
1876235633Sdim    AccessTarget Entity(Context, AccessedEntity::Member, Class,
1877235633Sdim                        DeclAccessPair::make(Decl, Decl->getAccess()),
1878235633Sdim                        qType);
1879235633Sdim    if (Entity.getAccess() == AS_public)
1880235633Sdim      return true;
1881226890Sdim
1882235633Sdim    EffectiveContext EC(CurContext);
1883235633Sdim    return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
1884235633Sdim  }
1885235633Sdim
1886235633Sdim  if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) {
1887235633Sdim    // @public and @package ivars are always accessible.
1888235633Sdim    if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||
1889235633Sdim        Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package)
1890235633Sdim      return true;
1891263509Sdim
1892235633Sdim    // If we are inside a class or category implementation, determine the
1893235633Sdim    // interface we're in.
1894235633Sdim    ObjCInterfaceDecl *ClassOfMethodDecl = 0;
1895235633Sdim    if (ObjCMethodDecl *MD = getCurMethodDecl())
1896235633Sdim      ClassOfMethodDecl =  MD->getClassInterface();
1897235633Sdim    else if (FunctionDecl *FD = getCurFunctionDecl()) {
1898235633Sdim      if (ObjCImplDecl *Impl
1899235633Sdim            = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) {
1900235633Sdim        if (ObjCImplementationDecl *IMPD
1901235633Sdim              = dyn_cast<ObjCImplementationDecl>(Impl))
1902235633Sdim          ClassOfMethodDecl = IMPD->getClassInterface();
1903235633Sdim        else if (ObjCCategoryImplDecl* CatImplClass
1904235633Sdim                   = dyn_cast<ObjCCategoryImplDecl>(Impl))
1905235633Sdim          ClassOfMethodDecl = CatImplClass->getClassInterface();
1906235633Sdim      }
1907235633Sdim    }
1908235633Sdim
1909235633Sdim    // If we're not in an interface, this ivar is inaccessible.
1910235633Sdim    if (!ClassOfMethodDecl)
1911235633Sdim      return false;
1912235633Sdim
1913235633Sdim    // If we're inside the same interface that owns the ivar, we're fine.
1914235633Sdim    if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface()))
1915235633Sdim      return true;
1916235633Sdim
1917235633Sdim    // If the ivar is private, it's inaccessible.
1918235633Sdim    if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private)
1919235633Sdim      return false;
1920235633Sdim
1921235633Sdim    return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl);
1922235633Sdim  }
1923235633Sdim
1924235633Sdim  return true;
1925226890Sdim}
1926