[cfe-commits] r98609 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/PartialDiagnostic.h lib/Sema/Sema.h lib/Sema/SemaAccess.cpp lib/Sema/SemaCXXCast.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExceptionSpec.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/CXX/class.access/p4.cpp

John McCall rjmccall at apple.com
Mon Mar 15 22:22:47 PDT 2010


Author: rjmccall
Date: Tue Mar 16 00:22:47 2010
New Revision: 98609

URL: http://llvm.org/viewvc/llvm-project?rev=98609&view=rev
Log:
Perform access control for the implicit base and member destructor calls
required when emitting a destructor definition.


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/PartialDiagnostic.h
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaAccess.cpp
    cfe/trunk/lib/Sema/SemaCXXCast.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/class.access/p4.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Mar 16 00:22:47 2010
@@ -428,11 +428,25 @@
 // 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 err_access :
+    Error<"%1 is a %select{private|protected}0 member of %3">,
+    NoSFINAE;
+def err_access_ctor :
+    Error<"calling a %select{private|protected}0 constructor of class %2">,
+    NoSFINAE;
+def err_access_dtor_base :
+    Error<"base class %0 has %select{private|protected}1 destructor">,
+    NoSFINAE;
+def err_access_dtor_vbase :
+    Error<"inherited virtual base class %0 has "
+    "%select{private|protected}1 destructor">,
+    NoSFINAE;
+def err_access_dtor_field :
+    Error<"field of type %1 has %select{private|protected}2 destructor">,
+    NoSFINAE;
+def err_access_dtor_var :
+    Error<"variable of type %1 has %select{private|protected}2 destructor">,
+    NoSFINAE;
 def note_previous_access_declaration : Note<
   "previously declared '%1' here">;
 def err_access_outside_class : Error<

Modified: cfe/trunk/include/clang/Basic/PartialDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/PartialDiagnostic.h?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/PartialDiagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/PartialDiagnostic.h Tue Mar 16 00:22:47 2010
@@ -69,6 +69,10 @@
     CodeModificationHint CodeModificationHints[MaxCodeModificationHints];    
   };
 
+  // NOTE: Sema assumes that PartialDiagnostic is location-invariant
+  // in the sense that its bits can be safely memcpy'ed and destructed
+  // in the new location.
+
   /// DiagID - The diagnostic ID.
   mutable unsigned DiagID;
   

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Mar 16 00:22:47 2010
@@ -300,60 +300,38 @@
   /// \brief The set of static functions seen so far that have not been used.
   std::vector<FunctionDecl*> UnusedStaticFuncs;
   
-  /// 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;
+    /// A member declaration found through lookup.  The target is the
+    /// member.
+    enum MemberNonce { Member };
+
+    /// A hierarchy (base-to-derived or derived-to-base) conversion.
+    /// The target is the base class.
+    enum BaseNonce { Base };
+
+    bool isMemberAccess() const { return IsMember; }
+
+    AccessedEntity(MemberNonce _,
+                   CXXRecordDecl *NamingClass,
+                   AccessSpecifier Access,
+                   NamedDecl *Target)
+      : Access(Access), IsMember(true), 
+        Target(Target), NamingClass(NamingClass),
+        Diag(0) {
+    }
+
+    AccessedEntity(BaseNonce _,
+                   CXXRecordDecl *BaseClass,
+                   CXXRecordDecl *DerivedClass,
+                   AccessSpecifier Access)
+      : Access(Access), IsMember(false),
+        Target(BaseClass), NamingClass(DerivedClass),
+        Diag(0) {
     }
 
-    Kind getKind() const { return Kind(K); }
+    bool isQuiet() const { return Diag.getDiagID() == 0; }
+
     AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
 
     // These apply to member decls...
@@ -364,11 +342,32 @@
     CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
     CXXRecordDecl *getDerivedClass() const { return NamingClass; }
 
+    /// Sets a diagnostic to be performed.  The diagnostic is given
+    /// four (additional) arguments:
+    ///   %0 - 0 if the entity was private, 1 if protected
+    ///   %1 - the DeclarationName of the entity
+    ///   %2 - the TypeDecl type of the naming class
+    ///   %3 - the TypeDecl type of the declaring class
+    void setDiag(const PartialDiagnostic &PDiag) {
+      assert(isQuiet() && "partial diagnostic already defined");
+      Diag = PDiag;
+    }
+    PartialDiagnostic &setDiag(unsigned DiagID) {
+      assert(isQuiet() && "partial diagnostic already defined");
+      assert(DiagID && "creating null diagnostic");
+      Diag = PartialDiagnostic(DiagID);
+      return Diag;
+    }
+    const PartialDiagnostic &getDiag() const {
+      return Diag;
+    }
+
   private:
