public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
@ 2012-03-26 11:25 Paolo Carlini
  2012-03-26 19:31 ` Jason Merrill
  0 siblings, 1 reply; 17+ messages in thread
From: Paolo Carlini @ 2012-03-26 11:25 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill

[sorry, I'm resending this because inadvertently I had some html and the 
message got rejected]

Hi,

thus, I have been working on c++/50043, which boils down to this:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3204.htm

My basic idea so far is very simple:

--- class.c (revision 185792)
+++ class.c (working copy)
@@ -1001,6 +1001,10 @@ add_method (tree type, tree method, tree using_dec
"destructor",
type);
}
+ else if (cxx_dialect >= cxx0x
+ && !TYPE_RAISES_EXCEPTIONS (TREE_TYPE (method)))
+ TREE_TYPE (method) = build_exception_variant (TREE_TYPE (method),
+ noexcept_true_spec);
}
else
{

thus, right before actually adding the method we check whether nothing 
has been deduced about it and we enforce the default noexcept. It's 
already enough to cover the testcase provided in c++/50043, which 
includes a good range of positive and negative tests. Does the idea make 
sense? As is, the patchlet leads to a few regressions, largely benign as 
far as I can see:

FAIL: g++.dg/cpp0x/noexcept01.C (test for excess errors)
FAIL: g++.dg/eh/ctor1.C -std=c++11 execution test
FAIL: g++.dg/eh/init-temp1.C -std=c++11 execution test
FAIL: g++.dg/tree-ssa/ehcleanup-1.C -std=gnu++11 scan-tree-dump-times 
ehcleanup1 "Removing unreachable" 4
FAIL: g++.old-deja/g++.eh/cleanup1.C -std=c++11 execution test

(the idea would changing the tests to be c++98 only and then adding 
c++11 counterparts)

Something the patchlet does not cover is:

struct B
{ ~B(); };

B::~B() { }

<mailto:paolo.carlini@oracle.com>
indeed the "as an implicit declaration" bits of the new wording in C++11 
doesn't guide so much about this, I guess it means something like:

--- decl.c (revision 185792)
+++ decl.c (working copy)
@@ -1144,7 +1144,10 @@ check_redeclaration_exception_specification (tree
if ((pedantic || ! DECL_IN_SYSTEM_HEADER (old_decl))
&& ! DECL_IS_BUILTIN (old_decl)
&& flag_exceptions
- && !comp_except_specs (new_exceptions, old_exceptions, ce_normal))
+ && !comp_except_specs (new_exceptions, old_exceptions, ce_normal)
+ && !(DECL_DESTRUCTOR_P (new_decl)
+ && cxx_dialect >= cxx0x
+ && !new_exceptions && TYPE_NOEXCEPT_P (old_type)))
{
error ("declaration of %qF has a different exception specifier",
new_decl);

does it make sense?

Another case which makes me nervous is when we add to the testcase in 
c++/50043 also a case for a virtual base class destructor, thus 
something like

struct True2 { virtual ~True2(); };
struct False { ~False() noexcept(false); };

template <typename Base, typename Member>
struct C : Base
{
Member mem;
};

SA(!noexcept(C<True2, False>()));

it doesn't compile at all because:

noexcept_PR50043.C:21:8: error: looser throw specifier for ‘virtual 
C<True2, False>::~C() noexcept (false)Â’
noexcept_PR50043.C:5:24: error: overriding ‘virtual True2::~True2() 
noexcept (true)Â’

is this expected? Maybe, but I'm not sure.

Thanks in advance for any tips!
Paolo.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-26 11:25 [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors" Paolo Carlini
@ 2012-03-26 19:31 ` Jason Merrill
  2012-03-26 23:08   ` Paolo Carlini
  2012-03-28 15:06   ` Paolo Carlini
  0 siblings, 2 replies; 17+ messages in thread
From: Jason Merrill @ 2012-03-26 19:31 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

On 03/26/2012 07:22 AM, Paolo Carlini wrote:
> My basic idea so far is very simple:
>
> --- class.c (revision 185792)
> +++ class.c (working copy)
> @@ -1001,6 +1001,10 @@ add_method (tree type, tree method, tree using_dec
> "destructor",
> type);
> }
> + else if (cxx_dialect >= cxx0x
> + && !TYPE_RAISES_EXCEPTIONS (TREE_TYPE (method)))
> + TREE_TYPE (method) = build_exception_variant (TREE_TYPE (method),
> + noexcept_true_spec);
> }

That would implement N1366, but implementing N3204 is a bit more 
involved.  You need to copy TYPE_RAISES_EXCEPTIONS from the result of 
implicitly_declare_fn; see defaulted_late_check for something similar.

Also, this is too early, since we can't know what the eh specification 
of the implicit declaration would be until the closing brace of the class.

> struct True2 { virtual ~True2(); };
> struct False { ~False() noexcept(false); };
>
> template <typename Base, typename Member>
> struct C : Base
> {
> Member mem;
> };
>
> SA(!noexcept(C<True2, False>()));
>
> it doesn't compile at all because:
>
> noexcept_PR50043.C:21:8: error: looser throw specifier for ‘virtual
> C<True2, False>::~C() noexcept (false)Â’
> noexcept_PR50043.C:5:24: error: overriding ‘virtual True2::~True2()
> noexcept (true)Â’
>
> is this expected? Maybe, but I'm not sure.

Yes.  Adding noexcept to ~True2 causes the same error without your patch.

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-26 19:31 ` Jason Merrill
@ 2012-03-26 23:08   ` Paolo Carlini
  2012-03-28 15:06   ` Paolo Carlini
  1 sibling, 0 replies; 17+ messages in thread
From: Paolo Carlini @ 2012-03-26 23:08 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On 03/26/2012 09:31 PM, Jason Merrill wrote:
> On 03/26/2012 07:22 AM, Paolo Carlini wrote:
>> My basic idea so far is very simple:
>>
>> --- class.c (revision 185792)
>> +++ class.c (working copy)
>> @@ -1001,6 +1001,10 @@ add_method (tree type, tree method, tree 
>> using_dec
>> "destructor",
>> type);
>> }
>> + else if (cxx_dialect >= cxx0x
>> + && !TYPE_RAISES_EXCEPTIONS (TREE_TYPE (method)))
>> + TREE_TYPE (method) = build_exception_variant (TREE_TYPE (method),
>> + noexcept_true_spec);
>> }
>
> That would implement N1366, but implementing N3204 is a bit more 
> involved.  You need to copy TYPE_RAISES_EXCEPTIONS from the result of 
> implicitly_declare_fn; see defaulted_late_check for something similar.
>
> Also, this is too early, since we can't know what the eh specification 
> of the implicit declaration would be until the closing brace of the class.
Thanks for the help Jason.

Paolo.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-26 19:31 ` Jason Merrill
  2012-03-26 23:08   ` Paolo Carlini
@ 2012-03-28 15:06   ` Paolo Carlini
  2012-03-28 15:18     ` Jason Merrill
  1 sibling, 1 reply; 17+ messages in thread
From: Paolo Carlini @ 2012-03-28 15:06 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1145 bytes --]

Hi again,

On 03/26/2012 09:31 PM, Jason Merrill wrote:
> On 03/26/2012 07:22 AM, Paolo Carlini wrote:
>> My basic idea so far is very simple:
>>
>> --- class.c (revision 185792)
>> +++ class.c (working copy)
>> @@ -1001,6 +1001,10 @@ add_method (tree type, tree method, tree 
>> using_dec
>> "destructor",
>> type);
>> }
>> + else if (cxx_dialect >= cxx0x
>> + && !TYPE_RAISES_EXCEPTIONS (TREE_TYPE (method)))
>> + TREE_TYPE (method) = build_exception_variant (TREE_TYPE (method),
>> + noexcept_true_spec);
>> }
>
> That would implement N1366, but implementing N3204 is a bit more 
> involved.  You need to copy TYPE_RAISES_EXCEPTIONS from the result of 
> implicitly_declare_fn; see defaulted_late_check for something similar.
>
> Also, this is too early, since we can't know what the eh specification 
> of the implicit declaration would be until the closing brace of the 
> class.
I think I understand your explanation and the below appears already to 
work pretty well. Is it on the right track? What about the 
check_redeclaration_exception_specification bits?

Thanks in advance for any further feedback,
Paolo.

////////////////////////

[-- Attachment #2: p2 --]
[-- Type: text/plain, Size: 3578 bytes --]

Index: class.c
===================================================================
--- class.c	(revision 185911)
+++ class.c	(working copy)
@@ -4321,6 +4321,37 @@ clone_constructors_and_destructors (tree t)
     clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
 }
 
+/* For each destructor in T, deduce noexcept per:
+
+   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))
+    {
+      tree fn = OVL_CURRENT (fns);
+      if (!TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
+	{
+	  tree ctx = DECL_CONTEXT (fn);
+	  tree implicit_fn = implicitly_declare_fn (sfk_destructor, ctx,
+						    /*const_p=*/false);
+	  tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
+
+	  TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
+	}
+    }
+}
+
 /* 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.  */
@@ -5129,6 +5160,10 @@ check_bases_and_members (tree t)
      do anything with non-static member functions.  */
   finalize_literal_type_property (t);
 
+  /* Deduce noexcept.  */
+  if (cxx_dialect >= cxx0x)
+    deduce_noexcept_on_destructors (t);
+
   /* Create the in-charge and not-in-charge variants of constructors
      and destructors.  */
   clone_constructors_and_destructors (t);
Index: decl.c
===================================================================
--- decl.c	(revision 185911)
+++ decl.c	(working copy)
@@ -1144,7 +1144,13 @@ check_redeclaration_exception_specification (tree
   if ((pedantic || ! DECL_IN_SYSTEM_HEADER (old_decl))
       && ! DECL_IS_BUILTIN (old_decl)
       && flag_exceptions
-      && !comp_except_specs (new_exceptions, old_exceptions, ce_normal))
+      && !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)))
     {
       error ("declaration of %qF has a different exception specifier",
 	     new_decl);
Index: method.c
===================================================================
--- method.c	(revision 185911)
+++ 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 185911)
+++ cp-tree.h	(working copy)
@@ -5264,6 +5264,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);

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-28 15:06   ` Paolo Carlini
@ 2012-03-28 15:18     ` Jason Merrill
  2012-03-28 22:44       ` Paolo Carlini
  0 siblings, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2012-03-28 15:18 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

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.

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-28 15:18     ` Jason Merrill
@ 2012-03-28 22:44       ` Paolo Carlini
  2012-03-28 22:47         ` Paolo Carlini
  2012-03-29 18:51         ` Jason Merrill
  0 siblings, 2 replies; 17+ messages in thread
