Starting with gcc 11.3, gcc tries to copy an object to await_transform() even if an overload that accepts a reference exists: #include <coroutine> #include <exception> // A move-only awaitable class MoveOnlyAwaitable { public: MoveOnlyAwaitable() = default; MoveOnlyAwaitable(MoveOnlyAwaitable &&) = default; MoveOnlyAwaitable &operator=(MoveOnlyAwaitable &&) = default; MoveOnlyAwaitable(const MoveOnlyAwaitable &) = delete; MoveOnlyAwaitable &operator=(const MoveOnlyAwaitable &) = delete; bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<>) noexcept {} void await_resume() {} }; struct task { struct promise_type { auto initial_suspend() const { return std::suspend_never{}; } auto final_suspend() const noexcept { return std::suspend_never(); } auto get_return_object() { return task{}; } void return_void() {} void unhandled_exception() {} template<typename T> T &&await_transform(T &&t) { return static_cast<T &&>(t); } }; bool await_ready() const { return false; } void await_suspend(std::coroutine_handle<> awaiter) {} void await_resume() {} }; task myCoroutine() { // GCC: OK // clang: OK { co_await MoveOnlyAwaitable(); } // GCC: OK // clang: OK { auto moveonly = MoveOnlyAwaitable(); co_await std::move(moveonly); } // GCC <= 11.2: OK // GCC 11.3:ERROR: error: use of deleted function 'MoveOnlyAwaitable::MoveOnlyAwaitable(const MoveOnlyAwaitable&) // clang: OK { auto moveonly = MoveOnlyAwaitable(); co_await moveonly; } } Both gcc<11.3 and clang invoke MoveOnlyAwaitable& task::promise_type::await_transform<MoveOnlyAwaitable&>(MoveOnlyAwaitable&) for the last co_await, while GCC 11.3 and on seems to attempt to pass `moveOnly` by value. Manually instantiating the template, or creating a non-template overload that accepts MoveOnlyAwaitable& doesn't work either. I believe that this is a bug because calling auto move_only = MoveOnlyAwaitable(); task::promise_type p; p.await_transform(moveonly); works even with GCC 11.3. As expected, the compiler produces the await_transform<MoveOnlyAwaitable&>(MoveOnlyAwaitable&) overload, so it's weird that it doesn't do so when `move_only` is passed to `co_await`.
Link to godbolt: https://godbolt.org/z/MecdTEzMT
Started with r12-618-g14ed21f8749ae359690d9c4a69ca38cc45d0d1b0 which has been backported to 11.3 in r11-9055-gb874ece3ff95d3afa575d40b6e14e95cae8baf87
The trunk branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:d0ed0690f1e86621a5cb62eec1d144036feb16f8 commit r13-6711-gd0ed0690f1e86621a5cb62eec1d144036feb16f8 Author: Jason Merrill <jason@redhat.com> Date: Wed Mar 15 17:02:15 2023 -0400 c++: co_await and move-only type [PR105406] Here we were building a temporary MoveOnlyAwaitable to hold the result of evaluating 'o', but since 'o' is an lvalue we should build a reference instead. PR c++/105406 gcc/cp/ChangeLog: * coroutines.cc (build_co_await): Handle lvalue 'o'. gcc/testsuite/ChangeLog: * g++.dg/coroutines/co-await-moveonly1.C: New test.
The releases/gcc-12 branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:6fd32842404ac1a3cd98189f61d93c5bc9c8680c commit r12-9435-g6fd32842404ac1a3cd98189f61d93c5bc9c8680c Author: Jason Merrill <jason@redhat.com> Date: Wed Mar 15 17:02:15 2023 -0400 c++: co_await and move-only type [PR105406] Here we were building a temporary MoveOnlyAwaitable to hold the result of evaluating 'o', but since 'o' is an lvalue we should build a reference instead. PR c++/105406 gcc/cp/ChangeLog: * coroutines.cc (build_co_await): Handle lvalue 'o'. gcc/testsuite/ChangeLog: * g++.dg/coroutines/co-await-moveonly1.C: New test.
The releases/gcc-11 branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:657fb0db2648a8cd7ba355fdec570fe2f08448ac commit r11-10642-g657fb0db2648a8cd7ba355fdec570fe2f08448ac Author: Jason Merrill <jason@redhat.com> Date: Wed Mar 15 17:02:15 2023 -0400 c++: co_await and move-only type [PR105406] Here we were building a temporary MoveOnlyAwaitable to hold the result of evaluating 'o', but since 'o' is an lvalue we should build a reference instead. PR c++/105406 gcc/cp/ChangeLog: * coroutines.cc (build_co_await): Handle lvalue 'o'. gcc/testsuite/ChangeLog: * g++.dg/coroutines/co-await-moveonly1.C: New test.
GCC 11.4 is being released, retargeting bugs to GCC 11.5.
Fixed in 11.4/12.3/13.