From 32bd8a1053d25cbb15172294e59a81bc134658aa Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 4 Jun 2023 12:00:55 -0400 Subject: [PATCH] c++: NRV and goto [PR92407] Here our named return value optimization was breaking the required destructor when the goto takes 'a' out of scope. A simple fix for the release branches is to disable the optimization in the presence of backward goto. We could do better by disabling the optimization only if there is a backward goto across the variable declaration, but we don't track that, and in GCC 14 we instead make the goto work with NRV. PR c++/92407 gcc/cp/ChangeLog: * cp-tree.h (struct language_function): Add backward_goto. * decl.c (check_goto): Set it. * typeck.c (check_return_expr): Prevent NRV if set. gcc/testsuite/ChangeLog: * g++.dg/opt/nrv22.C: New test. (cherry picked from commit a645347c19b07cc7abd7bf276c6769fc41afc932) --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 2 ++ gcc/cp/typeck.c | 3 +++ gcc/testsuite/g++.dg/opt/nrv22.C | 30 ++++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+) create mode 100644 gcc/testsuite/g++.dg/opt/nrv22.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8887e946d537..7e04a080f3a1 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2024,6 +2024,7 @@ struct GTY(()) language_function { BOOL_BITFIELD invalid_constexpr : 1; BOOL_BITFIELD throwing_cleanup : 1; + BOOL_BITFIELD backward_goto : 1; hash_table *x_named_labels; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 712e875edd04..52088a480fe5 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3563,6 +3563,8 @@ check_goto (tree decl) return; } + cp_function_chain->backward_goto = true; + bool saw_catch = false, complained = false; int identified = 0; tree bad; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 6e5a35202c71..61e3222c6c62 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -10307,6 +10307,9 @@ check_return_expr (tree retval, bool *no_warning) if (fn_returns_value_p && flag_elide_constructors) { if (named_return_value_okay_p + /* The current NRV implementation breaks if a backward goto needs to + destroy the object (PR92407). */ + && !cp_function_chain->backward_goto && (current_function_return_value == NULL_TREE || current_function_return_value == retval)) current_function_return_value = retval; diff --git a/gcc/testsuite/g++.dg/opt/nrv22.C b/gcc/testsuite/g++.dg/opt/nrv22.C new file mode 100644 index 000000000000..eb889fa615b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/nrv22.C @@ -0,0 +1,30 @@ +// PR c++/92407 +// { dg-do run } + +struct A +{ + A () { a++; } + A (const A &) { a++; } + ~A () { a--; } + static int a; +}; +int A::a = 0; + +A +foo () +{ + int cnt = 10; +lab: + A a; + if (cnt--) + goto lab; + return a; +} + +int +main () +{ + foo (); + if (A::a) + __builtin_abort (); +} -- 2.47.2