From: Paolo Carlini @ 2012-03-28 22:44 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1988 bytes --]

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.

/////////////////////

[-- Attachment #2: p3 --]
[-- Type: text/plain, Size: 4855 bytes --]

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

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-28 22:44       ` Paolo Carlini
@ 2012-03-28 22:47         ` Paolo Carlini
  2012-03-29 15:18           ` Paolo Carlini
  2012-03-29 18:51         ` Jason Merrill
  1 sibling, 1 reply; 17+ messages in thread
From: Paolo Carlini @ 2012-03-28 22:47 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Oops...
> 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();
> };
Last line of the snippet missing:

     C<True2> c;

Paolo.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-28 22:47         ` Paolo Carlini
@ 2012-03-29 15:18           ` Paolo Carlini
  0 siblings, 0 replies; 17+ messages in thread
From: Paolo Carlini @ 2012-03-29 15:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 129 bytes --]

... attached the testsuite changes I have so far (seem all rather 
straightforward to me).

Thanks,
Paolo.

////////////////////

[-- Attachment #2: patch_50043_testcases_draft --]
[-- Type: text/plain, Size: 4423 bytes --]

Index: testsuite/g++.old-deja/g++.eh/cleanup1.C
===================================================================
--- testsuite/g++.old-deja/g++.eh/cleanup1.C	(revision 185952)
+++ testsuite/g++.old-deja/g++.eh/cleanup1.C	(working copy)
@@ -2,6 +2,12 @@
 // Bug: obj gets destroyed twice because the fixups for the return are
 // inside its cleanup region.
 
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#define NOEXCEPT_FALSE noexcept (false)
+#else
+#define NOEXCEPT_FALSE
+#endif
+
 extern "C" int printf (const char *, ...);
 
 int d;
@@ -9,7 +15,7 @@ int d;
 struct myExc { };
 
 struct myExcRaiser {
-  ~myExcRaiser() { throw myExc(); }
+  ~myExcRaiser() NOEXCEPT_FALSE { throw myExc(); }
 };
 
 struct stackObj {
Index: testsuite/g++.dg/tree-ssa/ehcleanup-1.C
===================================================================
--- testsuite/g++.dg/tree-ssa/ehcleanup-1.C	(revision 185952)
+++ testsuite/g++.dg/tree-ssa/ehcleanup-1.C	(working copy)
@@ -1,9 +1,16 @@
 // { dg-options "-O2 -fdump-tree-ehcleanup1-details" }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#define NOEXCEPT_FALSE noexcept (false)
+#else
+#define NOEXCEPT_FALSE
+#endif
+
 extern void can_throw ();
 class a
 {
 public:
-  ~a ()
+  ~a () NOEXCEPT_FALSE
   {
     if (0)
       can_throw ();
Index: testsuite/g++.dg/cpp0x/noexcept17.C
===================================================================
--- testsuite/g++.dg/cpp0x/noexcept17.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/noexcept17.C	(revision 0)
@@ -0,0 +1,54 @@
+// PR c++/50043
+// { dg-options -std=c++11 }
+
+struct True1 {};
+struct True2 { ~True2(); };
+struct True3 { ~True3(){ throw 0; } };
+struct False { ~False() noexcept(false); };
+
+template <typename Base>
+struct A : Base
+{
+};
+
+template <typename Member>
+struct B
+{
+    Member mem;
+};
+
+template <typename Base, typename Member>
+struct C : Base
+{
+    Member mem;
+};
+
+#define SA(X) static_assert(X, #X)
+
+SA( noexcept(True1()));
+SA( noexcept(True2()));
+SA( noexcept(True3()));
+SA(!noexcept(False()));
+
+SA( noexcept(A<True1>()));
+SA( noexcept(A<True2>()));
+SA( noexcept(A<True3>()));
+SA(!noexcept(A<False>()));
+
+SA( noexcept(B<True1>()));
+SA( noexcept(B<True2>()));
+SA( noexcept(B<True3>()));
+SA(!noexcept(B<False>()));
+
+SA( noexcept(C<True1, True2>()));
+SA( noexcept(C<True1, True3>()));
+SA( noexcept(C<True2, True3>()));
+SA( noexcept(C<True2, True1>()));
+SA( noexcept(C<True3, True1>()));
+SA( noexcept(C<True3, True2>()));
+SA(!noexcept(C<False, True1>()));
+SA(!noexcept(C<False, True2>()));
+SA(!noexcept(C<False, True3>()));
+SA(!noexcept(C<True1, False>()));
+SA(!noexcept(C<True2, False>()));
+SA(!noexcept(C<True3, False>()));
Index: testsuite/g++.dg/cpp0x/noexcept01.C
===================================================================
--- testsuite/g++.dg/cpp0x/noexcept01.C	(revision 185952)
+++ testsuite/g++.dg/cpp0x/noexcept01.C	(working copy)
@@ -50,7 +50,7 @@ struct E
   ~E();
 };
 
-SA (!noexcept (E()));
+SA (noexcept (E()));
 
 struct F
 {
@@ -74,7 +74,7 @@ void tf()
 }
 
 template void tf<int,true>();
-template void tf<E, false>();
+template void tf<E, true>();
 
 // Make sure that noexcept uses the declared exception-specification, not
 // any knowledge we might have about whether or not the function really
Index: testsuite/g++.dg/eh/init-temp1.C
===================================================================
--- testsuite/g++.dg/eh/init-temp1.C	(revision 185952)
+++ testsuite/g++.dg/eh/init-temp1.C	(working copy)
@@ -1,6 +1,12 @@
 // PR c++/15764
 // { dg-do run }
 
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#define NOEXCEPT_FALSE noexcept (false)
+#else
+#define NOEXCEPT_FALSE
+#endif
+
 extern "C" void abort (); 
  
 int thrown; 
@@ -8,7 +14,7 @@ int thrown;
 int as;
 struct a {
   a () { ++as; }
-  ~a () { --as; if (thrown++ == 0) throw 42; }
+  ~a () NOEXCEPT_FALSE { --as; if (thrown++ == 0) throw 42; }
 }; 
  
 int f (a const&) { return 1; } 
Index: testsuite/g++.dg/eh/ctor1.C
===================================================================
--- testsuite/g++.dg/eh/ctor1.C	(revision 185952)
+++ testsuite/g++.dg/eh/ctor1.C	(working copy)
@@ -5,6 +5,12 @@
 
 // PR 411
 
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#define NOEXCEPT_FALSE noexcept (false)
+#else
+#define NOEXCEPT_FALSE
+#endif
+
 bool was_f_in_Bar_destroyed=false;
 
 struct Foo
@@ -17,7 +23,7 @@ struct Foo
 
 struct Bar
 {
-  ~Bar()
+  ~Bar() NOEXCEPT_FALSE
   {
     throw 1;
   }

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-28 22:44       ` Paolo Carlini
  2012-03-28 22:47         ` Paolo Carlini
@ 2012-03-29 18:51         ` Jason Merrill
  2012-03-29 19:10           ` Paolo Carlini
  1 sibling, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2012-03-29 18:51 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

On 03/28/2012 06:40 PM, Paolo Carlini wrote:
> +	  /* 12.4/3  */
> +	  if (cxx_dialect>= cxx0x
> +	      && DECL_DESTRUCTOR_P (decl)
> +	      && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl)))
> +	    deduce_noexcept_on_destructor (decl);

The exception specification on old_decl doesn't matter; we can drop that 
test.

> 2- The new register_specialization bits are needed to cope with (also in the C++ library and elsewhere):

That's the wrong place.  Why doesn't the code in grokfndecl handle this 
case?

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-29 18:51         ` Jason Merrill
@ 2012-03-29 19:10           ` Paolo Carlini
  2012-03-29 19:23             ` Paolo Carlini
  2012-03-29 19:27             ` Jason Merrill
  0 siblings, 2 replies; 17+ messages in thread
From: Paolo Carlini @ 2012-03-29 19:10 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi,
> On 03/28/2012 06:40 PM, Paolo Carlini wrote:
>> +      /* 12.4/3  */
>> +      if (cxx_dialect>= cxx0x
>> + && DECL_DESTRUCTOR_P (decl)
>> + && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl)))
>> +        deduce_noexcept_on_destructor (decl);
>
> 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)); 
I don't know if that rings a bell to you... I'll double check anyway.
>> 2- The new register_specialization bits are needed to cope with (also 
>> in the C++ library and elsewhere):
> That's the wrong place.  Why doesn't the code in grokfndecl handle 
> this case?
Ok, I will check, thanks.

Paolo.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-29 19:10           ` Paolo Carlini
@ 2012-03-29 19:23             ` Paolo Carlini
  2012-03-29 19:27             ` Jason Merrill
  1 sibling, 0 replies; 17+ messages in thread
From: Paolo Carlini @ 2012-03-29 19:23 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: Jason Merrill, gcc-patches

Hi,
>> On 03/28/2012 06:40 PM, Paolo Carlini wrote:
>>> +      /* 12.4/3  */
>>> +      if (cxx_dialect>= cxx0x
>>> + && DECL_DESTRUCTOR_P (decl)
>>> + && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl)))
>>> +        deduce_noexcept_on_destructor (decl);
>>
>> 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)); I don't know if that rings a bell to you... I'll double check 
> anyway.
Yes, If I remove that check, then we hit that gcc_assert for:

template<typename T>
struct A
{
   ~A();
};

template<typename T>
A<T>::~A() { }

Paolo.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-29 19:10           ` Paolo Carlini
  2012-03-29 19:23             ` Paolo Carlini
@ 2012-03-29 19:27             ` Jason Merrill
  2012-03-29 19:37               ` Paolo Carlini
  2012-03-29 22:30               ` Paolo Carlini
  1 sibling, 2 replies; 17+ messages in thread
From: Jason Merrill @ 2012-03-29 19:27 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

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.

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-29 19:27             ` Jason Merrill
@ 2012-03-29 19:37               ` Paolo Carlini
  2012-03-29 22:30               ` Paolo Carlini
  1 sibling, 0 replies; 17+ messages in thread
From: Paolo Carlini @ 2012-03-29 19:37 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

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.
Can you suggest a robust way to achieve that? I remained stuck a lot 
because of this, to make sure that the latter testcase and:

template<typename T>
struct A
{
   ~A() noexcept;
};

template<typename T>
A<T>::~A() { }

both work.

Thanks,
Paolo.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-29 19:27             ` Jason Merrill
  2012-03-29 19:37               ` Paolo Carlini
@ 2012-03-29 22:30               ` Paolo Carlini
  2012-03-31  1:38                 ` Paolo Carlini
  1 sibling, 1 reply; 17+ messages in thread
From: Paolo Carlini @ 2012-03-29 22:30 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1862 bytes --]

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.

///////////////////////



[-- Attachment #2: ppp --]
[-- Type: text/plain, Size: 3668 bytes --]

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

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-29 22:30               ` Paolo Carlini
@ 2012-03-31  1:38                 ` Paolo Carlini
  2012-04-01 18:26                   ` Jason Merrill
  0 siblings, 1 reply; 17+ messages in thread
