aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/typeck2.c12
-rw-r--r--gcc/testsuite/g++.dg/eh/aggregate1.C56
3 files changed, 69 insertions, 3 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b2d0c3b..40c8621 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,9 @@
2019-12-19 Jason Merrill <jason@redhat.com>
+ 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 0e7766a..def81b5 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 0000000..38dba89
--- /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;
+}