init = add_stmt_to_compound (init, register_dtor_fn (var));
else
{
+ /* ??? Instead of rebuilding the cleanup, we could replace the slot
+ with var in TARGET_EXPR_CLEANUP (expr). */
tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
if (cleanup)
{
cleanup = build3 (COND_EXPR, void_type_node,
*cond_guard, cleanup, NULL_TREE);
}
+ if (flag_exceptions && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
+ {
+ /* The normal cleanup for this extended variable isn't pushed
+ until cp_finish_decl, so we need to retain a TARGET_EXPR
+ to clean it up in case a later initializer throws
+ (g++.dg/eh/ref-temp3.C).
+
+ We don't do this for array temporaries because they have
+ the array cleanup region from build_vec_init.
+
+ Unlike maybe_push_temp_cleanup, we don't actually need a
+ flag, but a TARGET_EXPR needs a TARGET_EXPR_SLOT.
+ Perhaps this could use WITH_CLEANUP_EXPR instead, but
+ gimplify.cc doesn't handle that, and front-end handling
+ was removed in r8-1725 and r8-1818.
+
+ Alternately it might be preferable to flatten an
+ initialization with extended temps into a sequence of
+ (non-full-expression) statements, so we could immediately
+ push_cleanup here for only a single cleanup region, but we
+ don't have a mechanism for that in the front-end, only the
+ gimplifier. */
+ tree targ = get_internal_target_expr (boolean_true_node);
+ TARGET_EXPR_CLEANUP (targ) = cleanup;
+ CLEANUP_EH_ONLY (targ) = true;
+ /* Don't actually initialize the bool. */
+ init = (!init ? void_node
+ : convert_to_void (init, ICV_STATEMENT, tf_none));
+ TARGET_EXPR_INITIAL (targ) = init;
+ init = targ;
+ }
vec_safe_push (*cleanups, cleanup);
}
}
TREE_CODE (*p) == COMPONENT_REF || TREE_CODE (*p) == ARRAY_REF; )
p = &TREE_OPERAND (*p, 0);
- if (TREE_CODE (*p) == TARGET_EXPR)
+ if (TREE_CODE (*p) == TARGET_EXPR
+ /* An eliding TARGET_EXPR isn't a temporary at all. */
+ && !TARGET_EXPR_ELIDING_P (*p)
+ /* A TARGET_EXPR with CLEANUP_EH_ONLY is an artificial variable used
+ during initialization, and need not be extended. */
+ && !CLEANUP_EH_ONLY (*p))
{
tree subinit = NULL_TREE;
tree slot = TARGET_EXPR_SLOT (*p);
extern tree build_aggr_init_expr (tree, tree);
extern tree get_target_expr (tree,
tsubst_flags_t = tf_warning_or_error);
+extern tree get_internal_target_expr (tree);
extern tree build_cplus_array_type (tree, tree, int is_dep = -1);
extern tree build_array_of_n_type (tree, unsigned HOST_WIDE_INT);
extern bool array_of_runtime_bound_p (tree);
/* Wrap that value into a TARGET_EXPR, emit it right
away and save for later uses in the cp_parse_condition
or its instantiation. */
- cond = get_target_expr (cond);
+ cond = get_internal_target_expr (cond);
add_stmt (cond);
DECL_DECOMP_BASE (decl) = cond;
}
inner_if_stmt);
inner_then_clause = begin_compound_stmt (BCS_NO_SCOPE);
- begin = get_target_expr (boolean_false_node);
+ begin = get_internal_target_expr (boolean_false_node);
flag = TARGET_EXPR_SLOT (begin);
TARGET_EXPR_CLEANUP (begin)
allocate_expr = do_allocate_exception (temp_type);
if (allocate_expr == error_mark_node)
return error_mark_node;
- allocate_expr = get_target_expr (allocate_expr);
+ allocate_expr = get_internal_target_expr (allocate_expr);
ptr = TARGET_EXPR_SLOT (allocate_expr);
TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr);
CLEANUP_EH_ONLY (allocate_expr) = 1;
&& (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (TREE_TYPE (placement)))
|| VOID_TYPE_P (TREE_TYPE (TREE_TYPE (placement)))))
{
- placement_expr = get_target_expr (placement_first);
+ placement_expr = get_internal_target_expr (placement_first);
CALL_EXPR_ARG (alloc_call, 1)
= fold_convert (TREE_TYPE (placement), placement_expr);
}
/* Store the result of the allocation call in a variable so that we can
use it more than once. */
- alloc_expr = get_target_expr (alloc_expr);
+ alloc_expr = get_internal_target_expr (alloc_expr);
alloc_node = TARGET_EXPR_SLOT (alloc_expr);
/* Strip any COMPOUND_EXPRs from ALLOC_CALL. */
{
tree end, sentry, begin;
- begin = get_target_expr (boolean_true_node);
+ begin = get_internal_target_expr (boolean_true_node);
sentry = TARGET_EXPR_SLOT (begin);
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
rval = get_temp_regvar (ptype, base);
base = get_temp_regvar (ptype, rval);
- tree iterator_targ = get_target_expr (maxindex);
+ tree iterator_targ = get_internal_target_expr (maxindex);
add_stmt (iterator_targ);
iterator = TARGET_EXPR_SLOT (iterator_targ);
if (deleting)
/* We will use ADDR multiple times so we must save it. */
{
- addr_expr = get_target_expr (addr);
+ addr_expr = get_internal_target_expr (addr);
addr = TARGET_EXPR_SLOT (addr_expr);
}
delete'. */
else if (use_global_delete)
{
- head = get_target_expr (build_headof (addr));
+ head = get_internal_target_expr (build_headof (addr));
/* Delete the object. */
do_delete = build_op_delete_call (DELETE_EXPR,
head,
base = mark_rvalue_use (base);
if (TREE_SIDE_EFFECTS (base))
{
- base_init = get_target_expr (base);
+ base_init = get_internal_target_expr (base);
base = TARGET_EXPR_SLOT (base_init);
}
type = strip_array_types (TREE_TYPE (type));
return error_mark_node;
if (TREE_SIDE_EFFECTS (base))
{
- base_init = get_target_expr (base);
+ base_init = get_internal_target_expr (base);
base = TARGET_EXPR_SLOT (base_init);
}
}
}
}
+/* Like get_target_expr, but for an internal detail like a cleanup flag or loop
+ iterator. These variables should not be extended by extend_all_temps.
+
+ This function can also be used for an ephemeral copy of a scalar value such
+ as the pointer to the allocated memory in build_new_1.
+
+ This function should not be used for objects that are part of the abstract
+ C++ semantics such as in stabilize_expr. */
+
+tree
+get_internal_target_expr (tree init)
+{
+ init = convert_bitfield_to_declared_type (init);
+ tree t = build_target_expr_with_type (init, TREE_TYPE (init),
+ tf_warning_or_error);
+ /* No internal variable should have a cleanup on the normal path, and
+ extend_temps_r checks this flag to decide whether to extend. */
+ CLEANUP_EH_ONLY (t) = true;
+ return t;
+}
+
/* If EXPR is a bitfield reference, convert it to the declared type of
the bitfield, and return the resulting expression. Otherwise,
return EXPR itself. */
if (tree cleanup
= cxx_maybe_build_cleanup (sub, tf_warning_or_error))
{
- tree tx = get_target_expr (boolean_true_node);
+ tree tx = get_internal_target_expr (boolean_true_node);
tree flag = TARGET_EXPR_SLOT (tx);
CLEANUP_EH_ONLY (tx) = true;
TARGET_EXPR_CLEANUP (tx) = build3 (COND_EXPR, void_type_node,
--- /dev/null
+// { dg-do run }
+
+extern "C" void abort();
+
+int a;
+
+struct A {
+ A()
+ {
+ if (a == 1)
+ throw 42;
+ ++a;
+ }
+ ~A()
+ {
+ --a;
+ }
+};
+
+struct B {
+ const A &a1;
+ const A &a2;
+};
+
+void f();
+
+int main()
+{
+ try
+ {
+ B b = { A(), A() };
+ }
+ catch (...) { }
+ if (a != 0)
+ abort ();
+}
--- /dev/null
+// PR c++/118856
+// { dg-do run { target c++11 } }
+// { dg-additional-options -O2 }
+
+int a, b, c, d;
+struct A { A () { ++a; ++d; }; ~A () { --a; ++d; }; };
+struct B { B (const A & = A {}) { ++b; ++d; }; ~B () { --b; ++d; }; };
+struct C {
+ C (const B &, const A & = A {}) { ++c; ++d; throw 42; };
+ ~C () { --c; ++d; };
+ int *begin () { return nullptr; };
+ int *end () { return nullptr; };
+};
+
+void
+foo ()
+{
+ for (auto &i : C { B {} })
+ ;
+}
+
+int
+main ()
+{
+ try
+ {
+ foo ();
+ __builtin_abort ();
+ }
+ catch (int x)
+ {
+ if (x != 42 || a || b || c != 1 || d != 7)
+ __builtin_abort ();
+ }
+}