diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7e4e5497e3b9ec8eb948bb25d21a362e01ca6e39..89ea02d1935d5a2c0110745f6597e28bd51c33f9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +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 + 2012-03-29 Paolo Carlini <paolo.carlini@oracle.com> PR c++/52718 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index bc17c82c6a0308fa15c5fe80fb8794ace42b6bae..7b6559c4231ca1e03063af0f20880d8c6163ab57 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7d986a8cf735131a5f8c3620ad37921008124580..8bca1fa0b634dbf16f6a4b6b1e68a3e444dc4072 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index a89523d78f67ba71fd39ca35705826bb4e62899e..d210f199a2dc55a00f26f014b91a06e4a3f4002d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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 + diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 0d4793eb23b78fc3ae973313a819f72e48a06c5e..79bed4a053fd90e214cca52f4f755c57f758a622 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e2fa4a652820a93c44703974dadd946228231ec7..73f22f3ab4f7d41097909ff44911ce8ee1e8c32d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +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. + 2012-03-31 Eric Botcazou <ebotcazou@adacore.com> * gnat.dg/controlled6.adb: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept01.C b/gcc/testsuite/g++.dg/cpp0x/noexcept01.C index f314684eae8496088510662fe22d6eb8b8cbc0a4..b6be1ef7a3f3f71e87fa77ddaeedd51794e1ef52 100644 --- a/gcc/testsuite/g++.dg/cpp0x/noexcept01.C +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept01.C @@ -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 diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept17.C b/gcc/testsuite/g++.dg/cpp0x/noexcept17.C new file mode 100644 index 0000000000000000000000000000000000000000..82cd844c067df89b9a10cb0fa3e33535509664af --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept17.C @@ -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>())); diff --git a/gcc/testsuite/g++.dg/eh/ctor1.C b/gcc/testsuite/g++.dg/eh/ctor1.C index 43b735f0b00a5fb79c7a4a8ca82475f45128f9a6..b959d1c5620878108ebb20e86bff645bf3ce5ea3 100644 --- a/gcc/testsuite/g++.dg/eh/ctor1.C +++ b/gcc/testsuite/g++.dg/eh/ctor1.C @@ -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; } diff --git a/gcc/testsuite/g++.dg/eh/init-temp1.C b/gcc/testsuite/g++.dg/eh/init-temp1.C index 529014f497f2052ca5fc94ac035e28f3d5983463..4996cea230ff5791620b031eaa35847fb005f5cf 100644 --- a/gcc/testsuite/g++.dg/eh/init-temp1.C +++ b/gcc/testsuite/g++.dg/eh/init-temp1.C @@ -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; } diff --git a/gcc/testsuite/g++.dg/tree-ssa/ehcleanup-1.C b/gcc/testsuite/g++.dg/tree-ssa/ehcleanup-1.C index cc492a80975f97db23379638173f31ac65c73cff..0a29ce9cb4f3860013af6afa7e33e7122e7799e1 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/ehcleanup-1.C +++ b/gcc/testsuite/g++.dg/tree-ssa/ehcleanup-1.C @@ -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 (); diff --git a/gcc/testsuite/g++.old-deja/g++.eh/cleanup1.C b/gcc/testsuite/g++.old-deja/g++.eh/cleanup1.C index 16646438ed247a9595b35b3a22d40b6fae7d9cab..12f1ec7a0811e70ea210988458bd868b40938bc7 100644 --- a/gcc/testsuite/g++.old-deja/g++.eh/cleanup1.C +++ b/gcc/testsuite/g++.old-deja/g++.eh/cleanup1.C @@ -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 {