-    unsigned K : 2;
     unsigned Access : 2;
+    bool IsMember;
     NamedDecl *Target;
     CXXRecordDecl *NamingClass;    
+    PartialDiagnostic Diag;
   };
 
   struct DelayedDiagnostic {
@@ -384,9 +383,16 @@
       struct { NamedDecl *Decl; } DeprecationData;
 
       /// Access control.
-      AccessedEntity AccessData;
+      char AccessData[sizeof(AccessedEntity)];
     };
 
+    void destroy() {
+      switch (Kind) {
+      case Access: getAccessData().~AccessedEntity(); break;
+      case Deprecation: break;
+      }
+    }
+
     static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
                                              NamedDecl *D) {
       DelayedDiagnostic DD;
@@ -403,10 +409,16 @@
       DD.Kind = Access;
       DD.Triggered = false;
       DD.Loc = Loc;
-      DD.AccessData = Entity;
+      new (&DD.getAccessData()) AccessedEntity(Entity);
       return DD;
     }
 
+    AccessedEntity &getAccessData() {
+      return *reinterpret_cast<AccessedEntity*>(AccessData);
+    }
+    const AccessedEntity &getAccessData() const {
+      return *reinterpret_cast<const AccessedEntity*>(AccessData);
+    }
   };
 
   /// \brief The stack of diagnostics that were delayed due to being
@@ -2566,7 +2578,7 @@
                                     SourceLocation Loc, SourceRange Range,
                                     bool IgnoreAccess = false);
   bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
-                                    AccessDiagnosticsKind ADK,
+                                    unsigned InaccessibleBaseID,
                                     unsigned AmbigiousBaseConvID,
                                     SourceLocation Loc, SourceRange Range,
                                     DeclarationName Name);
@@ -2614,18 +2626,19 @@
                                       CXXConstructorDecl *D,
                                       AccessSpecifier Access);
   AccessResult CheckDestructorAccess(SourceLocation Loc,
-                                     const RecordType *Record);
+                                     CXXDestructorDecl *Dtor,
+                                     const PartialDiagnostic &PDiag);
   AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
                                          Expr *ObjectExpr,
+                                         Expr *ArgExpr,
                                          NamedDecl *D,
                                          AccessSpecifier Access);
   AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
-                                    bool IsBaseToDerived,
                                     QualType Base, QualType Derived,
                                     const CXXBasePath &Path,
+                                    unsigned DiagID,
                                     bool ForceCheck = false,
-                                    bool ForceUnprivileged = false,
-                                    AccessDiagnosticsKind ADK = ADK_normal);
+                                    bool ForceUnprivileged = false);
                             
   void CheckLookupAccess(const LookupResult &R);
 

Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Tue Mar 16 00:22:47 2010
@@ -255,18 +255,11 @@
   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);
-  }
+  S.Diag(Loc, Entity.getDiag())
+    << (Access == AS_protected)
+    << D->getDeclName()
+    << S.Context.getTypeDeclType(NamingClass)
+    << S.Context.getTypeDeclType(DeclaringClass);
   DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
 }
 
@@ -274,39 +267,25 @@
 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);
-  }
+                                     const Sema::AccessedEntity &Entity) {
+  S.Diag(Loc, Entity.getDiag())
+    << (Access == AS_protected)
+    << DeclarationName()
+    << S.Context.getTypeDeclType(Entity.getDerivedClass())
+    << S.Context.getTypeDeclType(Entity.getBaseClass());
   DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
                      Entity.getBaseClass(), 0, Access);
 }
 
-static void DiagnoseBadAccess(Sema &S,
-                              SourceLocation Loc,
+static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
                               const EffectiveContext &EC,
                               CXXRecordDecl *NamingClass,
                               AccessSpecifier Access,
-                              const Sema::AccessedEntity &Entity,
-                              Sema::AccessDiagnosticsKind ADK) {
+                              const Sema::AccessedEntity &Entity) {
   if (Entity.isMemberAccess())
     DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
   else
-    DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK);
+    DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
 }
 
 
