From 26a68e922133b84155aaf38562e231a4a1989aa7 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 19 Dec 2019 09:07:22 -0500 Subject: [PATCH] PR c++/52320 - EH cleanups for partially constructed arrays. This testcase wasn't fixed by the 66139 patch; split_nonconstant_init_1 was failing to add a cleanup for an array member of a class (e.g. e1) that will run if initializing a later member (e.g. e2) throws. * typeck2.c (split_nonconstant_init_1): Add nested parm. Add cleanup for whole array if true. From-SVN: r279577 --- gcc/cp/ChangeLog | 4 ++ gcc/cp/typeck2.c | 12 ++++-- gcc/testsuite/g++.dg/eh/aggregate1.C | 56 ++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/eh/aggregate1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b2d0c3bcc70..40c86210043 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2019-12-19 Jason Merrill + PR c++/52320 - EH cleanups for partially constructed arrays. + * typeck2.c (split_nonconstant_init_1): Add nested parm. + Add cleanup for whole array if true. + PR c++/66139 - EH cleanups for partially constructed aggregates. PR c++/57510 * cp-gimplify.c (cp_gimplify_init_expr): Use split_nonconstant_init. diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 0e7766a1f3d..def81b5b7ae 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -602,7 +602,7 @@ cxx_incomplete_type_error (location_t loc, const_tree value, const_tree type) generated statements. */ static bool -split_nonconstant_init_1 (tree dest, tree init) +split_nonconstant_init_1 (tree dest, tree init, bool nested) { unsigned HOST_WIDE_INT idx, tidx = HOST_WIDE_INT_M1U; tree field_index, value; @@ -626,6 +626,12 @@ split_nonconstant_init_1 (tree dest, tree init) tree code = build_vec_init (dest, NULL_TREE, init, false, 1, tf_warning_or_error); add_stmt (code); + if (nested) + /* Also clean up the whole array if something later in an enclosing + init-list throws. */ + if (tree cleanup = cxx_maybe_build_cleanup (dest, + tf_warning_or_error)) + finish_eh_cleanup (cleanup); return true; } /* FALLTHRU */ @@ -655,7 +661,7 @@ split_nonconstant_init_1 (tree dest, tree init) sub = build3 (COMPONENT_REF, inner_type, dest, field_index, NULL_TREE); - if (!split_nonconstant_init_1 (sub, value)) + if (!split_nonconstant_init_1 (sub, value, true)) complete_p = false; else { @@ -775,7 +781,7 @@ split_nonconstant_init (tree dest, tree init) { init = cp_fully_fold_init (init); code = push_stmt_list (); - if (split_nonconstant_init_1 (dest, init)) + if (split_nonconstant_init_1 (dest, init, false)) init = NULL_TREE; code = pop_stmt_list (code); if (VAR_P (dest) && !is_local_temp (dest)) diff --git a/gcc/testsuite/g++.dg/eh/aggregate1.C b/gcc/testsuite/g++.dg/eh/aggregate1.C new file mode 100644 index 00000000000..38dba89138c --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/aggregate1.C @@ -0,0 +1,56 @@ +// PR c++/52320 +// { dg-do run } + +#if DEBUG +extern "C" int printf (const char *, ...); +#define FUNCTION_NAME __PRETTY_FUNCTION__ +#define TRACE_FUNCTION printf ("%p->%s\n", this, FUNCTION_NAME); +#else +#define TRACE_FUNCTION +#endif +int c,d; +#define TRACE_CTOR TRACE_FUNCTION ++c +#define TRACE_DTOR TRACE_FUNCTION ++d + +int throw_at = 0; + +struct A { + A() { int i = c+1; if (i == throw_at) throw i; TRACE_CTOR; } + A(int i) { if (i == throw_at) throw i; TRACE_CTOR; } + A(const A&) { throw 10; } + A &operator=(const A&) { throw 11; return *this; } + ~A() { TRACE_DTOR; } +}; + +int fails; + +void try_idx (int i) +{ +#if DEBUG + printf ("trying %d\n", i); +#endif + throw_at = i; + c = d = 0; + int t = 10; + try { + struct X { + A e1[2], e2; + } + x2[3] = { { 1, 2, 3 }, { 4, 5, 6 } }; + } catch (int x) { t = x; } + if (t != i || c != d || c != i-1) + { +#if DEBUG + printf ("%d FAIL\n", i); +#endif + ++fails; + } +} + +int main() +{ + for (int i = 1; i <= 10; ++i) + try_idx (i); + + return fails; +} -- 2.30.2