From: Iain Sandoe Date: Wed, 31 Jul 2024 22:05:49 +0000 (+0100) Subject: c++, coroutines: Simplify separation of the user function body and ramp. X-Git-Url: https://gcc.gnu.org/git/?a=commitdiff_plain;h=86512292270860bbe1dd33cef1ebe041d597462c;p=gcc.git c++, coroutines: Simplify separation of the user function body and ramp. We need to separate the original user-authored function body from the definition of the ramp function (which is what is called instead). The function body tree is either in DECL_SAVED_TREE or the first operand of current_eh_spec_block (for functions with an EH spec). This version simplifies the process by extracting the second case directly instead of inspecting the DECL_SAVED_TREE trees to discover it. gcc/cp/ChangeLog: * coroutines.cc (split_coroutine_body_from_ramp): New. (morph_fn_to_coro): Use split_coroutine_body_from_ramp(). * cp-tree.h (use_eh_spec_block): New. * decl.cc (use_eh_spec_block): Make non-static. Signed-off-by: Iain Sandoe --- diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 742f0e505976..145ec4b1d16b 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4547,6 +4547,43 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, return update_body; } +/* Extract the body of the function we are going to outline, leaving + to original function decl ready to build the ramp. */ + +static tree +split_coroutine_body_from_ramp (tree fndecl) +{ + tree body; + /* Once we've tied off the original user-authored body in fn_body. + Start the replacement synthesized ramp body. */ + + if (use_eh_spec_block (fndecl)) + { + body = pop_stmt_list (TREE_OPERAND (current_eh_spec_block, 0)); + TREE_OPERAND (current_eh_spec_block, 0) = push_stmt_list (); + } + else + { + body = pop_stmt_list (DECL_SAVED_TREE (fndecl)); + DECL_SAVED_TREE (fndecl) = push_stmt_list (); + } + + /* We can't validly get here with an empty statement list, since there's no + way for the FE to decide it's a coroutine in the absence of any code. */ + gcc_checking_assert (body != NULL_TREE); + + /* If we have an empty or erroneous function body, do not try to transform it + since that would potentially wrap errors. */ + tree body_start = expr_first (body); + if (body_start == NULL_TREE || body_start == error_mark_node) + { + /* Restore the original state. */ + add_stmt (body); + return NULL_TREE; + } + return body; +} + /* Here we: a) Check that the function and promise type are valid for a coroutine. @@ -4593,57 +4630,22 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* Discard the body, we can't process it further. */ pop_stmt_list (DECL_SAVED_TREE (orig)); DECL_SAVED_TREE (orig) = push_stmt_list (); + /* Match the expected nesting when an eh block is in use. */ + if (use_eh_spec_block (orig)) + current_eh_spec_block = begin_eh_spec_block (); return false; } - /* We can't validly get here with an empty statement list, since there's no - way for the FE to decide it's a coroutine in the absence of any code. */ - tree fnbody = pop_stmt_list (DECL_SAVED_TREE (orig)); - gcc_checking_assert (fnbody != NULL_TREE); - /* We don't have the locus of the opening brace - it's filled in later (and there doesn't really seem to be any easy way to get at it). The closing brace is assumed to be input_location. */ location_t fn_start = DECL_SOURCE_LOCATION (orig); - gcc_rich_location fn_start_loc (fn_start); - - /* Initial processing of the function-body. - If we have no expressions or just an error then punt. */ - tree body_start = expr_first (fnbody); - if (body_start == NULL_TREE || body_start == error_mark_node) - { - DECL_SAVED_TREE (orig) = push_stmt_list (); - append_to_statement_list (fnbody, &DECL_SAVED_TREE (orig)); - /* Suppress warnings about the missing return value. */ - suppress_warning (orig, OPT_Wreturn_type); - return false; - } - - /* So, we've tied off the original user-authored body in fn_body. - - Start the replacement synthesized ramp body as newbody. - If we encounter a fatal error we might return a now-empty body. - - Note, the returned ramp body is not 'popped', to be compatible with - the way that decl.cc handles regular functions, the scope pop is done - in the caller. */ - tree newbody = push_stmt_list (); - DECL_SAVED_TREE (orig) = newbody; - - /* If our original body is noexcept, then that's what we apply to our - generated ramp, transfer any MUST_NOT_THOW_EXPR to that. */ - bool is_noexcept = TREE_CODE (body_start) == MUST_NOT_THROW_EXPR; - if (is_noexcept) - { - /* The function body we will continue with is the single operand to - the must-not-throw. */ - fnbody = TREE_OPERAND (body_start, 0); - /* Transfer the must-not-throw to the ramp body. */ - add_stmt (body_start); - /* Re-start the ramp as must-not-throw. */ - TREE_OPERAND (body_start, 0) = push_stmt_list (); - } + /* FIXME: This has the hidden side-effect of preparing the current function + to be the ramp. */ + tree fnbody = split_coroutine_body_from_ramp (orig); + if (!fnbody) + return false; /* 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 @@ -5169,7 +5171,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (get_ro == error_mark_node) { BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_body); - DECL_SAVED_TREE (orig) = newbody; /* Suppress warnings about the missing return value. */ suppress_warning (orig, OPT_Wreturn_type); return false; @@ -5396,7 +5397,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) pop_deferring_access_checks (); - DECL_SAVED_TREE (orig) = newbody; /* Link our new functions into the list. */ TREE_CHAIN (destroy) = TREE_CHAIN (orig); TREE_CHAIN (actor) = destroy; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 238d786b0674..911d1d7924cc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7097,6 +7097,7 @@ extern bool check_array_designated_initializer (constructor_elt *, unsigned HOST_WIDE_INT); extern bool check_for_uninitialized_const_var (tree, bool, tsubst_flags_t); extern tree build_explicit_specifier (tree, tsubst_flags_t); +extern bool use_eh_spec_block (tree); extern void do_push_parm_decls (tree, tree, tree *); extern tree do_aggregate_paren_init (tree, tree); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 687ae6937f53..641d44b21ea0 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -18303,7 +18303,7 @@ start_function (cp_decl_specifier_seq *declspecs, /* Returns true iff an EH_SPEC_BLOCK should be created in the body of FN. */ -static bool +bool use_eh_spec_block (tree fn) { return (flag_exceptions && flag_enforce_eh_specs