@@ -369,8 +348,7 @@
 static Sema::AccessResult CheckEffectiveAccess(Sema &S,
                                                const EffectiveContext &EC,
                                                SourceLocation Loc,
-                                         Sema::AccessedEntity const &Entity,
-                                         Sema::AccessDiagnosticsKind ADK) {
+                                         Sema::AccessedEntity const &Entity) {
   AccessSpecifier Access = Entity.getAccess();
   assert(Access != AS_public);
 
@@ -378,14 +356,14 @@
   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);
+    NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
 
   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);
+    if (!Entity.isQuiet())
+      DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
     return Sema::AR_inaccessible;
   }
 
@@ -418,15 +396,13 @@
   }
     
   // Okay, that's it, reject it.
-  if (ADK != Sema::ADK_quiet)
-    DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+  if (!Entity.isQuiet())
+    DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
   return Sema::AR_inaccessible;
 }
 
 static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
-                                      const Sema::AccessedEntity &Entity,
-                                      Sema::AccessDiagnosticsKind ADK
-                                        = Sema::ADK_normal) {
+                                      const Sema::AccessedEntity &Entity) {
   // If the access path is public, it's accessible everywhere.
   if (Entity.getAccess() == AS_public)
     return Sema::AR_accessible;
@@ -436,14 +412,13 @@
   // 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);
+                              Loc, Entity);
 }
 
 void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
@@ -451,18 +426,23 @@
   // declaration.
   EffectiveContext EC(Ctx->getDeclContext());
 
-  if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
+  if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
     DD.Triggered = true;
 }
 
 Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
                                                      NamedDecl *D,
                                                      AccessSpecifier Access) {
-  if (!getLangOptions().AccessControl || !E->getNamingClass())
+  if (!getLangOptions().AccessControl ||
+      !E->getNamingClass() ||
+      Access == AS_public)
     return AR_accessible;
 
-  return CheckAccess(*this, E->getNameLoc(),
-                 AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+  AccessedEntity Entity(AccessedEntity::Member,
+                        E->getNamingClass(), Access, D);
+  Entity.setDiag(diag::err_access) << E->getSourceRange();
+
+  return CheckAccess(*this, E->getNameLoc(), Entity);
 }
 
 /// Perform access-control checking on a previously-unresolved member
@@ -470,56 +450,73 @@
 Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
                                                      NamedDecl *D,
                                                      AccessSpecifier Access) {
-  if (!getLangOptions().AccessControl)
+  if (!getLangOptions().AccessControl ||
+      Access == AS_public)
     return AR_accessible;
 
-  return CheckAccess(*this, E->getMemberLoc(),
-                 AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+  AccessedEntity Entity(AccessedEntity::Member,
+                        E->getNamingClass(), Access, D);
+  Entity.setDiag(diag::err_access) << E->getSourceRange();
+
+  return CheckAccess(*this, E->getMemberLoc(), Entity);
 }
 
 Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
-                                               const RecordType *RT) {
+                                               CXXDestructorDecl *Dtor,
+                                               const PartialDiagnostic &PDiag) {
   if (!getLangOptions().AccessControl)
     return AR_accessible;
 
-  CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
-  CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
-
+  // There's never a path involved when checking implicit destructor access.
   AccessSpecifier Access = Dtor->getAccess();
   if (Access == AS_public)
     return AR_accessible;
 
-  return CheckAccess(*this, Loc,
-                 AccessedEntity::makeMember(NamingClass, Access, Dtor));
+  CXXRecordDecl *NamingClass = Dtor->getParent();
+  AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor);
+  Entity.setDiag(PDiag); // TODO: avoid copy
+
+  return CheckAccess(*this, Loc, Entity);
 }
 
 /// Checks access to a constructor.
 Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
                                   CXXConstructorDecl *Constructor,
                                   AccessSpecifier Access) {
-  if (!getLangOptions().AccessControl)
+  if (!getLangOptions().AccessControl ||
+      Access == AS_public)
     return AR_accessible;
 
   CXXRecordDecl *NamingClass = Constructor->getParent();
-  return CheckAccess(*this, UseLoc,
-                 AccessedEntity::makeMember(NamingClass, Access, Constructor));
+  AccessedEntity Entity(AccessedEntity::Member,
+                        NamingClass, Access, Constructor);
+  Entity.setDiag(diag::err_access_ctor);
+
+  return CheckAccess(*this, UseLoc, Entity);
 }
 
 /// Checks access to an overloaded member operator, including
 /// conversion operators.
 Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
                                                    Expr *ObjectExpr,
+                                                   Expr *ArgExpr,
                                                    NamedDecl *MemberOperator,
                                                    AccessSpecifier Access) {
-  if (!getLangOptions().AccessControl)
+  if (!getLangOptions().AccessControl ||
+      Access == AS_public)
     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));
