@@ -6321,7 +6321,9 @@ extern tree convert_for_arg_passing (tr
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);
@@ -11965,7 +11965,7 @@ make_temporary_var_for_ref_to_temp (tree
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, tre
/* 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, tre
{
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 ex
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
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
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 i
/* 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 i
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))
@@ -0,0 +1,36 @@
+// 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);
+}