https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95599
Bug ID: 95599 Summary: [coroutines] destructor for temporary operand to co_yield expression called before end of full-expression Product: gcc Version: 10.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: lewissbaker.opensource at gmail dot com Target Milestone: --- If I write the statement: co_yield T{}; Then I expect the T constructor to be called before the coroutine suspends and that the T destructor will not be called until after the coroutine resumes and execution reaches the semicolon (ie. end of full expression). However, I am observing that the T destructor is being called before the await_suspend() method on the awaitable returned from promise.yield_value() is called (ie. before the coroutine suspends). To reproduce, compile the following code sample using GCC trunk. Flags: -std=c++2a -fcoroutines ------- #include <coroutine> using namespace std; #include <cstdio> #include <utility> struct resource { resource() { std::printf("resource()\n"); } ~resource() { std::printf("~resource()\n"); } resource(resource&&) = delete; }; template<typename T> struct generator { struct promise_type { generator get_return_object() { return generator{coroutine_handle<promise_type>::from_promise(*this)}; } void return_void() {} void unhandled_exception() {} suspend_always initial_suspend() { return {}; } suspend_always final_suspend() { return {}; } struct awaitable { resource& r; awaitable(resource&& r) : r(r) {} ~awaitable() {} bool await_ready() noexcept { return false; } void await_suspend(coroutine_handle<> h) noexcept { std::printf("awaitable::await_suspend()\n"); } void await_resume() noexcept { std::printf("awaitable::await_resume()\n"); } }; awaitable yield_value(resource&& r) { return awaitable{std::move(r)}; } }; generator(coroutine_handle<promise_type> coro) : coro(coro) {} generator(generator&& g) noexcept : coro(std::exchange(g.coro, {})) {} ~generator() { if (coro) { coro.destroy(); } } coroutine_handle<promise_type> coro; }; generator<int> f() { co_yield resource{}; } int main() { generator x = f(); x.coro.resume(); x.coro.resume(); } ------- The expected output of this program is: ``` resource() awaitable::await_suspend() awaitable::await_resume() ~resource() ``` However, the observed output of this program is: ``` resource() ~resource() awaitable::await_suspend() awaitable::await_resume() ``` i.e. the temporary is not being kept alive until the end of the full-expression containing the co_yield statement.