+  AccessedEntity Entity(AccessedEntity::Member,
+                        NamingClass, Access, MemberOperator);
+  Entity.setDiag(diag::err_access)
+    << ObjectExpr->getSourceRange()
+    << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
+
+  return CheckAccess(*this, OpLoc, Entity);
 }
 
 /// Checks access for a hierarchy conversion.
@@ -532,31 +529,29 @@
 ///     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,
+                                              unsigned DiagID,
                                               bool ForceCheck,
-                                              bool ForceUnprivileged,
-                                              AccessDiagnosticsKind ADK) {
+                                              bool ForceUnprivileged) {
   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);
+
+  AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
+  if (DiagID)
+    Entity.setDiag(DiagID) << Derived << Base;
 
   if (ForceUnprivileged)
-    return CheckEffectiveAccess(*this, EffectiveContext(),
-                                AccessLoc, Entity, ADK);
-  return CheckAccess(*this, AccessLoc, Entity, ADK);
+    return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
+  return CheckAccess(*this, AccessLoc, Entity);
 }
 
 /// Checks access to all the declarations in the given result set.
@@ -565,9 +560,13 @@
          && "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));
+  for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+    if (I.getAccess() != AS_public) {
+      AccessedEntity Entity(AccessedEntity::Member,
+                            R.getNamingClass(), I.getAccess(), *I);
+      Entity.setDiag(diag::err_access);
+
+      CheckAccess(*this, R.getNameLoc(), Entity);
+    }
+  }
 }

Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Tue Mar 16 00:22:47 2010
@@ -780,9 +780,9 @@
   }
 
   if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
-                                           /*IsBaseToDerived*/ true,
                                            SrcType, DestType,
-                                           Paths.front())) {
+                                           Paths.front(),
+                                diag::err_downcast_from_inaccessible_base)) {
     msg = 0;
     return TC_Failed;
   }
@@ -858,9 +858,9 @@
   }
 
   if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
-                                           /*IsBaseToDerived*/ false,
                                            DestType, SrcType,
-                                           Paths.front())) {
+                                           Paths.front(),
+                                     diag::err_upcast_to_inaccessible_base)) {
     msg = 0;
     return TC_Failed;
   }

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Mar 16 00:22:47 2010
@@ -2038,6 +2038,8 @@
   assert(SavedIndex <= DelayedDiagnostics.size() &&
          "saved index is out of bounds");
 
+  unsigned E = DelayedDiagnostics.size();
+
   // We only want to actually emit delayed diagnostics when we
   // successfully parsed a decl.
   Decl *D = Ctx ? Ctx.getAs<Decl>() : 0;
@@ -2048,7 +2050,7 @@
     // only the declarator pops will be passed decls.  This is correct;
     // we really do need to consider delayed diagnostics from the decl spec
     // for each of the different declarations.
-    for (unsigned I = 0, E = DelayedDiagnostics.size(); I != E; ++I) {
+    for (unsigned I = 0; I != E; ++I) {
       if (DelayedDiagnostics[I].Triggered)
         continue;
 
@@ -2064,6 +2066,10 @@
     }
   }
 
+  // Destroy all the delayed diagnostics we're about to pop off.
+  for (unsigned I = SavedIndex; I != E; ++I)
+    DelayedDiagnostics[I].destroy();
+
   DelayedDiagnostics.set_size(SavedIndex);
 }
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Mar 16 00:22:47 2010
@@ -720,7 +720,7 @@
 /// if there is an error.
 bool
 Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
-                                   AccessDiagnosticsKind ADK,
+                                   unsigned InaccessibleBaseID,
                                    unsigned AmbigiousBaseConvID,
                                    SourceLocation Loc, SourceRange Range,
                                    DeclarationName Name) {
@@ -736,15 +736,12 @@
   (void)DerivationOkay;
   
   if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
-    if (ADK == ADK_quiet)
+    if (!InaccessibleBaseID)
       return false;
 
     // Check that the base class can be accessed.
-    switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false,
-                                 Base, Derived, Paths.front(),
-                                 /*force*/ false,
-                                 /*unprivileged*/ false,
-                                 ADK)) {
+    switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
+                                 InaccessibleBaseID)) {
     case AR_accessible: return false;
     case AR_inaccessible: return true;
     case AR_dependent: return false;
@@ -780,7 +777,8 @@
                                    SourceLocation Loc, SourceRange Range,
                                    bool IgnoreAccess) {
   return CheckDerivedToBaseConversion(Derived, Base,
-                                      IgnoreAccess ? ADK_quiet : ADK_normal,
+                                      IgnoreAccess ? 0
+                                       : diag::err_upcast_to_inaccessible_base,
                                       diag::err_ambiguous_derived_to_base_conv,
                                       Loc, Range, DeclarationName());
 }
