https://gcc.gnu.org/g:3b95be7bd1882add4b1e22f6b70bc130cd465eca
commit r16-1534-g3b95be7bd1882add4b1e22f6b70bc130cd465eca Author: Iain Sandoe <i...@sandoe.co.uk> Date: Tue Jun 3 13:07:27 2025 +0100 c++, coroutines: Avoid UNKNOWN_LOCATION synthesizing code [PR120273]. 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. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr120273.C: New test. Signed-off-by: Iain Sandoe <i...@sandoe.co.uk> Diff: --- gcc/cp/coroutines.cc | 15 ++++---- gcc/testsuite/g++.dg/coroutines/pr120273.C | 58 ++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 4057a0762baf..17d0ee997903 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4313,8 +4313,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 @@ -4455,7 +4454,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; @@ -4467,7 +4466,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 @@ -4529,9 +4528,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)); } @@ -4544,6 +4543,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); diff --git a/gcc/testsuite/g++.dg/coroutines/pr120273.C b/gcc/testsuite/g++.dg/coroutines/pr120273.C new file mode 100644 index 000000000000..19b9e51b9faf --- /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); +}