On 6/17/25 6:21 AM, Iain Sandoe wrote:
Hi Jason,

body use is still relevant.  The solution to this is to increment
the use before calling promise.unhanded_exception().

I expected that the body cleanup would check iarc and not do the decrement if 
iarc is true.

that also works, done as attached,
OK now?

Just one nit:

@@ -4457,6 +4569,14 @@ cp_coroutine_transform::wrap_original_function_body ()
    var_list = resume_idx_var;
    add_decl_expr (resume_idx_var);
+ tree coro_frame_refcount
+    = coro_build_artificial_var (loc, coro_frame_refcount_id,
+                                short_unsigned_type_node, orig_fn_decl,
+                                NULL_TREE);
+  DECL_CHAIN (coro_frame_refcount) = var_list;
+  var_list = coro_frame_refcount;
+  add_decl_expr (coro_frame_refcount);
+
    /* If the coroutine has a frame that needs to be freed, this will be set by
       the ramp.  */
    var = coro_build_artificial_var (loc, coro_frame_needs_free_id,
@@ -4465,6 +4585,14 @@ cp_coroutine_transform::wrap_original_function_body ()
    var_list = var;
    add_decl_expr (var);
+ /* We consider that the body has a use of the frame once we start to process
+     the initial suspend expression. (the use might be relinquished if we
+     encounter an exception before the body is finished).  */
+  tree body_use
+    = build2_loc (loc, PLUS_EXPR, short_unsigned_type_node, 
coro_frame_refcount,
+                 build_int_cst (short_unsigned_type_node, 1));
+  body_use = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, 
body_use,
+                                  tf_warning_or_error);
    if (flag_exceptions)
      {
        /* Build promise.unhandled_exception();  */
@@ -4485,10 +4613,29 @@ cp_coroutine_transform::wrap_original_function_body ()
        tree tcb = build_stmt (loc, TRY_BLOCK, NULL_TREE, NULL_TREE);
        add_stmt (tcb);
        TRY_STMTS (tcb) = push_stmt_list ();
+      finish_expr_stmt (body_use);
+      /* We need a new scope to handle the cleanup for the ramp use that is
+        needed for exceptions.  */
+      tree except_scope = begin_compound_stmt (0);
+      current_binding_level->artificial = 1;
+      tree release
+       = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node,
+                     coro_frame_refcount, build_int_cst 
(short_unsigned_type_node, 1));
+       release = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR,
+                                      release, tf_warning_or_error);
+      /* Once we pass the initial await resume, the cleanup rules on exception
+        change so that the responsibility lies with the caller.  */
+      release = build3 (COND_EXPR, void_type_node, i_a_r_c,
+                       build_empty_stmt (loc), release);
+      push_cleanup (NULL_TREE, release, /*ehonly*/true);
        /* Add the initial await to the start of the user-authored function.  */
        finish_expr_stmt (initial_await);
+      /* End the scope that handles the remove of frame-use on exception.  */
+      finish_compound_stmt (except_scope);
+
        /* Append the original function body.  */
        add_stmt (coroutine_body);
+
        if (return_void)
        add_stmt (return_void);
        TRY_STMTS (tcb) = pop_stmt_list (TRY_STMTS (tcb));
@@ -4539,6 +4686,7 @@ cp_coroutine_transform::wrap_original_function_body ()
                        coro_unhandled_exception_identifier,
                        get_coroutine_promise_type (orig_fn_decl));
        }
+      finish_expr_stmt (body_use);

Would it work to emit body_use where you build it, instead of separately for EH/non-EH? I don't see why the initial increment would need to be inside the try-block.

Jason

Reply via email to