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()) );