@@ -8411,6 +8411,7 @@ extern int abstract_virtuals_error (abstract_class_use, tree,
tsubst_flags_t = tf_warning_or_error);
extern tree store_init_value (tree, tree, vec<tree, va_gc>**, int);
+extern tree build_disable_temp_cleanup (tree);
extern tree split_nonconstant_init (tree, tree);
extern bool check_narrowing (tree, tree, tsubst_flags_t,
bool = false);
@@ -1063,11 +1063,11 @@ any_non_eliding_target_exprs (tree ctor)
the result. */
static void
-cp_genericize_init (tree *replace, tree from, tree to)
+cp_genericize_init (tree *replace, tree from, tree to, vec<tree,va_gc>** flags)
{
tree init = NULL_TREE;
if (TREE_CODE (from) == VEC_INIT_EXPR)
- init = expand_vec_init_expr (to, from, tf_warning_or_error);
+ init = expand_vec_init_expr (to, from, tf_warning_or_error, flags);
else if (TREE_CODE (from) == CONSTRUCTOR
&& TREE_SIDE_EFFECTS (from)
&& ((flag_exceptions
@@ -1101,7 +1101,7 @@ cp_genericize_init_expr (tree *stmt_p)
/* Return gets confused if we clobber its INIT_EXPR this soon. */
&& TREE_CODE (to) != RESULT_DECL)
from = TARGET_EXPR_INITIAL (from);
- cp_genericize_init (stmt_p, from, to);
+ cp_genericize_init (stmt_p, from, to, nullptr);
}
/* For a TARGET_EXPR, change the TARGET_EXPR_INITIAL. We will need to use
@@ -1112,9 +1112,19 @@ cp_genericize_target_expr (tree *stmt_p)
{
iloc_sentinel ils = EXPR_LOCATION (*stmt_p);
tree slot = TARGET_EXPR_SLOT (*stmt_p);
+ vec<tree, va_gc> *flags = make_tree_vector ();
cp_genericize_init (&TARGET_EXPR_INITIAL (*stmt_p),
- TARGET_EXPR_INITIAL (*stmt_p), slot);
+ TARGET_EXPR_INITIAL (*stmt_p), slot, &flags);
gcc_assert (!DECL_INITIAL (slot));
+ for (tree f : flags)
+ {
+ /* Once initialization is complete TARGET_EXPR_CLEANUP becomes active, so
+ disable any subobject cleanups. */
+ tree d = build_disable_temp_cleanup (f);
+ auto &r = TARGET_EXPR_INITIAL (*stmt_p);
+ r = add_stmt_to_compound (r, d);
+ }
+ release_tree_vector (flags);
}
/* Similar to if (target_expr_needs_replace) replace_decl, but TP is the
@@ -466,6 +466,25 @@ maybe_push_temp_cleanup (tree sub, vec<tree,va_gc> **flags)
}
}
+/* F is something added to a cleanup flags vec by maybe_push_temp_cleanup or
+ build_vec_init. Return the code to disable the cleanup it controls. */
+
+tree
+build_disable_temp_cleanup (tree f)
+{
+ tree d = f;
+ tree i = boolean_false_node;
+ if (TREE_CODE (f) == TREE_LIST)
+ {
+ /* To disable a build_vec_init cleanup, set
+ iterator = maxindex. */
+ d = TREE_PURPOSE (f);
+ i = TREE_VALUE (f);
+ ggc_free (f);
+ }
+ return build2 (MODIFY_EXPR, TREE_TYPE (d), d, i);
+}
+
/* The recursive part of split_nonconstant_init. DEST is an lvalue
expression to which INIT should be assigned. INIT is a CONSTRUCTOR.
Return true if the whole of the value was initialized by the
@@ -737,20 +756,7 @@ split_nonconstant_init (tree dest, tree init)
init = NULL_TREE;
for (tree f : flags)
- {
- /* See maybe_push_temp_cleanup. */
- tree d = f;
- tree i = boolean_false_node;
- if (TREE_CODE (f) == TREE_LIST)
- {
- /* To disable a build_vec_init cleanup, set
- iterator = maxindex. */
- d = TREE_PURPOSE (f);
- i = TREE_VALUE (f);
- ggc_free (f);
- }
- add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (d), d, i));
- }
+ add_stmt (build_disable_temp_cleanup (f));
release_tree_vector (flags);
code = pop_stmt_list (code);
new file mode 100644
@@ -0,0 +1,25 @@
+// { dg-do run { target c++11 } }
+
+#include <initializer_list>
+
+int as;
+struct A {
+ A(const char *) { ++as; }
+ A(const A&) { ++as; }
+ ~A() { --as; }
+};
+
+void __attribute__((noipa))
+tata(std::initializer_list<A> init)
+{
+ throw 1;
+}
+
+int
+main()
+{
+ try { tata({ "foo","bar" }); }
+ catch (...) { }
+
+ if (as != 0) __builtin_abort ();
+}