• R/O
  • HTTP
  • SSH
  • HTTPS

提交

標籤
無標籤

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

GCC with patches for OS216


Commit MetaInfo

修訂b1c3d3111a0ac36ae3c2d7412d20777fc073fdeb (tree)
時間2020-07-02 02:05:13
作者Iain Sandoe <iain@sand...>
CommiterIain Sandoe

Log Message

coroutines: Collect the function body rewrite code.

The standard describes a rewrite of the body of the user-authored
function (which wraps it in a try-catch block and provides the
initial and final suspend expressions). The exact arrangement of
this was still in flux right up until the DIS and as a consequence
was a bit of a moving target.

The net result was a fragmented implementation of the parts of
the rewrite which is now impeding progress in fixing other issues.

This patch collates the rewrite action into a single function and
carries this out earlier.

gcc/cp/ChangeLog:

* coroutines.cc (expand_one_await_expression): Remove
code dealing with initial suspend.
(build_actor_fn): Remove code special-casing initial
and final suspend. Handle the final suspend and marking
of the coroutine as done.
(coro_rewrite_function_body): New.
(bind_expr_find_in_subtree): Remove.
(coro_body_contains_bind_expr_p): Remove.
(morph_fn_to_coro): Split the rewrite of the original
function into coro_rewrite_function_body and call it.

(cherry picked from commit 9252a208f485eed2757d601657facfa0aee6cd21)

Change Summary

差異

