[cfe-commits] r95775 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ lib/Sema/ test/CXX/class.access/ test/CXX/class.access/class.access.base/ test/CXX/class/class.local/ test/CXX/conv/conv.mem/ test/SemaCXX/

John McCall rjmccall at apple.com
Wed Feb 10 01:31:13 PST 2010


Author: rjmccall
Date: Wed Feb 10 03:31:12 2010
New Revision: 95775

URL: http://llvm.org/viewvc/llvm-project?rev=95775&view=rev
Log:
Improve access control diagnostics.  Perform access control on member-pointer
conversions.  Fix an access-control bug where privileges were not considered
at intermediate points along the inheritance path.  Prepare for friends.


Modified:
    cfe/trunk/include/clang/AST/CXXInheritance.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Lookup.h
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaAccess.cpp
    cfe/trunk/lib/Sema/SemaCXXCast.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp
    cfe/trunk/test/CXX/class.access/p4.cpp
    cfe/trunk/test/CXX/class.access/p6.cpp
    cfe/trunk/test/CXX/class/class.local/p2.cpp
    cfe/trunk/test/CXX/conv/conv.mem/p4.cpp
    cfe/trunk/test/SemaCXX/access-base-class.cpp
    cfe/trunk/test/SemaCXX/access-control-check.cpp
    cfe/trunk/test/SemaCXX/conditional-expr.cpp
    cfe/trunk/test/SemaCXX/static-cast.cpp
    cfe/trunk/test/SemaCXX/virtual-override.cpp

Modified: cfe/trunk/include/clang/AST/CXXInheritance.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CXXInheritance.h?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/CXXInheritance.h (original)
+++ cfe/trunk/include/clang/AST/CXXInheritance.h Wed Feb 10 03:31:12 2010
@@ -161,7 +161,8 @@
   void ComputeDeclsFound();
   
 public:
-  typedef std::list<CXXBasePath>::const_iterator paths_iterator;
+  typedef std::list<CXXBasePath>::iterator paths_iterator;
+  typedef std::list<CXXBasePath>::const_iterator const_paths_iterator;
   typedef NamedDecl **decl_iterator;
   
   /// BasePaths - Construct a new BasePaths structure to record the
@@ -175,8 +176,10 @@
   
   ~CXXBasePaths() { delete [] DeclsFound; }
   
-  paths_iterator begin() const { return Paths.begin(); }
-  paths_iterator end()   const { return Paths.end(); }
+  paths_iterator begin() { return Paths.begin(); }
+  paths_iterator end()   { return Paths.end(); }
+  const_paths_iterator begin() const { return Paths.begin(); }
+  const_paths_iterator end()   const { return Paths.end(); }
   
   CXXBasePath&       front()       { return Paths.front(); }
   const CXXBasePath& front() const { return Paths.front(); }
@@ -206,7 +209,7 @@
   const RecordType* getDetectedVirtual() const {
     return DetectedVirtual;
   }
-  
+
   /// \brief Retrieve the type from which this base-paths search
   /// began
   CXXRecordDecl *getOrigin() const { return Origin; }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Feb 10 03:31:12 2010
@@ -417,17 +417,20 @@
 // C++ access checking
 def err_class_redeclared_with_different_access : Error<
   "%0 redeclared with '%1' access">;
+def err_access_private : Error<"%0 is a private member of %1">;
+def err_access_ctor_private : Error<"calling a private constructor of %0">;
+// Say something about the context for these?
+def err_access_protected : Error<"%0 is a protected member of %1">;
+def err_access_ctor_protected : Error<"calling a protected constructor of %0">;
 def note_previous_access_declaration : Note<
   "previously declared '%1' here">;
 def err_access_outside_class : Error<
   "access to %select{private|protected}0 member outside any class context">;
-def note_access_natural : Note<"declared %select{private|protected}0 here">;
+def note_access_natural : Note<
+  "%select{|implicitly }1declared %select{private|protected}0 here">;
 def note_access_constrained_by_path : Note<
-  "access to decl constrained by %select{private|protected}0 inheritance">;
-def err_access_protected : Error<
-  "access to protected member of %0 from %1, which is not a subclass">;
-def err_access_private : Error<
-  "access to private member of %0 from %1">;
+  "constrained by %select{|implicitly }1%select{private|protected}0"
+  " inheritance here">;
   
 // C++ name lookup
 def err_incomplete_nested_name_spec : Error<
@@ -509,9 +512,8 @@
   "overridden virtual function is here">;
 
 def err_covariant_return_inaccessible_base : Error<
-  "return type of virtual function %2 is not covariant with the return type "
-  "of the function it overrides "
-  "(conversion from %0 to inaccessible base class %1)">, NoSFINAE;
+  "invalid covariant return for virtual function: %1 is a "
+  "%select{private|protected}2 base class of %0">, NoSFINAE;
 def err_covariant_return_ambiguous_derived_to_base_conv : Error<
   "return type of virtual function %3 is not covariant with the return type of "
   "the function it overrides (ambiguous conversion from derived class "
@@ -1958,7 +1960,9 @@
 def err_static_downcast_via_virtual : Error<
   "cannot cast %0 to %1 via virtual base %2">;
 def err_downcast_from_inaccessible_base : Error<
-  "cannot cast %1 to %0 due to inaccessible conversion path">;
+  "cannot cast %select{private|protected}2 base class %1 to %0">;
+def err_upcast_to_inaccessible_base : Error<
+  "cannot cast %0 to its %select{private|protected}2 base class %1">;
 def err_bad_dynamic_cast_not_ref_or_ptr : Error<
   "%0 is not a reference or pointer">;
 def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">;

Modified: cfe/trunk/lib/Sema/Lookup.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Lookup.h?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Lookup.h (original)
+++ cfe/trunk/lib/Sema/Lookup.h Wed Feb 10 03:31:12 2010
@@ -503,7 +503,7 @@
     if (isAmbiguous())
       SemaRef.DiagnoseAmbiguousLookup(*this);
     else if (isClassLookup() && SemaRef.getLangOptions().AccessControl)
