* [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).