On 03/29/2012 09:27 PM, Jason Merrill wrote:
On 03/29/2012 03:06 PM, Paolo Carlini wrote:
The exception specification on old_decl doesn't matter; we can drop
that test.
I seem to remember something going wrong with templates otherwise,
because implicitly_declare_fn has gcc_assert (!dependent_type_p (type));
We shouldn't be doing this for templates anyway, as in general we
can't know what the implicitly declared function will look like.
Oh my, as simple as the below appears to work!
I simply added a !processing_template_decl check. Then I removed the
deduce_noexcept_on_destructor calls in register_specialization and when
I found a proper place in grokfndecl (must be before
check_explicit_specialization) I noticed that apparently I can remove
the other deduce_noexcept_on_destructor call which I had later on in
grokfndecl. Thus the below passes the (updated) testsuite on x86_64-linux.
I remark (once more) that whereas we accept (otherwise nothing works in,
eg, the library):
template<typename T>
struct A
{
~A();
};
template<typename T>
A<T>::~A() { }
we reject, with a "different exception specifier" error, both:
template<typename T>
struct A
{
~A() noexcept;
};
template<typename T>
A<T>::~A() { }
and:
template<typename T>
struct A
{
~A();
};
template<typename T>
A<T>::~A() noexcept { }
Over the last days I wasted a lot of time trying painfully to not reject
either, but actually now I'm pretty sure that we are right to reject the
former (there are exception specifiers on the declaration thus automatic
deduction should not trigger at all) and probably also the latter. These
cases, characterized by different situations on declaration and
definition, confused me quite a bit...
Anyway, I'm attaching the last iteration.
Thanks again for all your help!
Paolo.
///////////////////////
Index: class.c
===================================================================
--- class.c (revision 185977)
+++ class.c (working copy)
@@ -4321,6 +4321,41 @@ clone_constructors_and_destructors (tree t)
clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
}
+/* Deduce noexcept for a destructor DTOR. */
+
+void
+deduce_noexcept_on_destructor (tree dtor)
+{
+ if (!TYPE_RAISES_EXCEPTIONS (TREE_TYPE (dtor)))
+ {
+ tree ctx = DECL_CONTEXT (dtor);
+ tree implicit_fn = implicitly_declare_fn (sfk_destructor, ctx,
+ /*const_p=*/false);
+ tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
+ TREE_TYPE (dtor) = build_exception_variant (TREE_TYPE (dtor), eh_spec);
+ }
+}
+
+/* For each destructor in T, deduce noexcept:
+
+ 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)
+{
+ tree fns;
+
+ /* If for some reason we don't have a CLASSTYPE_METHOD_VEC, we bail
+ out now. */
+ if (!CLASSTYPE_METHOD_VEC (t))
+ return;
+
+ for (fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+ deduce_noexcept_on_destructor (OVL_CURRENT (fns));
+}
+
/* Subroutine of set_one_vmethod_tm_attributes. Search base classes
of TYPE for virtual functions which FNDECL overrides. Return a
mask of the tm attributes found therein. */
@@ -4994,6 +5029,10 @@ check_bases_and_members (tree t)
cant_have_const_ctor = 0;
no_const_asn_ref = 0;
+ /* Deduce noexcept on destructors. */
+ if (cxx_dialect >= cxx0x)
+ deduce_noexcept_on_destructors (t);
+
/* Check all the base-classes. */
check_bases (t, &cant_have_const_ctor,
&no_const_asn_ref);
Index: decl.c
===================================================================
--- decl.c (revision 185977)
+++ decl.c (working copy)
@@ -7448,6 +7448,12 @@ grokfndecl (tree ctype,
if (ctype != NULL_TREE)
grokclassfn (ctype, decl, flags);
+ /* 12.4/3 */
+ if (cxx_dialect >= cxx0x
+ && DECL_DESTRUCTOR_P (decl)
+ && !processing_template_decl)
+ deduce_noexcept_on_destructor (decl);
+
decl = check_explicit_specialization (orig_declarator, decl,
template_count,
2 * funcdef_flag +
Index: method.c
===================================================================
--- method.c (revision 185977)
+++ method.c (working copy)
@@ -1444,7 +1444,7 @@ explain_implicit_non_constexpr (tree decl)
reference argument or a non-const reference. Returns the
FUNCTION_DECL for the implicitly declared function. */
-static tree
+tree
implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
{
tree fn;
Index: cp-tree.h
===================================================================
--- cp-tree.h (revision 185977)
+++ cp-tree.h (working copy)
@@ -4978,6 +4978,7 @@ extern void fixup_attribute_variants (tree);
extern tree* decl_cloned_function_p (const_tree, bool);
extern void clone_function_decl (tree, int);
extern void adjust_clone_args (tree);
+extern void deduce_noexcept_on_destructor (tree);
/* in cvt.c */
extern tree convert_to_reference (tree, tree, int, int, tree);
@@ -5264,6 +5265,8 @@ extern tree get_copy_assign (tree);
extern tree get_default_ctor (tree);
extern tree get_dtor (tree, tsubst_flags_t);
extern tree locate_ctor (tree);
+extern tree implicitly_declare_fn (special_function_kind, tree,
+ bool);
/* In optimize.c */
extern bool maybe_clone_body (tree);