Tested on x86_64-darwin, powerpc64le-linux, OK for trunk? thanks Iain --- 8< ---
At present, we can issue diagnostics about missing or malformed awaiter or promise methods when we encounter their uses in the body of a users function. We might then re-issue the same diagnostics when processing the initial or final await expressions. This change avoids such duplication, and also attempts to identify issues with the initial or final expressions specifically since diagnostics for those do not have any useful line number. gcc/cp/ChangeLog: * coroutines.cc (build_co_await): Identify diagnostics for initial and final await expressions. (cp_coroutine_transform::wrap_original_function_body): Do not handle initial and final await expressions here ... (cp_coroutine_transform::apply_transforms): ... handle them here and avoid duplicate diagnostics. * coroutines.h: Declare inital and final await expressions in the transform class. gcc/testsuite/ChangeLog: * g++.dg/coroutines/coro-missing-final-suspend.C: Adjust for improved diagnostics. * g++.dg/coroutines/coro1-missing-await-method.C: Likewise. * g++.dg/coroutines/pr104051.C: Likewise. Signed-off-by: Iain Sandoe <i...@sandoe.co.uk> --- gcc/cp/coroutines.cc | 21 +++++++++++++++---- gcc/cp/coroutines.h | 3 +++ .../coroutines/coro-missing-final-suspend.C | 4 ++-- .../coroutines/coro1-missing-await-method.C | 2 +- gcc/testsuite/g++.dg/coroutines/pr104051.C | 4 ++-- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index bf3ab2d7250..aa00a8a4e68 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1277,8 +1277,13 @@ 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); + const char *extra = ""; + if (suspend_kind == FINAL_SUSPEND_POINT) + extra = "final_suspend "; + if (suspend_kind == INITIAL_SUSPEND_POINT) + extra = "initial_suspend "; + error_at (loc, "%sawaitable type %qT is not a structure", + extra, o_type); return error_mark_node; } @@ -4346,7 +4351,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 @@ -4540,7 +4544,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); @@ -5278,6 +5283,14 @@ 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 ()) + { + initial_await = build_init_or_final_await (fn_start, false); + if (initial_await && initial_await != error_mark_node) + final_await = build_init_or_final_await (input_location, true); + } + /* Transform the function body as per [dcl.fct.def.coroutine] / 5. */ wrap_original_function_body (); diff --git a/gcc/cp/coroutines.h b/gcc/cp/coroutines.h index 55caa6e61e3..77f7bd33f76 100644 --- a/gcc/cp/coroutines.h +++ b/gcc/cp/coroutines.h @@ -126,6 +126,9 @@ private: bool inline_p = false; bool valid_coroutine = false; + tree initial_await = error_mark_node; + tree final_await = error_mark_node; + void analyze_fn_parms (); void wrap_original_function_body (); bool build_ramp_function (); diff --git a/gcc/testsuite/g++.dg/coroutines/coro-missing-final-suspend.C b/gcc/testsuite/g++.dg/coroutines/coro-missing-final-suspend.C index 6a0878c1269..b2522311a49 100644 --- a/gcc/testsuite/g++.dg/coroutines/coro-missing-final-suspend.C +++ b/gcc/testsuite/g++.dg/coroutines/coro-missing-final-suspend.C @@ -7,10 +7,10 @@ #include "coro1-ret-int-yield-int.h" coro1 -my_coro () // { dg-error {no member named 'final_suspend' in} } +my_coro () { co_return 0; -} +} // { dg-error {no member named 'final_suspend' in} } // check we have not messed up continuation of the compilation. template <class... Args> diff --git a/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C b/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C index c1869e0654c..c6a3188ee35 100644 --- a/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C +++ b/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C @@ -7,7 +7,7 @@ #include "coro1-ret-int-yield-int.h" coro1 -bar0 () // { dg-error {no member named 'await_suspend' in 'coro1::suspend_always_prt'} } +bar0 () { co_await coro1::suspend_never_prt{}; // { dg-error {no member named 'await_ready' in 'coro1::suspend_never_prt'} } co_yield 5; // { dg-error {no member named 'await_suspend' in 'coro1::suspend_always_prt'} } diff --git a/gcc/testsuite/g++.dg/coroutines/pr104051.C b/gcc/testsuite/g++.dg/coroutines/pr104051.C index f77a915af74..fbeb15c2203 100644 --- a/gcc/testsuite/g++.dg/coroutines/pr104051.C +++ b/gcc/testsuite/g++.dg/coroutines/pr104051.C @@ -24,7 +24,7 @@ template <typename T> struct task { std::coroutine_handle<> await_suspend(std::coroutine_handle<>); T await_resume(); }; -task<std::vector<int>> foo() { // { dg-error {awaitable type 'bool' is not a structure} } +task<std::vector<int>> foo() { while ((co_await foo()).empty()) ; -} +} // { dg-error {final_suspend awaitable type 'bool' is not a structure} } -- 2.39.2 (Apple Git-143)