Hi,
On 03/28/2012 11:02 AM, Paolo Carlini wrote:
+&& !comp_except_specs (new_exceptions, old_exceptions, ce_normal)
+ /* Special case in C++11: noexcept has been deduced as true for
+ the declaration and there is no exception-specification on the
+ definition. */
+&& !(DECL_DESTRUCTOR_P (new_decl)
+ && cxx_dialect>= cxx0x
+ && !new_exceptions&& TYPE_NOEXCEPT_P (old_type)))
TYPE_NOEXCEPT_P is the wrong test; the implicit declaration might have
an exception-specification that allows some or all exceptions. I
think the most straightforward thing would be to add the implicit
exception-specification immediately when declaring a destructor
outside the class, so that by the time we get to
check_redeclaration_exception_specification the EH specs will match.
Agreed. The below is another iteration (which passes boot & test,
library included modulo the already mentioned "expected" failures in
C++11 mode), I'm trying to get to the point you by and large like the
code proper, thus I can start adjusting the testcases, etc.
Anyway, some notes about bits new wrt the previous iterations and not
totally obvious given your indications:
1- Turns out the check_bases_and_members change has to happen earlier,
because we want to fixup the exceptions before check_bases, otherwise we
reject things like (in the C++ library and elsewhere):
struct True2 { virtual ~True2() noexcept; };
template <typename Base>
struct C : Base
{
~C();
};
2- The new register_specialization bits are needed to cope with (also in
the C++ library and elsewhere):
template<typename T>
struct A
{
~A();
};
template<>
A<int>::~A();
template<>
A<int>::~A() { }
As a matter of fact, though, there is one more path in
register_specialization which leads to a duplicate_decls call, I'm not
100% sure we can leave it alone.
3- Names of the new functions, files to which belong, I'm just guessing.
Thanks,
Paolo.
/////////////////////
Index: class.c
===================================================================
--- class.c (revision 185920)
+++ class.c (working copy)
@@ -4321,6 +4321,40 @@ 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 +5028,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 185920)
+++ decl.c (working copy)
@@ -7528,6 +7528,12 @@ grokfndecl (tree ctype,
if (TREE_CODE (decl) == TEMPLATE_DECL)
decl = DECL_TEMPLATE_RESULT (decl);
+ /* 12.4/3 */
+ if (cxx_dialect >= cxx0x
+ && DECL_DESTRUCTOR_P (decl)
+ && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl)))
+ deduce_noexcept_on_destructor (decl);
+
/* Attempt to merge the declarations. This can fail, in
the case of some invalid specialization declarations. */
pushed_scope = push_scope (ctype);
Index: method.c
===================================================================
--- method.c (revision 185920)
+++ 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: pt.c
===================================================================
--- pt.c (revision 185920)
+++ pt.c (working copy)
@@ -1393,6 +1393,12 @@ register_specialization (tree spec, tree tmpl, tre
If there was a definition for the template, but not
for the specialization, we want this to look as if
there were no definition, and vice versa. */
+
+ /* 12.4/3 */
+ if (cxx_dialect >= cxx0x
+ && DECL_DESTRUCTOR_P (spec))
+ deduce_noexcept_on_destructor (spec);
+
DECL_INITIAL (fn) = NULL_TREE;
duplicate_decls (spec, fn, is_friend);
/* The call to duplicate_decls will have applied
@@ -1419,6 +1425,11 @@ register_specialization (tree spec, tree tmpl, tre
}
else if (DECL_TEMPLATE_SPECIALIZATION (fn))
{
+ /* 12.4/3 */
+ if (cxx_dialect >= cxx0x
+ && DECL_DESTRUCTOR_P (spec))
+ deduce_noexcept_on_destructor (spec);
+
if (!duplicate_decls (spec, fn, is_friend) && DECL_INITIAL (spec))
/* Dup decl failed, but this is a new definition. Set the
line number so any errors match this new
Index: cp-tree.h
===================================================================
--- cp-tree.h (revision 185920)
+++ 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);