Commit 2ee63d04 by Jakub Jelinek Committed by Jakub Jelinek

PR c++/92831 - CWG 1299, not extending temporary lifetime for ?:

	* cp-tree.h (extend_ref_init_temps): Add a new argument with NULL
	default arg.
	* call.c (set_up_extended_ref_temp): Add COND_GUARD argument, pass it
	down to extend_ref_init_temps.  Before pushing cleanup, if COND_GUARD
	is non-NULL, create a bool temporary if needed, initialize to false
	and guard the cleanup with the temporary being true.
	(extend_ref_init_temps_1): Add COND_GUARD argument, pass it down
	to recursive calls and set_up_extended_ref_temp.  Handle COND_EXPR.
	(extend_ref_init_temps): Add COND_GUARD argument, pass it down to
	recursive calls and to extend_ref_init_temps_1.

	* g++.dg/cpp0x/temp-extend2.C: New test.

From-SVN: r279064
parent eff6af8e
2019-12-06 Jakub Jelinek <jakub@redhat.com>
PR c++/92831 - CWG 1299, not extending temporary lifetime for ?:
* cp-tree.h (extend_ref_init_temps): Add a new argument with NULL
default arg.
* call.c (set_up_extended_ref_temp): Add COND_GUARD argument, pass it
down to extend_ref_init_temps. Before pushing cleanup, if COND_GUARD
is non-NULL, create a bool temporary if needed, initialize to false
and guard the cleanup with the temporary being true.
(extend_ref_init_temps_1): Add COND_GUARD argument, pass it down
to recursive calls and set_up_extended_ref_temp. Handle COND_EXPR.
(extend_ref_init_temps): Add COND_GUARD argument, pass it down to
recursive calls and to extend_ref_init_temps_1.
2019-12-06 Richard Sandiford <richard.sandiford@arm.com>
* decl.c (start_decl_1): Use verify_type_context to check whether
......
......@@ -11965,7 +11965,7 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type)
static tree
set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
tree *initp)
tree *initp, tree *cond_guard)
{
tree init;
tree type;
......@@ -11996,7 +11996,8 @@ set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
/* Recursively extend temps in this initializer. */
TARGET_EXPR_INITIAL (expr)
= extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups);
= extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups,
cond_guard);
/* Any reference temp has a non-trivial initializer. */
DECL_NONTRIVIALLY_INITIALIZED_P (var) = true;
......@@ -12037,7 +12038,24 @@ set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
{
tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
if (cleanup)
vec_safe_push (*cleanups, cleanup);
{
if (cond_guard && cleanup != error_mark_node)
{
if (*cond_guard == NULL_TREE)
{
*cond_guard = build_local_temp (boolean_type_node);
add_decl_expr (*cond_guard);
tree set = cp_build_modify_expr (UNKNOWN_LOCATION,
*cond_guard, NOP_EXPR,
boolean_false_node,
tf_warning_or_error);
finish_expr_stmt (set);
}
cleanup = build3 (COND_EXPR, void_type_node,
*cond_guard, cleanup, NULL_TREE);
}
vec_safe_push (*cleanups, cleanup);
}
}
/* We must be careful to destroy the temporary only
......@@ -12142,7 +12160,8 @@ initialize_reference (tree type, tree expr,
which is bound either to a reference or a std::initializer_list. */
static tree
extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups)
extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups,
tree *cond_guard)
{
tree sub = init;
tree *p;
......@@ -12150,20 +12169,52 @@ extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups)
if (TREE_CODE (sub) == COMPOUND_EXPR)
{
TREE_OPERAND (sub, 1)
= extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups);
= extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups,
cond_guard);
return init;
}
if (TREE_CODE (sub) == COND_EXPR)
{
tree cur_cond_guard = NULL_TREE;
if (TREE_OPERAND (sub, 1))
TREE_OPERAND (sub, 1)
= extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups,
&cur_cond_guard);
if (cur_cond_guard)
{
tree set = cp_build_modify_expr (UNKNOWN_LOCATION, cur_cond_guard,
NOP_EXPR, boolean_true_node,
tf_warning_or_error);
TREE_OPERAND (sub, 1)
= cp_build_compound_expr (set, TREE_OPERAND (sub, 1),
tf_warning_or_error);
}
cur_cond_guard = NULL_TREE;
if (TREE_OPERAND (sub, 2))
TREE_OPERAND (sub, 2)
= extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 2), cleanups,
&cur_cond_guard);
if (cur_cond_guard)
{
tree set = cp_build_modify_expr (UNKNOWN_LOCATION, cur_cond_guard,
NOP_EXPR, boolean_true_node,
tf_warning_or_error);
TREE_OPERAND (sub, 2)
= cp_build_compound_expr (set, TREE_OPERAND (sub, 2),
tf_warning_or_error);
}
return init;
}
if (TREE_CODE (sub) != ADDR_EXPR)
return init;
/* Deal with binding to a subobject. */
for (p = &TREE_OPERAND (sub, 0);
(TREE_CODE (*p) == COMPONENT_REF
|| TREE_CODE (*p) == ARRAY_REF); )
TREE_CODE (*p) == COMPONENT_REF || TREE_CODE (*p) == ARRAY_REF; )
p = &TREE_OPERAND (*p, 0);
if (TREE_CODE (*p) == TARGET_EXPR)
{
tree subinit = NULL_TREE;
*p = set_up_extended_ref_temp (decl, *p, cleanups, &subinit);
*p = set_up_extended_ref_temp (decl, *p, cleanups, &subinit, cond_guard);
recompute_tree_invariant_for_addr_expr (sub);
if (init != sub)
init = fold_convert (TREE_TYPE (init), sub);
......@@ -12178,13 +12229,14 @@ extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups)
lifetime to match that of DECL. */
tree
extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups)
extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups,
tree *cond_guard)
{
tree type = TREE_TYPE (init);
if (processing_template_decl)
return init;
if (TYPE_REF_P (type))
init = extend_ref_init_temps_1 (decl, init, cleanups);
init = extend_ref_init_temps_1 (decl, init, cleanups, cond_guard);
else
{
tree ctor = init;
......@@ -12203,7 +12255,8 @@ extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups)
/* The temporary array underlying a std::initializer_list
is handled like a reference temporary. */
tree array = CONSTRUCTOR_ELT (ctor, 0)->value;
array = extend_ref_init_temps_1 (decl, array, cleanups);
array = extend_ref_init_temps_1 (decl, array, cleanups,
cond_guard);
CONSTRUCTOR_ELT (ctor, 0)->value = array;
}
else
......@@ -12212,7 +12265,8 @@ extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups)
constructor_elt *p;
vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor);
FOR_EACH_VEC_SAFE_ELT (elts, i, p)
p->value = extend_ref_init_temps (decl, p->value, cleanups);
p->value = extend_ref_init_temps (decl, p->value, cleanups,
cond_guard);
}
recompute_constructor_flags (ctor);
if (decl_maybe_constant_var_p (decl) && TREE_CONSTANT (ctor))
......
......@@ -6321,7 +6321,9 @@ extern tree convert_for_arg_passing (tree, tree, tsubst_flags_t);
extern bool is_properly_derived_from (tree, tree);
extern tree initialize_reference (tree, tree, int,
tsubst_flags_t);
extern tree extend_ref_init_temps (tree, tree, vec<tree, va_gc>**);
extern tree extend_ref_init_temps (tree, tree,
vec<tree, va_gc>**,
tree * = NULL);
extern tree make_temporary_var_for_ref_to_temp (tree, tree);
extern bool type_has_extended_temps (tree);
extern tree strip_top_quals (tree);
......
2019-12-06 Jakub Jelinek <jakub@redhat.com>
PR c++/92831 - CWG 1299, not extending temporary lifetime for ?:
* g++.dg/cpp0x/temp-extend2.C: New test.
2019-12-06 Andreas Krebbel <krebbel@linux.ibm.com>
Vladimir Makarov <vmakarov@redhat.com>
......
// PR c++/92831
// { dg-do run { target c++11 } }
template<typename T> using id = T;
struct S { S () { s++; } ~S () { s--; } S (int) { s++; } static int s; };
int S::s = 0;
void
bar (bool cond, bool cond2)
{
if (S::s != (cond ? cond2 ? 7 : 5 : cond2 ? 8 : 9))
__builtin_abort ();
}
void
foo (bool cond, bool cond2)
{
int i = 1;
// temporary array has same lifetime as a
S&& a = id<S[3]>{1, 2, 3}[i];
// temporary S has same lifetime as b
const S& b = static_cast<const S&>(0);
// exactly one of the four temporaries is lifetime-extended
S&& c = cond ? cond2 ? id<S[3]>{1, 2, 3}[i] : static_cast<S&&>(0)
: cond2 ? id<S[4]>{1, 2, 3, 4}[i] : id<S[5]>{1, 2, 3, 4, 5}[i];
bar (cond, cond2);
}
int
main ()
{
foo (true, true);
foo (true, false);
foo (false, true);
foo (false, false);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment