From: jason Date: Sat, 15 May 2010 02:22:37 +0000 (+0000) Subject: C++ DR 475 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=94f22e3406cb5f51312575523bafd2c9d7b60376;p=thirdparty%2Fgcc.git C++ DR 475 * except.c (build_throw): Simplify, adjust for DR 475. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@159428 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2066fa7f13de..ce56b0d1fc6d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,8 @@ 2010-05-14 Jason Merrill + C++ DR 475 + * except.c (build_throw): Simplify, adjust for DR 475. + PR c++/44127 * except.c (dtor_nothrow): Return nonzero for type with trivial destructor. diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 74449fa8233a..48ace536c54f 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -665,8 +665,7 @@ build_throw (tree exp) tree cleanup; tree object, ptr; tree tmp; - tree temp_expr, allocate_expr; - bool elided; + tree allocate_expr; /* The CLEANUP_TYPE is the internal type of a destructor. */ if (!cleanup_type) @@ -719,11 +718,12 @@ build_throw (tree exp) allocate_expr = do_allocate_exception (temp_type); allocate_expr = get_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); + TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); + CLEANUP_EH_ONLY (allocate_expr) = 1; + object = build_nop (build_pointer_type (temp_type), ptr); object = cp_build_indirect_ref (object, RO_NULL, tf_warning_or_error); - elided = (TREE_CODE (exp) == TARGET_EXPR); - /* And initialize the exception object. */ if (CLASS_TYPE_P (temp_type)) { @@ -761,54 +761,16 @@ build_throw (tree exp) exp = build2 (INIT_EXPR, temp_type, object, tmp); } - /* Pre-evaluate the thrown expression first, since if we allocated - the space first we would have to deal with cleaning it up if - evaluating this expression throws. - - The case where EXP the initializer is a cast or a function - returning a class is a bit of a grey area in the standard; it's - unclear whether or not it should be allowed to throw. We used to - say no, as that allowed us to optimize this case without worrying - about deallocating the exception object if it does. But that - conflicted with expectations (PR 13944) and the EDG compiler; now - we wrap the initialization in a TRY_CATCH_EXPR to call - do_free_exception rather than in a MUST_NOT_THROW_EXPR, for this - case only. - - BUT: Issue 475 may do away with this inconsistency by removing the - terminate() in this situation. - - Note that we don't check the return value from stabilize_init - because it will only return false in cases where elided is true, - and therefore we don't need to work around the failure to - preevaluate. */ - temp_expr = NULL_TREE; - stabilize_init (exp, &temp_expr); - - /* Wrap the initialization in a CLEANUP_POINT_EXPR so that cleanups - for temporaries within the initialization are run before the one - for the exception object, preserving LIFO order. */ - exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); - - if (elided) - exp = build2 (TRY_CATCH_EXPR, void_type_node, exp, - do_free_exception (ptr)); - else - exp = build1 (MUST_NOT_THROW_EXPR, void_type_node, exp); + /* Mark any cleanups from the initialization as MUST_NOT_THROW, since + they are run after the exception object is initialized. */ + cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0); /* Prepend the allocation. */ exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); - if (temp_expr) - { - /* Prepend the calculation of the throw expression. Also, force - any cleanups from the expression to be evaluated here so that - we don't have to do them during unwinding. But first wrap - them in MUST_NOT_THROW_EXPR, since they are run after the - exception object is initialized. */ - cp_walk_tree_without_duplicates (&temp_expr, wrap_cleanups_r, 0); - exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), temp_expr, exp); - exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp); - } + + /* Force all the cleanups to be evaluated here so that we don't have + to do them during unwinding. */ + exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp); throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4cf711266f27..7c14d8cf5fdd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2010-05-14 Jason Merrill + + * g++.dg/eh/cond4.C: New. + * g++.dg/eh/elide2.C: Adjust. + * g++.old-deja/g++.eh/terminate1.C: Adjust. + 2010-05-14 Steven G. Kargl PR fortran/44135 diff --git a/gcc/testsuite/g++.dg/eh/cond4.C b/gcc/testsuite/g++.dg/eh/cond4.C new file mode 100644 index 000000000000..a8d1cfbf3e2a --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/cond4.C @@ -0,0 +1,32 @@ +// Runtime version of cond3.C. We call terminate when the A cleanup throws +// because we've already initialized the exception object. +// { dg-do run } + +#include +#include + +void my_terminate () +{ + std::exit (0); +} + +struct A { + A(int) { } + ~A() { throw 1; }; +}; +struct B { + B(A) { } + ~B() { } +}; +bool b; + +int main() +{ + std::set_terminate (my_terminate); + try + { + throw b ? B(1) : B(1); + } + catch (...) { } + return 1; +} diff --git a/gcc/testsuite/g++.dg/eh/elide2.C b/gcc/testsuite/g++.dg/eh/elide2.C index 618ee6f40063..7d65d9ee6abc 100644 --- a/gcc/testsuite/g++.dg/eh/elide2.C +++ b/gcc/testsuite/g++.dg/eh/elide2.C @@ -1,13 +1,10 @@ // PR c++/13944 -// Verify that we still call terminate() if we do run the copy constructor, -// and it throws. +// Verify that we don't call terminate() if initializing the exception +// object throws. // { dg-do run } -#include -#include - struct A { A() { } @@ -16,17 +13,17 @@ struct A A a; -void -good_terminate() { std::exit (0); } - int main() { - std::set_terminate (good_terminate); try { throw a; } - catch (...) + catch (int) + { + return 0; + } + catch (A&) { return 2; } diff --git a/gcc/testsuite/g++.old-deja/g++.eh/terminate1.C b/gcc/testsuite/g++.old-deja/g++.eh/terminate1.C index 09dd84f0ca21..623fb84009c9 100644 --- a/gcc/testsuite/g++.old-deja/g++.eh/terminate1.C +++ b/gcc/testsuite/g++.old-deja/g++.eh/terminate1.C @@ -1,6 +1,6 @@ -// { dg-do run } -// Test that an exception thrown out of the constructor for the exception -// object (i.e. "after completing evaluation of the expression to be thrown +// { dg-do run } +// Test that an exception thrown out of the constructor for the catch +// parameter (i.e. "after completing evaluation of the expression to be thrown // but before the exception is caught") causes us to call terminate. #include @@ -21,8 +21,7 @@ int main (void) { std::set_terminate (my_terminate); - A a; - try { throw a; } - catch (...) {} + try { throw A(); } + catch (A) {} return 1; }