https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95598
Bug ID: 95598 Summary: [coroutines] Destructor for object returned from get_return_object() never called 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: --- Compile the following code with GCC trunk with flags -std=c++2a -fcoroutines See https://godbolt.org/z/zTjjGm ---- #include <coroutine> #include <cstdio> using namespace std; 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 {}; } }; generator(coroutine_handle<promise_type> coro) { std::printf("generator() @ %p\n", this); } generator(generator&& g) noexcept { std::printf("generator(move from %p) @ %p\n", &g, this); } ~generator() { std::printf("~generator() @ %p\n", this); } }; generator f() { co_return; } int main() { generator g = f(); } ---- The expected output of this program is following (assuming copy-elision has occurred - this is what Clang outputs): ``` generator() @ <address-A> ~generator() @ <address-A> ``` Or if copy elision has not occurred, at least the number of constructor/destructor calls should be balanced: ``` generator() @ <address-A> generator(move from <address-A>) @ <address-B> ~generator() @ <address-A> ~generator() @ <address-B> ``` However, the observed output is: ``` generator() @ <address-A> generator(move from <address-A>) @ <address-B> ~generator() @ <address-B> ``` ie. the destructor of the generator constructed at <address-A> is never called. In this case the object constructed at <address-A> is the object returned from promise.get_return_object() and the object constructed at <address-B> is the object returned from the coroutine ramp function f(). It seems that the coroutine ramp function is failing to call the destructor of the object returned from promise.get_return_object() when the coroutine ramp function returns. Normally, this omission of the call to the destructor would not be observed as the return-value is moved and the destructor of a moved-from object has no effect, but that is not always the case.