From 2ee63d048eaee3c830c944970b1ad950bffc75b4 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 6 Dec 2019 21:16:27 +0100 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 14 ++++ gcc/cp/call.c | 78 +++++++++++++++++++---- gcc/cp/cp-tree.h | 4 +- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.dg/cpp0x/temp-extend2.C | 36 +++++++++++ 5 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/temp-extend2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5b0f3cd81f2..3ee98a43f83 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2019-12-06 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. + 2019-12-06 Richard Sandiford * decl.c (start_decl_1): Use verify_type_context to check whether diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 92d3d688f0c..af36f5f919e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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 **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 **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 **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 **cleanups) +extend_ref_init_temps_1 (tree decl, tree init, vec **cleanups, + tree *cond_guard) { tree sub = init; tree *p; @@ -12150,20 +12169,52 @@ extend_ref_init_temps_1 (tree decl, tree init, vec **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 **cleanups) lifetime to match that of DECL. */ tree -extend_ref_init_temps (tree decl, tree init, vec **cleanups) +extend_ref_init_temps (tree decl, tree init, vec **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 **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 **cleanups) constructor_elt *p; vec *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)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a392be6b24f..d7df6d91dae 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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**); +extern tree extend_ref_init_temps (tree, tree, + vec**, + 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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 360d1a9823c..fba5f81b50b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-12-06 Jakub Jelinek + + PR c++/92831 - CWG 1299, not extending temporary lifetime for ?: + * g++.dg/cpp0x/temp-extend2.C: New test. + 2019-12-06 Andreas Krebbel Vladimir Makarov diff --git a/gcc/testsuite/g++.dg/cpp0x/temp-extend2.C b/gcc/testsuite/g++.dg/cpp0x/temp-extend2.C new file mode 100644 index 00000000000..0b904e3ffbc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/temp-extend2.C @@ -0,0 +1,36 @@ +// PR c++/92831 +// { dg-do run { target c++11 } } + +template 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{1, 2, 3}[i]; + // temporary S has same lifetime as b + const S& b = static_cast(0); + // exactly one of the four temporaries is lifetime-extended + S&& c = cond ? cond2 ? id{1, 2, 3}[i] : static_cast(0) + : cond2 ? id{1, 2, 3, 4}[i] : id{1, 2, 3, 4, 5}[i]; + bar (cond, cond2); +} + +int +main () +{ + foo (true, true); + foo (true, false); + foo (false, true); + foo (false, false); +} -- 2.30.2