aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2023-06-05 23:58:32 -0400
committerJason Merrill <jason@redhat.com>2023-06-06 21:30:00 -0400
commit0fa9495553e0e0f4ceb764880b5bdd8ade197382 (patch)
treeaca36cafd1f8dd500890baac785a45898ff9715d /gcc/cp
parent4fe84e2a4c0b600d2bc01f171b3b9dd1f4357208 (diff)
downloadgcc-0fa9495553e0e0f4ceb764880b5bdd8ade197382.zip
gcc-0fa9495553e0e0f4ceb764880b5bdd8ade197382.tar.gz
gcc-0fa9495553e0e0f4ceb764880b5bdd8ade197382.tar.bz2
c++: fix contracts with NRV
The NRV implementation was blindly replacing the operand of RETURN_EXPR, clobbering anything that check_return_expr might have added on to the actual initialization, such as checking the postcondition. gcc/cp/ChangeLog: * semantics.cc (finalize_nrv_r): [RETURN_EXPR]: Only replace the INIT_EXPR. gcc/testsuite/ChangeLog: * g++.dg/contracts/contracts-post7.C: New test.
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/semantics.cc12
1 files changed, 10 insertions, 2 deletions
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c045146..c94ea09 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4940,9 +4940,17 @@ finalize_nrv_r (tree* tp, int* walk_subtrees, void* data)
*walk_subtrees = 0;
/* Change all returns to just refer to the RESULT_DECL; this is a nop,
but differs from using NULL_TREE in that it indicates that we care
- about the value of the RESULT_DECL. */
+ about the value of the RESULT_DECL. But preserve anything appended
+ by check_return_expr. */
else if (TREE_CODE (*tp) == RETURN_EXPR)
- TREE_OPERAND (*tp, 0) = dp->result;
+ {
+ tree *p = &TREE_OPERAND (*tp, 0);
+ while (TREE_CODE (*p) == COMPOUND_EXPR)
+ p = &TREE_OPERAND (*p, 0);
+ gcc_checking_assert (TREE_CODE (*p) == INIT_EXPR
+ && TREE_OPERAND (*p, 0) == dp->result);
+ *p = dp->result;
+ }
/* Change all cleanups for the NRV to only run when an exception is
thrown. */
else if (TREE_CODE (*tp) == CLEANUP_STMT