Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-04-01 Thread Jason Merrill

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:

templatetypename T
struct A
{
  ~A() noexcept;
};

templatetypename T
AT::~A() { }

and:

templatetypename T
struct A
{
  ~A();
};

templatetypename T
AT::~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


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-04-01 Thread Paolo Carlini

Hi,

we reject, with a different exception specifier error, both:

templatetypename T
struct A
{
  ~A() noexcept;
};

templatetypename T
AT::~A() { }

and:

templatetypename T
struct A
{
  ~A();
};

templatetypename T
AT::~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.


/cp
2012-04-01  Paolo Carlini  paolo.carl...@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.carl...@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.


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-30 Thread Paolo Carlini

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.


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(ATrue1()));
+SA( noexcept(ATrue2()));
+SA( noexcept(ATrue3()));
+SA(!noexcept(AFalse()));
+
+SA( noexcept(BTrue1()));
+SA( noexcept(BTrue2()));
+SA( noexcept(BTrue3()));
+SA(!noexcept(BFalse()));
+
+SA( noexcept(CTrue1, True2()));
+SA( noexcept(CTrue1, True3()));
+SA( noexcept(CTrue2, True3()));
+SA( noexcept(CTrue2, True1()));
+SA( noexcept(CTrue3, True1()));
+SA( noexcept(CTrue3, True2()));
+SA(!noexcept(CFalse, True1()));
+SA(!noexcept(CFalse, True2()));
+SA(!noexcept(CFalse, True3()));
+SA(!noexcept(CTrue1, False()));
+SA(!noexcept(CTrue2, False()));
+SA(!noexcept(CTrue3, 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 tfint,true();
-template void tfE, false();
+template void tfE, 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

Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-29 Thread Paolo Carlini
... attached the testsuite changes I have so far (seem all rather 
straightforward to me).


Thanks,
Paolo.


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(ATrue1()));
+SA( noexcept(ATrue2()));
+SA( noexcept(ATrue3()));
+SA(!noexcept(AFalse()));
+
+SA( noexcept(BTrue1()));
+SA( noexcept(BTrue2()));
+SA( noexcept(BTrue3()));
+SA(!noexcept(BFalse()));
+
+SA( noexcept(CTrue1, True2()));
+SA( noexcept(CTrue1, True3()));
+SA( noexcept(CTrue2, True3()));
+SA( noexcept(CTrue2, True1()));
+SA( noexcept(CTrue3, True1()));
+SA( noexcept(CTrue3, True2()));
+SA(!noexcept(CFalse, True1()));
+SA(!noexcept(CFalse, True2()));
+SA(!noexcept(CFalse, True3()));
+SA(!noexcept(CTrue1, False()));
+SA(!noexcept(CTrue2, False()));
+SA(!noexcept(CTrue3, 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 tfint,true();
-template void tfE, false();
+template void tfE, 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;
   }


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-29 Thread Jason Merrill

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


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-29 Thread Paolo Carlini

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.


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-29 Thread Paolo Carlini

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:

templatetypename T
struct A
{
  ~A();
};

templatetypename T
AT::~A() { }

Paolo.


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-29 Thread Jason Merrill

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


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-29 Thread Paolo Carlini

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:


templatetypename T
struct A
{
  ~A() noexcept;
};

templatetypename T
AT::~A() { }

both work.

Thanks,
Paolo.


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-29 Thread Paolo Carlini

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


templatetypename T
struct A
{
  ~A();
};

templatetypename T
AT::~A() { }

we reject, with a different exception specifier error, both:

templatetypename T
struct A
{
  ~A() noexcept;
};

templatetypename T
AT::~A() { }

and:

templatetypename T
struct A
{
  ~A();
};

templatetypename T
AT::~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

Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-28 Thread Paolo Carlini

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.


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


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-28 Thread Jason Merrill

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


Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-28 Thread Paolo Carlini

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


templatetypename T
struct A
{
  ~A();
};

template
Aint::~A();

template
Aint::~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

Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-28 Thread Paolo Carlini

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:

CTrue2 c;

Paolo.


[C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-26 Thread Paolo Carlini
[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.carl...@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(CTrue2, False()));

it doesn't compile at all because:

noexcept_PR50043.C:21:8: error: looser throw specifier for ‘virtual 
CTrue2, 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.



Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-26 Thread Jason Merrill

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(CTrue2, False()));

it doesn't compile at all because:

noexcept_PR50043.C:21:8: error: looser throw specifier for ‘virtual
CTrue2, 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



Re: [C++ RFC / Patch] Implementing Deducing noexcept for destructors

2012-03-26 Thread Paolo Carlini

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.