-      SemaRef.CheckAccess(*this);
+      SemaRef.CheckLookupAccess(*this);
   }
 
   void setAmbiguous(AmbiguityKind AK) {

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Feb 10 03:31:12 2010
@@ -96,6 +96,7 @@
   class ObjCPropertyDecl;
   class ObjCContainerDecl;
   class FunctionProtoType;
+  class CXXBasePath;
   class CXXBasePaths;
   class CXXTemporary;
   class LookupResult;
@@ -275,6 +276,77 @@
   /// \brief All the tentative definitions encountered in the TU.
   std::vector<VarDecl *> TentativeDefinitions;
 
+  /// An enum describing the kind of diagnostics to use when checking
+  /// access.
+  enum AccessDiagnosticsKind {
+    /// Suppress diagnostics.
+    ADK_quiet,
+
+    /// Use the normal diagnostics.
+    ADK_normal,
+
+    /// Use the diagnostics appropriate for checking a covariant
+    /// return type.
+    ADK_covariance
+  };
+
+  class AccessedEntity {
+  public:
+    enum Kind {
+      /// A member declaration found through lookup.  The target is the
+      /// member.
+      Member,
+
+      /// A base-to-derived conversion.  The target is the base class.
+      BaseToDerivedConversion,
+
+      /// A derived-to-base conversion.  The target is the base class.
+      DerivedToBaseConversion
+    };
+
+    bool isMemberAccess() const { return K == Member; }
+
+    static AccessedEntity makeMember(CXXRecordDecl *NamingClass,
+                                     AccessSpecifier Access,
+                                     NamedDecl *Target) {
+      AccessedEntity E;
+      E.K = Member;
+      E.Access = Access;
+      E.Target = Target;
+      E.NamingClass = NamingClass;
+      return E;
+    }
+
+    static AccessedEntity makeBaseClass(bool BaseToDerived,
+                                        CXXRecordDecl *BaseClass,
+                                        CXXRecordDecl *DerivedClass,
+                                        AccessSpecifier Access) {
+      AccessedEntity E;
+      E.K = BaseToDerived ? BaseToDerivedConversion : DerivedToBaseConversion;
+      E.Access = Access;
+      E.Target = BaseClass;
+      E.NamingClass = DerivedClass;
+      return E;
+    }
+
+    Kind getKind() const { return Kind(K); }
+    AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
+
+    // These apply to member decls...
+    NamedDecl *getTargetDecl() const { return Target; }
+    CXXRecordDecl *getNamingClass() const { return NamingClass; }
+
+    // ...and these apply to hierarchy conversions.
+    CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
+    CXXRecordDecl *getDerivedClass() const { return NamingClass; }
+
+  private:
+    unsigned K : 2;
+    unsigned Access : 2;
+    NamedDecl *Target;
+    CXXRecordDecl *NamingClass;    
+  };
+
   struct DelayedDiagnostic {
     enum DDKind { Deprecation, Access };
 
@@ -288,11 +360,7 @@
       struct { NamedDecl *Decl; } DeprecationData;
 
       /// Access control.
-      struct {
-        NamedDecl *Decl;
-        AccessSpecifier Access; 
-        CXXRecordDecl *NamingClass;
-      } AccessData;
+      AccessedEntity AccessData;
     };
 
     static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
@@ -306,16 +374,12 @@
     }
 
     static DelayedDiagnostic makeAccess(SourceLocation Loc,
-                                        NamedDecl *Decl,
-                                        AccessSpecifier AS,
-                                        CXXRecordDecl *NamingClass) {
+                                        const AccessedEntity &Entity) {
       DelayedDiagnostic DD;
       DD.Kind = Access;
       DD.Triggered = false;
       DD.Loc = Loc;
-      DD.AccessData.Decl = Decl;
-      DD.AccessData.Access = AS;
-      DD.AccessData.NamingClass = NamingClass;
+      DD.AccessData = Entity;
       return DD;
     }
 
@@ -2385,7 +2449,7 @@
                                     SourceLocation Loc, SourceRange Range,
                                     bool IgnoreAccess = false);
   bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
-                                    unsigned InaccessibleBaseID,
+                                    AccessDiagnosticsKind ADK,
                                     unsigned AmbigiousBaseConvID,
                                     SourceLocation Loc, SourceRange Range,
                                     DeclarationName Name);
@@ -2412,38 +2476,43 @@
   // C++ Access Control
   //
 
+  enum AccessResult {
+    AR_accessible,
+    AR_inaccessible,
+    AR_dependent,
+    AR_delayed
+  };
+
   bool SetMemberAccessSpecifier(NamedDecl *MemberDecl,
                                 NamedDecl *PrevMemberDecl,
                                 AccessSpecifier LexicalAS);
 
-  const CXXBaseSpecifier *FindInaccessibleBase(QualType Derived, QualType Base,
-                                               CXXBasePaths &Paths,
-                                               bool NoPrivileges = false);
-
-  bool CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
-                                   NamedDecl *D,
-                                   AccessSpecifier Access);
-  bool CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
-                                   NamedDecl *D,
-                                   AccessSpecifier Access);
-  bool CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D,
-                              AccessSpecifier Access);
-  bool CheckDestructorAccess(SourceLocation Loc, const RecordType *Record);
-  bool CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr,
-                                 NamedDecl *D, AccessSpecifier Access);
-  bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access);
-  void CheckAccess(const LookupResult &R);
+  AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+                                           NamedDecl *D,
+                                           AccessSpecifier Access);
+  AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+                                           NamedDecl *D,
+                                           AccessSpecifier Access);
+  AccessResult CheckConstructorAccess(SourceLocation Loc,
+                                      CXXConstructorDecl *D,
+                                      AccessSpecifier Access);
+  AccessResult CheckDestructorAccess(SourceLocation Loc,
+                                     const RecordType *Record);
+  AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
+                                         Expr *ObjectExpr,
+                                         NamedDecl *D,
+                                         AccessSpecifier Access);
+  AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
+                                    bool IsBaseToDerived,
+                                    QualType Base, QualType Derived,
+                                    const CXXBasePath &Path,
+                                    bool ForceCheck = false,
+                                    bool ForceUnprivileged = false,
+                                    AccessDiagnosticsKind ADK = ADK_normal);
+                            
+  void CheckLookupAccess(const LookupResult &R);
 
   void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx);
