https://github.com/gcc-mirror/gcc/commit/59693b226e245aeb991ab2275a9c37d35da1191b.patch https://bugs.gentoo.org/701866 From 59693b226e245aeb991ab2275a9c37d35da1191b Mon Sep 17 00:00:00 2001 From: jakub Date: Fri, 20 Dec 2019 17:37:45 +0000 Subject: [PATCH] Backported from mainline 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. * g++.dg/cpp0x/temp-extend2.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-9-branch@279669 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/call.c | 83 +++++++++++++++++++---- gcc/cp/cp-tree.h | 4 +- gcc/testsuite/g++.dg/cpp0x/temp-extend2.C | 36 ++++++++++ 5 files changed, 129 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/temp-extend2.C --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -11449,7 +11449,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; @@ -11480,7 +11480,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; @@ -11521,7 +11522,29 @@ 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_decl (input_location, VAR_DECL, + NULL_TREE, boolean_type_node); + DECL_ARTIFICIAL (*cond_guard) = 1; + DECL_IGNORED_P (*cond_guard) = 1; + DECL_CONTEXT (*cond_guard) = current_function_decl; + layout_decl (*cond_guard, 0); + 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 @@ -11626,7 +11649,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; @@ -11634,20 +11658,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); @@ -11662,13 +11718,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; @@ -11681,7 +11738,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 @@ -11690,7 +11748,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)) --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6229,7 +6229,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); --- /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); +}