aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/except.cc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2023-06-04 12:09:11 -0400
committerJason Merrill <jason@redhat.com>2023-06-06 21:31:31 -0400
commit7e0b65b239c3a0d68ce94896b236b03de666ffd6 (patch)
treef64aca7b8eb03218b0de96a1925666483966791b /gcc/cp/except.cc
parentb192e2007e1c98b548f4aa878523b485968d24a4 (diff)
downloadgcc-7e0b65b239c3a0d68ce94896b236b03de666ffd6.zip
gcc-7e0b65b239c3a0d68ce94896b236b03de666ffd6.tar.gz
gcc-7e0b65b239c3a0d68ce94896b236b03de666ffd6.tar.bz2
c++: enable NRVO from inner block [PR51571]
Our implementation of the named return value optimization has been limited to variables declared in the outermost block of the function, to avoid needing to handle the case where the variable needs to be destroyed due to going out of scope. PR92407 pointed out a case we were missing, where the variable goes out of scope due to a goto and we were failing to destroy it. It occurred to me that this problem is the flip side of PR33799, where we need to be sure to destroy the return value if a cleanup throws on return; here we want to avoid destroying the return value when exiting the variable's scope on return. We can use the same flag to indicate to both cleanups that we're returning. This implements the guaranteed copy elision specified by P2025 (which is not yet part of the draft standard). PR c++/51571 PR c++/92407 gcc/cp/ChangeLog: * decl.cc (finish_function): Simplify NRV handling. * except.cc (maybe_set_retval_sentinel): Also set if NRV. (maybe_splice_retval_cleanup): Don't add the cleanup region if we don't need it. * semantics.cc (nrv_data): Add simple field. (finalize_nrv): Set it. (finalize_nrv_r): Check it and retval sentinel. * cp-tree.h (finalize_nrv): Adjust declaration. * typeck.cc (check_return_expr): Remove named_labels check. gcc/testsuite/ChangeLog: * g++.dg/opt/nrv23.C: New test.
Diffstat (limited to 'gcc/cp/except.cc')
-rw-r--r--gcc/cp/except.cc12
1 files changed, 10 insertions, 2 deletions
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index 28106da..6c0f081 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -1280,7 +1280,9 @@ build_noexcept_spec (tree expr, tsubst_flags_t complain)
/* If the current function has a cleanup that might throw, and the return value
has a non-trivial destructor, return a MODIFY_EXPR to set
current_retval_sentinel so that we know that the return value needs to be
- destroyed on throw. Otherwise, returns NULL_TREE. */
+ destroyed on throw. Do the same if the current function might use the
+ named return value optimization, so we don't destroy it on return.
+ Otherwise, returns NULL_TREE. */
tree
maybe_set_retval_sentinel ()
@@ -1290,7 +1292,9 @@ maybe_set_retval_sentinel ()
tree retval = DECL_RESULT (current_function_decl);
if (!TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (retval)))
return NULL_TREE;
- if (!cp_function_chain->throwing_cleanup)
+ if (!cp_function_chain->throwing_cleanup
+ && (current_function_return_value == error_mark_node
+ || current_function_return_value == NULL_TREE))
return NULL_TREE;
if (!current_retval_sentinel)
@@ -1338,6 +1342,10 @@ maybe_splice_retval_cleanup (tree compound_stmt, bool is_try)
tsi_link_before (&iter, decl_expr, TSI_SAME_STMT);
}
+ if (!cp_function_chain->throwing_cleanup)
+ /* We're only using the sentinel for an NRV. */
+ return;
+
/* Skip past other decls, they can't contain a return. */
while (TREE_CODE (tsi_stmt (iter)) == DECL_EXPR)
tsi_next (&iter);