--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1576,8 +1576,6 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d)
15761576 tree awaiter_calls = TREE_OPERAND (saved_co_await, 3);
15771577
15781578 tree source = TREE_OPERAND (saved_co_await, 4);
1579- bool is_initial =
1580- (source && TREE_INT_CST_LOW (source) == (int) INITIAL_SUSPEND_POINT);
15811579 bool is_final = (source
15821580 && TREE_INT_CST_LOW (source) == (int) FINAL_SUSPEND_POINT);
15831581 bool needs_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var));
@@ -1727,16 +1725,6 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d)
17271725 resume_label = build_stmt (loc, LABEL_EXPR, resume_label);
17281726 append_to_statement_list (resume_label, &stmt_list);
17291727
1730- if (is_initial)
1731- {
1732- /* Note that we are about to execute the await_resume() for the initial
1733- await expression. */
1734- r = build2_loc (loc, MODIFY_EXPR, boolean_type_node, data->i_a_r_c,
1735- boolean_true_node);
1736- r = coro_build_cvt_void_expr_stmt (r, loc);
1737- append_to_statement_list (r, &stmt_list);
1738- }
1739-
17401728 /* This will produce the value (if one is provided) from the co_await
17411729 expression. */
17421730 tree resume_call = TREE_VEC_ELT (awaiter_calls, 2); /* await_resume(). */
@@ -2103,19 +2091,16 @@ static void
21032091 build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
21042092 tree orig, hash_map<tree, param_info> *param_uses,
21052093 hash_map<tree, local_var_info> *local_var_uses,
2106- vec<tree, va_gc> *param_dtor_list, tree initial_await,
2107- tree final_await, unsigned body_count, tree frame_size)
2094+ vec<tree, va_gc> *param_dtor_list,
2095+ tree fs_label, tree resume_fn_field,
2096+ unsigned body_count, tree frame_size)
21082097 {
21092098 verify_stmt_tree (fnbody);
21102099 /* Some things we inherit from the original function. */
2111- tree coro_frame_ptr = build_pointer_type (coro_frame_type);
21122100 tree handle_type = get_coroutine_handle_type (orig);
21132101 tree self_h_proxy = get_coroutine_self_handle_proxy (orig);
21142102 tree promise_type = get_coroutine_promise_type (orig);
21152103 tree promise_proxy = get_coroutine_promise_proxy (orig);
2116- tree act_des_fn_type
2117- = build_function_type_list (void_type_node, coro_frame_ptr, NULL_TREE);
2118- tree act_des_fn_ptr = build_pointer_type (act_des_fn_type);
21192104
21202105 /* One param, the coro frame pointer. */
21212106 tree actor_fp = DECL_ARGUMENTS (actor);
@@ -2146,21 +2131,15 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
21462131 DECL_CONTEXT (continuation) = actor;
21472132 BIND_EXPR_VARS (actor_bind) = continuation;
21482133
2149- /* Update the block associated with the outer scope of the orig fn. */
2134+ /* Link in the block associated with the outer scope of the re-written
2135+ function body. */
21502136 tree first = expr_first (fnbody);
2151- if (first && TREE_CODE (first) == BIND_EXPR)
2152- {
2153- /* We will discard this, since it's connected to the original scope
2154- nest. */
2155- tree block = BIND_EXPR_BLOCK (first);
2156- if (block) /* For this to be missing is probably a bug. */
2157- {
2158- gcc_assert (BLOCK_SUPERCONTEXT (block) == NULL_TREE);
2159- gcc_assert (BLOCK_CHAIN (block) == NULL_TREE);
2160- BLOCK_SUPERCONTEXT (block) = top_block;
2161- BLOCK_SUBBLOCKS (top_block) = block;
2162- }
2163- }
2137+ gcc_checking_assert (first && TREE_CODE (first) == BIND_EXPR);
2138+ tree block = BIND_EXPR_BLOCK (first);
2139+ gcc_checking_assert (BLOCK_SUPERCONTEXT (block) == NULL_TREE);
2140+ gcc_checking_assert (BLOCK_CHAIN (block) == NULL_TREE);
2141+ BLOCK_SUPERCONTEXT (block) = top_block;
2142+ BLOCK_SUBBLOCKS (top_block) = block;
21642143
21652144 add_stmt (actor_bind);
21662145 tree actor_body = push_stmt_list ();
@@ -2237,7 +2216,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
22372216 add_stmt (b);
22382217
22392218 short unsigned lab_num = 3;
2240- for (unsigned destr_pt = 0; destr_pt < body_count + 2; destr_pt++)
2219+ for (unsigned destr_pt = 0; destr_pt < body_count; destr_pt++)
22412220 {
22422221 tree l_num = build_int_cst (short_unsigned_type_node, lab_num);
22432222 b = build_case_label (l_num, NULL_TREE,
@@ -2273,8 +2252,10 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
22732252 add_stmt (b);
22742253
22752254 lab_num = 2;
2276- /* The final resume should be made to hit the default (trap, UB) entry. */
2277- for (unsigned resu_pt = 0; resu_pt < body_count + 1; resu_pt++)
2255+ /* The final resume should be made to hit the default (trap, UB) entry
2256+ although it will be unreachable via the normal entry point, since that
2257+ is set to NULL on reaching final suspend. */
2258+ for (unsigned resu_pt = 0; resu_pt < body_count; resu_pt++)
22782259 {
22792260 tree l_num = build_int_cst (short_unsigned_type_node, lab_num);
22802261 b = build_case_label (l_num, NULL_TREE,
@@ -2327,55 +2308,19 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
23272308 await_xform_data xform
23282309 = {actor, actor_frame, promise_proxy, ap, self_h_proxy, ash};
23292310
2330- /* Get a reference to the initial suspend var in the frame. */
2331- transform_await_expr (initial_await, &xform);
2332- tree initial_await_stmt = coro_build_expr_stmt (initial_await, loc);
2333-
2334- /* co_return branches to the final_suspend label, so declare that now. */
2335- tree fs_label = create_named_label_with_ctx (loc, "final.suspend", actor);
2336-
23372311 /* Expand co_returns in the saved function body */
23382312 fnbody = expand_co_returns (&fnbody, promise_proxy, ap, fs_label);
23392313
2340- /* n4849 adds specific behaviour to treat exceptions thrown by the
2341- await_resume () of the initial suspend expression. In order to
2342- implement this, we need to treat the initial_suspend expression
2343- as if it were part of the user-authored function body. This
2344- only applies if exceptions are enabled. */
2345- if (flag_exceptions)
2346- {
2347- tree outer = fnbody;
2348- if (TREE_CODE (outer) == BIND_EXPR)
2349- outer = BIND_EXPR_BODY (outer);
2350- gcc_checking_assert (TREE_CODE (outer) == TRY_BLOCK);
2351- tree sl = TRY_STMTS (outer);
2352- if (TREE_CODE (sl) == STATEMENT_LIST)
2353- {
2354- tree_stmt_iterator si = tsi_start (sl);
2355- tsi_link_before (&si, initial_await_stmt, TSI_NEW_STMT);
2356- }
2357- else
2358- {
2359- tree new_try = NULL_TREE;
2360- append_to_statement_list (initial_await_stmt, &new_try);
2361- append_to_statement_list (sl, &new_try);
2362- TRY_STMTS (outer) = new_try;
2363- }
2364- }
2365- else
2366- add_stmt (initial_await_stmt);
2367-
23682314 /* Transform the await expressions in the function body. Only do each
23692315 await tree once! */
23702316 hash_set<tree> pset;
23712317 cp_walk_tree (&fnbody, transform_await_wrapper, &xform, &pset);
23722318
2373- /* Add in our function body with the co_returns rewritten to final form. */
2374- add_stmt (fnbody);
2375-
2376- /* Final suspend starts here. */
2377- r = build_stmt (loc, LABEL_EXPR, fs_label);
2378- add_stmt (r);
2319+ /* Now replace the promise proxy with its real value. */
2320+ proxy_replace p_data;
2321+ p_data.from = promise_proxy;
2322+ p_data.to = ap;
2323+ cp_walk_tree (&fnbody, replace_proxy, &p_data, NULL);
23792324
23802325 /* Set the actor pointer to null, so that 'done' will work.
23812326 Resume from here is UB anyway - although a 'ready' await will
@@ -2385,15 +2330,12 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
23852330 /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
23862331 tree res_x = build_class_member_access_expr (actor_frame, resume_m, NULL_TREE,
23872332 false, tf_warning_or_error);
2388- r = build1 (CONVERT_EXPR, act_des_fn_ptr, integer_zero_node);
2389- r = build2 (INIT_EXPR, act_des_fn_ptr, res_x, r);
2390- r = coro_build_cvt_void_expr_stmt (r, loc);
2391- add_stmt (r);
2333+ p_data.from = resume_fn_field;
2334+ p_data.to = res_x;
2335+ cp_walk_tree (&fnbody, replace_proxy, &p_data, NULL);
23922336
2393- /* Get a reference to the final suspend var in the frame. */
2394- transform_await_expr (final_await, &xform);
2395- r = coro_build_expr_stmt (final_await, loc);
2396- add_stmt (r);
2337+ /* Add in our function body with the co_returns rewritten to final form. */
2338+ add_stmt (fnbody);
23972339
23982340 /* now do the tail of the function. */
23992341 tree del_promise_label
@@ -2560,20 +2502,10 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
25602502 = build_class_member_access_expr (actor_frame, res_idx_m, NULL_TREE, false,
25612503 tf_warning_or_error);
25622504
2563- /* Boolean value to flag that the initial suspend expression's
2564- await_resume () has been called, and therefore we are in the user's
2565- function body for the purposes of handing exceptions. */
2566- tree i_a_r_c_m
2567- = lookup_member (coro_frame_type, get_identifier ("__i_a_r_c"),
2568- /*protect=*/1, /*want_type=*/0, tf_warning_or_error);
2569- tree i_a_r_c
2570- = build_class_member_access_expr (actor_frame, i_a_r_c_m, NULL_TREE,
2571- false, tf_warning_or_error);
2572-
25732505 /* We've now rewritten the tree and added the initial and final
25742506 co_awaits. Now pass over the tree and expand the co_awaits. */
25752507
2576- coro_aw_data data = {actor, actor_fp, resume_pt_number, i_a_r_c,
2508+ coro_aw_data data = {actor, actor_fp, resume_pt_number, NULL_TREE,
25772509 ash, del_promise_label, ret_label,
25782510 continue_label, continuation, 2};
25792511 cp_walk_tree (&actor_body, await_statement_expander, &data, NULL);
@@ -3642,23 +3574,165 @@ act_des_fn (tree orig, tree fn_type, tree coro_frame_ptr, const char* name)
36423574 return fn;
36433575 }
36443576
3645-/* Return a bind expression if we see one, else NULL_TREE. */
3577+/* Re-write the body as per [dcl.fct.def.coroutine] / 5. */
3578+
36463579 static tree
3647-bind_expr_find_in_subtree (tree *stmt, int *, void *)
3580+coro_rewrite_function_body (location_t fn_start, tree fnbody,
3581+ tree orig, tree resume_fn_ptr_type,
3582+ tree& resume_fn_field, tree& fs_label)
36483583 {
3649- if (TREE_CODE (*stmt) == BIND_EXPR)
3650- return *stmt;
3651- return NULL_TREE;
3652-}
3584+ /* This will be our new outer scope. */
3585+ tree update_body = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
3586+ tree top_block = make_node (BLOCK);
3587+ BIND_EXPR_BLOCK (update_body) = top_block;
3588+ BIND_EXPR_BODY (update_body) = push_stmt_list ();
36533589
3654-/* Return the first bind expression that the sub-tree given by STMT
3655- contains. */
3590+ /* If the function has a top level bind expression, then connect that
3591+ after first making sure we give it a new block. */
3592+ tree first = expr_first (fnbody);
3593+ if (first && TREE_CODE (first) == BIND_EXPR)
3594+ {
3595+ tree block = BIND_EXPR_BLOCK (first);
3596+ gcc_checking_assert (block);
3597+ gcc_checking_assert (BLOCK_SUPERCONTEXT (block) == NULL_TREE);
3598+ gcc_checking_assert (BLOCK_CHAIN (block) == NULL_TREE);
3599+ /* Replace the top block to avoid issues with locations for args
3600+ appearing to be in a non-existent place. */
3601+ tree replace_blk = make_node (BLOCK);
3602+ BLOCK_VARS (replace_blk) = BLOCK_VARS (block);
3603+ BLOCK_SUBBLOCKS (replace_blk) = BLOCK_SUBBLOCKS (block);
3604+ for (tree b = BLOCK_SUBBLOCKS (replace_blk); b; b = BLOCK_CHAIN (b))
3605+ BLOCK_SUPERCONTEXT (b) = replace_blk;
3606+ BIND_EXPR_BLOCK (first) = replace_blk;
3607+ /* The top block has one child, so far, and we have now got a
3608+ superblock. */
3609+ BLOCK_SUPERCONTEXT (block) = top_block;
3610+ BLOCK_SUBBLOCKS (top_block) = block;
3611+ }
36563612
3657-static tree
3658-coro_body_contains_bind_expr_p (tree *stmt)
3659-{
3660- hash_set<tree> visited;
3661- return cp_walk_tree (stmt, bind_expr_find_in_subtree, NULL, &visited);
3613+ /* Wrap the function body in a try {} catch (...) {} block, if exceptions
3614+ are enabled. */
3615+ tree promise = get_coroutine_promise_proxy (orig);
3616+ tree var_list = NULL_TREE;
3617+ tree initial_await = build_init_or_final_await (fn_start, false);
3618+
3619+ /* [stmt.return.coroutine] / 3
3620+ If p.return_void() is a valid expression, flowing off the end of a
3621+ coroutine is equivalent to a co_return with no operand; otherwise
3622+ flowing off the end of a coroutine results in undefined behavior. */
3623+ tree return_void
3624+ = get_coroutine_return_void_expr (current_function_decl, fn_start, false);
3625+
3626+ if (flag_exceptions)
3627+ {
3628+ /* Build promise.unhandled_exception(); */
3629+ tree ueh
3630+ = coro_build_promise_expression (current_function_decl, promise,
3631+ coro_unhandled_exception_identifier,
3632+ fn_start, NULL, /*musthave=*/true);
3633+ /* Create and initialize the initial-await-resume-called variable per
3634+ [dcl.fct.def.coroutine] / 5.3. */
3635+ tree i_a_r_c = build_lang_decl (VAR_DECL, get_identifier ("__i_a_r_c"),
3636+ boolean_type_node);
3637+ DECL_ARTIFICIAL (i_a_r_c) = true;
3638+ DECL_CHAIN (i_a_r_c) = var_list;
3639+ var_list = i_a_r_c;
3640+ DECL_INITIAL (i_a_r_c) = boolean_false_node;
3641+ add_decl_expr (i_a_r_c);
3642+ /* Start the try-catch. */
3643+ tree tcb = build_stmt (fn_start, TRY_BLOCK, NULL_TREE, NULL_TREE);
3644+ add_stmt (tcb);
3645+ TRY_STMTS (tcb) = push_stmt_list ();
3646+ if (initial_await != error_mark_node)
3647+ {
3648+ /* Build a compound expression that sets the
3649+ initial-await-resume-called variable true and then calls the
3650+ initial suspend expression await resume. */
3651+ tree vec = TREE_OPERAND (initial_await, 3);
3652+ tree aw_r = TREE_VEC_ELT (vec, 2);
3653+ tree update = build2 (MODIFY_EXPR, boolean_type_node, i_a_r_c,
3654+ boolean_true_node);
3655+ aw_r = cp_build_compound_expr (update, aw_r, tf_warning_or_error);
3656+ TREE_VEC_ELT (vec, 2) = aw_r;
3657+ }
3658+ /* Add the initial await to the start of the user-authored function. */
3659+ finish_expr_stmt (initial_await);
3660+ /* Append the original function body. */
3661+ add_stmt (fnbody);
3662+ if (return_void)
3663+ add_stmt (return_void);
3664+ TRY_STMTS (tcb) = pop_stmt_list (TRY_STMTS (tcb));
3665+ TRY_HANDLERS (tcb) = push_stmt_list ();
3666+ /* Mimic what the parser does for the catch. */
3667+ tree handler = begin_handler ();
3668+ finish_handler_parms (NULL_TREE, handler); /* catch (...) */
3669+
3670+ /* Get the initial await resume called value. */
3671+ tree not_iarc_if = begin_if_stmt ();
3672+ tree not_iarc = build1_loc (fn_start, TRUTH_NOT_EXPR,
3673+ boolean_type_node, i_a_r_c);
3674+ finish_if_stmt_cond (not_iarc, not_iarc_if);
3675+ /* If the initial await resume called value is false, rethrow... */
3676+ tree rethrow = build_throw (fn_start, NULL_TREE);
3677+ TREE_NO_WARNING (rethrow) = true;
3678+ finish_expr_stmt (rethrow);
3679+ finish_then_clause (not_iarc_if);
3680+ tree iarc_scope = IF_SCOPE (not_iarc_if);
3681+ IF_SCOPE (not_iarc_if) = NULL;
3682+ not_iarc_if = do_poplevel (iarc_scope);
3683+ add_stmt (not_iarc_if);
3684+ /* ... else call the promise unhandled exception method. */
3685+ ueh = maybe_cleanup_point_expr_void (ueh);
3686+ add_stmt (ueh);
3687+ finish_handler (handler);
3688+ TRY_HANDLERS (tcb) = pop_stmt_list (TRY_HANDLERS (tcb));
3689+ }
3690+ else
3691+ {
3692+ if (pedantic)
3693+ {
3694+ /* We still try to look for the promise method and warn if it's not
3695+ present. */
3696+ tree ueh_meth
3697+ = lookup_promise_method (orig, coro_unhandled_exception_identifier,
3698+ fn_start, /*musthave=*/false);
3699+ if (!ueh_meth || ueh_meth == error_mark_node)
3700+ warning_at (fn_start, 0, "no member named %qE in %qT",
3701+ coro_unhandled_exception_identifier,
3702+ get_coroutine_promise_type (orig));
3703+ }
3704+ /* Else we don't check and don't care if the method is missing..
3705+ just add the initial suspend, function and return. */
3706+ finish_expr_stmt (initial_await);
3707+ /* Append the original function body. */
3708+ add_stmt (fnbody);
3709+ if (return_void)
3710+ add_stmt (return_void);
3711+ }
3712+
3713+ /* co_return branches to the final_suspend label, so declare that now. */
3714+ fs_label
3715+ = create_named_label_with_ctx (fn_start, "final.suspend", NULL_TREE);
3716+ add_stmt (build_stmt (fn_start, LABEL_EXPR, fs_label));
3717+
3718+ /* Before entering the final suspend point, we signal that this point has
3719+ been reached by setting the resume function pointer to zero (this is
3720+ what the 'done()' builtin tests) as per the current ABI. */
3721+ resume_fn_field
3722+ = build_lang_decl (VAR_DECL, get_identifier ("resume.fn.ptr.proxy"),
3723+ resume_fn_ptr_type);
3724+ DECL_ARTIFICIAL (resume_fn_field) = true;
3725+ tree zero_resume
3726+ = build1 (CONVERT_EXPR, resume_fn_ptr_type, integer_zero_node);
3727+ zero_resume
3728+ = build2 (INIT_EXPR, resume_fn_ptr_type, resume_fn_field, zero_resume);
3729+ finish_expr_stmt (zero_resume);
3730+ finish_expr_stmt (build_init_or_final_await (fn_start, true));
3731+ BIND_EXPR_BODY (update_body) = pop_stmt_list (BIND_EXPR_BODY (update_body));
3732+ BIND_EXPR_VARS (update_body) = nreverse (var_list);
3733+ BLOCK_VARS (top_block) = BIND_EXPR_VARS (update_body);
3734+
3735+ return update_body;
36623736 }
36633737
36643738 /* Here we:
@@ -3735,55 +3809,32 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
37353809 return false;
37363810 }
37373811
3738- /* So, we've tied off the original body. Now start the replacement.
3812+ /* So, we've tied off the original user-authored body in fn_body.
3813+
3814+ Start the replacement synthesized ramp body as newbody.
37393815 If we encounter a fatal error we might return a now-empty body.
3740- TODO: determine if it would help to restore the original.
3741- determine if looking for more errors in coro_function_valid_p()
3742- and stashing types is a better solution. */
3816+
3817+ Note, the returned ramp body is not 'popped', to be compatible with
3818+ the way that decl.c handles regular functions, the scope pop is done
3819+ in the caller. */
37433820
37443821 tree newbody = push_stmt_list ();
37453822 DECL_SAVED_TREE (orig) = newbody;
37463823
37473824 /* If our original body is noexcept, then that's what we apply to our
3748- generated functions. Remember that we're NOEXCEPT and fish out the
3749- contained list (we tied off to the top level already). */
3825+ generated ramp, transfer any MUST_NOT_THOW_EXPR to that. */
37503826 bool is_noexcept = TREE_CODE (body_start) == MUST_NOT_THROW_EXPR;
37513827 if (is_noexcept)
37523828 {
3753- /* Simplified abstract from begin_eh_spec_block, since we already
3754- know the outcome. */
3755- fnbody = TREE_OPERAND (body_start, 0); /* Stash the original... */
3756- add_stmt (body_start); /* ... and start the new. */
3829+ /* The function body we will continue with is the single operand to
3830+ the must-not-throw. */
3831+ fnbody = TREE_OPERAND (body_start, 0);
3832+ /* Transfer the must-not-throw to the ramp body. */
3833+ add_stmt (body_start);
3834+ /* Re-start the ramp as must-not-throw. */
37573835 TREE_OPERAND (body_start, 0) = push_stmt_list ();
37583836 }
37593837
3760- /* We can be presented with a function that currently has no outer bind
3761- expression. We will insert bind scopes in expanding await expressions,
3762- and therefore need a top level to the tree, so synthesize an outer bind
3763- expression and scope. */
3764- tree check_bind = expr_first (fnbody);
3765- if (check_bind && TREE_CODE (check_bind) != BIND_EXPR)
3766- {
3767- tree update_body = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
3768- tree blk = make_node (BLOCK);
3769- gcc_checking_assert (!coro_body_contains_bind_expr_p (&fnbody));
3770- BIND_EXPR_BLOCK (update_body) = blk;
3771- if (TREE_CODE (fnbody) == STATEMENT_LIST)
3772- BIND_EXPR_BODY (update_body) = fnbody;
3773- else
3774- {
3775- tree tlist = NULL_TREE;
3776- append_to_statement_list_force (fnbody, &tlist);
3777- TREE_SIDE_EFFECTS (tlist) = TREE_SIDE_EFFECTS (fnbody);
3778- BIND_EXPR_BODY (update_body) = tlist;
3779- }
3780- tree new_body_list = NULL_TREE;
3781- TREE_SIDE_EFFECTS (update_body) = true;
3782- append_to_statement_list (update_body, &new_body_list);
3783- TREE_SIDE_EFFECTS (new_body_list) = true;
3784- fnbody = new_body_list;
3785- }
3786-
37873838 /* Create the coro frame type, as far as it can be known at this stage.
37883839 1. Types we already know. */
37893840
@@ -3793,35 +3844,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
37933844
37943845 /* 2. Types we need to define or look up. */
37953846
3796- /* We need to know, and inspect, each suspend point in the function
3797- in several places. It's convenient to place this map out of line
3798- since it's used from tree walk callbacks. */
3799- suspend_points = new hash_map<tree, suspend_point_info>;
3800-
3801- /* Initial and final suspend types are special in that the co_awaits for
3802- them are synthetic. We need to find the type for each awaiter from
3803- the coroutine promise. */
3804- tree initial_await = build_init_or_final_await (fn_start, false);
3805- if (initial_await == error_mark_node)
3806- {
3807- /* Suppress warnings about the missing return value. */
3808- TREE_NO_WARNING (orig) = true;
3809- return false;
3810- }
3811- /* The type of the frame var for this is the type of its temp proxy. */
3812- tree initial_suspend_type = TREE_TYPE (TREE_OPERAND (initial_await, 1));
3813-
3814- tree final_await = build_init_or_final_await (fn_start, true);
3815- if (final_await == error_mark_node)
3816- {
3817- /* Suppress warnings about the missing return value. */
3818- TREE_NO_WARNING (orig) = true;
3819- return false;
3820- }
3821-
3822- /* The type of the frame var for this is the type of its temp proxy. */
3823- tree final_suspend_type = TREE_TYPE (TREE_OPERAND (final_await, 1));
3824-
38253847 tree fr_name = get_fn_local_identifier (orig, "frame");
38263848 tree coro_frame_type = xref_tag (record_type, fr_name, ts_current, false);
38273849 DECL_CONTEXT (TYPE_NAME (coro_frame_type)) = current_scope ();
@@ -3834,20 +3856,27 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
38343856 tree actor = act_des_fn (orig, act_des_fn_type, coro_frame_ptr, "actor");
38353857 tree destroy = act_des_fn (orig, act_des_fn_type, coro_frame_ptr, "destroy");
38363858
3859+ /* Construct the wrapped function body; we will analyze this to determine
3860+ the requirements for the coroutine frame. */
3861+
3862+ tree resume_fn_field = NULL_TREE;
3863+ tree fs_label = NULL_TREE;
3864+ fnbody = coro_rewrite_function_body (fn_start, fnbody, orig, act_des_fn_ptr,
3865+ resume_fn_field, fs_label);
38373866 /* Build our dummy coro frame layout. */
38383867 coro_frame_type = begin_class_definition (coro_frame_type);
38393868
38403869 tree field_list = NULL_TREE;
38413870 tree resume_name
3842- = coro_make_frame_entry (&field_list, "__resume", act_des_fn_ptr, fn_start);
3843- tree destroy_name = coro_make_frame_entry (&field_list, "__destroy",
3844- act_des_fn_ptr, fn_start);
3871+ = coro_make_frame_entry (&field_list, "__resume",
3872+ act_des_fn_ptr, fn_start);
3873+ tree destroy_name
3874+ = coro_make_frame_entry (&field_list, "__destroy",
3875+ act_des_fn_ptr, fn_start);
38453876 tree promise_name
38463877 = coro_make_frame_entry (&field_list, "__p", promise_type, fn_start);
38473878 tree fnf_name = coro_make_frame_entry (&field_list, "__frame_needs_free",
38483879 boolean_type_node, fn_start);
3849- tree iarc_name = coro_make_frame_entry (&field_list, "__i_a_r_c",
3850- boolean_type_node, fn_start);
38513880 tree resume_idx_name
38523881 = coro_make_frame_entry (&field_list, "__resume_at",
38533882 short_unsigned_type_node, fn_start);
@@ -3938,11 +3967,10 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
39383967 cp_walk_tree (&fnbody, register_param_uses, &param_data, NULL);
39393968 }
39403969
3941- /* Initial suspend is mandated. */
3942- tree init_susp_name = coro_make_frame_entry (&field_list, "__aw_s.is",
3943- initial_suspend_type, fn_start);
3944-
3945- register_await_info (initial_await, initial_suspend_type, init_susp_name);
3970+ /* We need to know, and inspect, each suspend point in the function
3971+ in several places. It's convenient to place this map out of line
3972+ since it's used from tree walk callbacks. */
3973+ suspend_points = new hash_map<tree, suspend_point_info>;
39463974
39473975 /* Now insert the data for any body await points, at this time we also need
39483976 to promote any temporaries that are captured by reference (to regular
@@ -3955,12 +3983,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
39553983 body_aw_points.to_replace = make_tree_vector ();
39563984 cp_walk_tree (&fnbody, await_statement_walker, &body_aw_points, NULL);
39573985
3958- /* Final suspend is mandated. */
3959- tree fin_susp_name = coro_make_frame_entry (&field_list, "__aw_s.fs",
3960- final_suspend_type, fn_start);
3961-
3962- register_await_info (final_await, final_suspend_type, fin_susp_name);
3963-
39643986 /* 4. Now make space for local vars, this is conservative again, and we
39653987 would expect to delete unused entries later. */
39663988 hash_map<tree, local_var_info> local_var_uses;
@@ -4465,17 +4487,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
44654487 r = coro_build_cvt_void_expr_stmt (r, fn_start);
44664488 add_stmt (r);
44674489
4468- /* Initialize 'initial-await-resume-called' as per
4469- [dcl.fct.def.coroutine] / 5.3 */
4470- tree i_a_r_c_m
4471- = lookup_member (coro_frame_type, iarc_name, 1, 0, tf_warning_or_error);
4472- tree i_a_r_c = build_class_member_access_expr (deref_fp, i_a_r_c_m,
4473- NULL_TREE, false,
4474- tf_warning_or_error);
4475- r = build2 (INIT_EXPR, boolean_type_node, i_a_r_c, boolean_false_node);
4476- r = coro_build_cvt_void_expr_stmt (r, fn_start);
4477- add_stmt (r);
4478-
44794490 /* So .. call the actor .. */
44804491 r = build_call_expr_loc (fn_start, actor, 1, coro_fp);
44814492 r = maybe_cleanup_point_expr_void (r);
@@ -4545,133 +4556,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
45454556 BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_body);
45464557 TREE_SIDE_EFFECTS (ramp_bind) = true;
45474558
4548- /* We know the "real" promise and have a frame layout with a slot for each
4549- suspend point, so we can build an actor function (which contains the
4550- functionality for both 'resume' and 'destroy').
4551-
4552- wrap the function body in a try {} catch (...) {} block, if exceptions
4553- are enabled. */
4554-
4555- /* First make a new block for the body - that will be embedded in the
4556- re-written function. */
4557- tree first = expr_first (fnbody);
4558- bool orig_fn_has_outer_bind = false;
4559- tree replace_blk = NULL_TREE;
4560- if (first && TREE_CODE (first) == BIND_EXPR)
4561- {
4562- orig_fn_has_outer_bind = true;
4563- tree block = BIND_EXPR_BLOCK (first);
4564- replace_blk = make_node (BLOCK);
4565- if (block) /* missing block is probably an error. */
4566- {
4567- gcc_assert (BLOCK_SUPERCONTEXT (block) == NULL_TREE);
4568- gcc_assert (BLOCK_CHAIN (block) == NULL_TREE);
4569- BLOCK_VARS (replace_blk) = BLOCK_VARS (block);
4570- BLOCK_SUBBLOCKS (replace_blk) = BLOCK_SUBBLOCKS (block);
4571- for (tree b = BLOCK_SUBBLOCKS (replace_blk); b; b = BLOCK_CHAIN (b))
4572- BLOCK_SUPERCONTEXT (b) = replace_blk;
4573- }
4574- BIND_EXPR_BLOCK (first) = replace_blk;
4575- }
4576-
4577- /* actor's version of the promise. */
4578- tree actor_frame = build1_loc (fn_start, INDIRECT_REF, coro_frame_type,
4579- DECL_ARGUMENTS (actor));
4580- tree ap_m = lookup_member (coro_frame_type, get_identifier ("__p"), 1, 0,
4581- tf_warning_or_error);
4582- tree ap = build_class_member_access_expr (actor_frame, ap_m, NULL_TREE,
4583- false, tf_warning_or_error);
4584-
4585- /* Now we've built the promise etc, process fnbody for co_returns.
4586- We want the call to return_void () below and it has no params so
4587- we can create it once here.
4588- Calls to return_value () will have to be checked and created as
4589- required. */
4590-
4591- tree return_void
4592- = coro_build_promise_expression (current_function_decl, ap,
4593- coro_return_void_identifier,
4594- fn_start, NULL, /*musthave=*/false);
4595-
4596- /* [stmt.return.coroutine] (2.2 : 3) if p.return_void() is a valid
4597- expression, flowing off the end of a coroutine is equivalent to
4598- co_return; otherwise UB.
4599- We just inject the call to p.return_void() here, and fall through to
4600- the final_suspend: label (eliding the goto). If the function body has
4601- a co_return, then this statement will be unreachable and DCEd. */
4602- if (return_void != NULL_TREE)
4603- {
4604- tree append = push_stmt_list ();
4605- add_stmt (fnbody);
4606- add_stmt (return_void);
4607- fnbody = pop_stmt_list(append);
4608- }
4609-
4610- if (flag_exceptions)
4611- {
4612- tree ueh
4613- = coro_build_promise_expression (current_function_decl, ap,
4614- coro_unhandled_exception_identifier,
4615- fn_start, NULL, /*musthave=*/true);
4616-
4617- /* The try block is just the original function, there's no real
4618- need to call any function to do this. */
4619- fnbody = build_stmt (fn_start, TRY_BLOCK, fnbody, NULL_TREE);
4620- TRY_HANDLERS (fnbody) = push_stmt_list ();
4621- /* Mimic what the parser does for the catch. */
4622- tree handler = begin_handler ();
4623- finish_handler_parms (NULL_TREE, handler); /* catch (...) */
4624-
4625- /* Get the initial await resume called value. */
4626- tree i_a_r_c = build_class_member_access_expr (actor_frame, i_a_r_c_m,
4627- NULL_TREE, false,
4628- tf_warning_or_error);
4629- tree not_iarc_if = begin_if_stmt ();
4630- tree not_iarc = build1_loc (fn_start, TRUTH_NOT_EXPR,
4631- boolean_type_node, i_a_r_c);
4632- finish_if_stmt_cond (not_iarc, not_iarc_if);
4633- /* If the initial await resume called value is false, rethrow... */
4634- tree rethrow = build_throw (fn_start, NULL_TREE);
4635- TREE_NO_WARNING (rethrow) = true;
4636- finish_expr_stmt (rethrow);
4637- finish_then_clause (not_iarc_if);
4638- tree iarc_scope = IF_SCOPE (not_iarc_if);
4639- IF_SCOPE (not_iarc_if) = NULL;
4640- not_iarc_if = do_poplevel (iarc_scope);
4641- add_stmt (not_iarc_if);
4642- /* ... else call the promise unhandled exception method. */
4643- ueh = maybe_cleanup_point_expr_void (ueh);
4644- add_stmt (ueh);
4645- finish_handler (handler);
4646- TRY_HANDLERS (fnbody) = pop_stmt_list (TRY_HANDLERS (fnbody));
4647- /* If the function starts with a BIND_EXPR, then we need to create
4648- one here to contain the try-catch and to link up the scopes. */
4649- if (orig_fn_has_outer_bind)
4650- {
4651- fnbody = build3 (BIND_EXPR, void_type_node, NULL, fnbody, NULL);
4652- /* Make and connect the scope blocks. */
4653- tree tcb_block = make_node (BLOCK);
4654- /* .. and connect it here. */
4655- BLOCK_SUPERCONTEXT (replace_blk) = tcb_block;
4656- BLOCK_SUBBLOCKS (tcb_block) = replace_blk;
4657- BIND_EXPR_BLOCK (fnbody) = tcb_block;
4658- TREE_SIDE_EFFECTS (fnbody) = true;
4659- }
4660- }
4661- else if (pedantic)
4662- {
4663- /* We still try to look for the promise method and warn if it's not
4664- present. */
4665- tree ueh_meth
4666- = lookup_promise_method (orig, coro_unhandled_exception_identifier,
4667- fn_start, /*musthave=*/false);
4668- if (!ueh_meth || ueh_meth == error_mark_node)
4669- warning_at (fn_start, 0, "no member named %qE in %qT",
4670- coro_unhandled_exception_identifier,
4671- get_coroutine_promise_type (orig));
4672- }
4673- /* Else we don't check and don't care if the method is missing. */
4674-
46754559 /* Start to build the final functions.
46764560
46774561 We push_deferring_access_checks to avoid these routines being seen as
@@ -4681,7 +4565,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
46814565
46824566 /* Build the actor... */
46834567 build_actor_fn (fn_start, coro_frame_type, actor, fnbody, orig, param_uses,
4684- &local_var_uses, param_dtor_list, initial_await, final_await,
4568+ &local_var_uses, param_dtor_list, fs_label, resume_fn_field,
46854569 body_aw_points.await_number, frame_size);
46864570
46874571 /* Destroyer ... */