diff options
author | Jason Merrill <jason@redhat.com> | 2023-06-05 23:58:32 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2023-06-06 21:30:00 -0400 |
commit | 0fa9495553e0e0f4ceb764880b5bdd8ade197382 (patch) | |
tree | aca36cafd1f8dd500890baac785a45898ff9715d | |
parent | 4fe84e2a4c0b600d2bc01f171b3b9dd1f4357208 (diff) | |
download | gcc-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.
-rw-r--r-- | gcc/cp/semantics.cc | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/contracts/contracts-post7.C | 29 |
2 files changed, 39 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 diff --git a/gcc/testsuite/g++.dg/contracts/contracts-post7.C b/gcc/testsuite/g++.dg/contracts/contracts-post7.C new file mode 100644 index 0000000..1c33181 --- /dev/null +++ b/gcc/testsuite/g++.dg/contracts/contracts-post7.C @@ -0,0 +1,29 @@ +// { dg-do run } +// { dg-options "-std=c++2a -fcontracts" } + +#include <experimental/contract> + +using std::experimental::contract_violation; +void handle_contract_violation(const contract_violation &violation) +{ + __builtin_exit (0); +} + +struct A { + int i; + A(): i(42) {} + A(const A&); +}; + +A f() + [[ post r: r.i == 24 ]] +{ + A a; + return a; +} + +int main() +{ + f(); + return -1; +} |