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.
This commit is contained in:
Simon Martin 2024-11-05 10:44:34 +01:00
parent 5821f5c8c8
commit f31b72b75e
4 changed files with 59 additions and 1 deletions

View file

@ -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

View file

@ -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" }
}

View file

@ -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;
}

View file

@ -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 }
}
}