diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/coroutines.cc | 138 |
1 files changed, 124 insertions, 14 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index af03f5e..742f0e5 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -91,6 +91,7 @@ struct GTY((for_user)) coroutine_info one that will eventually be allocated in the coroutine frame. */ tree promise_proxy; /* Likewise, a proxy promise instance. */ + tree from_address; /* handle_type from_address function. */ tree return_void; /* The expression for p.return_void() if it exists. */ location_t first_coro_keyword; /* The location of the keyword that made this function into a coroutine. */ @@ -203,7 +204,6 @@ static GTY(()) tree coro_final_suspend_identifier; static GTY(()) tree coro_return_void_identifier; static GTY(()) tree coro_return_value_identifier; static GTY(()) tree coro_yield_value_identifier; -static GTY(()) tree coro_resume_identifier; static GTY(()) tree coro_address_identifier; static GTY(()) tree coro_from_address_identifier; static GTY(()) tree coro_get_return_object_identifier; @@ -243,7 +243,6 @@ coro_init_identifiers () coro_return_void_identifier = get_identifier ("return_void"); coro_return_value_identifier = get_identifier ("return_value"); coro_yield_value_identifier = get_identifier ("yield_value"); - coro_resume_identifier = get_identifier ("resume"); coro_address_identifier = get_identifier ("address"); coro_from_address_identifier = get_identifier ("from_address"); coro_get_return_object_identifier = get_identifier ("get_return_object"); @@ -271,6 +270,7 @@ coro_init_identifiers () static GTY(()) tree coro_traits_templ; static GTY(()) tree coro_handle_templ; static GTY(()) tree void_coro_handle_type; +static GTY(()) tree void_coro_handle_address; /* ================= Parse, Semantics and Type checking ================= */ @@ -389,7 +389,97 @@ find_coro_handle_template_decl (location_t kw) return handle_decl; } -/* Instantiate the handle template for a given promise type. */ +/* Get and validate HANDLE_TYPE::address. The resulting function, if any, will + be a non-overloaded member function that takes no arguments and returns + void*. If that is not the case, signals an error and returns NULL_TREE. */ + +static tree +get_handle_type_address (location_t kw, tree handle_type) +{ + tree addr_getter = lookup_member (handle_type, coro_address_identifier, 1, + 0, tf_warning_or_error); + if (!addr_getter || addr_getter == error_mark_node) + { + qualified_name_lookup_error (handle_type, coro_address_identifier, + error_mark_node, kw); + return NULL_TREE; + } + + if (!BASELINK_P (addr_getter) + || TREE_CODE (TREE_TYPE (addr_getter)) != METHOD_TYPE) + { + error_at (kw, "%qE must be a non-overloaded method", addr_getter); + return NULL_TREE; + } + + tree fn_t = TREE_TYPE (addr_getter); + tree arg = TYPE_ARG_TYPES (fn_t); + + /* Skip the 'this' pointer. */ + arg = TREE_CHAIN (arg); + + /* Check that from_addr has the argument list (). */ + if (arg != void_list_node) + { + error_at (kw, "%qE must take no arguments", addr_getter); + return NULL_TREE; + } + + tree ret_t = TREE_TYPE (fn_t); + if (!same_type_p (ret_t, ptr_type_node)) + { + error_at (kw, "%qE must return %qT, not %qT", + addr_getter, ptr_type_node, ret_t); + return NULL_TREE; + } + + return addr_getter; +} + +/* Get and validate HANDLE_TYPE::from_address. The resulting function, if + any, will be a non-overloaded static function that takes a single void* and + returns HANDLE_TYPE. If that is not the case, signals an error and returns + NULL_TREE. */ + +static tree +get_handle_type_from_address (location_t kw, tree handle_type) +{ + tree from_addr = lookup_member (handle_type, coro_from_address_identifier, 1, + 0, tf_warning_or_error); + if (!from_addr || from_addr == error_mark_node) + { + qualified_name_lookup_error (handle_type, coro_from_address_identifier, + error_mark_node, kw); + return NULL_TREE; + } + if (!BASELINK_P (from_addr) + || TREE_CODE (TREE_TYPE (from_addr)) != FUNCTION_TYPE) + { + error_at (kw, "%qE must be a non-overloaded static function", from_addr); + return NULL_TREE; + } + + tree fn_t = TREE_TYPE (from_addr); + tree arg = TYPE_ARG_TYPES (fn_t); + /* Check that from_addr has the argument list (void*). */ + if (!arg + || !same_type_p (TREE_VALUE (arg), ptr_type_node) + || TREE_CHAIN (arg) != void_list_node) + { + error_at (kw, "%qE must take a single %qT", from_addr, ptr_type_node); + return NULL_TREE; + } + + tree ret_t = TREE_TYPE (fn_t); + if (!same_type_p (ret_t, handle_type)) + { + error_at (kw, "%qE must return %qT, not %qT", + from_addr, handle_type, ret_t); + return NULL_TREE; + } + + return from_addr; +} static tree instantiate_coro_handle_for_promise_type (location_t kw, tree promise_type) @@ -453,11 +543,16 @@ ensure_coro_initialized (location_t loc) return false; /* We can also instantiate the void coroutine_handle<> */ - void_coro_handle_type = - instantiate_coro_handle_for_promise_type (loc, NULL_TREE); + void_coro_handle_type + = instantiate_coro_handle_for_promise_type (loc, void_type_node); if (void_coro_handle_type == NULL_TREE) return false; + void_coro_handle_address + = get_handle_type_address (loc, void_coro_handle_type); + if (!void_coro_handle_address) + return false; + /* A table to hold the state, per coroutine decl. */ gcc_checking_assert (coroutine_info_table == NULL); coroutine_info_table = @@ -552,13 +647,17 @@ coro_promise_type_found_p (tree fndecl, location_t loc) } /* Try to find the handle type for the promise. */ - tree handle_type = - instantiate_coro_handle_for_promise_type (loc, coro_info->promise_type); + tree handle_type + = instantiate_coro_handle_for_promise_type (loc, coro_info->promise_type); if (handle_type == NULL_TREE) return false; + tree from_address = get_handle_type_from_address (loc, handle_type); + if (from_address == NULL_TREE) + return false; /* Complete this, we're going to use it. */ coro_info->handle_type = complete_type_or_else (handle_type, fndecl); + coro_info->from_address = from_address; /* Diagnostic would be emitted by complete_type_or_else. */ if (!coro_info->handle_type) @@ -675,6 +774,15 @@ get_coroutine_promise_proxy (tree decl) } static tree +get_coroutine_from_address (tree decl) +{ + if (coroutine_info *info = get_coroutine_info (decl)) + return info->from_address; + + return NULL_TREE; +} + +static tree lookup_promise_method (tree fndecl, tree member_id, location_t loc, bool musthave) { @@ -2232,7 +2340,6 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, { verify_stmt_tree (fnbody); /* Some things we inherit from the original function. */ - tree handle_type = get_coroutine_handle_type (orig); tree promise_type = get_coroutine_promise_type (orig); tree promise_proxy = get_coroutine_promise_proxy (orig); @@ -2392,8 +2499,9 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree ash = build_class_member_access_expr (actor_frame, ash_m, NULL_TREE, false, tf_warning_or_error); /* So construct the self-handle from the frame address. */ - tree hfa_m = lookup_member (handle_type, coro_from_address_identifier, 1, - 0, tf_warning_or_error); + tree hfa_m = get_coroutine_from_address (orig); + /* Should have been set earlier by coro_promise_type_found_p. */ + gcc_assert (hfa_m); r = build1 (CONVERT_EXPR, build_pointer_type (void_type_node), actor_fp); vec<tree, va_gc> *args = make_tree_vector_single (r); @@ -2488,12 +2596,14 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, r = build_stmt (loc, LABEL_EXPR, continue_label); add_stmt (r); + /* Should have been set earlier by the coro_initialized code. */ + gcc_assert (void_coro_handle_address); + /* We want to force a tail-call even for O0/1, so this expands the resume call into its underlying implementation. */ - tree addr = lookup_member (void_coro_handle_type, coro_address_identifier, - 1, 0, tf_warning_or_error); - addr = build_new_method_call (continuation, addr, NULL, NULL_TREE, - LOOKUP_NORMAL, NULL, tf_warning_or_error); + tree addr = build_new_method_call (continuation, void_coro_handle_address, + NULL, NULL_TREE, LOOKUP_NORMAL, NULL, + tf_warning_or_error); tree resume = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_CORO_RESUME), 1, addr); |