> On 3 Jun 2025, at 17:03, Jason Merrill <ja...@redhat.com> wrote:
>
> On 5/29/25 8:29 AM, Iain Sandoe wrote:
>> To trigger this involves somewhat tortuous pathways through the
>> c++ requires code. I did consider the alternative of putting in
>> an assert and then checking every call-site, but that seemed to
>> be a much larger change.
>> tested on x86_64-darwin and powerpc64le-linux, OK for trunk?
>> thanks
>> Iain
>> --- 8< ---
>> This was reported against the coroutines implementation, but could
>> affect other code.
>> We intentionally synthesize code with UNKNOWN_LOCATIONs in the
>> implementation to avoid the effect of the code position jumping
>> around in debug sessions.
>
> It seems like we're doing that too broadly if it means we get classes with no
> location.
Not 100% sure what you mean here;
We are only synthesizing the extra code specified in the std. with
UKNOWN_LOCATION, the user-defined awaiters (and the user’s function body) etc
would have their actual locations.
> Here we're building the initial co_await, which seems like it should have
> the location of the open brace of the function?
Unfortunately, we do not have the location of the open brace, that gets set
after finish_function, but we do have the function location.
I did originally associate the startup code with the function location and the
shutdown code with ‘input_location’ which is at the closing brace when we reach
finish_function, so we could return to that mechanism, if preferred ( I am not
sure how serious the unstable debug locations is when in code that has no
source equivalent ).
Iain
>> The location expansion of fileinfo is not expecting to deal with
>> NULL name pointers. The patch here checks this case and adds a
>> "<unknown file>" as the name, avoiding the ICE and providing at
>> least a basic indication to the end-user.
>> PR c++/120273
>> gcc/c-family/ChangeLog:
>> * c-lex.cc (get_fileinfo): When presented with a NULL
>> name pointer, report "<unknown file>".
>> gcc/testsuite/ChangeLog:
>> * g++.dg/coroutines/pr120273.C: New test.
>> Signed-off-by: Iain Sandoe <i...@sandoe.co.uk>
>> ---
>> gcc/c-family/c-lex.cc | 4 ++
>> gcc/testsuite/g++.dg/coroutines/pr120273.C | 58 ++++++++++++++++++++++
>> 2 files changed, 62 insertions(+)
>> create mode 100644 gcc/testsuite/g++.dg/coroutines/pr120273.C
>> diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc
>> index fef6ae6f457..43054f105ea 100644
>> --- a/gcc/c-family/c-lex.cc
>> +++ b/gcc/c-family/c-lex.cc
>> @@ -109,6 +109,10 @@ get_fileinfo (const char *name)
>> 0,
>> splay_tree_delete_pointers);
>> + /* If we have an UNKOWN_LOCATION, it has no filename. */
>> + if (!name)
>> + name = "<unknown file>";
>> +
>> n = splay_tree_lookup (file_info_tree, (splay_tree_key) name);
>> if (n)
>> return (struct c_fileinfo *) n->value;
>> 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);
>> +}