From: Jakub Jelinek Date: Fri, 20 Dec 2019 17:37:45 +0000 (+0100) Subject: backport: PR c++/92831 - CWG 1299, not extending temporary lifetime for ?: X-Git-Tag: releases/gcc-9.3.0~284 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e8b31b238934483cc865dcd1c610bd0b29048cd3;p=thirdparty%2Fgcc.git backport: PR c++/92831 - CWG 1299, not extending temporary lifetime for ?: 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. From-SVN: r279669 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7b09a30d0ab2..b2e49a4da4c4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,6 +1,20 @@ 2019-12-20 Jakub Jelinek 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. + 2019-12-03 Jakub Jelinek PR c++/92732 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 8e56705d6ce1..bc182e2f6da0 100644 --- 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)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 050e4b0f3a71..f7c3eea4cdfa 100644 --- 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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index af36fed2ae28..3127761d8acc 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,11 @@ 2019-12-20 Jakub Jelinek Backported from mainline + 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-05 Jakub Jelinek PR fortran/92781 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 000000000000..0b904e3ffbcb --- /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); +}