Hi,

when I implemented Core/1123 "Destructors should be noexcept by default", unfortunately I caused this regression, present now in mainline and 4_8-branch.

When the destructor is user provided, with no exception specifications, and the type has data members (not bases, those are already Ok) with the destructor which can throw, the destructor is wrongly deduced to be noexcept. The reason is that deduce_noexcept_on_destructors is called from check_bases_and_members after check_bases but *before* check_methods and therefore the latter does too late work relevant for the deduction, namely possibly setting TYPE_HAS_NONTRIVIAL_DESTRUCTOR.

My proposal for a fix involves simply anticipating that work as part of deduce_noexcept_on_destructors, renamed now check_destructors, and called unconditionally. Things appear to work fine. Of course different refactorings and naming schemes could make perfect sense.

Tested x86_64-linux.

Thanks,
Paolo.

//////////////////////////
/cp
2013-06-19  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/57645
        * class.c (check_methods): Don't set TYPE_HAS_NONTRIVIAL_DESTRUCTOR
        here...
        (deduce_noexcept_on_destructors): ... do it here. Rename the
        function to check_destructors. 
        (check_bases_and_members): Adjust.

/testsuite
2013-06-19  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/57645
        * testsuite/g++.dg/cpp0x/noexcept21.C: New.
Index: cp/class.c
===================================================================
--- cp/class.c  (revision 200197)
+++ cp/class.c  (working copy)
@@ -4256,11 +4256,6 @@ check_methods (tree t)
          if (DECL_PURE_VIRTUAL_P (x))
            vec_safe_push (CLASSTYPE_PURE_VIRTUALS (t), x);
        }
-      /* All user-provided destructors are non-trivial.
-         Constructors and assignment ops are handled in
-        grok_special_member_properties.  */
-      if (DECL_DESTRUCTOR_P (x) && user_provided_p (x))
-       TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
     }
 }
 
@@ -4568,8 +4563,12 @@ clone_constructors_and_destructors (tree t)
     clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
 }
 
-/* Deduce noexcept for a destructor DTOR.  */
+/* Deduce noexcept for a destructor DTOR. 
 
+   12.4/3: A declaration of a destructor that does not have an
+   exception-specification is implicitly considered to have the
+   same exception-specification as an implicit declaration (15.4).  */
+
 void
 deduce_noexcept_on_destructor (tree dtor)
 {
@@ -4584,14 +4583,11 @@ deduce_noexcept_on_destructor (tree dtor)
     }
 }
 
-/* For each destructor in T, deduce noexcept:
+/* Possibly set TYPE_HAS_NONTRIVIAL_DESTRUCTOR and deduce noexcept for
+   each destructor.  */
 
-   12.4/3: A declaration of a destructor that does not have an
-   exception-specification is implicitly considered to have the
-   same exception-specification as an implicit declaration (15.4).  */
-
 static void
-deduce_noexcept_on_destructors (tree t)
+check_destructors (tree t)
 {
   tree fns;
 
@@ -4601,7 +4597,12 @@ static void
     return;
 
   for (fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
-    deduce_noexcept_on_destructor (OVL_CURRENT (fns));
+    {
+      if (user_provided_p (OVL_CURRENT (fns)))
+       TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
+      if (cxx_dialect >= cxx0x)
+       deduce_noexcept_on_destructor (OVL_CURRENT (fns));
+    }
 }
 
 /* Subroutine of set_one_vmethod_tm_attributes.  Search base classes
@@ -5319,10 +5320,10 @@ check_bases_and_members (tree t)
   check_bases (t, &cant_have_const_ctor,
               &no_const_asn_ref);
 
-  /* Deduce noexcept on destructors.  This needs to happen after we've set
-     triviality flags appropriately for our bases.  */
-  if (cxx_dialect >= cxx0x)
-    deduce_noexcept_on_destructors (t);
+  /* Possibly set TYPE_HAS_NONTRIVIAL_DESTRUCTOR and deduce noexcept on
+     destructors.  This needs to happen after we've set triviality flags
+     appropriately for our bases.  */
+  check_destructors (t);
 
   /* Check all the method declarations.  */
   check_methods (t);
Index: testsuite/g++.dg/cpp0x/noexcept21.C
===================================================================
--- testsuite/g++.dg/cpp0x/noexcept21.C (revision 0)
+++ testsuite/g++.dg/cpp0x/noexcept21.C (working copy)
@@ -0,0 +1,28 @@
+// PR c++/57645
+// { dg-do compile { target c++11 } }
+
+struct Thrower
+{
+  ~Thrower() noexcept(false) { throw 1; }
+};
+
+struct ExplicitA
+{
+  ~ExplicitA() {}
+
+  Thrower t;
+};
+
+struct ExplicitB
+{
+  ~ExplicitB();
+
+  Thrower t;
+};
+
+ExplicitB::~ExplicitB() { }
+
+#define SA(X) static_assert(X, #X)
+
+SA( !noexcept(ExplicitA()) );
+SA( !noexcept(ExplicitB()) );

Reply via email to