From 3904cc106e394ef2a4621576c9fdd53b597add36 Mon Sep 17 00:00:00 2001 From: Bin Cheng Date: Thu, 30 Jan 2020 12:33:47 +0800 Subject: [PATCH] Use promise in coroutine frame in actor function. By standard, coroutine body should be encapsulated in try-catch block as following: try { // coroutine body } catch(...) { promise.unhandled_exception(); } Given above try-catch block is implemented in the coroutine actor function called by coroutine ramp function, so the promise should be accessed via actor function's coroutine frame pointer argument, rather than the ramp function's coroutine frame variable. This patch cleans code a bit to make fix easy. gcc/cp * coroutines.cc (act_des_fn): New. (morph_fn_to_coro): Call act_des_fn to build actor/destroy decls. Access promise via actor function's frame pointer argument. (build_actor_fn, build_destroy_fn): Use frame pointer argument. --- gcc/cp/ChangeLog | 7 +++++ gcc/cp/coroutines.cc | 69 +++++++++++++++++++++++--------------------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 335652451bd..a402b975ce3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2020-01-30 Bin Cheng + + * coroutines.cc (act_des_fn): New. + (morph_fn_to_coro): Call act_des_fn to build actor/destroy decls. + Access promise via actor function's frame pointer argument. + (build_actor_fn, build_destroy_fn): Use frame pointer argument. + 2020-01-30 Bin Cheng * coroutines.cc (co_await_expander): Handle type conversion case. diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 7deb6f6e3e4..f7f85cb7643 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1828,11 +1828,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree act_des_fn_ptr = build_pointer_type (act_des_fn_type); /* One param, the coro frame pointer. */ - tree actor_fp - = build_lang_decl (PARM_DECL, get_identifier ("frame_ptr"), coro_frame_ptr); - DECL_CONTEXT (actor_fp) = actor; - DECL_ARG_TYPE (actor_fp) = type_passed_as (coro_frame_ptr); - DECL_ARGUMENTS (actor) = actor_fp; + tree actor_fp = DECL_ARGUMENTS (actor); /* A void return. */ tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node); @@ -2219,12 +2215,7 @@ build_destroy_fn (location_t loc, tree coro_frame_type, tree destroy, tree actor) { /* One param, the coro frame pointer. */ - tree coro_frame_ptr = build_pointer_type (coro_frame_type); - tree destr_fp - = build_lang_decl (PARM_DECL, get_identifier ("frame_ptr"), coro_frame_ptr); - DECL_CONTEXT (destr_fp) = destroy; - DECL_ARG_TYPE (destr_fp) = type_passed_as (coro_frame_ptr); - DECL_ARGUMENTS (destroy) = destr_fp; + tree destr_fp = DECL_ARGUMENTS (destroy); /* A void return. */ tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node); @@ -2865,6 +2856,24 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) return NULL_TREE; } +/* Build, return FUNCTION_DECL node with its coroutine frame pointer argument + for either actor or destroy functions. */ + +static tree +act_des_fn (tree orig, tree fn_type, tree coro_frame_ptr, const char* name) +{ + tree fn_name = get_fn_local_identifier (orig, name); + tree fn = build_lang_decl (FUNCTION_DECL, fn_name, fn_type); + DECL_CONTEXT (fn) = DECL_CONTEXT (orig); + DECL_INITIAL (fn) = error_mark_node; + tree id = get_identifier ("frame_ptr"); + tree fp = build_lang_decl (PARM_DECL, id, coro_frame_ptr); + DECL_CONTEXT (fp) = fn; + DECL_ARG_TYPE (fp) = type_passed_as (coro_frame_ptr); + DECL_ARGUMENTS (fn) = fp; + return fn; +} + /* Here we: a) Check that the function and promise type are valid for a coroutine. @@ -2991,17 +3000,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) = build_function_type_list (void_type_node, coro_frame_ptr, NULL_TREE); tree act_des_fn_ptr = build_pointer_type (act_des_fn_type); - /* Declare the actor function. */ - tree actor_name = get_fn_local_identifier (orig, "actor"); - tree actor = build_lang_decl (FUNCTION_DECL, actor_name, act_des_fn_type); - DECL_CONTEXT (actor) = DECL_CONTEXT (orig); - DECL_INITIAL (actor) = error_mark_node; - - /* Declare the destroyer function. */ - tree destr_name = get_fn_local_identifier (orig, "destroy"); - tree destroy = build_lang_decl (FUNCTION_DECL, destr_name, act_des_fn_type); - DECL_CONTEXT (destroy) = DECL_CONTEXT (orig); - DECL_INITIAL (destroy) = error_mark_node; + /* Declare the actor and destroyer function. */ + tree actor = act_des_fn (orig, act_des_fn_type, coro_frame_ptr, "actor"); + tree destroy = act_des_fn (orig, act_des_fn_type, coro_frame_ptr, "destroy"); /* Build our dummy coro frame layout. */ coro_frame_type = begin_class_definition (coro_frame_type); @@ -3598,39 +3599,41 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) tree ueh_meth = lookup_promise_method (orig, coro_unhandled_exception_identifier, fn_start, /*musthave=*/true); + /* actor's version of the promise. */ + tree actor_frame = build1_loc (fn_start, INDIRECT_REF, coro_frame_type, + DECL_ARGUMENTS (actor)); + tree ap_m = lookup_member (coro_frame_type, get_identifier ("__p"), 1, 0, + tf_warning_or_error); + tree ap = build_class_member_access_expr (actor_frame, ap_m, NULL_TREE, + false, tf_warning_or_error); /* Build promise.unhandled_exception(); */ tree ueh - = build_new_method_call (p, ueh_meth, NULL, NULL_TREE, LOOKUP_NORMAL, + = build_new_method_call (ap, ueh_meth, NULL, NULL_TREE, LOOKUP_NORMAL, NULL, tf_warning_or_error); /* The try block is just the original function, there's no real need to call any function to do this. */ - tree tcb = build_stmt (fn_start, TRY_BLOCK, NULL_TREE, NULL_TREE); - TRY_STMTS (tcb) = fnbody; - TRY_HANDLERS (tcb) = push_stmt_list (); + fnbody = build_stmt (fn_start, TRY_BLOCK, fnbody, NULL_TREE); + TRY_HANDLERS (fnbody) = push_stmt_list (); /* Mimic what the parser does for the catch. */ tree handler = begin_handler (); finish_handler_parms (NULL_TREE, handler); /* catch (...) */ ueh = maybe_cleanup_point_expr_void (ueh); add_stmt (ueh); finish_handler (handler); - TRY_HANDLERS (tcb) = pop_stmt_list (TRY_HANDLERS (tcb)); + TRY_HANDLERS (fnbody) = pop_stmt_list (TRY_HANDLERS (fnbody)); /* If the function starts with a BIND_EXPR, then we need to create one here to contain the try-catch and to link up the scopes. */ if (orig_fn_has_outer_bind) { - tree tcb_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL); + fnbody = build3 (BIND_EXPR, void_type_node, NULL, fnbody, NULL); /* Make and connect the scope blocks. */ tree tcb_block = make_node (BLOCK); /* .. and connect it here. */ BLOCK_SUPERCONTEXT (replace_blk) = tcb_block; BLOCK_SUBBLOCKS (tcb_block) = replace_blk; - BIND_EXPR_BLOCK (tcb_bind) = tcb_block; - BIND_EXPR_BODY (tcb_bind) = tcb; - fnbody = tcb_bind; + BIND_EXPR_BLOCK (fnbody) = tcb_block; } - else - fnbody = tcb; } else if (pedantic) { -- 2.30.2