Commit b33a0480 by Jason Merrill Committed by Jason Merrill

C++ DR 475

	C++ DR 475
	* except.c (build_throw): Simplify, adjust for DR 475.

From-SVN: r159428
parent 8efab4c8
2010-05-14 Jason Merrill <jason@redhat.com> 2010-05-14 Jason Merrill <jason@redhat.com>
C++ DR 475
* except.c (build_throw): Simplify, adjust for DR 475.
PR c++/44127 PR c++/44127
* except.c (dtor_nothrow): Return nonzero for type with * except.c (dtor_nothrow): Return nonzero for type with
trivial destructor. trivial destructor.
......
...@@ -665,8 +665,7 @@ build_throw (tree exp) ...@@ -665,8 +665,7 @@ build_throw (tree exp)
tree cleanup; tree cleanup;
tree object, ptr; tree object, ptr;
tree tmp; tree tmp;
tree temp_expr, allocate_expr; tree allocate_expr;
bool elided;
/* The CLEANUP_TYPE is the internal type of a destructor. */ /* The CLEANUP_TYPE is the internal type of a destructor. */
if (!cleanup_type) if (!cleanup_type)
...@@ -719,11 +718,12 @@ build_throw (tree exp) ...@@ -719,11 +718,12 @@ build_throw (tree exp)
allocate_expr = do_allocate_exception (temp_type); allocate_expr = do_allocate_exception (temp_type);
allocate_expr = get_target_expr (allocate_expr); allocate_expr = get_target_expr (allocate_expr);
ptr = TARGET_EXPR_SLOT (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 = build_nop (build_pointer_type (temp_type), ptr);
object = cp_build_indirect_ref (object, RO_NULL, tf_warning_or_error); object = cp_build_indirect_ref (object, RO_NULL, tf_warning_or_error);
elided = (TREE_CODE (exp) == TARGET_EXPR);
/* And initialize the exception object. */ /* And initialize the exception object. */
if (CLASS_TYPE_P (temp_type)) if (CLASS_TYPE_P (temp_type))
{ {
...@@ -761,54 +761,16 @@ build_throw (tree exp) ...@@ -761,54 +761,16 @@ build_throw (tree exp)
exp = build2 (INIT_EXPR, temp_type, object, tmp); exp = build2 (INIT_EXPR, temp_type, object, tmp);
} }
/* Pre-evaluate the thrown expression first, since if we allocated /* Mark any cleanups from the initialization as MUST_NOT_THROW, since
the space first we would have to deal with cleaning it up if they are run after the exception object is initialized. */
evaluating this expression throws. cp_walk_tree_without_duplicates (&exp, wrap_cleanups_r, 0);
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);
/* Prepend the allocation. */ /* Prepend the allocation. */
exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); exp = build2 (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp);
if (temp_expr)
{ /* Force all the cleanups to be evaluated here so that we don't have
/* Prepend the calculation of the throw expression. Also, force to do them during unwinding. */
any cleanups from the expression to be evaluated here so that exp = build1 (CLEANUP_POINT_EXPR, void_type_node, exp);
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);
}
throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object))); throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
......
2010-05-14 Jason Merrill <jason@redhat.com>
* 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 <kargl@gcc.gnu.org> 2010-05-14 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/44135 PR fortran/44135
......
// 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 <exception>
#include <cstdlib>
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;
}
// PR c++/13944 // PR c++/13944
// Verify that we still call terminate() if we do run the copy constructor, // Verify that we don't call terminate() if initializing the exception
// and it throws. // object throws.
// { dg-do run } // { dg-do run }
#include <cstdlib>
#include <exception>
struct A struct A
{ {
A() { } A() { }
...@@ -16,17 +13,17 @@ struct A ...@@ -16,17 +13,17 @@ struct A
A a; A a;
void
good_terminate() { std::exit (0); }
int main() int main()
{ {
std::set_terminate (good_terminate);
try try
{ {
throw a; throw a;
} }
catch (...) catch (int)
{
return 0;
}
catch (A&)
{ {
return 2; return 2;
} }
......
// { dg-do run } // { dg-do run }
// Test that an exception thrown out of the constructor for the exception // Test that an exception thrown out of the constructor for the catch
// object (i.e. "after completing evaluation of the expression to be thrown // parameter (i.e. "after completing evaluation of the expression to be thrown
// but before the exception is caught") causes us to call terminate. // but before the exception is caught") causes us to call terminate.
#include <exception> #include <exception>
...@@ -21,8 +21,7 @@ int main (void) ...@@ -21,8 +21,7 @@ int main (void)
{ {
std::set_terminate (my_terminate); std::set_terminate (my_terminate);
A a; try { throw A(); }
try { throw a; } catch (A) {}
catch (...) {}
return 1; return 1;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment