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

Reply via email to