In the following code example, the lambda coroutine g performs co_await f, where f is coroutine return type with deleted copy- and move- constructors:
#include <coroutine>
class task {
public:
class task_promise {
public:
task get_return_object() { return task{handle_type::from_promise(*this)}; }
auto initial_suspend() { return std::suspend_always{}; }
auto final_suspend() noexcept { return std::suspend_never{}; }
void return_void() {}
void unhandled_exception() {}
};
using handle_type = std::coroutine_handle<task_promise>;
handle_type handle;
auto await_ready() { return false; }
auto await_suspend(handle_type) { return handle; }
void await_resume() { handle.resume(); }
using promise_type = task_promise;
task(handle_type h) : handle(h) {}
task(const task&) = delete;
task& operator=(const task&) = delete;
task(task&&) = delete;
task& operator=(task&&) = delete;
};
int main() {
task f = []() -> task { co_return; }();
task g = [&f]() -> task { co_await f; }();
g.handle.resume();
}
The code is accepted in MSVC, but not in GCC.
GCC 11.2 complains on the missing move-constructor:
error: use of deleted function 'task::task(task&&)'
and GCC trunk - on the missing copy-constructor:
error: use of deleted function 'task::task(const task&)'
Demo: https://gcc.godbolt.org/z/1c7fajqn8
Which compiler is right here?
P.S. There is a related question Why must the return type of a coroutine be move-constructible? but
- the issue there was fixed in GCC 10.2, while the example from this question is still valid in GCC 11 and trunk;
- this question asks about
co_awaitrequirements, while the other does not mentionco_awaitat all; - the other question is about move-constructor only, while here the latest GCC demands copy-constructor.