https://gcc.gnu.org/g:f31b72b75ef7cde61469c774162db7b1cc4c3d03
commit r15-4959-gf31b72b75ef7cde61469c774162db7b1cc4c3d03 Author: Simon Martin <si...@nasilyan.com> Date: Tue Nov 5 10:44:34 2024 +0100 c++: Fix crash during NRV optimization with invalid input [PR117099, PR117129] PR117099 and PR117129 are ICEs upon invalid code that happen when NRVO is activated, and both due to the fact that we don't consistently set current_function_return_value to error_mark_node upon error in finish_return_expr. This patch fixes this inconsistency which fixes both cases since we skip calling finalize_nrv when current_function_return_value is error_mark_node. PR c++/117099 PR c++/117129 gcc/cp/ChangeLog: * typeck.cc (check_return_expr): Upon error, set current_function_return_value to error_mark_node. gcc/testsuite/ChangeLog: * g++.dg/parse/crash78.C: New test. * g++.dg/parse/crash78a.C: New test. * g++.dg/parse/crash79.C: New test. Diff: --- gcc/cp/typeck.cc | 8 +++++++- gcc/testsuite/g++.dg/parse/crash78.C | 15 +++++++++++++++ gcc/testsuite/g++.dg/parse/crash78a.C | 22 ++++++++++++++++++++++ gcc/testsuite/g++.dg/parse/crash79.C | 15 +++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 439681216bed..4c15e26f692a 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -11239,6 +11239,8 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling) "function returning %qT", valtype); /* Remember that this function did return. */ current_function_returns_value = 1; + /* But suppress NRV .*/ + current_function_return_value = error_mark_node; /* And signal caller that TREE_NO_WARNING should be set on the RETURN_EXPR to avoid control reaches end of non-void function warnings in tree-cfg.cc. */ @@ -11449,7 +11451,11 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling) /* If the conversion failed, treat this just like `return;'. */ if (retval == error_mark_node) - return retval; + { + /* And suppress NRV. */ + current_function_return_value = error_mark_node; + return retval; + } /* We can't initialize a register from a AGGR_INIT_EXPR. */ else if (! cfun->returns_struct && TREE_CODE (retval) == TARGET_EXPR diff --git a/gcc/testsuite/g++.dg/parse/crash78.C b/gcc/testsuite/g++.dg/parse/crash78.C new file mode 100644 index 000000000000..f30fe08df54b --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/crash78.C @@ -0,0 +1,15 @@ +// PR c++/117099 +// { dg-do "compile" } + +struct X { + ~X(); +}; + +X test(bool b) { + { + X x; + return x; + } + return X(); + if (!(b)) return; // { dg-error "return-statement with no value" } +} diff --git a/gcc/testsuite/g++.dg/parse/crash78a.C b/gcc/testsuite/g++.dg/parse/crash78a.C new file mode 100644 index 000000000000..241a5e390dee --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/crash78a.C @@ -0,0 +1,22 @@ +// PR c++/117099 +// With -fpermissive, make sure we don't do NRV in this case, but keep +// executing fine. Note that the return at line 16 is undefined behaviour. +// { dg-do "run" } +// { dg-options "-fpermissive" } + +struct X { + ~X() {} +}; + +X test(bool b) { + X x; + if (b) + return x; + else + return; // { dg-warning "return-statement with no value" } +} + +int main(int, char*[]) { + (void) test (false); + return 0; +} diff --git a/gcc/testsuite/g++.dg/parse/crash79.C b/gcc/testsuite/g++.dg/parse/crash79.C new file mode 100644 index 000000000000..08d62af39c62 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/crash79.C @@ -0,0 +1,15 @@ +// PR c++/117129 +// { dg-do "compile" { target c++11 } } + +struct Noncopyable { + Noncopyable(); + Noncopyable(const Noncopyable &) = delete; // { dg-note "declared here" } + virtual ~Noncopyable(); +}; +Noncopyable nrvo() { + { + Noncopyable A; + return A; // { dg-error "use of deleted function" } + // { dg-note "display considered" "" { target *-*-* } .-1 } + } +}