-  bool CheckEffectiveAccess(DeclContext *EffectiveContext,
-                            const LookupResult &R, NamedDecl *D,
-                            AccessSpecifier Access);
-
-  bool CheckBaseClassAccess(QualType Derived, QualType Base,
-                            unsigned InaccessibleBaseID,
-                            CXXBasePaths& Paths, SourceLocation AccessLoc,
-                            DeclarationName Name);
-
 
   enum AbstractDiagSelID {
     AbstractNone = -1,

Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Wed Feb 10 03:31:12 2010
@@ -49,326 +49,500 @@
   return false;
 }
 
-/// Find a class on the derivation path between Derived and Base that is
-/// inaccessible. If @p NoPrivileges is true, special access rights (members
-/// and friends) are not considered.
-const CXXBaseSpecifier *Sema::FindInaccessibleBase(
-    QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) {
-  Base = Context.getCanonicalType(Base).getUnqualifiedType();
-  assert(!Paths.isAmbiguous(Base) &&
-         "Can't check base class access if set of paths is ambiguous");
-  assert(Paths.isRecordingPaths() &&
-         "Can't check base class access without recorded paths");
-
-
-  const CXXBaseSpecifier *InaccessibleBase = 0;
-
-  const CXXRecordDecl *CurrentClassDecl = 0;
-  if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
-    CurrentClassDecl = MD->getParent();
-
-  for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
-      Path != PathsEnd; ++Path) {
-
-    bool FoundInaccessibleBase = false;
-
-    for (CXXBasePath::const_iterator Element = Path->begin(),
-         ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
-      const CXXBaseSpecifier *Base = Element->Base;
-
-      switch (Base->getAccessSpecifier()) {
-      default:
-        assert(0 && "invalid access specifier");
-      case AS_public:
-        // Nothing to do.
-        break;
-      case AS_private:
-        // FIXME: Check if the current function/class is a friend.
-        if (NoPrivileges || CurrentClassDecl != Element->Class)
-          FoundInaccessibleBase = true;
-        break;
-      case AS_protected:
-        // FIXME: Implement
-        break;
-      }
+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;
+}
 
-      if (FoundInaccessibleBase) {
-        InaccessibleBase = Base;
-        break;
+/// 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);
     }
 
-    if (!FoundInaccessibleBase) {
-      // We found a path to the base, our work here is done.
-      return 0;
+    // 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;
     }
   }
 
-  assert(InaccessibleBase && "no path found, but no inaccessible base");
-  return InaccessibleBase;
+  return BestPath;
 }
 
-/// CheckBaseClassAccess - Check that a derived class can access its base class
-/// and report an error if it can't. [class.access.base]
-bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
-                                unsigned InaccessibleBaseID,
-                                CXXBasePaths &Paths, SourceLocation AccessLoc,
-                                DeclarationName Name) {
+/// 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;
+    }
 
-  if (!getLangOptions().AccessControl)
-    return false;
-  const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase(
-                                               Derived, Base, Paths);
-
-  if (InaccessibleBase) {
-    Diag(AccessLoc, InaccessibleBaseID)
-      << Derived << Base << Name;
-
-    AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
-
-    // If there's no written access specifier, then the inheritance specifier
-    // is implicitly private.
-    if (AS == AS_none)
-      Diag(InaccessibleBase->getSourceRange().getBegin(),
-           diag::note_inheritance_implicitly_private_here);
-    else
-      Diag(InaccessibleBase->getSourceRange().getBegin(),
-           diag::note_inheritance_specifier_here) << AS;
+    case Sema::AR_accessible: break;
 
-    return true;
+    case Sema::AR_dependent:
+    case Sema::AR_delayed:
+      llvm_unreachable("dependent/delayed not allowed");
+      return;
+    }
   }
 
-  return false;
+  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 the path which caused the given declaration to become
-/// inaccessible.
-static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D,
-                               AccessSpecifier Access) {
-  // Easy case: the decl's natural access determined its path access.
-  if (Access == D->getAccess() || D->getAccess() == AS_private) {
-    S.Diag(D->getLocation(), diag::note_access_natural)
-      << (unsigned) (Access == AS_protected);
-    return;
+/// 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);
+}
 
-  // TODO: flesh this out
-  S.Diag(D->getLocation(), diag::note_access_constrained_by_path)
-    << (unsigned) (Access == AS_protected);
+/// 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);
 }
 
-/// Checks access to the given declaration in the current context.
-///
-/// \param R the means via which the access was made; must have a naming
-///   class set
-/// \param D the declaration accessed
-/// \param Access the best access along any inheritance path from the
-///   naming class to the declaration.  AS_none means the path is impossible
-bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D,
-                       AccessSpecifier Access) {
-  assert(R.getNamingClass() && "performing access check without naming class");
+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);
+}
 
-  // If the access path is public, it's accessible everywhere.
-  if (Access == AS_public)
-    return false;
 
-  // 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 (CurContext->isFileContext() && ParsingDeclDepth) {
-    DelayedDiagnostics.push_back(
-        DelayedDiagnostic::makeAccess(R.getNameLoc(), D, Access,
-                                      R.getNamingClass()));
-    return false;
-  }
-
-  return CheckEffectiveAccess(CurContext, R, D, Access);
-}
-
-/// Checks access from the given effective context.
-bool Sema::CheckEffectiveAccess(DeclContext *EffectiveContext,
-                                const LookupResult &R,
-                                NamedDecl *D, AccessSpecifier Access) {
-  DeclContext *DC = EffectiveContext;
-  while (isa<CXXRecordDecl>(DC) &&
-         cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
-    DC = DC->getParent();
-
-  CXXRecordDecl *CurRecord;
-  if (isa<CXXRecordDecl>(DC))
-    CurRecord = cast<CXXRecordDecl>(DC);
-  else if (isa<CXXMethodDecl>(DC))
-    CurRecord = cast<CXXMethodDecl>(DC)->getParent();
-  else {
-    Diag(R.getNameLoc(), diag::err_access_outside_class)
-      << (Access == AS_protected);
-    DiagnoseAccessPath(*this, R, D, Access);
-    return true;
+/// 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;
   }
 
-  CXXRecordDecl *NamingClass = R.getNamingClass();
+  // 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 &&
-      CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl())
-    return false;
+  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 (CurRecord->isDerivedFrom(NamingClass))
-      return false;
+    if (EC.Record->isDerivedFrom(NamingClass))
+      return Sema::AR_accessible;
 
-    // FIXME: dependent classes
+    // FIXME: delay dependent classes
   }
 
