c++: fix array cleanup with throwing temp dtor
While working on PR66139 I noticed that if the destructor of a temporary created during array initialization throws, we were failing to destroy the last array element constructed. Throwing destructors are rare since C++11, but this should be fixed. gcc/cp/ChangeLog: * init.c (build_vec_init): Append the decrement to elt_init. gcc/testsuite/ChangeLog: * g++.dg/eh/array2.C: New test.
This commit is contained in:
parent
092e60f57a
commit
c743614e70
2 changed files with 54 additions and 6 deletions
|
@ -4665,11 +4665,13 @@ build_vec_init (tree base, tree maxindex, tree init,
|
|||
finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator,
|
||||
build_int_cst (TREE_TYPE (iterator), -1)),
|
||||
for_stmt, false, 0);
|
||||
elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, false,
|
||||
complain);
|
||||
if (elt_init == error_mark_node)
|
||||
errors = true;
|
||||
finish_for_expr (elt_init, for_stmt);
|
||||
/* We used to pass this decrement to finish_for_expr; now we add it to
|
||||
elt_init below so it's part of the same full-expression as the
|
||||
initialization, and thus happens before any potentially throwing
|
||||
temporary cleanups. */
|
||||
tree decr = cp_build_unary_op (PREDECREMENT_EXPR, iterator, false,
|
||||
complain);
|
||||
|
||||
|
||||
to = build1 (INDIRECT_REF, type, base);
|
||||
|
||||
|
@ -4794,7 +4796,10 @@ build_vec_init (tree base, tree maxindex, tree init,
|
|||
|
||||
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
|
||||
if (elt_init && !errors)
|
||||
finish_expr_stmt (elt_init);
|
||||
elt_init = build2 (COMPOUND_EXPR, void_type_node, elt_init, decr);
|
||||
else
|
||||
elt_init = decr;
|
||||
finish_expr_stmt (elt_init);
|
||||
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
|
||||
|
||||
finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, false,
|
||||
|
|
43
gcc/testsuite/g++.dg/eh/array2.C
Normal file
43
gcc/testsuite/g++.dg/eh/array2.C
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Test that we clean up the right number of array elements when
|
||||
// a temporary destructor throws.
|
||||
// { dg-do run }
|
||||
|
||||
#if __cplusplus > 201100L
|
||||
#define THROWING noexcept(false)
|
||||
#else
|
||||
#define THROWING
|
||||
#endif
|
||||
|
||||
extern "C" void abort ();
|
||||
|
||||
int b;
|
||||
int d = -1;
|
||||
struct A {
|
||||
A() { }
|
||||
A(const A&);
|
||||
~A() THROWING {
|
||||
if (b == d) throw b;
|
||||
}
|
||||
};
|
||||
struct B {
|
||||
B(const A& = A()) { ++b; }
|
||||
B(const B&);
|
||||
~B() { --b; }
|
||||
};
|
||||
void f()
|
||||
{
|
||||
b = 0;
|
||||
try
|
||||
{
|
||||
B bs[3];
|
||||
if (b != 3) abort ();
|
||||
}
|
||||
catch (int i) { }
|
||||
if (b != 0) abort ();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
for (d = 0; d <= 3; ++d)
|
||||
f();
|
||||
}
|
Loading…
Add table
Reference in a new issue