[cfe-commits] r107385 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/CodeGenCXX/destructors.cpp test/SemaCXX/destructor.cpp

Douglas Gregor dgregor at apple.com
Wed Jun 30 22:10:53 PDT 2010


Author: dgregor
Date: Thu Jul  1 00:10:53 2010
New Revision: 107385

URL: http://llvm.org/viewvc/llvm-project?rev=107385&view=rev
Log:
Reinstate fix for PR7526, which was failing because, now that we
aren't dropping all exception specifications on destructors, the
exception specifications on implicitly-declared destructors were
detected as being wrong (which they were). 

Introduce logic to provide a proper exception-specification for
implicitly-declared destructors. This also fixes PR6972.

Note that the other implicitly-declared special member functions also
need to get exception-specifications. I'll deal with that in a
subsequent commit.


Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/CodeGenCXX/destructors.cpp
    cfe/trunk/test/SemaCXX/destructor.cpp

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=107385&r1=107384&r2=107385&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Jul  1 00:10:53 2010
@@ -2672,7 +2672,7 @@
   QualType CheckConstructorDeclarator(Declarator &D, QualType R,
                                       FunctionDecl::StorageClass& SC);
   void CheckConstructor(CXXConstructorDecl *Constructor);
-  QualType CheckDestructorDeclarator(Declarator &D,
+  QualType CheckDestructorDeclarator(Declarator &D, QualType R,
                                      FunctionDecl::StorageClass& SC);
   bool CheckDestructor(CXXDestructorDecl *Destructor);
   void CheckConversionDeclarator(Declarator &D, QualType &R,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=107385&r1=107384&r2=107385&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jul  1 00:10:53 2010
@@ -3023,7 +3023,7 @@
   } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
     // This is a C++ destructor declaration.
     if (DC->isRecord()) {
-      R = CheckDestructorDeclarator(D, SC);
+      R = CheckDestructorDeclarator(D, R, SC);
 
       NewFD = CXXDestructorDecl::Create(Context,
                                         cast<CXXRecordDecl>(DC),

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=107385&r1=107384&r2=107385&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jul  1 00:10:53 2010
@@ -2588,6 +2588,65 @@
                       dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>()));
 }
 
+namespace {
+  /// \brief Helper class that collects exception specifications for 
+  /// implicitly-declared special member functions.
+  class ImplicitExceptionSpecification {
+    ASTContext &Context;
+    bool AllowsAllExceptions;
+    llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
+    llvm::SmallVector<QualType, 4> Exceptions;
+    
+  public:
+    explicit ImplicitExceptionSpecification(ASTContext &Context) 
+      : Context(Context), AllowsAllExceptions(false) { }
+    
+    /// \brief Whether the special member function should have any
+    /// exception specification at all.
+    bool hasExceptionSpecification() const {
+      return !AllowsAllExceptions;
+    }
+    
+    /// \brief Whether the special member function should have a
+    /// throw(...) exception specification (a Microsoft extension).
+    bool hasAnyExceptionSpecification() const {
+      return false;
+    }
+    
+    /// \brief The number of exceptions in the exception specification.
+    unsigned size() const { return Exceptions.size(); }
+    
+    /// \brief The set of exceptions in the exception specification.
+    const QualType *data() const { return Exceptions.data(); }
+    
+    /// \brief Note that 
+    void CalledDecl(CXXMethodDecl *Method) {
+      // If we already know that we allow all exceptions, do nothing.
+      if (AllowsAllExceptions)
+        return;
+      
+      const FunctionProtoType *Proto
+        = Method->getType()->getAs<FunctionProtoType>();
+      
+      // If this function can throw any exceptions, make a note of that.
+      if (!Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec()) {
+        AllowsAllExceptions = true;
+        ExceptionsSeen.clear();
+        Exceptions.clear();
+        return;
+      }
+        
+      // Record the exceptions in this function's exception specification.
+      for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
+                                              EEnd = Proto->exception_end();
+           E != EEnd; ++E) 
+        if (ExceptionsSeen.insert(Context.getCanonicalType(*E)))
+          Exceptions.push_back(*E);
+    }
+  };
+}
+
+
 /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
 /// special functions, such as the default constructor, copy
 /// constructor, or destructor, to the given C++ class (C++
@@ -2822,10 +2881,47 @@
     //   If a class has no user-declared destructor, a destructor is
     //   declared implicitly. An implicitly-declared destructor is an
     //   inline public member of its class.
+    
+    // C++ [except.spec]p14: 
+    //   An implicitly declared special member function (Clause 12) shall have 
+    //   an exception-specification.
+    ImplicitExceptionSpecification ExceptSpec(Context);
+    
+    // Direct base-class destructors.
+    for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
+                                         BEnd = ClassDecl->bases_end();
+         B != BEnd; ++B) {
+      if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
+        ExceptSpec.CalledDecl(
+              cast<CXXRecordDecl>(BaseType->getDecl())->getDestructor(Context));
+    }
+         
+    // Virtual base-class destructors.
+    for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
+                                         BEnd = ClassDecl->vbases_end();
+         B != BEnd; ++B) {
+      if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
+        ExceptSpec.CalledDecl(
+              cast<CXXRecordDecl>(BaseType->getDecl())->getDestructor(Context));
+    }
+
+    // Field destructors.
+    for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
+                                 FEnd = ClassDecl->field_end();
+         F != FEnd; ++F) {
+      if (const RecordType *RecordTy
+                = Context.getBaseElementType(F->getType())->getAs<RecordType>())
+        ExceptSpec.CalledDecl(
+              cast<CXXRecordDecl>(RecordTy->getDecl())->getDestructor(Context));
+    }
+    
     QualType Ty = Context.getFunctionType(Context.VoidTy,
                                           0, 0, false, 0,
-                                          /*FIXME: hasExceptionSpec*/false,
-                                          false, 0, 0, FunctionType::ExtInfo());
+                                        ExceptSpec.hasExceptionSpecification(),
+                                      ExceptSpec.hasAnyExceptionSpecification(),
+                                          ExceptSpec.size(),
+                                          ExceptSpec.data(),
+                                          FunctionType::ExtInfo());
 
     DeclarationName Name
       = Context.DeclarationNames.getCXXDestructorName(ClassType);
@@ -2990,9 +3086,7 @@
 
   // Rebuild the function type "R" without any type qualifiers (in
   // case any of the errors above fired) and with "void" as the
-  // return type, since constructors don't have return types. We
-  // *always* have to do this, because GetTypeForDeclarator will
-  // put in a result type of "int" when none was specified.
+  // return type, since constructors don't have return types.
   const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
   return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
                                  Proto->getNumArgs(),
@@ -3087,7 +3181,7 @@
 /// emit diagnostics and set the declarator to invalid.  Even if this happens,
 /// will be updated to reflect a well-formed type for the destructor and
 /// returned.
-QualType Sema::CheckDestructorDeclarator(Declarator &D,
+QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
                                          FunctionDecl::StorageClass& SC) {
   // C++ [class.dtor]p1:
   //   [...] A typedef-name that names a class is a class-name
@@ -3095,11 +3189,9 @@
   //   be used as the identifier in the declarator for a destructor
   //   declaration.
   QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName);
-  if (isa<TypedefType>(DeclaratorType)) {
+  if (isa<TypedefType>(DeclaratorType))
     Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
       << DeclaratorType;
-    D.setInvalidType();
-  }
 
   // C++ [class.dtor]p2:
   //   A destructor is used to destroy objects of its class type. A
@@ -3113,9 +3205,10 @@
     if (!D.isInvalidType())
       Diag(D.getIdentifierLoc(), diag::err_destructor_cannot_be)
         << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc())
-        << SourceRange(D.getIdentifierLoc());
+        << SourceRange(D.getIdentifierLoc())
+        << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+    
     SC = FunctionDecl::None;
-    D.setInvalidType();
   }
   if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) {
     // Destructors don't have return types, but the parser will
@@ -3163,11 +3256,17 @@
   // Rebuild the function type "R" without any type qualifiers or
   // parameters (in case any of the errors above fired) and with
   // "void" as the return type, since destructors don't have return
-  // types. We *always* have to do this, because GetTypeForDeclarator
-  // will put in a result type of "int" when none was specified.
-  // FIXME: Exceptions!
+  // types. 
+  const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+  if (!Proto)
+    return QualType();
+  
   return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0,
-                                 false, false, 0, 0, FunctionType::ExtInfo());
+                                 Proto->hasExceptionSpec(),
+                                 Proto->hasAnyExceptionSpec(),
+                                 Proto->getNumExceptions(),
+                                 Proto->exception_begin(),
+                                 Proto->getExtInfo());
 }
 
 /// CheckConversionDeclarator - Called by ActOnDeclarator to check the

Modified: cfe/trunk/test/CodeGenCXX/destructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/destructors.cpp?rev=107385&r1=107384&r2=107385&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/destructors.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/destructors.cpp Thu Jul  1 00:10:53 2010
@@ -32,6 +32,25 @@
 
 C::~C() { }
 
+namespace PR7526 {
+  extern void foo();
+  struct allocator {
+    ~allocator() throw();
+  };
+
+  struct allocator_derived : allocator { };
+
+  // CHECK: define void @_ZN6PR75269allocatorD2Ev
+  // CHECK: call void @__cxa_call_unexpected
+  allocator::~allocator() throw() { foo(); }
+
+  // CHECK: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev
+  // CHECK: call void @__cxa_call_unexpected
+  void foo() {
+    allocator_derived ad;
+  }
+}
+
 // PR5084
 template<typename T>
 class A1 {

Modified: cfe/trunk/test/SemaCXX/destructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/destructor.cpp?rev=107385&r1=107384&r2=107385&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/destructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/destructor.cpp Thu Jul  1 00:10:53 2010
@@ -19,7 +19,9 @@
     // expected-error{{type qualifier is not allowed on this function}} \
     // expected-error{{destructor cannot be declared 'static'}}  \
     // expected-error{{destructor cannot have any parameters}}   \
-    // expected-error{{destructor cannot be variadic}}
+    // expected-error{{destructor cannot be variadic}} \
+    // expected-error{{destructor cannot have a return type}} \
+    // expected-error{{'const' qualifier is not allowed on a destructor}}
 };
 
 struct D2 {
@@ -83,3 +85,6 @@
   template<class T> class X { T v; ~X() { ++*v; } };
   void a(X<int> x) {}
 }
+
+struct X0 { virtual ~X0() throw(); };
+struct X1 : public X0 { };





More information about the cfe-commits mailing list