aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/coroutines.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/coroutines.cc')
-rw-r--r--gcc/cp/coroutines.cc57
1 files changed, 50 insertions, 7 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 97eee6e..4057a07 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1277,8 +1277,14 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind,
if (TREE_CODE (o_type) != RECORD_TYPE)
{
- error_at (loc, "awaitable type %qT is not a structure",
- o_type);
+ if (suspend_kind == FINAL_SUSPEND_POINT)
+ error_at (loc, "%qs awaitable type %qT is not a structure",
+ "final_suspend()", o_type);
+ else if (suspend_kind == INITIAL_SUSPEND_POINT)
+ error_at (loc, "%qs awaitable type %qT is not a structure",
+ "initial_suspend()", o_type);
+ else
+ error_at (loc, "awaitable type %qT is not a structure", o_type);
return error_mark_node;
}
@@ -2406,6 +2412,11 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
bool spf = start_preparsed_function (actor, NULL_TREE, SF_PRE_PARSED);
gcc_checking_assert (spf);
gcc_checking_assert (cfun && current_function_decl && TREE_STATIC (actor));
+ if (flag_exceptions)
+ /* We, unconditionally, add a try/catch and rethrow.
+ TODO: Determine if the combination of initial suspend and the original
+ body cannot throw, and elide these additions. */
+ cp_function_chain->can_throw = true;
tree stmt = begin_function_body ();
tree actor_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
@@ -3420,7 +3431,8 @@ maybe_promote_temps (tree *stmt, void *d)
return cp_walk_tree (stmt, register_awaits, d, &visited);
}
-/* Lightweight callback to determine two key factors:
+/* Relatively lightweight callback to do initial assessment:
+ 0) Rewrite some await expressions.
1) If the statement/expression contains any await expressions.
2) If the statement/expression potentially requires a re-write to handle
TRUTH_{AND,OR}IF_EXPRs since, in most cases, they will need expansion
@@ -3437,6 +3449,26 @@ analyze_expression_awaits (tree *stmt, int *do_subtree, void *d)
switch (TREE_CODE (*stmt))
{
default: return NULL_TREE;
+ case CALL_EXPR:
+ {
+ tree fn = cp_get_callee_fndecl_nofold (*stmt);
+ /* Special-cases where we want to re-write await expressions to some
+ other value before they are otherwise processed. */
+ if (fn && DECL_IS_BUILTIN_CONSTANT_P (fn))
+ {
+ gcc_checking_assert (call_expr_nargs (*stmt) == 1);
+ tree expr = CALL_EXPR_ARG (*stmt, 0);
+ if (cp_walk_tree (&expr, find_any_await, nullptr, NULL))
+ {
+ if (TREE_CONSTANT (maybe_constant_value (expr)))
+ *stmt = integer_one_node;
+ else
+ *stmt = integer_zero_node;
+ }
+ *do_subtree = 0;
+ }
+ }
+ break;
case CO_YIELD_EXPR:
/* co_yield is syntactic sugar, re-write it to co_await. */
*stmt = TREE_OPERAND (*stmt, 1);
@@ -4330,7 +4362,6 @@ cp_coroutine_transform::wrap_original_function_body ()
/* Wrap the function body in a try {} catch (...) {} block, if exceptions
are enabled. */
tree var_list = NULL_TREE;
- tree initial_await = build_init_or_final_await (fn_start, false);
/* [stmt.return.coroutine] / 3
If p.return_void() is a valid expression, flowing off the end of a
@@ -4524,7 +4555,8 @@ cp_coroutine_transform::wrap_original_function_body ()
zero_resume = build2_loc (loc, MODIFY_EXPR, act_des_fn_ptr_type,
resume_fn_ptr, zero_resume);
finish_expr_stmt (zero_resume);
- finish_expr_stmt (build_init_or_final_await (fn_start, true));
+ finish_expr_stmt (final_await);
+
BIND_EXPR_BODY (update_body) = pop_stmt_list (BIND_EXPR_BODY (update_body));
BIND_EXPR_VARS (update_body) = nreverse (var_list);
BLOCK_VARS (top_block) = BIND_EXPR_VARS (update_body);
@@ -5181,9 +5213,10 @@ cp_coroutine_transform::cp_coroutine_transform (tree _orig_fn, bool _inl)
}
/* 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. */
+ there doesn't really seem to be any easy way to get at it). */
fn_start = DECL_SOURCE_LOCATION (orig_fn_decl);
+ /* The closing brace is assumed to be input_location. */
+ fn_end = input_location;
/* Build types we need. */
tree fr_name = get_fn_local_identifier (orig_fn_decl, "Frame");
@@ -5262,6 +5295,16 @@ cp_coroutine_transform::apply_transforms ()
= coro_build_actor_or_destroy_function (orig_fn_decl, act_des_fn_type,
frame_ptr_type, false);
+ /* Avoid repeating diagnostics about promise or awaiter fails. */
+ if (!seen_error ())
+ {
+ iloc_sentinel stable_input_loc (fn_start);
+ initial_await = build_init_or_final_await (fn_start, false);
+ input_location = fn_end;
+ if (initial_await && initial_await != error_mark_node)
+ final_await = build_init_or_final_await (fn_end, true);
+ }
+
/* Transform the function body as per [dcl.fct.def.coroutine] / 5. */
wrap_original_function_body ();