-  // FIXME: friends
-
-  // Okay, it's a bad access, reject it.
+  // 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;
+}
 
-  
-  CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+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 (Access == AS_protected) {
-    Diag(R.getNameLoc(), diag::err_access_protected)
-      << Context.getTypeDeclType(DeclaringClass)
-      << Context.getTypeDeclType(CurRecord);
-    DiagnoseAccessPath(*this, R, D, Access);
-    return true;
+  // 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;
   }
 
-  assert(Access == AS_private || Access == AS_none);
-  Diag(R.getNameLoc(), diag::err_access_private)
-    << Context.getTypeDeclType(DeclaringClass)
-    << Context.getTypeDeclType(CurRecord);
-  DiagnoseAccessPath(*this, R, D, Access);
-  return true;
+  return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
+                              Loc, Entity, ADK);
 }
 
 void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
-  NamedDecl *D = DD.AccessData.Decl;
-
-  // Fake up a lookup result.
-  LookupResult R(*this, D->getDeclName(), DD.Loc, LookupOrdinaryName);
-  R.suppressDiagnostics();
-  R.setNamingClass(DD.AccessData.NamingClass);
-
   // Pretend we did this from the context of the newly-parsed
   // declaration.
-  DeclContext *EffectiveContext = Ctx->getDeclContext();
+  EffectiveContext EC(Ctx->getDeclContext());
 
-  if (CheckEffectiveAccess(EffectiveContext, R, D, DD.AccessData.Access))
+  if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
     DD.Triggered = true;
 }
 
-bool Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
-                                       NamedDecl *D, AccessSpecifier Access) {
+Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
+                                                     NamedDecl *D,
+                                                     AccessSpecifier Access) {
   if (!getLangOptions().AccessControl || !E->getNamingClass())
-    return false;
-
-  // Fake up a lookup result.
-  LookupResult R(*this, E->getName(), E->getNameLoc(), LookupOrdinaryName);
-  R.suppressDiagnostics();
-
-  R.setNamingClass(E->getNamingClass());
-  R.addDecl(D, Access);
+    return AR_accessible;
 
-  // FIXME: protected check (triggers for member-address expressions)
-
-  return CheckAccess(R, D, Access);
+  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.
-bool Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
-                                       NamedDecl *D, AccessSpecifier Access) {
+Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
+                                                     NamedDecl *D,
+                                                     AccessSpecifier Access) {
   if (!getLangOptions().AccessControl)
-    return false;
-
-  // Fake up a lookup result.
-  LookupResult R(*this, E->getMemberName(), E->getMemberLoc(),
-                 LookupOrdinaryName);
-  R.suppressDiagnostics();
-
-  R.setNamingClass(E->getNamingClass());
-  R.addDecl(D, Access);
+    return AR_accessible;
 
-  if (CheckAccess(R, D, Access))
-    return true;
-
-  // FIXME: protected check
-
-  return false;
+  return CheckAccess(*this, E->getMemberLoc(),
+                 AccessedEntity::makeMember(E->getNamingClass(), Access, D));
 }
 
-bool Sema::CheckDestructorAccess(SourceLocation Loc, const RecordType *RT) {
+Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
+                                               const RecordType *RT) {
   if (!getLangOptions().AccessControl)
-    return false;
+    return AR_accessible;
 
   CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
   CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
 
   AccessSpecifier Access = Dtor->getAccess();
   if (Access == AS_public)
-    return false;
+    return AR_accessible;
 
-  LookupResult R(*this, Dtor->getDeclName(), Loc, LookupOrdinaryName);
-  R.suppressDiagnostics();
-
-  R.setNamingClass(NamingClass);
-  return CheckAccess(R, Dtor, Access);
-
-  // FIXME: protected check
+  return CheckAccess(*this, Loc,
+                 AccessedEntity::makeMember(NamingClass, Access, Dtor));
 }
 
 /// Checks access to a constructor.
-bool Sema::CheckConstructorAccess(SourceLocation UseLoc,
+Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
                                   CXXConstructorDecl *Constructor,
                                   AccessSpecifier Access) {
   if (!getLangOptions().AccessControl)
-    return false;
-
-  CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Constructor->getParent());
+    return AR_accessible;
 
-  LookupResult R(*this, Constructor->getDeclName(), UseLoc, LookupOrdinaryName);
-  R.suppressDiagnostics();
-
-  R.setNamingClass(NamingClass);
-  return CheckAccess(R, Constructor, Access);
+  CXXRecordDecl *NamingClass = Constructor->getParent();
+  return CheckAccess(*this, UseLoc,
+                 AccessedEntity::makeMember(NamingClass, Access, Constructor));
 }
 
 /// Checks access to an overloaded member operator, including
 /// conversion operators.
-bool Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
-                                     Expr *ObjectExpr,
-                                     NamedDecl *MemberOperator,
-                                     AccessSpecifier Access) {
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+                                                   Expr *ObjectExpr,
+                                                   NamedDecl *MemberOperator,
+                                                   AccessSpecifier Access) {
   if (!getLangOptions().AccessControl)
-    return false;
+    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());
 
-  LookupResult R(*this, DeclarationName(), OpLoc, LookupOrdinaryName);
-  R.suppressDiagnostics();
-
-  R.setNamingClass(NamingClass);
-  if (CheckAccess(R, MemberOperator, Access))
-    return true;
-
-  // FIXME: protected check
+  return CheckAccess(*this, OpLoc,
+            AccessedEntity::makeMember(NamingClass, Access, MemberOperator));
+}
 