From: Paolo Carlini @ 2012-03-31  1:38 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1719 bytes --]

Hi again,

On 03/30/2012 12:26 AM, Paolo Carlini wrote:
> 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.
Sorry for essentially self-replying, but today, while I was traveling, I 
reviewed in my mind your comments over the last days, and I think I had 
a buglet in the patch which I sent in the last message: it doesn't make 
sure, in grokfndecl, to *not* call deduce_noexcept_on_destructor on a 
destructor of a class still being defined. Thus I'm adding a 
!TYPE_BEING_DEFINED (DECL_CONTEXT (decl)) check and the complete patch 
(which I'm attaching below) still passes testing. I also double checked 
that, for a simple case like:

struct A
{
   ~A();
};

A::~A() { }

we process the declaration from check_bases_and_members and then the 
definition from grokfndecl.

Thanks,
Paolo.

////////////////////////

[-- Attachment #2: patch_50043_draft_3 --]
[-- Type: text/plain, Size: 8179 bytes --]

Index: testsuite/g++.old-deja/g++.eh/cleanup1.C
===================================================================
--- testsuite/g++.old-deja/g++.eh/cleanup1.C	(revision 185982)
+++ testsuite/g++.old-deja/g++.eh/cleanup1.C	(working copy)
@@ -2,6 +2,12 @@
 // Bug: obj gets destroyed twice because the fixups for the return are
 // inside its cleanup region.
 
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#define NOEXCEPT_FALSE noexcept (false)
+#else
+#define NOEXCEPT_FALSE
+#endif
+
 extern "C" int printf (const char *, ...);
 
 int d;
@@ -9,7 +15,7 @@ int d;
 struct myExc { };
 
 struct myExcRaiser {
-  ~myExcRaiser() { throw myExc(); }
+  ~myExcRaiser() NOEXCEPT_FALSE { throw myExc(); }
 };
 
 struct stackObj {
Index: testsuite/g++.dg/tree-ssa/ehcleanup-1.C
===================================================================
--- testsuite/g++.dg/tree-ssa/ehcleanup-1.C	(revision 185982)
+++ testsuite/g++.dg/tree-ssa/ehcleanup-1.C	(working copy)
@@ -1,9 +1,16 @@
 // { dg-options "-O2 -fdump-tree-ehcleanup1-details" }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#define NOEXCEPT_FALSE noexcept (false)
+#else
+#define NOEXCEPT_FALSE
+#endif
+
 extern void can_throw ();
 class a
 {
 public:
-  ~a ()
+  ~a () NOEXCEPT_FALSE
   {
     if (0)
       can_throw ();
Index: testsuite/g++.dg/cpp0x/noexcept17.C
===================================================================
--- testsuite/g++.dg/cpp0x/noexcept17.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/noexcept17.C	(revision 0)
@@ -0,0 +1,54 @@
+// PR c++/50043
+// { dg-options -std=c++11 }
+
+struct True1 {};
+struct True2 { ~True2(); };
+struct True3 { ~True3(){ throw 0; } };
+struct False { ~False() noexcept(false); };
+
+template <typename Base>
+struct A : Base
+{
+};
+
+template <typename Member>
+struct B
+{
+    Member mem;
+};
+
+template <typename Base, typename Member>
+struct C : Base
+{
+    Member mem;
+};
+
+#define SA(X) static_assert(X, #X)
+
+SA( noexcept(True1()));
+SA( noexcept(True2()));
+SA( noexcept(True3()));
+SA(!noexcept(False()));
+
+SA( noexcept(A<True1>()));
+SA( noexcept(A<True2>()));
+SA( noexcept(A<True3>()));
+SA(!noexcept(A<False>()));
+
+SA( noexcept(B<True1>()));
+SA( noexcept(B<True2>()));
+SA( noexcept(B<True3>()));
+SA(!noexcept(B<False>()));
+
+SA( noexcept(C<True1, True2>()));
+SA( noexcept(C<True1, True3>()));
+SA( noexcept(C<True2, True3>()));
+SA( noexcept(C<True2, True1>()));
+SA( noexcept(C<True3, True1>()));
+SA( noexcept(C<True3, True2>()));
+SA(!noexcept(C<False, True1>()));
+SA(!noexcept(C<False, True2>()));
+SA(!noexcept(C<False, True3>()));
+SA(!noexcept(C<True1, False>()));
+SA(!noexcept(C<True2, False>()));
+SA(!noexcept(C<True3, False>()));
Index: testsuite/g++.dg/cpp0x/noexcept01.C
===================================================================
--- testsuite/g++.dg/cpp0x/noexcept01.C	(revision 185982)
+++ testsuite/g++.dg/cpp0x/noexcept01.C	(working copy)
@@ -50,7 +50,7 @@ struct E
   ~E();
 };
 
-SA (!noexcept (E()));
+SA (noexcept (E()));
 
 struct F
 {
@@ -74,7 +74,7 @@ void tf()
 }
 
 template void tf<int,true>();
-template void tf<E, false>();
+template void tf<E, true>();
 
 // Make sure that noexcept uses the declared exception-specification, not
 // any knowledge we might have about whether or not the function really
Index: testsuite/g++.dg/eh/init-temp1.C
===================================================================
--- testsuite/g++.dg/eh/init-temp1.C	(revision 185982)
+++ testsuite/g++.dg/eh/init-temp1.C	(working copy)
@@ -1,6 +1,12 @@
 // PR c++/15764
 // { dg-do run }
 
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#define NOEXCEPT_FALSE noexcept (false)
+#else
+#define NOEXCEPT_FALSE
+#endif
+
 extern "C" void abort (); 
  
 int thrown; 
@@ -8,7 +14,7 @@ int thrown;
 int as;
 struct a {
   a () { ++as; }
-  ~a () { --as; if (thrown++ == 0) throw 42; }
+  ~a () NOEXCEPT_FALSE { --as; if (thrown++ == 0) throw 42; }
 }; 
  
 int f (a const&) { return 1; } 
Index: testsuite/g++.dg/eh/ctor1.C
===================================================================
--- testsuite/g++.dg/eh/ctor1.C	(revision 185982)
+++ testsuite/g++.dg/eh/ctor1.C	(working copy)
@@ -5,6 +5,12 @@
 
 // PR 411
 
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#define NOEXCEPT_FALSE noexcept (false)
+#else
+#define NOEXCEPT_FALSE
+#endif
+
 bool was_f_in_Bar_destroyed=false;
 
 struct Foo
@@ -17,7 +23,7 @@ struct Foo
 
 struct Bar
 {
-  ~Bar()
+  ~Bar() NOEXCEPT_FALSE
   {
     throw 1;
   }
Index: cp/class.c
===================================================================
--- cp/class.c	(revision 185982)
+++ cp/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: cp/decl.c
===================================================================
--- cp/decl.c	(revision 185983)
+++ cp/decl.c	(working copy)
@@ -7448,6 +7448,13 @@ grokfndecl (tree ctype,
   if (ctype != NULL_TREE)
     grokclassfn (ctype, decl, flags);
 
+  /* 12.4/3  */
+  if (cxx_dialect >= cxx0x
+      && DECL_DESTRUCTOR_P (decl)
+      && !TYPE_BEING_DEFINED (DECL_CONTEXT (decl))
+      && !processing_template_decl)
+    deduce_noexcept_on_destructor (decl);
+
   decl = check_explicit_specialization (orig_declarator, decl,
 					template_count,
 					2 * funcdef_flag +
Index: cp/method.c
===================================================================
--- cp/method.c	(revision 185982)
+++ cp/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/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 185982)
+++ cp/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);

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-03-31  1:38                 ` Paolo Carlini
@ 2012-04-01 18:26                   ` Jason Merrill
  2012-04-02  0:17                     ` Paolo Carlini
  0 siblings, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2012-04-01 18:26 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

On 03/30/2012 09:34 PM, Paolo Carlini wrote:
> Thus I'm adding a
> !TYPE_BEING_DEFINED (DECL_CONTEXT (decl)) check

Sounds good.

> 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.

I'm OK with that, as long as we correctly allow

struct B
{
   ~B() noexcept;
};

B::~B() { }

and

struct B
{
   ~B();
};
B::~B() noexcept { }

The patch is OK.

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors"
  2012-04-01 18:26                   ` Jason Merrill
@ 2012-04-02  0:17                     ` Paolo Carlini
  0 siblings, 0 replies; 17+ messages in thread
From: Paolo Carlini @ 2012-04-02  0:17 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 949 bytes --]

Hi,
>> 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.
>
> I'm OK with that, as long as we correctly allow
>
> struct B
> {
>   ~B() noexcept;
> };
>
> B::~B() { }
>
> and
>
> struct B
> {
>   ~B();
> };
> B::~B() noexcept { }
Agreed. Thanks for asking on the reflector.
>
> The patch is OK.
Thanks again, the patch is in with the attached ChangeLog.

Paolo.

////////////////////////

[-- Attachment #2: CL_50043 --]
[-- Type: text/plain, Size: 679 bytes --]

/cp
2012-04-01  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/50043
	* class.c (deduce_noexcept_on_destructor,
	deduce_noexcept_on_destructors): New.
	(check_bases_and_members): Call the latter.
	* decl.c (grokfndecl): Call the former.
	* method.c (implicitly_declare_fn): Not static.
	* cp-tree.h (deduce_noexcept_on_destructor, implicitly_declare_fn):
	Declare

/testsuite
2012-04-01  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/50043
	* g++.dg/cpp0x/noexcept17.C: New.
	* g++.old-deja/g++.eh/cleanup1.C: Adjust.
	* g++.dg/tree-ssa/ehcleanup-1.C: Likewise.
	* g++.dg/cpp0x/noexcept01.C: Likewise.
	* g++.dg/eh/init-temp1.C: Likewise.
	* g++.dg/eh/ctor1.C: Likwise.

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2012-04-02  0:17 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-26 11:25 [C++ RFC / Patch] Implementing "Deducing "noexcept" for destructors" Paolo Carlini
2012-03-26 19:31 ` Jason Merrill
2012-03-26 23:08   ` Paolo Carlini
2012-03-28 15:06   ` Paolo Carlini
2012-03-28 15:18     ` Jason Merrill
2012-03-28 22:44       ` Paolo Carlini
2012-03-28 22:47         ` Paolo Carlini
2012-03-29 15:18           ` Paolo Carlini
2012-03-29 18:51         ` Jason Merrill
2012-03-29 19:10           ` Paolo Carlini
2012-03-29 19:23             ` Paolo Carlini
2012-03-29 19:27             ` Jason Merrill
2012-03-29 19:37               ` Paolo Carlini
2012-03-29 22:30               ` Paolo Carlini
2012-03-31  1:38                 ` Paolo Carlini
2012-04-01 18:26                   ` Jason Merrill
2012-04-02  0:17                     ` Paolo Carlini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).