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