-  return false;
+/// 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::CheckAccess(const LookupResult &R) {
+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)
-    CheckAccess(R, *I, I.getAccess());
+    if (I.getAccess() != AS_public)
+      CheckAccess(*this, R.getNameLoc(),
+                  AccessedEntity::makeMember(R.getNamingClass(),
+                                             I.getAccess(), *I));
 }

Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Wed Feb 10 03:31:12 2010
@@ -778,9 +778,10 @@
     return TC_Failed;
   }
 
-  if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
-                          diag::err_downcast_from_inaccessible_base, Paths,
-                          OpRange.getBegin(), DeclarationName())) {
+  if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
+                                           /*IsBaseToDerived*/ true,
+                                           SrcType, DestType,
+                                           Paths.front())) {
     msg = 0;
     return TC_Failed;
   }
@@ -844,9 +845,10 @@
     return TC_Failed;
   }
 
-  if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType,
-                          diag::err_downcast_from_inaccessible_base, Paths,
-                          OpRange.getBegin(), DeclarationName())) {
+  if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
+                                           /*IsBaseToDerived*/ false,
+                                           DestType, SrcType,
+                                           Paths.front())) {
     msg = 0;
     return TC_Failed;
   }

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Feb 10 03:31:12 2010
@@ -713,7 +713,7 @@
 /// if there is an error.
 bool
 Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
-                                   unsigned InaccessibleBaseID,
+                                   AccessDiagnosticsKind ADK,
                                    unsigned AmbigiousBaseConvID,
                                    SourceLocation Loc, SourceRange Range,
                                    DeclarationName Name) {
@@ -729,11 +729,20 @@
   (void)DerivationOkay;
   
   if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
-    if (InaccessibleBaseID == 0)
+    if (ADK == ADK_quiet)
       return false;
+
     // Check that the base class can be accessed.
-    return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc,
-                                Name);
+    switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false,
+                                 Base, Derived, Paths.front(),
+                                 /*force*/ false,
+                                 /*unprivileged*/ false,
+                                 ADK)) {
+    case AR_accessible: return false;
+    case AR_inaccessible: return true;
+    case AR_dependent: return false;
+    case AR_delayed: return false;
+    }
   }
   
   // We know that the derived-to-base conversion is ambiguous, and
@@ -764,8 +773,7 @@
                                    SourceLocation Loc, SourceRange Range,
                                    bool IgnoreAccess) {
   return CheckDerivedToBaseConversion(Derived, Base,
-                                      IgnoreAccess ? 0 :
-                                        diag::err_conv_to_inaccessible_base,
+                                      IgnoreAccess ? ADK_quiet : ADK_normal,
                                       diag::err_ambiguous_derived_to_base_conv,
                                       Loc, Range, DeclarationName());
 }
@@ -5626,8 +5634,7 @@
     }
 
     // Check if we the conversion from derived to base is valid.
-    if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
-                      diag::err_covariant_return_inaccessible_base,
+    if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance,
                       diag::err_covariant_return_ambiguous_derived_to_base_conv,
                       // FIXME: Should this point to the return type?
                       New->getLocation(), SourceRange(), New->getDeclName())) {

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Wed Feb 10 03:31:12 2010
@@ -232,8 +232,22 @@
       if (Paths.isAmbiguous(CanonicalSuperT))
         continue;
 
-      if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true))
-        continue;
+      // Do this check from a context without privileges.
+      switch (CheckBaseClassAccess(SourceLocation(), false,
+                                   CanonicalSuperT, CanonicalSubT,
+                                   Paths.front(),
+                                   /*ForceCheck*/ true,
+                                   /*ForceUnprivileged*/ true,
+                                   ADK_quiet)) {
+      case AR_accessible: break;
+      case AR_inaccessible: continue;
+      case AR_dependent:
+        llvm_unreachable("access check dependent for unprivileged context");
+        break;
+      case AR_delayed:
+        llvm_unreachable("access check delayed in non-declaration");
+        break;
+      }
 
       Contained = true;
       break;

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Feb 10 03:31:12 2010
@@ -404,7 +404,7 @@
 }
 
 void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
-  CXXBasePaths::paths_iterator I, E;
+  CXXBasePaths::const_paths_iterator I, E;
   DeclContext::lookup_iterator DI, DE;
   for (I = P.begin(), E = P.end(); I != E; ++I)
     for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI)

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Feb 10 03:31:12 2010
@@ -1355,14 +1355,13 @@
   
 /// CheckMemberPointerConversion - Check the member pointer conversion from the
 /// expression From to the type ToType. This routine checks for ambiguous or
-/// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions
+/// virtual or inaccessible base-to-derived member pointer conversions
 /// for which IsMemberPointerConversion has already returned true. It returns
 /// true and produces a diagnostic if there was an error, or returns false
 /// otherwise.
 bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
                                         CastExpr::CastKind &Kind,
                                         bool IgnoreBaseAccess) {
-  (void)IgnoreBaseAccess;
   QualType FromType = From->getType();
   const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
   if (!FromPtrType) {
@@ -1385,7 +1384,7 @@
   assert(FromClass->isRecordType() && "Pointer into non-class.");
   assert(ToClass->isRecordType() && "Pointer into non-class.");
 
-  CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+  CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/ true,
                      /*DetectVirtual=*/true);
   bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
   assert(DerivationOkay &&
@@ -1394,13 +1393,6 @@
 
   if (Paths.isAmbiguous(Context.getCanonicalType(FromClass).
                                   getUnqualifiedType())) {
-    // Derivation is ambiguous. Redo the check to find the exact paths.
-    Paths.clear();
-    Paths.setRecordingPaths(true);
-    bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths);
-    assert(StillOkay && "Derivation changed due to quantum fluctuation.");
-    (void)StillOkay;
-
     std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
     Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv)
       << 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange();
@@ -1414,6 +1406,10 @@
     return true;
   }
 
+  if (!IgnoreBaseAccess)
+    CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true,
+                         FromClass, ToClass, Paths.front());
+
   // Must be a base to derived member conversion.
   Kind = CastExpr::CK_BaseToDerivedMemberPointer;
   return false;

