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>
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.
......
......@@ -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)));
......
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>
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
// 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 <cstdlib>
#include <exception>
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;
}
......
// { 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 <exception>
......@@ -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;
}
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