Hi Jason, >>+ point to the closing brace. */ >>+ input_location = fn_end;
>If we're going to have the loc variable at all, how about adjusting it here... Done. >> resume_fn_ptr, zero_resume); >...so you don't need to change these uses... >> finish_expr_stmt (zero_resume); >>- finish_expr_stmt (build_init_or_final_await (fn_start, true)); >>+ finish_expr_stmt (build_init_or_final_await (fn_end, true)); >...and use it here as well. Done here too - now adjusted to use 'loc' consistently. We still have to reset input_location, because of other code that might refer to it directly. OK for trunk now? thanks Iain --- 8< --- Some of the lookup code is expecting to find a valid (not UNKNOWN) location, which triggers in the reported case. To avoid this, we are reverting the change to use UNKNOWN_LOCATION for synthesizing the wrapper, and instead using the start and end locations of the original function. PR c++/120273 gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::wrap_original_function_body): Use function start and end locations when synthesizing code. (cp_coroutine_transform::cp_coroutine_transform): Set the function end location. * coroutines.h: Add the function end location. gcc/testsuite/ChangeLog: * g++.dg/coroutines/coro-missing-final-suspend.C: Adjust for changed final suspend diagnostics line number change. * g++.dg/coroutines/coro1-missing-await-method.C: Likewise. * g++.dg/coroutines/pr104051.C: Likewise. * g++.dg/coroutines/pr120273.C: New test. Signed-off-by: Iain Sandoe <i...@sandoe.co.uk> --- gcc/cp/coroutines.cc | 22 ++++--- gcc/cp/coroutines.h | 1 + .../coroutines/coro-missing-final-suspend.C | 4 +- .../coroutines/coro1-missing-await-method.C | 2 +- gcc/testsuite/g++.dg/coroutines/pr104051.C | 4 +- gcc/testsuite/g++.dg/coroutines/pr120273.C | 58 +++++++++++++++++++ 6 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/coroutines/pr120273.C diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 1fbdee1b4f6..6518e9202d0 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4307,8 +4307,7 @@ cp_coroutine_transform::wrap_original_function_body () { /* Avoid the code here attaching a location that makes the debugger jump. */ iloc_sentinel stable_input_loc (fn_start); - location_t loc = UNKNOWN_LOCATION; - input_location = loc; + location_t loc = fn_start; /* This will be our new outer scope. */ tree update_body @@ -4450,7 +4449,7 @@ cp_coroutine_transform::wrap_original_function_body () /* If the coroutine has a frame that needs to be freed, this will be set by the ramp. */ - var = coro_build_artificial_var (fn_start, coro_frame_needs_free_id, + var = coro_build_artificial_var (loc, coro_frame_needs_free_id, boolean_type_node, orig_fn_decl, NULL_TREE); DECL_CHAIN (var) = var_list; var_list = var; @@ -4462,7 +4461,7 @@ cp_coroutine_transform::wrap_original_function_body () tree ueh = coro_build_promise_expression (orig_fn_decl, promise, coro_unhandled_exception_identifier, - fn_start, NULL, /*musthave=*/true); + loc, NULL, /*musthave=*/true); /* Create and initialize the initial-await-resume-called variable per [dcl.fct.def.coroutine] / 5.3. */ tree i_a_r_c @@ -4524,9 +4523,9 @@ cp_coroutine_transform::wrap_original_function_body () tree ueh_meth = lookup_promise_method (orig_fn_decl, coro_unhandled_exception_identifier, - fn_start, /*musthave=*/false); + loc, /*musthave=*/false); if (!ueh_meth || ueh_meth == error_mark_node) - warning_at (fn_start, 0, "no member named %qE in %qT", + warning_at (loc, 0, "no member named %qE in %qT", coro_unhandled_exception_identifier, get_coroutine_promise_type (orig_fn_decl)); } @@ -4539,6 +4538,10 @@ cp_coroutine_transform::wrap_original_function_body () add_stmt (return_void); } + /* We are now doing actions associated with the end of the function, so + point to the closing brace. */ + input_location = loc = fn_end; + /* co_return branches to the final_suspend label, so declare that now. */ fs_label = create_named_label_with_ctx (loc, "final.suspend", NULL_TREE); @@ -4550,7 +4553,7 @@ 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 (build_init_or_final_await (loc, true)); 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); @@ -5207,9 +5210,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"); diff --git a/gcc/cp/coroutines.h b/gcc/cp/coroutines.h index 55caa6e61e3..cb5d5572733 100644 --- a/gcc/cp/coroutines.h +++ b/gcc/cp/coroutines.h @@ -102,6 +102,7 @@ private: tree orig_fn_decl; /* The original function decl. */ tree orig_fn_body = NULL_TREE; /* The original function body. */ location_t fn_start = UNKNOWN_LOCATION; + location_t fn_end = UNKNOWN_LOCATION; tree resumer = error_mark_node; tree destroyer = error_mark_node; tree coroutine_body = NULL_TREE; 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..93b6159216f 100644 --- a/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C +++ b/gcc/testsuite/g++.dg/coroutines/coro1-missing-await-method.C @@ -13,7 +13,7 @@ bar0 () // { dg-error {no member named 'await_suspend' in 'coro1::suspend_always co_yield 5; // { dg-error {no member named 'await_suspend' in 'coro1::suspend_always_prt'} } co_await coro1::suspend_always_intprt(5); // { dg-error {no member named 'await_resume' in 'coro1::suspend_always_intprt'} } co_return 0; -} +} // { dg-error {no member named 'await_suspend' in 'coro1::suspend_always_prt'} } int main (int ac, char *av[]) { struct coro1 x0 = bar0 (); diff --git a/gcc/testsuite/g++.dg/coroutines/pr104051.C b/gcc/testsuite/g++.dg/coroutines/pr104051.C index f77a915af74..cd69877361d 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 {awaitable type 'bool' is not a structure} } diff --git a/gcc/testsuite/g++.dg/coroutines/pr120273.C b/gcc/testsuite/g++.dg/coroutines/pr120273.C new file mode 100644 index 00000000000..19b9e51b9fa --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr120273.C @@ -0,0 +1,58 @@ +// PR120273 +// { dg-additional-options "-Wno-literal-suffix" } +namespace std { +void declval(); +template < typename > struct invoke_result; +template < typename _Fn > using invoke_result_t = invoke_result< _Fn >; +template < typename _Derived, typename _Base > +concept derived_from = __is_base_of(_Base, _Derived); +template < typename, typename > +concept convertible_to = requires { declval; }; +template < char... > int operator""ms(); +template < typename _Result, typename > struct coroutine_traits : _Result {}; +template < typename = void > struct coroutine_handle { + static coroutine_handle from_address(void *); + operator coroutine_handle<>(); + void *address(); +}; +} + +using namespace std; + +template < class > using CoroutineHandle = coroutine_handle<>; + +template < class Callable > + requires(derived_from< invoke_result_t< Callable >, int >) +Callable operator co_await(Callable); + +struct FinalSuspendProxy { + bool await_ready() noexcept; + void await_suspend(CoroutineHandle< void >) noexcept ; + void await_resume() noexcept; +}; + +struct Task { + struct Promise; + using promise_type = Promise; + + struct Promise { + auto initial_suspend() { return FinalSuspendProxy(); } + auto final_suspend () noexcept { return FinalSuspendProxy(); } + void unhandled_exception () {} + Task get_return_object () { return {}; } + }; +} ; + +struct TestEventLoop { + struct Sleep { + Sleep(TestEventLoop, int); + bool await_ready(); + void await_suspend(CoroutineHandle< void >); + void await_resume(); + }; + auto sleep(int tm) { return Sleep(*this, tm); } +}; + +Task test_body_11(TestEventLoop t) { + co_await t.sleep(5ms); +} -- 2.39.2 (Apple Git-143)