Modified: cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp Wed Feb 10 03:31:12 2010
@@ -54,13 +54,13 @@
 //   of the base class are accessible as protected members of the
 //   derived class.
 namespace test1 {
-  class Base { // expected-note 6 {{constrained by protected inheritance}}
-  public: int pub; static int spub; // expected-note 2 {{constrained by protected inheritance}}
+  class Base {
+  public: int pub; static int spub;
   protected: int prot; static int sprot; // expected-note 4 {{declared protected here}}
   private: int priv; static int spriv; // expected-note 8 {{declared private here}}
   };
 
-  class Test : protected Base {
+  class Test : protected Base { // expected-note 6 {{declared protected here}} expected-note 8 {{constrained by protected inheritance here}}
     void test() {
       pub++;
       spub++;
@@ -79,19 +79,19 @@
   };
 
   void test(Test *t) {
-    t->pub++; // expected-error {{protected member}}
+    t->pub++; // expected-error {{protected member}} expected-error {{protected base class}}
     t->spub++; // expected-error {{protected member}}
-    t->prot++; // expected-error {{protected member}}
+    t->prot++; // expected-error {{protected member}} expected-error {{protected base class}}
     t->sprot++; // expected-error {{protected member}}
-    t->priv++; // expected-error {{private member}}
+    t->priv++; // expected-error {{private member}} expected-error {{protected base class}}
     t->spriv++; // expected-error {{private member}}
 
     // Two possible errors here: one for Base, one for the member
-    t->Base::pub++; // expected-error {{protected member}}
+    t->Base::pub++; // expected-error {{protected member}} expected-error {{protected base class}}
     t->Base::spub++; // expected-error {{protected member}}
-    t->Base::prot++; // expected-error 2 {{protected member}}
+    t->Base::prot++; // expected-error 2 {{protected member}} expected-error {{protected base class}}
     t->Base::sprot++; // expected-error 2 {{protected member}}
-    t->Base::priv++; // expected-error {{protected member}} expected-error {{private member}}
+    t->Base::priv++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{protected base class}}
     t->Base::spriv++; // expected-error {{protected member}} expected-error {{private member}}
   }
 }
@@ -102,21 +102,20 @@
 //   the base class are accessible as private members of the derived
 //   class.
 namespace test2 {
-  class Base { //expected-note 6 {{constrained by private inheritance}}
+  class Base {
   public:
-    int pub; // expected-note {{constrained by private inheritance}}
-    static int spub; // expected-note {{constrained by private inheritance}}
+    int pub;
+    static int spub;
   protected:
-    int prot; // expected-note {{constrained by private inheritance}} \
-              // expected-note {{declared protected here}}
-    static int sprot; // expected-note {{constrained by private inheritance}} \
-                      // expected-note {{declared protected here}}
+    int prot; // expected-note {{declared protected here}}
+    static int sprot; // expected-note {{declared protected here}}
   private:
     int priv; // expected-note 4 {{declared private here}}
     static int spriv; // expected-note 4 {{declared private here}}
   };
 
-  class Test : private Base { // expected-note 6 {{'private' inheritance specifier here}}
+  class Test : private Base { // expected-note 6 {{declared private here}} \
+                              // expected-note 10 {{constrained by private inheritance here}}
     void test() {
       pub++;
       spub++;
@@ -135,18 +134,18 @@
   };
 
   void test(Test *t) {
-    t->pub++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->pub++; // expected-error {{private member}} expected-error {{private base class}}
     t->spub++; // expected-error {{private member}}
-    t->prot++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->prot++; // expected-error {{private member}} expected-error {{private base class}}
     t->sprot++; // expected-error {{private member}}
-    t->priv++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->priv++; // expected-error {{private member}} expected-error {{private base class}}
     t->spriv++; // expected-error {{private member}}
 
-    t->Base::pub++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->Base::pub++; // expected-error {{private member}} expected-error {{private base class}}
     t->Base::spub++; // expected-error {{private member}}
-    t->Base::prot++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->Base::prot++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{private base class}}
     t->Base::sprot++; // expected-error {{protected member}} expected-error {{private member}}
-    t->Base::priv++; // expected-error 2 {{private member}} expected-error {{inaccessible base class}}
+    t->Base::priv++; // expected-error 2 {{private member}} expected-error {{private base class}}
     t->Base::spriv++; // expected-error 2 {{private member}}
   }
 }

Modified: cfe/trunk/test/CXX/class.access/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p4.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/CXX/class.access/p4.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p4.cpp Wed Feb 10 03:31:12 2010
@@ -23,12 +23,12 @@
 
   void test(A *op) {
     op->foo(PublicInst);
-    op->foo(ProtectedInst); // expected-error {{access to protected member outside any class}}
-    op->foo(PrivateInst); // expected-error {{access to private member outside any class}}
+    op->foo(ProtectedInst); // expected-error {{'foo' is a protected member}}
+    op->foo(PrivateInst); // expected-error {{'foo' is a private member}}
 
     void (A::*a)(Public&) = &A::foo;
-    void (A::*b)(Protected&) = &A::foo; // expected-error {{access to protected member outside any class}}
-    void (A::*c)(Private&) = &A::foo; // expected-error {{access to private member outside any class}}
+    void (A::*b)(Protected&) = &A::foo; // expected-error {{'foo' is a protected member}}
+    void (A::*c)(Private&) = &A::foo; // expected-error {{'foo' is a private member}}
   }
 }
 
@@ -62,15 +62,15 @@
 
   void test(A &a, Public &pub, Protected &prot, Private &priv) {
     a + pub;
-    a + prot; // expected-error {{access to protected member}}
-    a + priv; // expected-error {{access to private member}}
+    a + prot; // expected-error {{'operator+' is a protected member}}
+    a + priv; // expected-error {{'operator+' is a private member}}
     a[pub];
-    a[prot]; // expected-error {{access to protected member}}
-    a[priv]; // expected-error {{access to private member}}
+    a[prot]; // expected-error {{'operator[]' is a protected member}}
+    a[priv]; // expected-error {{'operator[]' is a private member}}
     a(pub);
-    a(prot); // expected-error {{access to protected member}}
-    a(priv); // expected-error {{access to private member}}
-    -a;       // expected-error {{access to private member}}
+    a(prot); // expected-error {{'operator()' is a protected member}}
+    a(priv); // expected-error {{'operator()' is a private member}}
+    -a;       // expected-error {{'operator-' is a private member}}
 
     const A &ca = a;
     ca + pub;
@@ -79,8 +79,8 @@
     -ca;
     // These are all surrogate calls
     ca(pub);
-    ca(prot); // expected-error {{access to protected member}}
-    ca(priv); // expected-error {{access to private member}}
+    ca(prot); // expected-error {{'operator void (*)(class Protected &)' is a protected member}}
+    ca(priv); // expected-error {{'operator void (*)(class Private &)' is a private member}}
   }
 }
 
@@ -93,7 +93,7 @@
     static A foo;
   };
 
-  A a; // expected-error {{access to private member}}
+  A a; // expected-error {{calling a private constructor}}
   A A::foo; // okay
 }
 
