Check in LLVM r95781.
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
new file mode 100644
index 0000000..eca8bb4
--- /dev/null
+++ b/lib/Sema/SemaAccess.cpp
@@ -0,0 +1,548 @@
+//===---- 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 "Sema.h"
+#include "Lookup.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+
+using namespace clang;
+
+/// 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;
+}
+
+namespace {
+struct EffectiveContext {
+  EffectiveContext() : Record(0), Function(0) {}
+
+  explicit EffectiveContext(DeclContext *DC) {
+    if (isa<FunctionDecl>(DC)) {
+      Function = cast<FunctionDecl>(DC);
+      DC = Function->getDeclContext();
+    } else
+      Function = 0;
+    
+    if (isa<CXXRecordDecl>(DC))
+      Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+    else
+      Record = 0;
+  }
+
+  bool isClass(const CXXRecordDecl *R) const {
+    return R->getCanonicalDecl() == Record;
+  }
+
+  CXXRecordDecl *Record;
+  FunctionDecl *Function;
+};
+}
+
+static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
+  CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+  while (DeclaringClass->isAnonymousStructOrUnion())
+    DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
+  return DeclaringClass;
+}
+
+static Sema::AccessResult GetFriendKind(Sema &S,
+                                        const EffectiveContext &EC,
+                                        const CXXRecordDecl *Class) {
+  if (EC.isClass(Class))
+    return Sema::AR_accessible;
+
+  // FIXME: implement
+  return Sema::AR_inaccessible;
+}
+
+/// Finds the best path from the naming class to the declaring class,
+/// taking friend declarations into account.
+///
+/// \return null if friendship is dependent
+static CXXBasePath *FindBestPath(Sema &S,
+                                 const EffectiveContext &EC,
+                                 CXXRecordDecl *Derived,
+                                 CXXRecordDecl *Base,
+                                 CXXBasePaths &Paths) {
+  // Derive the paths to the desired base.
+  bool isDerived = Derived->isDerivedFrom(Base, Paths);
+  assert(isDerived && "derived class not actually derived from base");
+  (void) isDerived;
+
+  CXXBasePath *BestPath = 0;
+
+  // Derive the friend-modified access along each path.
+  for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
+         PI != PE; ++PI) {
+
+    // Walk through the path backwards.
+    AccessSpecifier PathAccess = AS_public;
+    CXXBasePath::iterator I = PI->end(), E = PI->begin();
+    while (I != E) {
+      --I;
+
+      AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
+      if (BaseAccess != AS_public) {
+        switch (GetFriendKind(S, EC, I->Class)) {
+        case Sema::AR_inaccessible: break;
+        case Sema::AR_accessible: BaseAccess = AS_public; break;
+        case Sema::AR_dependent: return 0;
+        case Sema::AR_delayed:
+          llvm_unreachable("friend resolution is never delayed"); break;
+        }
+      }
+
+      PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
+    }
+
+    // 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;
+    }
+  }
+
+  return BestPath;
+}
+
+/// Diagnose the path which caused the given declaration or base class
+/// to become inaccessible.
+static void DiagnoseAccessPath(Sema &S,
+                               const EffectiveContext &EC,
+                               CXXRecordDecl *NamingClass,
+                               CXXRecordDecl *DeclaringClass,
+                               NamedDecl *D, AccessSpecifier Access) {
+  // 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.
+  //
+  // DependentFriend should be impossible here.
+  if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
+    switch (GetFriendKind(S, EC, DeclaringClass)) {
+    case Sema::AR_inaccessible: {
+      S.Diag(D->getLocation(), diag::note_access_natural)
+        << (unsigned) (Access == AS_protected)
+        << /*FIXME: not implicitly*/ 0;
+      return;
+    }
+
+    case Sema::AR_accessible: break;
+
+    case Sema::AR_dependent:
+    case Sema::AR_delayed:
+      llvm_unreachable("dependent/delayed not allowed");
+      return;
+    }
+  }
+
+  CXXBasePaths Paths;
+  CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, 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 Sema::AR_accessible: continue;
+    case Sema::AR_inaccessible: break;
+
+    case Sema::AR_dependent:
+    case Sema::AR_delayed:
+      llvm_unreachable("dependent friendship, should not be diagnosing");
+    }
+
+    // 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);
+      return;
+    }
+  }
+
+  llvm_unreachable("access not apparently constrained by path");
+}
+
+/// Diagnose an inaccessible class member.
+static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
+                                       const EffectiveContext &EC,
+                                       CXXRecordDecl *NamingClass,
+                                       AccessSpecifier Access,
+                                       const Sema::AccessedEntity &Entity) {
+  NamedDecl *D = Entity.getTargetDecl();
+  CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+
+  if (isa<CXXConstructorDecl>(D)) {
+    unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected
+                                              : diag::err_access_ctor_private);
+    S.Diag(Loc, DiagID)
+      << S.Context.getTypeDeclType(DeclaringClass);
+  } else {
+    unsigned DiagID = (Access == AS_protected ? diag::err_access_protected
+                                              : diag::err_access_private);
+    S.Diag(Loc, DiagID)
+      << D->getDeclName()
+      << S.Context.getTypeDeclType(DeclaringClass);
+  }
+  DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
+}
+
+/// Diagnose an inaccessible hierarchy conversion.
+static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
+                                     const EffectiveContext &EC,
+                                     AccessSpecifier Access,
+                                     const Sema::AccessedEntity &Entity,
+                                     Sema::AccessDiagnosticsKind ADK) {
+  if (ADK == Sema::ADK_covariance) {
+    S.Diag(Loc, diag::err_covariant_return_inaccessible_base)
+      << S.Context.getTypeDeclType(Entity.getDerivedClass())
+      << S.Context.getTypeDeclType(Entity.getBaseClass())
+      << (Access == AS_protected);
+  } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) {
+    S.Diag(Loc, diag::err_downcast_from_inaccessible_base)
+      << S.Context.getTypeDeclType(Entity.getDerivedClass())
+      << S.Context.getTypeDeclType(Entity.getBaseClass())
+      << (Access == AS_protected);
+  } else {
+    S.Diag(Loc, diag::err_upcast_to_inaccessible_base)
+      << S.Context.getTypeDeclType(Entity.getDerivedClass())
+      << S.Context.getTypeDeclType(Entity.getBaseClass())
+      << (Access == AS_protected);
+  }
+  DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
+                     Entity.getBaseClass(), 0, Access);
+}
+
+static void DiagnoseBadAccess(Sema &S,
+                              SourceLocation Loc,
+                              const EffectiveContext &EC,
+                              CXXRecordDecl *NamingClass,
+                              AccessSpecifier Access,
+                              const Sema::AccessedEntity &Entity,
+                              Sema::AccessDiagnosticsKind ADK) {
+  if (Entity.isMemberAccess())
+    DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
+  else
+    DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK);
+}
+
+
+/// Try to elevate access using friend declarations.  This is
+/// potentially quite expensive.
+static void TryElevateAccess(Sema &S,
+                             const EffectiveContext &EC,
+                             const Sema::AccessedEntity &Entity,
+                             AccessSpecifier &Access) {
+  CXXRecordDecl *DeclaringClass;
+  if (Entity.isMemberAccess()) {
+    DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
+  } else {
+    DeclaringClass = Entity.getBaseClass();
+  }
+  CXXRecordDecl *NamingClass = Entity.getNamingClass();
+
+  // Adjust the declaration of the referred entity.
+  AccessSpecifier DeclAccess = AS_none;
+  if (Entity.isMemberAccess()) {
+    NamedDecl *Target = Entity.getTargetDecl();
+
+    DeclAccess = Target->getAccess();
+    if (DeclAccess != AS_public) {
+      switch (GetFriendKind(S, EC, DeclaringClass)) {
+      case Sema::AR_accessible: DeclAccess = AS_public; break;
+      case Sema::AR_inaccessible: break;
+      case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
+      case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
+      }
+    }
+
+    if (DeclaringClass == NamingClass) {
+      Access = DeclAccess;
+      return;
+    }
+  }
+
+  assert(DeclaringClass != NamingClass);
+
+  // Append the declaration's access if applicable.
+  CXXBasePaths Paths;
+  CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
+                                   DeclaringClass, Paths);
+  if (!Path) {
+    // FIXME: delay dependent friendship
+    return;
+  }
+
+  // Grab the access along the best path.
+  AccessSpecifier NewAccess = Path->Access;
+  if (Entity.isMemberAccess())
+    NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess);
+  
+  assert(NewAccess <= Access && "access along best path worse than direct?");
+  Access = NewAccess;
+}
+
+/// Checks access to an entity from the given effective context.
+static Sema::AccessResult CheckEffectiveAccess(Sema &S,
+                                               const EffectiveContext &EC,
+                                               SourceLocation Loc,
+                                         Sema::AccessedEntity const &Entity,
+                                         Sema::AccessDiagnosticsKind ADK) {
+  AccessSpecifier Access = Entity.getAccess();
+  assert(Access != AS_public);
+
+  CXXRecordDecl *NamingClass = Entity.getNamingClass();
+  while (NamingClass->isAnonymousStructOrUnion())
+    // This should be guaranteed by the fact that the decl has
+    // non-public access.  If not, we should make it guaranteed!
+    NamingClass = cast<CXXRecordDecl>(NamingClass);
+
+  if (!EC.Record) {
+    TryElevateAccess(S, EC, Entity, Access);
+    if (Access == AS_public) return Sema::AR_accessible;
+
+    if (ADK != Sema::ADK_quiet)
+      DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+    return Sema::AR_inaccessible;
+  }
+
+  // White-list accesses from within the declaring class.
+  if (Access != AS_none && EC.isClass(NamingClass))
+    return Sema::AR_accessible;
+  
+  // If the access is worse than 'protected', try to promote to it using
+  // friend declarations.
+  bool TriedElevation = false;
+  if (Access != AS_protected) {
+    TryElevateAccess(S, EC, Entity, Access);
+    if (Access == AS_public) return Sema::AR_accessible;
+    TriedElevation = true;
+  }
+
+  // Protected access.
+  if (Access == AS_protected) {
+    // FIXME: implement [class.protected]p1
+    if (EC.Record->isDerivedFrom(NamingClass))
+      return Sema::AR_accessible;
+
+    // FIXME: delay dependent classes
+  }
+
+  // We're about to reject;  one last chance to promote access.
+  if (!TriedElevation) {
+    TryElevateAccess(S, EC, Entity, Access);
+    if (Access == AS_public) return Sema::AR_accessible;
+  }
+    
+  // Okay, that's it, reject it.
+  if (ADK != Sema::ADK_quiet)
+    DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+  return Sema::AR_inaccessible;
+}
+
+static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
+                                      const Sema::AccessedEntity &Entity,
+                                      Sema::AccessDiagnosticsKind ADK
+                                        = Sema::ADK_normal) {
+  // If the access path is public, it's accessible everywhere.
+  if (Entity.getAccess() == AS_public)
+    return Sema::AR_accessible;
+
+  // If we're currently parsing a top-level declaration, delay
+  // diagnostics.  This is the only case where parsing a declaration
+  // can actually change our effective context for the purposes of
+  // access control.
+  if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
+    assert(ADK == Sema::ADK_normal && "delaying abnormal access check");
+    S.DelayedDiagnostics.push_back(
+        Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
+    return Sema::AR_delayed;
+  }
+
+  return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
+                              Loc, Entity, ADK);
+}
+
+void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
+  // Pretend we did this from the context of the newly-parsed
+  // declaration.
+  EffectiveContext EC(Ctx->getDeclContext());
+
+  if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
+    DD.Triggered = true;
+}
+
+Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+                                                     NamedDecl *D,
+                                                     AccessSpecifier Access) {
+  if (!getLangOptions().AccessControl || !E->getNamingClass())
+    return AR_accessible;
+
+  return CheckAccess(*this, E->getNameLoc(),
+                 AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+}
+
+/// Perform access-control checking on a previously-unresolved member
+/// access which has now been resolved to a member.
+Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+                                                     NamedDecl *D,
+                                                     AccessSpecifier Access) {
+  if (!getLangOptions().AccessControl)
+    return AR_accessible;
+
+  return CheckAccess(*this, E->getMemberLoc(),
+                 AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+}
+
+Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
+                                               const RecordType *RT) {
+  if (!getLangOptions().AccessControl)
+    return AR_accessible;
+
+  CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
+  CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
+
+  AccessSpecifier Access = Dtor->getAccess();
+  if (Access == AS_public)
+    return AR_accessible;
+
+  return CheckAccess(*this, Loc,
+                 AccessedEntity::makeMember(NamingClass, Access, Dtor));
+}
+
+/// Checks access to a constructor.
+Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
+                                  CXXConstructorDecl *Constructor,
+                                  AccessSpecifier Access) {
+  if (!getLangOptions().AccessControl)
+    return AR_accessible;
+
+  CXXRecordDecl *NamingClass = Constructor->getParent();
+  return CheckAccess(*this, UseLoc,
+                 AccessedEntity::makeMember(NamingClass, Access, Constructor));
+}
+
+/// Checks access to an overloaded member operator, including
+/// conversion operators.
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+                                                   Expr *ObjectExpr,
+                                                   NamedDecl *MemberOperator,
+                                                   AccessSpecifier Access) {
+  if (!getLangOptions().AccessControl)
+    return AR_accessible;
+
+  const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
+  assert(RT && "found member operator but object expr not of record type");
+  CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
+
+  return CheckAccess(*this, OpLoc,
+            AccessedEntity::makeMember(NamingClass, Access, MemberOperator));
+}
+
+/// 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,
+                                              bool IsBaseToDerived,
+                                              QualType Base,
+                                              QualType Derived,
+                                              const CXXBasePath &Path,
+                                              bool ForceCheck,
+                                              bool ForceUnprivileged,
+                                              AccessDiagnosticsKind ADK) {
+  if (!ForceCheck && !getLangOptions().AccessControl)
+    return AR_accessible;
+
+  if (Path.Access == AS_public)
+    return AR_accessible;
+
+  // TODO: preserve the information about which types exactly were used.
+  CXXRecordDecl *BaseD, *DerivedD;
+  BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
+  DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
+  AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived,
+                                                        BaseD, DerivedD,
+                                                        Path.Access);
+
+  if (ForceUnprivileged)
+    return CheckEffectiveAccess(*this, EffectiveContext(),
+                                AccessLoc, Entity, ADK);
+  return CheckAccess(*this, AccessLoc, Entity, ADK);
+}
+
+/// Checks access to all the declarations in the given result set.
+void Sema::CheckLookupAccess(const LookupResult &R) {
+  assert(getLangOptions().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)
+      CheckAccess(*this, R.getNameLoc(),
+                  AccessedEntity::makeMember(R.getNamingClass(),
+                                             I.getAccess(), *I));
+}