https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118074
--- Comment #7 from Weibo He <newsigma at 163 dot com> --- Thanks, @Yanzuo Liu It seems there are three issues with the bug: 1. [GCC 15 Regression]: Bad interaction with NRV for the trunk 2. [GCC 15 Regression]: Return object is being prematurely converted Clang community resolved a similar issue: https://github.com/llvm/llvm-project/issues/56532 https://godbolt.org/z/aE7jMxoE5 Expected Output(GCC 10 ~ 14): return_void final suspend A&& Wrong Output(GCC 15): A&& return_void final suspend 3. [Undefined behaviour]: When should the result object is initialized? (1) According to CWG2563(https://github.com/GorNishanov/await/blob/master/2023_Issaquah/cwg2563-response.md), for the third common pattern of coroutine: > get_return_object returns a proxy, coroutine body executes, conversion to > return type happens when coroutine return the caller. > Need coroutine body to execute before initialising the return-value since > coroutine body produces the result. which says conversion occurs when a coroutine returns to the caller. Referring to cppreference, we can conclude that conversion happens after await_suspend() if and only if it returns to the caller/resumer. > if await_suspend returns void, control is immediately returned to the > caller/resumer of the current coroutine (this coroutine remains suspended), > otherwise > if await_suspend returns bool, > the value true returns control to the caller/resumer of the current > coroutine > the value false resumes the current coroutine. > if await_suspend returns a coroutine handle for some other coroutine, that > handle is resumed (by a call to handle.resume()) (note this may chain to > eventually cause the current coroutine to resume). > if await_suspend throws an exception, the exception is caught, the coroutine > is resumed, and the exception is immediately re-thrown. Note that return_value() happens before final_suspend(), I consider the behavior is well defined. (2) Agree with your second point: 9.5.4 [dcl.fct.def.coroutine] paragraph 11 reads: > The coroutine state is destroyed when control flows off the end of the > coroutine > or the destroy member function ([coroutine.handle.resumption]) of a coroutine > handle ([coroutine.handle]) that refers to the coroutine is invoked. If I am not misunderstanding, 'flows off the end of the coroutine' occurs before 'returning to the caller'. It is unclear whether return value initialization happens before or after destruction. And the wording 'flows off the end of the coroutine' seems too strict. I suggest the following change: > The coroutine state is destroyed when returns from the await_resume() of > final_suspend > or the destroy member function ([coroutine.handle.resumption]) of a coroutine > handle ([coroutine.handle]) that refers to the coroutine is invoked. Note that initialization will be done before destruction of coroutine state. Maybe we should seperate this bug into three.