@@ -105,10 +105,10 @@
     static A foo;
   };
 
-  A a; // expected-error {{access to private member}}
+  A a; // expected-error {{'~A' is a private member}}
   A A::foo;
 
-  void foo(A param) { // expected-error {{access to private member}}
-    A local; // expected-error {{access to private member}}
+  void foo(A param) { // expected-error {{'~A' is a private member}}
+    A local; // expected-error {{'~A' is a private member}}
   }
 }

Modified: cfe/trunk/test/CXX/class.access/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p6.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/CXX/class.access/p6.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p6.cpp Wed Feb 10 03:31:12 2010
@@ -23,7 +23,7 @@
     type foo();
   };
 
-  A::type foo() { } // expected-error {{access to private member}}
+  A::type foo() { } // expected-error {{'type' is a private member}}
   A::type A::foo() { }
 }
 
@@ -45,10 +45,10 @@
   void test() {
     A a;
     Public pub = a;
-    Protected prot = a; // expected-error {{access to protected member}}
-    Private priv = a; // expected-error {{access to private member}}
+    Protected prot = a; // expected-error {{'operator Protected' is a protected member}}
+    Private priv = a; // expected-error {{'operator Private' is a private member}}
     A apub = pub;
-    A aprot = prot; // expected-error {{access to protected member}}
-    A apriv = priv; // expected-error {{access to private member}}
+    A aprot = prot; // expected-error {{protected constructor}}
+    A apriv = priv; // expected-error {{private constructor}}
   }
 }

Modified: cfe/trunk/test/CXX/class/class.local/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.local/p2.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/CXX/class/class.local/p2.cpp (original)
+++ cfe/trunk/test/CXX/class/class.local/p2.cpp Wed Feb 10 03:31:12 2010
@@ -3,9 +3,9 @@
 struct A { };
 
 void f() {
-  struct B : private A {}; // expected-note{{'private' inheritance specifier here}}
+  struct B : private A {}; // expected-note{{declared private here}}
   
   B b;
   
-  A *a = &b; // expected-error{{conversion from 'struct B' to inaccessible base class 'struct A'}}
+  A *a = &b; // expected-error{{cannot cast 'struct B' to its private base class 'struct A'}}
 }

Modified: cfe/trunk/test/CXX/conv/conv.mem/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/conv/conv.mem/p4.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/CXX/conv/conv.mem/p4.cpp (original)
+++ cfe/trunk/test/CXX/conv/conv.mem/p4.cpp Wed Feb 10 03:31:12 2010
@@ -15,12 +15,12 @@
   }
 }
 
-// FIXME: can't be inaccessible.
+// Can't be inaccessible.
 namespace test1 {
-  struct Derived : private Base {};
+  struct Derived : private Base {}; // expected-note 2 {{declared private here}}
   void test() {
-    int (Derived::*d) = data_ptr; // error
-    int (Derived::*m)() = method_ptr; // error
+    int (Derived::*d) = data_ptr; // expected-error {{cannot cast private base class 'struct Base' to 'struct test1::Derived'}}
+    int (Derived::*m)() = method_ptr; // expected-error {{cannot cast private base class 'struct Base' to 'struct test1::Derived'}}
   }
 };
 

Modified: cfe/trunk/test/SemaCXX/access-base-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/access-base-class.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/access-base-class.cpp (original)
+++ cfe/trunk/test/SemaCXX/access-base-class.cpp Wed Feb 10 03:31:12 2010
@@ -2,10 +2,10 @@
 namespace T1 {
   
 class A { };
-class B : private A { }; // expected-note {{'private' inheritance specifier here}}
+class B : private A { }; // expected-note {{declared private here}}
 
 void f(B* b) {
-  A *a = b; // expected-error{{conversion from 'class T1::B' to inaccessible base class 'class T1::A'}}
+  A *a = b; // expected-error{{cannot cast 'class T1::B' to its private base class 'class T1::A'}}
 }
 
 }
@@ -13,10 +13,10 @@
 namespace T2 { 
 
 class A { };
-class B : A { }; // expected-note {{inheritance is implicitly 'private'}}
+class B : A { }; // expected-note {{implicitly declared private here}}
 
 void f(B* b) {
-  A *a = b; // expected-error {{conversion from 'class T2::B' to inaccessible base class 'class T2::A'}}
+  A *a = b; // expected-error {{cannot cast 'class T2::B' to its private base class 'class T2::A'}}
 }
 
 }
@@ -63,13 +63,13 @@
   
   class A {};
   
-  class B : private A { // expected-note {{'private' inheritance specifier here}}
+  class B : private A { // expected-note {{declared private here}}
     void f(C* c);
   };
   
   class C : public B { 
     void f(C *c) {
-      A* a = c; // expected-error {{conversion from 'class T6::C' to inaccessible base class 'class T6::A'}}
+      A* a = c; // expected-error {{cannot cast 'class T6::C' to its private base class 'class T6::A'}}
     }
   };
   
@@ -77,3 +77,14 @@
     A *a = c;
   }
 }
