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.

Tested x86_64-pc-linux-gnu, applying to trunk.

        * typeck2.c (split_nonconstant_init_1): Add nested parm.
        Add cleanup for whole array if true.
---
 gcc/cp/typeck2.c                     | 12 ++++--
 gcc/testsuite/g++.dg/eh/aggregate1.C | 56 ++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/eh/aggregate1.C

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.18.1

Reply via email to