@@ -1854,6 +1852,11 @@
   // Ignore dependent destructors.
   if (Destructor->isDependentContext())
     return;
+
+  // FIXME: all the access-control diagnostics are positioned on the
+  // field/base declaration.  That's probably good; that said, the
+  // user might reasonably want to know why the destructor is being
+  // emitted, and we currently don't say.
   
   CXXRecordDecl *ClassDecl = Destructor->getParent();
 
@@ -1872,25 +1875,41 @@
     if (FieldClassDecl->hasTrivialDestructor())
       continue;
 
-    const CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
+    CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
+    CheckDestructorAccess(Field->getLocation(), Dtor,
+                          PartialDiagnostic(diag::err_access_dtor_field)
+                            << Field->getDeclName()
+                            << FieldType);
+
     MarkDeclarationReferenced(Destructor->getLocation(),
                               const_cast<CXXDestructorDecl*>(Dtor));
   }
 
+  llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
+
   // Bases.
   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
        E = ClassDecl->bases_end(); Base != E; ++Base) {
-    // Ignore virtual bases.
+    // Bases are always records in a well-formed non-dependent class.
+    const RecordType *RT = Base->getType()->getAs<RecordType>();
+
+    // Remember direct virtual bases.
     if (Base->isVirtual())
-      continue;
+      DirectVirtualBases.insert(RT);
 
     // Ignore trivial destructors.
-    CXXRecordDecl *BaseClassDecl
-      = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+    CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
     if (BaseClassDecl->hasTrivialDestructor())
       continue;
+
+    CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+
+    // FIXME: caret should be on the start of the class name
+    CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor,
+                          PartialDiagnostic(diag::err_access_dtor_base)
+                            << Base->getType()
+                            << Base->getSourceRange());
     
-    const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
     MarkDeclarationReferenced(Destructor->getLocation(),
                               const_cast<CXXDestructorDecl*>(Dtor));
   }
@@ -1898,13 +1917,24 @@
   // Virtual bases.
   for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
        E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+
+    // Bases are always records in a well-formed non-dependent class.
+    const RecordType *RT = VBase->getType()->getAs<RecordType>();
+
+    // Ignore direct virtual bases.
+    if (DirectVirtualBases.count(RT))
+      continue;
+
     // Ignore trivial destructors.
-    CXXRecordDecl *BaseClassDecl
-      = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+    CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
     if (BaseClassDecl->hasTrivialDestructor())
       continue;
-    
-    const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+
+    CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+    CheckDestructorAccess(ClassDecl->getLocation(), Dtor,
+                          PartialDiagnostic(diag::err_access_dtor_vbase)
+                            << VBase->getType());
+
     MarkDeclarationReferenced(Destructor->getLocation(),
                               const_cast<CXXDestructorDecl*>(Dtor));
   }
@@ -4062,7 +4092,10 @@
       !ClassDecl->hasTrivialDestructor()) {
     CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
     MarkDeclarationReferenced(VD->getLocation(), Destructor);
-    CheckDestructorAccess(VD->getLocation(), Record);
+    CheckDestructorAccess(VD->getLocation(), Destructor,
+                          PartialDiagnostic(diag::err_access_dtor_var)
+                            << VD->getDeclName()
+                            << VD->getType());
   }
 }
 
@@ -5725,7 +5758,8 @@
     }
 
     // Check if we the conversion from derived to base is valid.
-    if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance,
+    if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
+                      diag::err_covariant_return_inaccessible_base,
                       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=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Tue Mar 16 00:22:47 2010
@@ -294,12 +294,12 @@
         continue;
 
       // Do this check from a context without privileges.
