diff --git a/stl/inc/coroutine b/stl/inc/coroutine index 59ceb440fcb..ad2c2f30dd8 100644 --- a/stl/inc/coroutine +++ b/stl/inc/coroutine @@ -88,13 +88,14 @@ struct coroutine_handle { __builtin_coro_destroy(_Ptr); } -protected: +private: void* _Ptr = nullptr; }; template -struct coroutine_handle : coroutine_handle<> { - using coroutine_handle<>::coroutine_handle; +struct coroutine_handle { + constexpr coroutine_handle() noexcept = default; + constexpr coroutine_handle(nullptr_t) noexcept {} _NODISCARD static coroutine_handle from_promise(_Promise& _Prom) noexcept { // strengthened const auto _Prom_ptr = const_cast(static_cast(_STD addressof(_Prom))); @@ -109,15 +110,46 @@ struct coroutine_handle : coroutine_handle<> { return *this; } + _NODISCARD constexpr void* address() const noexcept { + return _Ptr; + } + _NODISCARD static constexpr coroutine_handle from_address(void* const _Addr) noexcept { // strengthened coroutine_handle _Result; _Result._Ptr = _Addr; return _Result; } + constexpr operator coroutine_handle<>() const noexcept { + return coroutine_handle<>::from_address(_Ptr); + } + + constexpr explicit operator bool() const noexcept { + return _Ptr != nullptr; + } + + _NODISCARD bool done() const noexcept { // strengthened + return __builtin_coro_done(_Ptr); + } + + void operator()() const { + __builtin_coro_resume(_Ptr); + } + + void resume() const { + __builtin_coro_resume(_Ptr); + } + + void destroy() const noexcept { // strengthened + __builtin_coro_destroy(_Ptr); + } + _NODISCARD _Promise& promise() const noexcept { // strengthened return *reinterpret_cast<_Promise*>(__builtin_coro_promise(_Ptr, 0, false)); } + +private: + void* _Ptr = nullptr; }; _NODISCARD constexpr bool operator==(const coroutine_handle<> _Left, const coroutine_handle<> _Right) noexcept { @@ -145,9 +177,13 @@ struct noop_coroutine_promise {}; // STRUCT coroutine_handle template <> -struct coroutine_handle : coroutine_handle<> { +struct coroutine_handle { friend coroutine_handle noop_coroutine() noexcept; + constexpr operator coroutine_handle<>() const noexcept { + return coroutine_handle<>::from_address(_Ptr); + } + constexpr explicit operator bool() const noexcept { return true; } @@ -159,17 +195,19 @@ struct coroutine_handle : coroutine_handle<> { constexpr void resume() const noexcept {} constexpr void destroy() const noexcept {} - using _Promise = noop_coroutine_promise; - - _NODISCARD _Promise& promise() const noexcept { + _NODISCARD noop_coroutine_promise& promise() const noexcept { // Returns a reference to the associated promise - return *reinterpret_cast<_Promise*>(__builtin_coro_promise(_Ptr, 0, false)); + return *reinterpret_cast(__builtin_coro_promise(_Ptr, 0, false)); } -private: - coroutine_handle() noexcept { - _Ptr = __builtin_coro_noop(); + _NODISCARD constexpr void* address() const noexcept { + return _Ptr; } + +private: + coroutine_handle() noexcept = default; + + void* _Ptr = __builtin_coro_noop(); }; // ALIAS noop_coroutine_handle diff --git a/tests/std/tests/P0912R5_coroutine/test.cpp b/tests/std/tests/P0912R5_coroutine/test.cpp index 818fe9bc562..0aa48651cb6 100644 --- a/tests/std/tests/P0912R5_coroutine/test.cpp +++ b/tests/std/tests/P0912R5_coroutine/test.cpp @@ -95,6 +95,54 @@ Task triangular_number(const int n) { co_return n + co_await triangular_number(n - 1); } +void test_noop_handle() { // Validate noop_coroutine_handle + const noop_coroutine_handle noop = noop_coroutine(); + static_assert(noexcept(noop_coroutine())); + + const coroutine_handle<> as_void = noop; + static_assert(noexcept(static_cast>(noop_coroutine()))); + + assert(noop); + assert(as_void); + static_assert(noexcept(static_cast(noop))); + static_assert(noexcept(static_cast(as_void))); + + assert(!noop.done()); + assert(!as_void.done()); + static_assert(noexcept(noop.done())); + static_assert(noexcept(as_void.done())); + + assert(noop); + assert(as_void); + noop(); + as_void(); + static_assert(noexcept(noop())); + + assert(noop); + assert(as_void); + noop.resume(); + as_void.resume(); + static_assert(noexcept(noop.resume())); + + assert(noop); + assert(as_void); + noop.destroy(); + as_void.destroy(); + static_assert(noexcept(noop.destroy())); + + assert(noop); + assert(as_void); + assert(&noop.promise() != nullptr); + static_assert(noexcept(noop.promise())); + + assert(noop); + assert(as_void); + assert(noop.address() != nullptr); + assert(noop.address() == as_void.address()); + static_assert(noexcept(noop.address())); + static_assert(noexcept(as_void.address())); +} + int main() { assert(g_tasks_destroyed == 0); @@ -126,6 +174,8 @@ int main() { const hash> h; (void) h(coroutine_handle<>{}); } + + test_noop_handle(); } #else // ^^^ test ^^^ / vvv don't test vvv