Hi Jason, This replaces "c-lex: Handle NULL filenames from UNKNOWN_LOCATION" as we discussed off-list, you prefer a solution that has valid locations during the synthesis. I have reverted to using the function location for code that represents start-up and the closing brace for code that represents shut-down. Note that we do not have (and cannot easily get) the position of the opening brace.
Tested on x86_64 darwin and powerpc64le linux, OK for trunk? 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 | 18 +++--- 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, 75 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/g++.dg/coroutines/pr120273.C diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 97eee6e8ea4..d482f52fefa 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4281,8 +4281,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 @@ -4513,18 +4512,22 @@ 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 = 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); - add_stmt (build_stmt (loc, LABEL_EXPR, fs_label)); + add_stmt (build_stmt (fn_end, LABEL_EXPR, fs_label)); /* Before entering the final suspend point, we signal that this point has been reached by setting the resume function pointer to zero (this is what the 'done()' builtin tests) as per the current ABI. */ - zero_resume = build2_loc (loc, MODIFY_EXPR, act_des_fn_ptr_type, + zero_resume = build2_loc (fn_end, 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 (fn_end, 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); @@ -5181,9 +5184,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)