public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/95599] New: [coroutines] destructor for temporary operand to co_yield expression called before end of full-expression
@ 2020-06-09  5:29 lewissbaker.opensource at gmail dot com
  2020-06-09  5:33 ` [Bug c++/95599] " lewissbaker.opensource at gmail dot com
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: lewissbaker.opensource at gmail dot com @ 2020-06-09  5:29 UTC (permalink / raw)
  To: gcc-bugs

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.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-08-13 16:38 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-09  5:29 [Bug c++/95599] New: [coroutines] destructor for temporary operand to co_yield expression called before end of full-expression lewissbaker.opensource at gmail dot com
2020-06-09  5:33 ` [Bug c++/95599] " lewissbaker.opensource at gmail dot com
2020-06-09  9:40 ` iains at gcc dot gnu.org
2020-06-09 15:08 ` lewissbaker.opensource at gmail dot com
2020-06-09 15:25 ` iains at gcc dot gnu.org
2020-07-16 21:02 ` cvs-commit at gcc dot gnu.org
2020-07-23  6:51 ` rguenth at gcc dot gnu.org
2020-07-29  9:59 ` cvs-commit at gcc dot gnu.org
2020-08-04 15:36 ` iains at gcc dot gnu.org
2020-08-13 16:38 ` redi at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).