]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++, coroutines: Rework handling of throwing_cleanups [PR102051].
authorIain Sandoe <iain@sandoe.co.uk>
Sun, 18 Aug 2024 21:54:50 +0000 (22:54 +0100)
committerIain Sandoe <iain@sandoe.co.uk>
Mon, 5 May 2025 19:35:09 +0000 (20:35 +0100)
In the fix for PR95822 (r11-7402) we set throwing_cleanup false in the top
level of the coroutine transform code.  However, as the current PR shows,
that is not sufficient.

Any use of cxx_maybe_build_cleanup() can reset the flag, which causes the
check_return_expr () logic to try to add a guard variable and set it.

For the coroutine code, we need to handle the cleanups separately, since
the responsibility for them changes after the first resume point, which
we handle in the ramp exception processing.

Fix this by forcing the "throwing_cleanup" flag false right before the
processing of the return expression.

PR c++/102051

gcc/cp/ChangeLog:

* coroutines.cc
(cp_coroutine_transform::build_ramp_function): Handle
"throwing_cleanup" here instead of ...
(cp_coroutine_transform::apply_transforms): ... here.

gcc/testsuite/ChangeLog:

* g++.dg/coroutines/pr102051.C: New test.

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
(cherry picked from commit f0315f7a325ffccb446fe378fcdfccda6eead8ba)

gcc/cp/coroutines.cc
gcc/testsuite/g++.dg/coroutines/pr102051.C [new file with mode: 0644]

index 00a016d1bd31545e6c35b263783447e07ca628d5..82ba96f6567478b35d83e948f8d26d024bca3130 100644 (file)
@@ -4632,17 +4632,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
       TREE_OPERAND (body_start, 0) = push_stmt_list ();
     }
 
-  /* If the original function has a return value with a non-trivial DTOR
-     and the body contains a var with a DTOR that might throw, the decl is
-     marked "throwing_cleanup".
-     We do not [in the ramp, which is synthesised here], use any body var
-     types with DTORs that might throw.
-     The original body is transformed into the actor function which only
-     contains void returns, and is also wrapped in a try-catch block.
-     So (a) the 'throwing_cleanup' is not correct for the ramp and (b) we do
-     not need to transfer it to the actor which only contains void returns.  */
-  cp_function_chain->throwing_cleanup = false;
-
   /* Create the coro frame type, as far as it can be known at this stage.
      1. Types we already know.  */
 
@@ -5270,6 +5259,10 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
      either as the return value (if it's the same type) or to the CTOR
      for an object of the return type.  */
 
+  /* We must manage the cleanups ourselves, because the responsibility for
+     them changes after the initial suspend.  However, any use of
+     cxx_maybe_build_cleanup () can set the throwing_cleanup flag.  */
+  cp_function_chain->throwing_cleanup = false;
   if (same_type_p (gro_type, fn_return_type))
     r = void_ramp_p ? NULL_TREE : DECL_RESULT (orig);
   else
diff --git a/gcc/testsuite/g++.dg/coroutines/pr102051.C b/gcc/testsuite/g++.dg/coroutines/pr102051.C
new file mode 100644 (file)
index 0000000..bba98b6
--- /dev/null
@@ -0,0 +1,16 @@
+#include <coroutine>
+
+struct Foo {
+    ~Foo() noexcept(false); // true succeeds
+    struct promise_type {
+        Foo get_return_object() { return {}; }
+        std::suspend_never initial_suspend() { return {}; }
+        void return_void() {}
+        void unhandled_exception() {}
+        std::suspend_always final_suspend() noexcept { return {}; }
+    };
+};
+
+Foo bar() {
+    co_return;
+}