-      switch (CheckBaseClassAccess(SourceLocation(), false,
+      switch (CheckBaseClassAccess(SourceLocation(),
                                    CanonicalSuperT, CanonicalSubT,
                                    Paths.front(),
+                                   /*Diagnostic*/ 0,
                                    /*ForceCheck*/ true,
-                                   /*ForceUnprivileged*/ true,
-                                   ADK_quiet)) {
+                                   /*ForceUnprivileged*/ true)) {
       case AR_accessible: break;
       case AR_inaccessible: continue;
       case AR_dependent:

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Mar 16 00:22:47 2010
@@ -3401,7 +3401,7 @@
         // Build a call to the conversion function.
         CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
 
-        S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr,
+        S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0,
                                     Conversion, FnAccess);
         
         // FIXME: Should we move this initialization into a separate 

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Mar 16 00:22:47 2010
@@ -1411,8 +1411,9 @@
   }
 
   if (!IgnoreBaseAccess)
-    CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true,
-                         FromClass, ToClass, Paths.front());
+    CheckBaseClassAccess(From->getExprLoc(), FromClass, ToClass,
+                         Paths.front(),
+                         diag::err_downcast_from_inaccessible_base);
 
   // Must be a base to derived member conversion.
   Kind = CastExpr::CK_BaseToDerivedMemberPointer;
@@ -5548,7 +5549,7 @@
 
       // Convert the arguments.
       if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
-        CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess());
+        CheckMemberOperatorAccess(OpLoc, Args[0], 0, Method, Best->getAccess());
 
         if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method))
           return ExprError();
@@ -5732,7 +5733,8 @@
         // Convert the arguments.
         if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
           // Best->Access is only meaningful for class members.
-          CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess());
+          CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Method,
+                                    Best->getAccess());
 
           OwningExprResult Arg1
             = PerformCopyInitialization(
@@ -5906,7 +5908,8 @@
         // We matched an overloaded operator. Build a call to that
         // operator.
 
-        CheckMemberOperatorAccess(LLoc, Args[0], FnDecl, Best->getAccess());
+        CheckMemberOperatorAccess(LLoc, Args[0], Args[1], FnDecl,
+                                  Best->getAccess());
 
         // Convert the arguments.
         CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
@@ -6275,7 +6278,7 @@
       = cast<CXXConversionDecl>(
                          Best->Conversions[0].UserDefined.ConversionFunction);
 
-    CheckMemberOperatorAccess(LParenLoc, Object, Conv, Best->getAccess());
+    CheckMemberOperatorAccess(LParenLoc, Object, 0, Conv, Best->getAccess());
 
     // We selected one of the surrogate functions that converts the
     // object parameter to a function pointer. Perform the conversion
@@ -6290,7 +6293,7 @@
                          CommaLocs, RParenLoc).release();
   }
 
-  CheckMemberOperatorAccess(LParenLoc, Object,
+  CheckMemberOperatorAccess(LParenLoc, Object, 0,
                             Best->Function, Best->getAccess());
 
   // We found an overloaded operator(). Build a CXXOperatorCallExpr

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=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/p4.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p4.cpp Tue Mar 16 00:22:47 2010
@@ -99,18 +99,36 @@
 
 // Implicit destructor calls.
 namespace test3 {
-  class A{
+  class A {
   private:
     ~A(); // expected-note 3 {{declared private here}}
     static A foo;
   };
 
-  A a; // expected-error {{'~A' is a private member}}
+  A a; // expected-error {{variable of type 'test3::A' has private destructor}}
   A A::foo;
 
-  void foo(A param) { // expected-error {{'~A' is a private member}}
-    A local; // expected-error {{'~A' is a private member}}
+  void foo(A param) { // expected-error {{variable of type 'test3::A' has private destructor}}
+    A local; // expected-error {{variable of type 'test3::A' has private destructor}}
   }
+
+  template <unsigned N> class Base { ~Base(); }; // expected-note 4 {{declared private here}}
+  class Base2 : virtual Base<2> { ~Base2(); }; // expected-note {{declared private here}}
+  class Base3 : virtual Base<3> { public: ~Base3(); };
+
+  // These don't cause diagnostics because we don't need the destructor.
+  class Derived0 : Base<0> { ~Derived0(); };
+  class Derived1 : Base<1> { };
+
+  class Derived2 : // expected-error {{inherited virtual base class 'Base<2>' has private destructor}} \
+                   // expected-error {{inherited virtual base class 'Base<3>' has private destructor}}
+    Base<0>,  // expected-error {{base class 'Base<0>' has private destructor}}
+    virtual Base<1>, // expected-error {{base class 'Base<1>' has private destructor}}
+    Base2, // expected-error {{base class 'test3::Base2' has private destructor}}
+    virtual Base3
+  {
+    ~Derived2() {}
+  };
 }
 
 // Conversion functions.





More information about the cfe-commits mailing list