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.

Reply via email to