]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: fix contracts with NRV
authorJason Merrill <jason@redhat.com>
Tue, 6 Jun 2023 03:58:32 +0000 (23:58 -0400)
committerJason Merrill <jason@redhat.com>
Fri, 17 Nov 2023 00:20:45 +0000 (19:20 -0500)
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 12 note: There are no contracts in GCC 12, but this issue also broke
setting current_retval_sentinel.

gcc/cp/ChangeLog:

* semantics.cc (finalize_nrv_r): [RETURN_EXPR]: Only replace the
INIT_EXPR.

gcc/cp/semantics.cc

index 5289131e591e3210ca9e0cd17a42a85ea93e4a97..d6351d2d8a32aa567f0e3c7df07ef953e391eb19 100644 (file)
@@ -4859,9 +4859,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