+
+namespace T7 {
+  class A {};
+  class B : public A {};
+  class C : private B { 
+    void f(C *c) {
+      A* a = c; // okay
+    }
+  };
+}
+

Modified: cfe/trunk/test/SemaCXX/access-control-check.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/access-control-check.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/access-control-check.cpp (original)
+++ cfe/trunk/test/SemaCXX/access-control-check.cpp Wed Feb 10 03:31:12 2010
@@ -11,5 +11,5 @@
 
 class N : M,P {
   N() {}
-  int PR() { return iP + PPR(); } // expected-error 2 {{access to private member of 'class P'}}
+  int PR() { return iP + PPR(); } // expected-error 2 {{private member of 'class P'}}
 };

Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Wed Feb 10 03:31:12 2010
@@ -25,7 +25,7 @@
   void fn2();
 };
 struct Convertible { operator Base&(); };
-struct Priv : private Base {}; // expected-note 4 {{'private' inheritance specifier here}}
+struct Priv : private Base {}; // expected-note 4 {{declared private here}}
 struct Mid : Base {};
 struct Fin : Mid, Derived {};
 typedef void (Derived::*DFnPtr)();
@@ -111,12 +111,12 @@
 
   Priv priv;
   Fin fin;
-  (void)(i1 ? Base() : Priv()); // expected-error{{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
-  (void)(i1 ? Priv() : Base()); // expected-error{{error: conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
+  (void)(i1 ? Base() : Priv()); // expected-error{{private base class}}
+  (void)(i1 ? Priv() : Base()); // expected-error{{private base class}}
   (void)(i1 ? Base() : Fin()); // expected-error{{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
   (void)(i1 ? Fin() : Base()); // expected-error{{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
-  (void)(i1 ? base : priv); // expected-error {{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
-  (void)(i1 ? priv : base); // expected-error {{conversion from 'struct Priv' to inaccessible base class 'struct Base'}}
+  (void)(i1 ? base : priv); // expected-error {{private base class}}
+  (void)(i1 ? priv : base); // expected-error {{private base class}}
   (void)(i1 ? base : fin); // expected-error {{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
   (void)(i1 ? fin : base); // expected-error {{ambiguous conversion from derived class 'struct Fin' to base class 'struct Base'}}
 

Modified: cfe/trunk/test/SemaCXX/static-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-cast.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/static-cast.cpp (original)
+++ cfe/trunk/test/SemaCXX/static-cast.cpp Wed Feb 10 03:31:12 2010
@@ -4,7 +4,7 @@
 struct C1 : public virtual B {};    // Single virtual base.
 struct C2 : public virtual B {};
 struct D : public C1, public C2 {}; // Diamond
-struct E : private A {};            // Single private base. expected-note 3 {{'private' inheritance specifier here}}
+struct E : private A {};            // Single private base. expected-note 3 {{declared private here}}
 struct F : public C1 {};            // Single path to B with virtual.
 struct G1 : public B {};
 struct G2 : public B {};
@@ -56,7 +56,7 @@
   // Bad code below
 
   (void)static_cast<void*>((const int*)0); // expected-error {{static_cast from 'int const *' to 'void *' is not allowed}}
-  (void)static_cast<A*>((E*)0); // expected-error {{inaccessible base class 'struct A'}}
+  (void)static_cast<A*>((E*)0); // expected-error {{private base class 'struct A'}}
   (void)static_cast<A*>((H*)0); // expected-error {{ambiguous conversion}}
   (void)static_cast<int>((int*)0); // expected-error {{static_cast from 'int *' to 'int' is not allowed}}
   (void)static_cast<A**>((B**)0); // expected-error {{static_cast from 'struct B **' to 'struct A **' is not allowed}}
@@ -86,8 +86,8 @@
   (void)static_cast<D&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct D &' via virtual base 'struct B'}}
   (void)static_cast<B*>((const A*)0); // expected-error {{static_cast from 'struct A const *' to 'struct B *' casts away constness}}
   (void)static_cast<B&>(*((const A*)0)); // expected-error {{static_cast from 'struct A const' to 'struct B &' casts away constness}}
-  (void)static_cast<E*>((A*)0); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
-  (void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast 'struct A' to 'struct E' due to inaccessible}}
+  (void)static_cast<E*>((A*)0); // expected-error {{cannot cast private base class 'struct A' to 'struct E'}}
+  (void)static_cast<E&>(*((A*)0)); // expected-error {{cannot cast private base class 'struct A' to 'struct E'}}
   (void)static_cast<H*>((A*)0); // expected-error {{ambiguous cast from base 'struct A' to derived 'struct H':\n    struct A -> struct B -> struct G1 -> struct H\n    struct A -> struct B -> struct G2 -> struct H}}
   (void)static_cast<H&>(*((A*)0)); // expected-error {{ambiguous cast from base 'struct A' to derived 'struct H':\n    struct A -> struct B -> struct G1 -> struct H\n    struct A -> struct B -> struct G2 -> struct H}}
   (void)static_cast<E*>((B*)0); // expected-error {{static_cast from 'struct B *' to 'struct E *' is not allowed}}

Modified: cfe/trunk/test/SemaCXX/virtual-override.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/virtual-override.cpp?rev=95775&r1=95774&r2=95775&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/virtual-override.cpp (original)
+++ cfe/trunk/test/SemaCXX/virtual-override.cpp Wed Feb 10 03:31:12 2010
@@ -29,14 +29,14 @@
 namespace T3 {
 
 struct a { };
-struct b : private a { }; // expected-note{{'private' inheritance specifier here}}
+struct b : private a { }; // expected-note{{declared private here}}
   
 class A {
   virtual a* f(); // expected-note{{overridden virtual function is here}}
 };
 
 class B : A {
-  virtual b* f(); // expected-error{{return type of virtual function 'f' is not covariant with the return type of the function it overrides (conversion from 'struct T3::b' to inaccessible base class 'struct T3::a')}}
+  virtual b* f(); // expected-error{{invalid covariant return for virtual function: 'struct T3::a' is a private base class of 'struct T3::b'}}
 };
 
 }





More information about the cfe-commits mailing list