diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp | 1843 | 
1 files changed, 1843 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp new file mode 100644 index 000000000000..dea5e76d9e13 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp @@ -0,0 +1,1843 @@ +//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Sema routines for C++ access control semantics. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DependentDiagnostic.h" +#include "clang/AST/ExprCXX.h" + +using namespace clang; +using namespace sema; + +/// A copy of Sema's enum without AR_delayed. +enum AccessResult { +  AR_accessible, +  AR_inaccessible, +  AR_dependent +}; + +/// SetMemberAccessSpecifier - Set the access specifier of a member. +/// Returns true on error (when the previous member decl access specifier +/// is different from the new member decl access specifier). +bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, +                                    NamedDecl *PrevMemberDecl, +                                    AccessSpecifier LexicalAS) { +  if (!PrevMemberDecl) { +    // Use the lexical access specifier. +    MemberDecl->setAccess(LexicalAS); +    return false; +  } + +  // C++ [class.access.spec]p3: When a member is redeclared its access +  // specifier must be same as its initial declaration. +  if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { +    Diag(MemberDecl->getLocation(), +         diag::err_class_redeclared_with_different_access) +      << MemberDecl << LexicalAS; +    Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) +      << PrevMemberDecl << PrevMemberDecl->getAccess(); + +    MemberDecl->setAccess(LexicalAS); +    return true; +  } + +  MemberDecl->setAccess(PrevMemberDecl->getAccess()); +  return false; +} + +static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { +  DeclContext *DC = D->getDeclContext(); + +  // This can only happen at top: enum decls only "publish" their +  // immediate members. +  if (isa<EnumDecl>(DC)) +    DC = cast<EnumDecl>(DC)->getDeclContext(); + +  CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); +  while (DeclaringClass->isAnonymousStructOrUnion()) +    DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); +  return DeclaringClass; +} + +namespace { +struct EffectiveContext { +  EffectiveContext() : Inner(0), Dependent(false) {} + +  explicit EffectiveContext(DeclContext *DC) +    : Inner(DC), +      Dependent(DC->isDependentContext()) { + +    // C++ [class.access.nest]p1: +    //   A nested class is a member and as such has the same access +    //   rights as any other member. +    // C++ [class.access]p2: +    //   A member of a class can also access all the names to which +    //   the class has access.  A local class of a member function +    //   may access the same names that the member function itself +    //   may access. +    // This almost implies that the privileges of nesting are transitive. +    // Technically it says nothing about the local classes of non-member +    // functions (which can gain privileges through friendship), but we +    // take that as an oversight. +    while (true) { +      if (isa<CXXRecordDecl>(DC)) { +        CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); +        Records.push_back(Record); +        DC = Record->getDeclContext(); +      } else if (isa<FunctionDecl>(DC)) { +        FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); +        Functions.push_back(Function); +         +        if (Function->getFriendObjectKind()) +          DC = Function->getLexicalDeclContext(); +        else +          DC = Function->getDeclContext(); +      } else if (DC->isFileContext()) { +        break; +      } else { +        DC = DC->getParent(); +      } +    } +  } + +  bool isDependent() const { return Dependent; } + +  bool includesClass(const CXXRecordDecl *R) const { +    R = R->getCanonicalDecl(); +    return std::find(Records.begin(), Records.end(), R) +             != Records.end(); +  } + +  /// Retrieves the innermost "useful" context.  Can be null if we're +  /// doing access-control without privileges. +  DeclContext *getInnerContext() const { +    return Inner; +  } + +  typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; + +  DeclContext *Inner; +  SmallVector<FunctionDecl*, 4> Functions; +  SmallVector<CXXRecordDecl*, 4> Records; +  bool Dependent; +}; + +/// Like sema::AccessedEntity, but kindly lets us scribble all over +/// it. +struct AccessTarget : public AccessedEntity { +  AccessTarget(const AccessedEntity &Entity) +    : AccessedEntity(Entity) { +    initialize(); +  } +     +  AccessTarget(ASTContext &Context,  +               MemberNonce _, +               CXXRecordDecl *NamingClass, +               DeclAccessPair FoundDecl, +               QualType BaseObjectType) +    : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) { +    initialize(); +  } + +  AccessTarget(ASTContext &Context,  +               BaseNonce _, +               CXXRecordDecl *BaseClass, +               CXXRecordDecl *DerivedClass, +               AccessSpecifier Access) +    : AccessedEntity(Context, Base, BaseClass, DerivedClass, Access) { +    initialize(); +  } + +  bool isInstanceMember() const { +    return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember()); +  } + +  bool hasInstanceContext() const { +    return HasInstanceContext; +  } + +  class SavedInstanceContext { +  public: +    ~SavedInstanceContext() { +      Target.HasInstanceContext = Has; +    } + +  private: +    friend struct AccessTarget; +    explicit SavedInstanceContext(AccessTarget &Target) +      : Target(Target), Has(Target.HasInstanceContext) {} +    AccessTarget &Target; +    bool Has; +  }; + +  SavedInstanceContext saveInstanceContext() { +    return SavedInstanceContext(*this); +  } + +  void suppressInstanceContext() { +    HasInstanceContext = false; +  } + +  const CXXRecordDecl *resolveInstanceContext(Sema &S) const { +    assert(HasInstanceContext); +    if (CalculatedInstanceContext) +      return InstanceContext; + +    CalculatedInstanceContext = true; +    DeclContext *IC = S.computeDeclContext(getBaseObjectType()); +    InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0); +    return InstanceContext; +  } + +  const CXXRecordDecl *getDeclaringClass() const { +    return DeclaringClass; +  } + +private: +  void initialize() { +    HasInstanceContext = (isMemberAccess() && +                          !getBaseObjectType().isNull() && +                          getTargetDecl()->isCXXInstanceMember()); +    CalculatedInstanceContext = false; +    InstanceContext = 0; + +    if (isMemberAccess()) +      DeclaringClass = FindDeclaringClass(getTargetDecl()); +    else +      DeclaringClass = getBaseClass(); +    DeclaringClass = DeclaringClass->getCanonicalDecl(); +  } + +  bool HasInstanceContext : 1; +  mutable bool CalculatedInstanceContext : 1; +  mutable const CXXRecordDecl *InstanceContext; +  const CXXRecordDecl *DeclaringClass; +}; + +} + +/// Checks whether one class might instantiate to the other. +static bool MightInstantiateTo(const CXXRecordDecl *From, +                               const CXXRecordDecl *To) { +  // Declaration names are always preserved by instantiation. +  if (From->getDeclName() != To->getDeclName()) +    return false; + +  const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext(); +  const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext(); +  if (FromDC == ToDC) return true; +  if (FromDC->isFileContext() || ToDC->isFileContext()) return false; + +  // Be conservative. +  return true; +} + +/// Checks whether one class is derived from another, inclusively. +/// Properly indicates when it couldn't be determined due to +/// dependence. +/// +/// This should probably be donated to AST or at least Sema. +static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, +                                           const CXXRecordDecl *Target) { +  assert(Derived->getCanonicalDecl() == Derived); +  assert(Target->getCanonicalDecl() == Target); + +  if (Derived == Target) return AR_accessible; + +  bool CheckDependent = Derived->isDependentContext(); +  if (CheckDependent && MightInstantiateTo(Derived, Target)) +    return AR_dependent; + +  AccessResult OnFailure = AR_inaccessible; +  SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack + +  while (true) { +    if (Derived->isDependentContext() && !Derived->hasDefinition()) +      return AR_dependent; +     +    for (CXXRecordDecl::base_class_const_iterator +           I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) { + +      const CXXRecordDecl *RD; + +      QualType T = I->getType(); +      if (const RecordType *RT = T->getAs<RecordType>()) { +        RD = cast<CXXRecordDecl>(RT->getDecl()); +      } else if (const InjectedClassNameType *IT +                   = T->getAs<InjectedClassNameType>()) { +        RD = IT->getDecl(); +      } else { +        assert(T->isDependentType() && "non-dependent base wasn't a record?"); +        OnFailure = AR_dependent; +        continue; +      } + +      RD = RD->getCanonicalDecl(); +      if (RD == Target) return AR_accessible; +      if (CheckDependent && MightInstantiateTo(RD, Target)) +        OnFailure = AR_dependent; + +      Queue.push_back(RD); +    } + +    if (Queue.empty()) break; + +    Derived = Queue.back(); +    Queue.pop_back(); +  } + +  return OnFailure; +} + + +static bool MightInstantiateTo(Sema &S, DeclContext *Context, +                               DeclContext *Friend) { +  if (Friend == Context) +    return true; + +  assert(!Friend->isDependentContext() && +         "can't handle friends with dependent contexts here"); + +  if (!Context->isDependentContext()) +    return false; + +  if (Friend->isFileContext()) +    return false; + +  // TODO: this is very conservative +  return true; +} + +// Asks whether the type in 'context' can ever instantiate to the type +// in 'friend'. +static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) { +  if (Friend == Context) +    return true; + +  if (!Friend->isDependentType() && !Context->isDependentType()) +    return false; + +  // TODO: this is very conservative. +  return true; +} + +static bool MightInstantiateTo(Sema &S, +                               FunctionDecl *Context, +                               FunctionDecl *Friend) { +  if (Context->getDeclName() != Friend->getDeclName()) +    return false; + +  if (!MightInstantiateTo(S, +                          Context->getDeclContext(), +                          Friend->getDeclContext())) +    return false; + +  CanQual<FunctionProtoType> FriendTy +    = S.Context.getCanonicalType(Friend->getType()) +         ->getAs<FunctionProtoType>(); +  CanQual<FunctionProtoType> ContextTy +    = S.Context.getCanonicalType(Context->getType()) +         ->getAs<FunctionProtoType>(); + +  // There isn't any way that I know of to add qualifiers +  // during instantiation. +  if (FriendTy.getQualifiers() != ContextTy.getQualifiers()) +    return false; + +  if (FriendTy->getNumArgs() != ContextTy->getNumArgs()) +    return false; + +  if (!MightInstantiateTo(S, +                          ContextTy->getResultType(), +                          FriendTy->getResultType())) +    return false; + +  for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I) +    if (!MightInstantiateTo(S, +                            ContextTy->getArgType(I), +                            FriendTy->getArgType(I))) +      return false; + +  return true; +} + +static bool MightInstantiateTo(Sema &S, +                               FunctionTemplateDecl *Context, +                               FunctionTemplateDecl *Friend) { +  return MightInstantiateTo(S, +                            Context->getTemplatedDecl(), +                            Friend->getTemplatedDecl()); +} + +static AccessResult MatchesFriend(Sema &S, +                                  const EffectiveContext &EC, +                                  const CXXRecordDecl *Friend) { +  if (EC.includesClass(Friend)) +    return AR_accessible; + +  if (EC.isDependent()) { +    CanQualType FriendTy +      = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend)); + +    for (EffectiveContext::record_iterator +           I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { +      CanQualType ContextTy +        = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); +      if (MightInstantiateTo(S, ContextTy, FriendTy)) +        return AR_dependent; +    } +  } + +  return AR_inaccessible; +} + +static AccessResult MatchesFriend(Sema &S, +                                  const EffectiveContext &EC, +                                  CanQualType Friend) { +  if (const RecordType *RT = Friend->getAs<RecordType>()) +    return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); + +  // TODO: we can do better than this +  if (Friend->isDependentType()) +    return AR_dependent; + +  return AR_inaccessible; +} + +/// Determines whether the given friend class template matches +/// anything in the effective context. +static AccessResult MatchesFriend(Sema &S, +                                  const EffectiveContext &EC, +                                  ClassTemplateDecl *Friend) { +  AccessResult OnFailure = AR_inaccessible; + +  // Check whether the friend is the template of a class in the +  // context chain. +  for (SmallVectorImpl<CXXRecordDecl*>::const_iterator +         I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { +    CXXRecordDecl *Record = *I; + +    // Figure out whether the current class has a template: +    ClassTemplateDecl *CTD; + +    // A specialization of the template... +    if (isa<ClassTemplateSpecializationDecl>(Record)) { +      CTD = cast<ClassTemplateSpecializationDecl>(Record) +        ->getSpecializedTemplate(); + +    // ... or the template pattern itself. +    } else { +      CTD = Record->getDescribedClassTemplate(); +      if (!CTD) continue; +    } + +    // It's a match. +    if (Friend == CTD->getCanonicalDecl()) +      return AR_accessible; + +    // If the context isn't dependent, it can't be a dependent match. +    if (!EC.isDependent()) +      continue; + +    // If the template names don't match, it can't be a dependent +    // match. +    if (CTD->getDeclName() != Friend->getDeclName()) +      continue; + +    // If the class's context can't instantiate to the friend's +    // context, it can't be a dependent match. +    if (!MightInstantiateTo(S, CTD->getDeclContext(), +                            Friend->getDeclContext())) +      continue; + +    // Otherwise, it's a dependent match. +    OnFailure = AR_dependent; +  } + +  return OnFailure; +} + +/// Determines whether the given friend function matches anything in +/// the effective context. +static AccessResult MatchesFriend(Sema &S, +                                  const EffectiveContext &EC, +                                  FunctionDecl *Friend) { +  AccessResult OnFailure = AR_inaccessible; + +  for (SmallVectorImpl<FunctionDecl*>::const_iterator +         I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { +    if (Friend == *I) +      return AR_accessible; + +    if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) +      OnFailure = AR_dependent; +  } + +  return OnFailure; +} + +/// Determines whether the given friend function template matches +/// anything in the effective context. +static AccessResult MatchesFriend(Sema &S, +                                  const EffectiveContext &EC, +                                  FunctionTemplateDecl *Friend) { +  if (EC.Functions.empty()) return AR_inaccessible; + +  AccessResult OnFailure = AR_inaccessible; + +  for (SmallVectorImpl<FunctionDecl*>::const_iterator +         I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { + +    FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); +    if (!FTD) +      FTD = (*I)->getDescribedFunctionTemplate(); +    if (!FTD) +      continue; + +    FTD = FTD->getCanonicalDecl(); + +    if (Friend == FTD) +      return AR_accessible; + +    if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) +      OnFailure = AR_dependent; +  } + +  return OnFailure; +} + +/// Determines whether the given friend declaration matches anything +/// in the effective context. +static AccessResult MatchesFriend(Sema &S, +                                  const EffectiveContext &EC, +                                  FriendDecl *FriendD) { +  // Whitelist accesses if there's an invalid or unsupported friend +  // declaration. +  if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend()) +    return AR_accessible; + +  if (TypeSourceInfo *T = FriendD->getFriendType()) +    return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); + +  NamedDecl *Friend +    = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl()); + +  // FIXME: declarations with dependent or templated scope. + +  if (isa<ClassTemplateDecl>(Friend)) +    return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend)); + +  if (isa<FunctionTemplateDecl>(Friend)) +    return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend)); + +  if (isa<CXXRecordDecl>(Friend)) +    return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend)); + +  assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind"); +  return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); +} + +static AccessResult GetFriendKind(Sema &S, +                                  const EffectiveContext &EC, +                                  const CXXRecordDecl *Class) { +  AccessResult OnFailure = AR_inaccessible; + +  // Okay, check friends. +  for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), +         E = Class->friend_end(); I != E; ++I) { +    FriendDecl *Friend = *I; + +    switch (MatchesFriend(S, EC, Friend)) { +    case AR_accessible: +      return AR_accessible; + +    case AR_inaccessible: +      continue; + +    case AR_dependent: +      OnFailure = AR_dependent; +      break; +    } +  } + +  // That's it, give up. +  return OnFailure; +} + +namespace { + +/// A helper class for checking for a friend which will grant access +/// to a protected instance member. +struct ProtectedFriendContext { +  Sema &S; +  const EffectiveContext &EC; +  const CXXRecordDecl *NamingClass; +  bool CheckDependent; +  bool EverDependent; + +  /// The path down to the current base class. +  SmallVector<const CXXRecordDecl*, 20> CurPath; + +  ProtectedFriendContext(Sema &S, const EffectiveContext &EC, +                         const CXXRecordDecl *InstanceContext, +                         const CXXRecordDecl *NamingClass) +    : S(S), EC(EC), NamingClass(NamingClass), +      CheckDependent(InstanceContext->isDependentContext() || +                     NamingClass->isDependentContext()), +      EverDependent(false) {} + +  /// Check classes in the current path for friendship, starting at +  /// the given index. +  bool checkFriendshipAlongPath(unsigned I) { +    assert(I < CurPath.size()); +    for (unsigned E = CurPath.size(); I != E; ++I) { +      switch (GetFriendKind(S, EC, CurPath[I])) { +      case AR_accessible:   return true; +      case AR_inaccessible: continue; +      case AR_dependent:    EverDependent = true; continue; +      } +    } +    return false; +  } + +  /// Perform a search starting at the given class. +  /// +  /// PrivateDepth is the index of the last (least derived) class +  /// along the current path such that a notional public member of +  /// the final class in the path would have access in that class. +  bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) { +    // If we ever reach the naming class, check the current path for +    // friendship.  We can also stop recursing because we obviously +    // won't find the naming class there again. +    if (Cur == NamingClass) +      return checkFriendshipAlongPath(PrivateDepth); + +    if (CheckDependent && MightInstantiateTo(Cur, NamingClass)) +      EverDependent = true; + +    // Recurse into the base classes. +    for (CXXRecordDecl::base_class_const_iterator +           I = Cur->bases_begin(), E = Cur->bases_end(); I != E; ++I) { + +      // If this is private inheritance, then a public member of the +      // base will not have any access in classes derived from Cur. +      unsigned BasePrivateDepth = PrivateDepth; +      if (I->getAccessSpecifier() == AS_private) +        BasePrivateDepth = CurPath.size() - 1; + +      const CXXRecordDecl *RD; + +      QualType T = I->getType(); +      if (const RecordType *RT = T->getAs<RecordType>()) { +        RD = cast<CXXRecordDecl>(RT->getDecl()); +      } else if (const InjectedClassNameType *IT +                   = T->getAs<InjectedClassNameType>()) { +        RD = IT->getDecl(); +      } else { +        assert(T->isDependentType() && "non-dependent base wasn't a record?"); +        EverDependent = true; +        continue; +      } + +      // Recurse.  We don't need to clean up if this returns true. +      CurPath.push_back(RD); +      if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth)) +        return true; +      CurPath.pop_back(); +    } + +    return false; +  } + +  bool findFriendship(const CXXRecordDecl *Cur) { +    assert(CurPath.empty()); +    CurPath.push_back(Cur); +    return findFriendship(Cur, 0); +  } +}; +} + +/// Search for a class P that EC is a friend of, under the constraint +///   InstanceContext <= P +/// if InstanceContext exists, or else +///   NamingClass <= P +/// and with the additional restriction that a protected member of +/// NamingClass would have some natural access in P, which implicitly +/// imposes the constraint that P <= NamingClass. +/// +/// This isn't quite the condition laid out in the standard. +/// Instead of saying that a notional protected member of NamingClass +/// would have to have some natural access in P, it says the actual +/// target has to have some natural access in P, which opens up the +/// possibility that the target (which is not necessarily a member +/// of NamingClass) might be more accessible along some path not +/// passing through it.  That's really a bad idea, though, because it +/// introduces two problems: +///   - Most importantly, it breaks encapsulation because you can +///     access a forbidden base class's members by directly subclassing +///     it elsewhere. +///   - It also makes access substantially harder to compute because it +///     breaks the hill-climbing algorithm: knowing that the target is +///     accessible in some base class would no longer let you change +///     the question solely to whether the base class is accessible, +///     because the original target might have been more accessible +///     because of crazy subclassing. +/// So we don't implement that. +static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC, +                                           const CXXRecordDecl *InstanceContext, +                                           const CXXRecordDecl *NamingClass) { +  assert(InstanceContext == 0 || +         InstanceContext->getCanonicalDecl() == InstanceContext); +  assert(NamingClass->getCanonicalDecl() == NamingClass); + +  // If we don't have an instance context, our constraints give us +  // that NamingClass <= P <= NamingClass, i.e. P == NamingClass. +  // This is just the usual friendship check. +  if (!InstanceContext) return GetFriendKind(S, EC, NamingClass); + +  ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass); +  if (PRC.findFriendship(InstanceContext)) return AR_accessible; +  if (PRC.EverDependent) return AR_dependent; +  return AR_inaccessible; +} + +static AccessResult HasAccess(Sema &S, +                              const EffectiveContext &EC, +                              const CXXRecordDecl *NamingClass, +                              AccessSpecifier Access, +                              const AccessTarget &Target) { +  assert(NamingClass->getCanonicalDecl() == NamingClass && +         "declaration should be canonicalized before being passed here"); + +  if (Access == AS_public) return AR_accessible; +  assert(Access == AS_private || Access == AS_protected); + +  AccessResult OnFailure = AR_inaccessible; + +  for (EffectiveContext::record_iterator +         I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { +    // All the declarations in EC have been canonicalized, so pointer +    // equality from this point on will work fine. +    const CXXRecordDecl *ECRecord = *I; + +    // [B2] and [M2] +    if (Access == AS_private) { +      if (ECRecord == NamingClass) +        return AR_accessible; + +      if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass)) +        OnFailure = AR_dependent; + +    // [B3] and [M3] +    } else { +      assert(Access == AS_protected); +      switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { +      case AR_accessible: break; +      case AR_inaccessible: continue; +      case AR_dependent: OnFailure = AR_dependent; continue; +      } + +      // C++ [class.protected]p1: +      //   An additional access check beyond those described earlier in +      //   [class.access] is applied when a non-static data member or +      //   non-static member function is a protected member of its naming +      //   class.  As described earlier, access to a protected member is +      //   granted because the reference occurs in a friend or member of +      //   some class C.  If the access is to form a pointer to member, +      //   the nested-name-specifier shall name C or a class derived from +      //   C. All other accesses involve a (possibly implicit) object +      //   expression. In this case, the class of the object expression +      //   shall be C or a class derived from C. +      // +      // We interpret this as a restriction on [M3]. + +      // In this part of the code, 'C' is just our context class ECRecord. +       +      // These rules are different if we don't have an instance context. +      if (!Target.hasInstanceContext()) { +        // If it's not an instance member, these restrictions don't apply. +        if (!Target.isInstanceMember()) return AR_accessible; + +        // If it's an instance member, use the pointer-to-member rule +        // that the naming class has to be derived from the effective +        // context. + +        // Despite the standard's confident wording, there is a case +        // where you can have an instance member that's neither in a +        // pointer-to-member expression nor in a member access:  when +        // it names a field in an unevaluated context that can't be an +        // implicit member.  Pending clarification, we just apply the +        // same naming-class restriction here. +        //   FIXME: we're probably not correctly adding the +        //   protected-member restriction when we retroactively convert +        //   an expression to being evaluated. + +        // We know that ECRecord derives from NamingClass.  The +        // restriction says to check whether NamingClass derives from +        // ECRecord, but that's not really necessary: two distinct +        // classes can't be recursively derived from each other.  So +        // along this path, we just need to check whether the classes +        // are equal. +        if (NamingClass == ECRecord) return AR_accessible; + +        // Otherwise, this context class tells us nothing;  on to the next. +        continue; +      } + +      assert(Target.isInstanceMember()); + +      const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); +      if (!InstanceContext) { +        OnFailure = AR_dependent; +        continue; +      } + +      switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { +      case AR_accessible: return AR_accessible; +      case AR_inaccessible: continue; +      case AR_dependent: OnFailure = AR_dependent; continue; +      } +    } +  } + +  // [M3] and [B3] say that, if the target is protected in N, we grant +  // access if the access occurs in a friend or member of some class P +  // that's a subclass of N and where the target has some natural +  // access in P.  The 'member' aspect is easy to handle because P +  // would necessarily be one of the effective-context records, and we +  // address that above.  The 'friend' aspect is completely ridiculous +  // to implement because there are no restrictions at all on P +  // *unless* the [class.protected] restriction applies.  If it does, +  // however, we should ignore whether the naming class is a friend, +  // and instead rely on whether any potential P is a friend. +  if (Access == AS_protected && Target.isInstanceMember()) { +    // Compute the instance context if possible. +    const CXXRecordDecl *InstanceContext = 0; +    if (Target.hasInstanceContext()) { +      InstanceContext = Target.resolveInstanceContext(S); +      if (!InstanceContext) return AR_dependent; +    } + +    switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) { +    case AR_accessible: return AR_accessible; +    case AR_inaccessible: return OnFailure; +    case AR_dependent: return AR_dependent; +    } +    llvm_unreachable("impossible friendship kind"); +  } + +  switch (GetFriendKind(S, EC, NamingClass)) { +  case AR_accessible: return AR_accessible; +  case AR_inaccessible: return OnFailure; +  case AR_dependent: return AR_dependent; +  } + +  // Silence bogus warnings +  llvm_unreachable("impossible friendship kind"); +} + +/// Finds the best path from the naming class to the declaring class, +/// taking friend declarations into account. +/// +/// C++0x [class.access.base]p5: +///   A member m is accessible at the point R when named in class N if +///   [M1] m as a member of N is public, or +///   [M2] m as a member of N is private, and R occurs in a member or +///        friend of class N, or +///   [M3] m as a member of N is protected, and R occurs in a member or +///        friend of class N, or in a member or friend of a class P +///        derived from N, where m as a member of P is public, private, +///        or protected, or +///   [M4] there exists a base class B of N that is accessible at R, and +///        m is accessible at R when named in class B. +/// +/// C++0x [class.access.base]p4: +///   A base class B of N is accessible at R, if +///   [B1] an invented public member of B would be a public member of N, or +///   [B2] R occurs in a member or friend of class N, and an invented public +///        member of B would be a private or protected member of N, or +///   [B3] R occurs in a member or friend of a class P derived from N, and an +///        invented public member of B would be a private or protected member +///        of P, or +///   [B4] there exists a class S such that B is a base class of S accessible +///        at R and S is a base class of N accessible at R. +/// +/// Along a single inheritance path we can restate both of these +/// iteratively: +/// +/// First, we note that M1-4 are equivalent to B1-4 if the member is +/// treated as a notional base of its declaring class with inheritance +/// access equivalent to the member's access.  Therefore we need only +/// ask whether a class B is accessible from a class N in context R. +/// +/// Let B_1 .. B_n be the inheritance path in question (i.e. where +/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of +/// B_i).  For i in 1..n, we will calculate ACAB(i), the access to the +/// closest accessible base in the path: +///   Access(a, b) = (* access on the base specifier from a to b *) +///   Merge(a, forbidden) = forbidden +///   Merge(a, private) = forbidden +///   Merge(a, b) = min(a,b) +///   Accessible(c, forbidden) = false +///   Accessible(c, private) = (R is c) || IsFriend(c, R) +///   Accessible(c, protected) = (R derived from c) || IsFriend(c, R) +///   Accessible(c, public) = true +///   ACAB(n) = public +///   ACAB(i) = +///     let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in +///     if Accessible(B_i, AccessToBase) then public else AccessToBase +/// +/// B is an accessible base of N at R iff ACAB(1) = public. +/// +/// \param FinalAccess the access of the "final step", or AS_public if +///   there is no final step. +/// \return null if friendship is dependent +static CXXBasePath *FindBestPath(Sema &S, +                                 const EffectiveContext &EC, +                                 AccessTarget &Target, +                                 AccessSpecifier FinalAccess, +                                 CXXBasePaths &Paths) { +  // Derive the paths to the desired base. +  const CXXRecordDecl *Derived = Target.getNamingClass(); +  const CXXRecordDecl *Base = Target.getDeclaringClass(); + +  // FIXME: fail correctly when there are dependent paths. +  bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base), +                                          Paths); +  assert(isDerived && "derived class not actually derived from base"); +  (void) isDerived; + +  CXXBasePath *BestPath = 0; + +  assert(FinalAccess != AS_none && "forbidden access after declaring class"); + +  bool AnyDependent = false; + +  // Derive the friend-modified access along each path. +  for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); +         PI != PE; ++PI) { +    AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext(); + +    // Walk through the path backwards. +    AccessSpecifier PathAccess = FinalAccess; +    CXXBasePath::iterator I = PI->end(), E = PI->begin(); +    while (I != E) { +      --I; + +      assert(PathAccess != AS_none); + +      // If the declaration is a private member of a base class, there +      // is no level of friendship in derived classes that can make it +      // accessible. +      if (PathAccess == AS_private) { +        PathAccess = AS_none; +        break; +      } + +      const CXXRecordDecl *NC = I->Class->getCanonicalDecl(); + +      AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); +      PathAccess = std::max(PathAccess, BaseAccess); + +      switch (HasAccess(S, EC, NC, PathAccess, Target)) { +      case AR_inaccessible: break; +      case AR_accessible: +        PathAccess = AS_public; + +        // Future tests are not against members and so do not have +        // instance context. +        Target.suppressInstanceContext(); +        break; +      case AR_dependent: +        AnyDependent = true; +        goto Next; +      } +    } + +    // Note that we modify the path's Access field to the +    // friend-modified access. +    if (BestPath == 0 || PathAccess < BestPath->Access) { +      BestPath = &*PI; +      BestPath->Access = PathAccess; + +      // Short-circuit if we found a public path. +      if (BestPath->Access == AS_public) +        return BestPath; +    } + +  Next: ; +  } + +  assert((!BestPath || BestPath->Access != AS_public) && +         "fell out of loop with public path"); + +  // We didn't find a public path, but at least one path was subject +  // to dependent friendship, so delay the check. +  if (AnyDependent) +    return 0; + +  return BestPath; +} + +/// Given that an entity has protected natural access, check whether +/// access might be denied because of the protected member access +/// restriction. +/// +/// \return true if a note was emitted +static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC, +                                       AccessTarget &Target) { +  // Only applies to instance accesses. +  if (!Target.isInstanceMember()) +    return false; + +  assert(Target.isMemberAccess()); + +  const CXXRecordDecl *NamingClass = Target.getNamingClass(); +  NamingClass = NamingClass->getCanonicalDecl(); + +  for (EffectiveContext::record_iterator +         I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { +    const CXXRecordDecl *ECRecord = *I; +    switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { +    case AR_accessible: break; +    case AR_inaccessible: continue; +    case AR_dependent: continue; +    } + +    // The effective context is a subclass of the declaring class. +    // Check whether the [class.protected] restriction is limiting +    // access. + +    // To get this exactly right, this might need to be checked more +    // holistically;  it's not necessarily the case that gaining +    // access here would grant us access overall. + +    NamedDecl *D = Target.getTargetDecl(); + +    // If we don't have an instance context, [class.protected] says the +    // naming class has to equal the context class. +    if (!Target.hasInstanceContext()) { +      // If it does, the restriction doesn't apply. +      if (NamingClass == ECRecord) continue; + +      // TODO: it would be great to have a fixit here, since this is +      // such an obvious error. +      S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject) +        << S.Context.getTypeDeclType(ECRecord); +      return true; +    } + +    const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); +    assert(InstanceContext && "diagnosing dependent access"); + +    switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { +    case AR_accessible: continue; +    case AR_dependent: continue; +    case AR_inaccessible: +      break; +    } + +    // Okay, the restriction seems to be what's limiting us. + +    // Use a special diagnostic for constructors and destructors. +    if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) || +        (isa<FunctionTemplateDecl>(D) && +         isa<CXXConstructorDecl>( +                cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) { +      S.Diag(D->getLocation(), diag::note_access_protected_restricted_ctordtor) +        << isa<CXXDestructorDecl>(D); +      return true; +    } + +    // Otherwise, use the generic diagnostic. +    S.Diag(D->getLocation(), diag::note_access_protected_restricted_object) +      << S.Context.getTypeDeclType(ECRecord); +    return true; +  } + +  return false; +} + +/// Diagnose the path which caused the given declaration or base class +/// to become inaccessible. +static void DiagnoseAccessPath(Sema &S, +                               const EffectiveContext &EC, +                               AccessTarget &Entity) { +  AccessSpecifier Access = Entity.getAccess(); + +  NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); +  const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); + +  // Easy case: the decl's natural access determined its path access. +  // We have to check against AS_private here in case Access is AS_none, +  // indicating a non-public member of a private base class. +  if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) { +    switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) { +    case AR_inaccessible: { +      if (Access == AS_protected && +          TryDiagnoseProtectedAccess(S, EC, Entity)) +        return; + +      // Find an original declaration. +      while (D->isOutOfLine()) { +        NamedDecl *PrevDecl = 0; +        if (VarDecl *VD = dyn_cast<VarDecl>(D)) +          PrevDecl = VD->getPreviousDecl(); +        else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) +          PrevDecl = FD->getPreviousDecl(); +        else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D)) +          PrevDecl = TND->getPreviousDecl(); +        else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { +          if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName()) +            break; +          PrevDecl = TD->getPreviousDecl(); +        } +        if (!PrevDecl) break; +        D = PrevDecl; +      } + +      CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); +      Decl *ImmediateChild; +      if (D->getDeclContext() == DeclaringClass) +        ImmediateChild = D; +      else { +        DeclContext *DC = D->getDeclContext(); +        while (DC->getParent() != DeclaringClass) +          DC = DC->getParent(); +        ImmediateChild = cast<Decl>(DC); +      } +       +      // Check whether there's an AccessSpecDecl preceding this in the +      // chain of the DeclContext. +      bool Implicit = true; +      for (CXXRecordDecl::decl_iterator +             I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end(); +           I != E; ++I) { +        if (*I == ImmediateChild) break; +        if (isa<AccessSpecDecl>(*I)) { +          Implicit = false; +          break; +        } +      } + +      S.Diag(D->getLocation(), diag::note_access_natural) +        << (unsigned) (Access == AS_protected) +        << Implicit; +      return; +    } + +    case AR_accessible: break; + +    case AR_dependent: +      llvm_unreachable("can't diagnose dependent access failures"); +    } +  } + +  CXXBasePaths Paths; +  CXXBasePath &Path = *FindBestPath(S, EC, Entity, AS_public, Paths); + +  CXXBasePath::iterator I = Path.end(), E = Path.begin(); +  while (I != E) { +    --I; + +    const CXXBaseSpecifier *BS = I->Base; +    AccessSpecifier BaseAccess = BS->getAccessSpecifier(); + +    // If this is public inheritance, or the derived class is a friend, +    // skip this step. +    if (BaseAccess == AS_public) +      continue; + +    switch (GetFriendKind(S, EC, I->Class)) { +    case AR_accessible: continue; +    case AR_inaccessible: break; +    case AR_dependent: +      llvm_unreachable("can't diagnose dependent access failures"); +    } + +    // Check whether this base specifier is the tighest point +    // constraining access.  We have to check against AS_private for +    // the same reasons as above. +    if (BaseAccess == AS_private || BaseAccess >= Access) { + +      // We're constrained by inheritance, but we want to say +      // "declared private here" if we're diagnosing a hierarchy +      // conversion and this is the final step. +      unsigned diagnostic; +      if (D) diagnostic = diag::note_access_constrained_by_path; +      else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural; +      else diagnostic = diag::note_access_constrained_by_path; + +      S.Diag(BS->getSourceRange().getBegin(), diagnostic) +        << BS->getSourceRange() +        << (BaseAccess == AS_protected) +        << (BS->getAccessSpecifierAsWritten() == AS_none); +       +      if (D) +        S.Diag(D->getLocation(), diag::note_field_decl); +       +      return; +    } +  } + +  llvm_unreachable("access not apparently constrained by path"); +} + +static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, +                              const EffectiveContext &EC, +                              AccessTarget &Entity) { +  const CXXRecordDecl *NamingClass = Entity.getNamingClass(); +  const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); +  NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); + +  S.Diag(Loc, Entity.getDiag()) +    << (Entity.getAccess() == AS_protected) +    << (D ? D->getDeclName() : DeclarationName()) +    << S.Context.getTypeDeclType(NamingClass) +    << S.Context.getTypeDeclType(DeclaringClass); +  DiagnoseAccessPath(S, EC, Entity); +} + +/// MSVC has a bug where if during an using declaration name lookup,  +/// the declaration found is unaccessible (private) and that declaration  +/// was bring into scope via another using declaration whose target +/// declaration is accessible (public) then no error is generated. +/// Example: +///   class A { +///   public: +///     int f(); +///   }; +///   class B : public A { +///   private: +///     using A::f; +///   }; +///   class C : public B { +///   private: +///     using B::f; +///   }; +/// +/// Here, B::f is private so this should fail in Standard C++, but  +/// because B::f refers to A::f which is public MSVC accepts it. +static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,  +                                                 SourceLocation AccessLoc, +                                                 AccessTarget &Entity) { +  if (UsingShadowDecl *Shadow = +                         dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) { +    const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl(); +    if (Entity.getTargetDecl()->getAccess() == AS_private &&  +        (OrigDecl->getAccess() == AS_public || +         OrigDecl->getAccess() == AS_protected)) { +      S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible) +        << Shadow->getUsingDecl()->getQualifiedNameAsString() +        << OrigDecl->getQualifiedNameAsString(); +      return true; +    } +  } +  return false; +} + +/// Determines whether the accessed entity is accessible.  Public members +/// have been weeded out by this point. +static AccessResult IsAccessible(Sema &S, +                                 const EffectiveContext &EC, +                                 AccessTarget &Entity) { +  // Determine the actual naming class. +  CXXRecordDecl *NamingClass = Entity.getNamingClass(); +  while (NamingClass->isAnonymousStructOrUnion()) +    NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); +  NamingClass = NamingClass->getCanonicalDecl(); + +  AccessSpecifier UnprivilegedAccess = Entity.getAccess(); +  assert(UnprivilegedAccess != AS_public && "public access not weeded out"); + +  // Before we try to recalculate access paths, try to white-list +  // accesses which just trade in on the final step, i.e. accesses +  // which don't require [M4] or [B4]. These are by far the most +  // common forms of privileged access. +  if (UnprivilegedAccess != AS_none) { +    switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) { +    case AR_dependent: +      // This is actually an interesting policy decision.  We don't +      // *have* to delay immediately here: we can do the full access +      // calculation in the hope that friendship on some intermediate +      // class will make the declaration accessible non-dependently. +      // But that's not cheap, and odds are very good (note: assertion +      // made without data) that the friend declaration will determine +      // access. +      return AR_dependent; + +    case AR_accessible: return AR_accessible; +    case AR_inaccessible: break; +    } +  } + +  AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext(); + +  // We lower member accesses to base accesses by pretending that the +  // member is a base class of its declaring class. +  AccessSpecifier FinalAccess; + +  if (Entity.isMemberAccess()) { +    // Determine if the declaration is accessible from EC when named +    // in its declaring class. +    NamedDecl *Target = Entity.getTargetDecl(); +    const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); + +    FinalAccess = Target->getAccess(); +    switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) { +    case AR_accessible: +      FinalAccess = AS_public; +      break; +    case AR_inaccessible: break; +    case AR_dependent: return AR_dependent; // see above +    } + +    if (DeclaringClass == NamingClass) +      return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible); + +    Entity.suppressInstanceContext(); +  } else { +    FinalAccess = AS_public; +  } + +  assert(Entity.getDeclaringClass() != NamingClass); + +  // Append the declaration's access if applicable. +  CXXBasePaths Paths; +  CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); +  if (!Path) +    return AR_dependent; + +  assert(Path->Access <= UnprivilegedAccess && +         "access along best path worse than direct?"); +  if (Path->Access == AS_public) +    return AR_accessible; +  return AR_inaccessible; +} + +static void DelayDependentAccess(Sema &S, +                                 const EffectiveContext &EC, +                                 SourceLocation Loc, +                                 const AccessTarget &Entity) { +  assert(EC.isDependent() && "delaying non-dependent access"); +  DeclContext *DC = EC.getInnerContext(); +  assert(DC->isDependentContext() && "delaying non-dependent access"); +  DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access, +                              Loc, +                              Entity.isMemberAccess(), +                              Entity.getAccess(), +                              Entity.getTargetDecl(), +                              Entity.getNamingClass(), +                              Entity.getBaseObjectType(), +                              Entity.getDiag()); +} + +/// Checks access to an entity from the given effective context. +static AccessResult CheckEffectiveAccess(Sema &S, +                                         const EffectiveContext &EC, +                                         SourceLocation Loc, +                                         AccessTarget &Entity) { +  assert(Entity.getAccess() != AS_public && "called for public access!"); + +  if (S.getLangOpts().MicrosoftMode && +      IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) +    return AR_accessible; + +  switch (IsAccessible(S, EC, Entity)) { +  case AR_dependent: +    DelayDependentAccess(S, EC, Loc, Entity); +    return AR_dependent; + +  case AR_inaccessible: +    if (!Entity.isQuiet()) +      DiagnoseBadAccess(S, Loc, EC, Entity); +    return AR_inaccessible; + +  case AR_accessible: +    return AR_accessible; +  } + +  // silence unnecessary warning +  llvm_unreachable("invalid access result"); +} + +static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, +                                      AccessTarget &Entity) { +  // If the access path is public, it's accessible everywhere. +  if (Entity.getAccess() == AS_public) +    return Sema::AR_accessible; + +  if (S.SuppressAccessChecking) +    return Sema::AR_accessible; + +  // If we're currently parsing a declaration, we may need to delay +  // access control checking, because our effective context might be +  // different based on what the declaration comes out as. +  // +  // For example, we might be parsing a declaration with a scope +  // specifier, like this: +  //   A::private_type A::foo() { ... } +  // +  // Or we might be parsing something that will turn out to be a friend: +  //   void foo(A::private_type); +  //   void B::foo(A::private_type); +  if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { +    S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity)); +    return Sema::AR_delayed; +  } + +  EffectiveContext EC(S.CurContext); +  switch (CheckEffectiveAccess(S, EC, Loc, Entity)) { +  case AR_accessible: return Sema::AR_accessible; +  case AR_inaccessible: return Sema::AR_inaccessible; +  case AR_dependent: return Sema::AR_dependent; +  } +  llvm_unreachable("falling off end"); +} + +void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *decl) { +  // Access control for names used in the declarations of functions +  // and function templates should normally be evaluated in the context +  // of the declaration, just in case it's a friend of something. +  // However, this does not apply to local extern declarations. + +  DeclContext *DC = decl->getDeclContext(); +  if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) { +    if (!DC->isFunctionOrMethod()) DC = fn; +  } else if (FunctionTemplateDecl *fnt = dyn_cast<FunctionTemplateDecl>(decl)) { +    // Never a local declaration. +    DC = fnt->getTemplatedDecl(); +  } + +  EffectiveContext EC(DC); + +  AccessTarget Target(DD.getAccessData()); + +  if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible) +    DD.Triggered = true; +} + +void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, +                        const MultiLevelTemplateArgumentList &TemplateArgs) { +  SourceLocation Loc = DD.getAccessLoc(); +  AccessSpecifier Access = DD.getAccess(); + +  Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(), +                                       TemplateArgs); +  if (!NamingD) return; +  Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(), +                                       TemplateArgs); +  if (!TargetD) return; + +  if (DD.isAccessToMember()) { +    CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD); +    NamedDecl *TargetDecl = cast<NamedDecl>(TargetD); +    QualType BaseObjectType = DD.getAccessBaseObjectType(); +    if (!BaseObjectType.isNull()) { +      BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc, +                                 DeclarationName()); +      if (BaseObjectType.isNull()) return; +    } + +    AccessTarget Entity(Context, +                        AccessTarget::Member, +                        NamingClass, +                        DeclAccessPair::make(TargetDecl, Access), +                        BaseObjectType); +    Entity.setDiag(DD.getDiagnostic()); +    CheckAccess(*this, Loc, Entity); +  } else { +    AccessTarget Entity(Context, +                        AccessTarget::Base, +                        cast<CXXRecordDecl>(TargetD), +                        cast<CXXRecordDecl>(NamingD), +                        Access); +    Entity.setDiag(DD.getDiagnostic()); +    CheckAccess(*this, Loc, Entity); +  } +} + +Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, +                                                     DeclAccessPair Found) { +  if (!getLangOpts().AccessControl || +      !E->getNamingClass() || +      Found.getAccess() == AS_public) +    return AR_accessible; + +  AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),  +                      Found, QualType()); +  Entity.setDiag(diag::err_access) << E->getSourceRange(); + +  return CheckAccess(*this, E->getNameLoc(), Entity); +} + +/// Perform access-control checking on a previously-unresolved member +/// access which has now been resolved to a member. +Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, +                                                     DeclAccessPair Found) { +  if (!getLangOpts().AccessControl || +      Found.getAccess() == AS_public) +    return AR_accessible; + +  QualType BaseType = E->getBaseType(); +  if (E->isArrow()) +    BaseType = BaseType->getAs<PointerType>()->getPointeeType(); + +  AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), +                      Found, BaseType); +  Entity.setDiag(diag::err_access) << E->getSourceRange(); + +  return CheckAccess(*this, E->getMemberLoc(), Entity); +} + +/// Is the given special member function accessible for the purposes of +/// deciding whether to define a special member function as deleted? +bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, +                                                AccessSpecifier access, +                                                QualType objectType) { +  // Fast path. +  if (access == AS_public || !getLangOpts().AccessControl) return true; + +  AccessTarget entity(Context, AccessTarget::Member, decl->getParent(), +                      DeclAccessPair::make(decl, access), objectType); + +  // Suppress diagnostics. +  entity.setDiag(PDiag()); + +  switch (CheckAccess(*this, SourceLocation(), entity)) { +  case AR_accessible: return true; +  case AR_inaccessible: return false; +  case AR_dependent: llvm_unreachable("dependent for =delete computation"); +  case AR_delayed: llvm_unreachable("cannot delay =delete computation"); +  } +  llvm_unreachable("bad access result"); +} + +Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, +                                               CXXDestructorDecl *Dtor, +                                               const PartialDiagnostic &PDiag, +                                               QualType ObjectTy) { +  if (!getLangOpts().AccessControl) +    return AR_accessible; + +  // There's never a path involved when checking implicit destructor access. +  AccessSpecifier Access = Dtor->getAccess(); +  if (Access == AS_public) +    return AR_accessible; + +  CXXRecordDecl *NamingClass = Dtor->getParent(); +  if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass); + +  AccessTarget Entity(Context, AccessTarget::Member, NamingClass, +                      DeclAccessPair::make(Dtor, Access), +                      ObjectTy); +  Entity.setDiag(PDiag); // TODO: avoid copy + +  return CheckAccess(*this, Loc, Entity); +} + +/// Checks access to a constructor. +Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, +                                                CXXConstructorDecl *Constructor, +                                                const InitializedEntity &Entity, +                                                AccessSpecifier Access, +                                                bool IsCopyBindingRefToTemp) { +  if (!getLangOpts().AccessControl || Access == AS_public) +    return AR_accessible; + +  PartialDiagnostic PD(PDiag()); +  switch (Entity.getKind()) { +  default: +    PD = PDiag(IsCopyBindingRefToTemp +                 ? diag::ext_rvalue_to_reference_access_ctor +                 : diag::err_access_ctor); + +    break; + +  case InitializedEntity::EK_Base: +    PD = PDiag(diag::err_access_base_ctor); +    PD << Entity.isInheritedVirtualBase() +       << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor); +    break; + +  case InitializedEntity::EK_Member: { +    const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); +    PD = PDiag(diag::err_access_field_ctor); +    PD << Field->getType() << getSpecialMember(Constructor); +    break; +  } + +  case InitializedEntity::EK_LambdaCapture: { +    const VarDecl *Var = Entity.getCapturedVar(); +    PD = PDiag(diag::err_access_lambda_capture); +    PD << Var->getName() << Entity.getType() << getSpecialMember(Constructor); +    break; +  } + +  } + +  return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD); +} + +/// Checks access to a constructor. +Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, +                                                CXXConstructorDecl *Constructor, +                                                const InitializedEntity &Entity, +                                                AccessSpecifier Access, +                                                const PartialDiagnostic &PD) { +  if (!getLangOpts().AccessControl || +      Access == AS_public) +    return AR_accessible; + +  CXXRecordDecl *NamingClass = Constructor->getParent(); + +  // Initializing a base sub-object is an instance method call on an +  // object of the derived class.  Otherwise, we have an instance method +  // call on an object of the constructed type. +  CXXRecordDecl *ObjectClass; +  if (Entity.getKind() == InitializedEntity::EK_Base) { +    ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent(); +  } else { +    ObjectClass = NamingClass; +  } + +  AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, +                            DeclAccessPair::make(Constructor, Access), +                            Context.getTypeDeclType(ObjectClass)); +  AccessEntity.setDiag(PD); + +  return CheckAccess(*this, UseLoc, AccessEntity); +}  + +/// Checks direct (i.e. non-inherited) access to an arbitrary class +/// member. +Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, +                                                 NamedDecl *Target, +                                           const PartialDiagnostic &Diag) { +  AccessSpecifier Access = Target->getAccess(); +  if (!getLangOpts().AccessControl || +      Access == AS_public) +    return AR_accessible; + +  CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); +  AccessTarget Entity(Context, AccessTarget::Member, NamingClass, +                      DeclAccessPair::make(Target, Access), +                      QualType()); +  Entity.setDiag(Diag); +  return CheckAccess(*this, UseLoc, Entity); +} +                                            + +/// Checks access to an overloaded operator new or delete. +Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, +                                               SourceRange PlacementRange, +                                               CXXRecordDecl *NamingClass, +                                               DeclAccessPair Found, +                                               bool Diagnose) { +  if (!getLangOpts().AccessControl || +      !NamingClass || +      Found.getAccess() == AS_public) +    return AR_accessible; + +  AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, +                      QualType()); +  if (Diagnose) +    Entity.setDiag(diag::err_access) +      << PlacementRange; + +  return CheckAccess(*this, OpLoc, Entity); +} + +/// Checks access to an overloaded member operator, including +/// conversion operators. +Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, +                                                   Expr *ObjectExpr, +                                                   Expr *ArgExpr, +                                                   DeclAccessPair Found) { +  if (!getLangOpts().AccessControl || +      Found.getAccess() == AS_public) +    return AR_accessible; + +  const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>(); +  CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); + +  AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, +                      ObjectExpr->getType()); +  Entity.setDiag(diag::err_access) +    << ObjectExpr->getSourceRange() +    << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); + +  return CheckAccess(*this, OpLoc, Entity); +} + +Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, +                                                    DeclAccessPair Found) { +  if (!getLangOpts().AccessControl || +      Found.getAccess() == AS_none || +      Found.getAccess() == AS_public) +    return AR_accessible; + +  OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression; +  CXXRecordDecl *NamingClass = Ovl->getNamingClass(); + +  AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, +                      /*no instance context*/ QualType()); +  Entity.setDiag(diag::err_access) +    << Ovl->getSourceRange(); + +  return CheckAccess(*this, Ovl->getNameLoc(), Entity); +} + +/// Checks access for a hierarchy conversion. +/// +/// \param IsBaseToDerived whether this is a base-to-derived conversion (true) +///     or a derived-to-base conversion (false) +/// \param ForceCheck true if this check should be performed even if access +///     control is disabled;  some things rely on this for semantics +/// \param ForceUnprivileged true if this check should proceed as if the +///     context had no special privileges +/// \param ADK controls the kind of diagnostics that are used +Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, +                                              QualType Base, +                                              QualType Derived, +                                              const CXXBasePath &Path, +                                              unsigned DiagID, +                                              bool ForceCheck, +                                              bool ForceUnprivileged) { +  if (!ForceCheck && !getLangOpts().AccessControl) +    return AR_accessible; + +  if (Path.Access == AS_public) +    return AR_accessible; + +  CXXRecordDecl *BaseD, *DerivedD; +  BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); +  DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); + +  AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,  +                      Path.Access); +  if (DiagID) +    Entity.setDiag(DiagID) << Derived << Base; + +  if (ForceUnprivileged) { +    switch (CheckEffectiveAccess(*this, EffectiveContext(), +                                 AccessLoc, Entity)) { +    case ::AR_accessible: return Sema::AR_accessible; +    case ::AR_inaccessible: return Sema::AR_inaccessible; +    case ::AR_dependent: return Sema::AR_dependent; +    } +    llvm_unreachable("unexpected result from CheckEffectiveAccess"); +  } +  return CheckAccess(*this, AccessLoc, Entity); +} + +/// Checks access to all the declarations in the given result set. +void Sema::CheckLookupAccess(const LookupResult &R) { +  assert(getLangOpts().AccessControl +         && "performing access check without access control"); +  assert(R.getNamingClass() && "performing access check without naming class"); + +  for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { +    if (I.getAccess() != AS_public) { +      AccessTarget Entity(Context, AccessedEntity::Member, +                          R.getNamingClass(), I.getPair(), +                          R.getBaseObjectType()); +      Entity.setDiag(diag::err_access); +      CheckAccess(*this, R.getNameLoc(), Entity); +    } +  } +} + +/// Checks access to Decl from the given class. The check will take access +/// specifiers into account, but no member access expressions and such. +/// +/// \param Decl the declaration to check if it can be accessed +/// \param Class the class/context from which to start the search +/// \return true if the Decl is accessible from the Class, false otherwise. +bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) { +  if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) { +    if (!Decl->isCXXClassMember()) +      return true; + +    QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal(); +    AccessTarget Entity(Context, AccessedEntity::Member, Class, +                        DeclAccessPair::make(Decl, Decl->getAccess()), +                        qType); +    if (Entity.getAccess() == AS_public) +      return true; + +    EffectiveContext EC(CurContext); +    return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; +  } +   +  if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) { +    // @public and @package ivars are always accessible. +    if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public || +        Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package) +      return true; +     +     +     +    // If we are inside a class or category implementation, determine the +    // interface we're in. +    ObjCInterfaceDecl *ClassOfMethodDecl = 0; +    if (ObjCMethodDecl *MD = getCurMethodDecl()) +      ClassOfMethodDecl =  MD->getClassInterface(); +    else if (FunctionDecl *FD = getCurFunctionDecl()) { +      if (ObjCImplDecl *Impl  +            = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) { +        if (ObjCImplementationDecl *IMPD +              = dyn_cast<ObjCImplementationDecl>(Impl)) +          ClassOfMethodDecl = IMPD->getClassInterface(); +        else if (ObjCCategoryImplDecl* CatImplClass +                   = dyn_cast<ObjCCategoryImplDecl>(Impl)) +          ClassOfMethodDecl = CatImplClass->getClassInterface(); +      } +    } +     +    // If we're not in an interface, this ivar is inaccessible. +    if (!ClassOfMethodDecl) +      return false; +     +    // If we're inside the same interface that owns the ivar, we're fine. +    if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface())) +      return true; +     +    // If the ivar is private, it's inaccessible. +    if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private) +      return false; +     +    return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl); +  } +   +  return true; +} + +void Sema::ActOnStartSuppressingAccessChecks() { +  assert(!SuppressAccessChecking && +         "Tried to start access check suppression when already started."); +  SuppressAccessChecking = true; +} + +void Sema::ActOnStopSuppressingAccessChecks() { +  assert(SuppressAccessChecking && +         "Tried to stop access check suprression when already stopped."); +  SuppressAccessChecking = false; +}  | 
