From 601461a33afcce500baed9404ae476e0cb97caf2 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 21 Aug 2020 15:10:21 -0700 Subject: [PATCH 1/8] Implement LWG-3460 --- stl/inc/coroutine | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/stl/inc/coroutine b/stl/inc/coroutine index 59ceb440fcb..4f84a930789 100644 --- a/stl/inc/coroutine +++ b/stl/inc/coroutine @@ -93,7 +93,7 @@ protected: }; template -struct coroutine_handle : coroutine_handle<> { +struct coroutine_handle : private coroutine_handle<> { using coroutine_handle<>::coroutine_handle; _NODISCARD static coroutine_handle from_promise(_Promise& _Prom) noexcept { // strengthened @@ -109,12 +109,24 @@ struct coroutine_handle : coroutine_handle<> { return *this; } + using coroutine_handle<>::address; _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 static_cast&>(*this); + } + + using coroutine_handle<>::explicit operator bool; + using coroutine_handle<>::done; + + using coroutine_handle<>::operator(); + using coroutine_handle<>::resume; + using coroutine_handle<>::destroy; + _NODISCARD _Promise& promise() const noexcept { // strengthened return *reinterpret_cast<_Promise*>(__builtin_coro_promise(_Ptr, 0, false)); } @@ -145,9 +157,13 @@ struct noop_coroutine_promise {}; // STRUCT coroutine_handle template <> -struct coroutine_handle : coroutine_handle<> { +struct coroutine_handle : private coroutine_handle<> { friend coroutine_handle noop_coroutine() noexcept; + constexpr operator coroutine_handle<>() const noexcept { + return static_cast&>(*this); + } + constexpr explicit operator bool() const noexcept { return true; } @@ -159,11 +175,9 @@ 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: From d744965ad65439bfcff7205c687b58312c4919ba Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Wed, 11 Nov 2020 22:14:43 -0800 Subject: [PATCH 2/8] Derp --- stl/inc/coroutine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/coroutine b/stl/inc/coroutine index 4f84a930789..4bc975fe1dd 100644 --- a/stl/inc/coroutine +++ b/stl/inc/coroutine @@ -120,7 +120,7 @@ struct coroutine_handle : private coroutine_handle<> { return static_cast&>(*this); } - using coroutine_handle<>::explicit operator bool; + using coroutine_handle<>::operator bool; using coroutine_handle<>::done; using coroutine_handle<>::operator(); From dbf617a9626d54a6c6f749b847600d192f87a552 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 12 Nov 2020 08:31:50 -0800 Subject: [PATCH 3/8] no plan survives first contact with the enemy --- stl/inc/coroutine | 50 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/stl/inc/coroutine b/stl/inc/coroutine index 4bc975fe1dd..d54710f0f49 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 : private 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,7 +110,10 @@ struct coroutine_handle : private coroutine_handle<> { return *this; } - using coroutine_handle<>::address; + _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; @@ -117,19 +121,35 @@ struct coroutine_handle : private coroutine_handle<> { } constexpr operator coroutine_handle<>() const noexcept { - return static_cast&>(*this); + 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); } - using coroutine_handle<>::operator bool; - using coroutine_handle<>::done; + void operator()() const { + __builtin_coro_resume(_Ptr); + } - using coroutine_handle<>::operator(); - using coroutine_handle<>::resume; - using coroutine_handle<>::destroy; + 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 { @@ -157,11 +177,11 @@ struct noop_coroutine_promise {}; // STRUCT coroutine_handle template <> -struct coroutine_handle : private coroutine_handle<> { +struct coroutine_handle { friend coroutine_handle noop_coroutine() noexcept; constexpr operator coroutine_handle<>() const noexcept { - return static_cast&>(*this); + return coroutine_handle<>::from_address(_Ptr); } constexpr explicit operator bool() const noexcept { @@ -181,9 +201,9 @@ struct coroutine_handle : private coroutine_handle<> { } private: - coroutine_handle() noexcept { - _Ptr = __builtin_coro_noop(); - } + coroutine_handle() noexcept = default; + + void* _Ptr = __builtin_coro_noop(); }; // ALIAS noop_coroutine_handle From 1be493b54d899e28918702a1299aae1157b7829f Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 1 Dec 2020 12:57:04 -0800 Subject: [PATCH 4/8] Bah - missed noop_coroutine_handle::address --- stl/inc/coroutine | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stl/inc/coroutine b/stl/inc/coroutine index d54710f0f49..ad2c2f30dd8 100644 --- a/stl/inc/coroutine +++ b/stl/inc/coroutine @@ -200,6 +200,10 @@ struct coroutine_handle { return *reinterpret_cast(__builtin_coro_promise(_Ptr, 0, false)); } + _NODISCARD constexpr void* address() const noexcept { + return _Ptr; + } + private: coroutine_handle() noexcept = default; From 5958b3062db0824091f044834be0d3c6583b865f Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 1 Dec 2020 13:18:22 -0800 Subject: [PATCH 5/8] Add a bit more test coverage for noop_coroutine_handle --- tests/std/tests/P0912R5_coroutine/test.cpp | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/std/tests/P0912R5_coroutine/test.cpp b/tests/std/tests/P0912R5_coroutine/test.cpp index 818fe9bc562..ff88767a7e5 100644 --- a/tests/std/tests/P0912R5_coroutine/test.cpp +++ b/tests/std/tests/P0912R5_coroutine/test.cpp @@ -95,6 +95,46 @@ 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(); + const coroutine_handle<> as_void = noop; + + 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 +166,8 @@ int main() { const hash> h; (void) h(coroutine_handle<>{}); } + + test_noop_handle(); } #else // ^^^ test ^^^ / vvv don't test vvv From 250bf06424340ec3b1a86fd4639fe078077621b4 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 1 Dec 2020 13:19:51 -0800 Subject: [PATCH 6/8] Oops - finish noexcept coverage --- tests/std/tests/P0912R5_coroutine/test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/std/tests/P0912R5_coroutine/test.cpp b/tests/std/tests/P0912R5_coroutine/test.cpp index ff88767a7e5..a9917ecee6f 100644 --- a/tests/std/tests/P0912R5_coroutine/test.cpp +++ b/tests/std/tests/P0912R5_coroutine/test.cpp @@ -97,7 +97,10 @@ Task triangular_number(const int n) { 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.done()); assert(!as_void.done()); From 1f604587fa905b839191168214a386ba7501d9a3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 1 Dec 2020 15:53:47 -0800 Subject: [PATCH 7/8] Verify that `explicit operator bool` is noexcept. --- tests/std/tests/P0912R5_coroutine/test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/tests/P0912R5_coroutine/test.cpp b/tests/std/tests/P0912R5_coroutine/test.cpp index a9917ecee6f..4763c915998 100644 --- a/tests/std/tests/P0912R5_coroutine/test.cpp +++ b/tests/std/tests/P0912R5_coroutine/test.cpp @@ -109,6 +109,7 @@ void test_noop_handle() { // Validate noop_coroutine_handle assert(noop); assert(as_void); + static_assert(noexcept(static_cast(noop))); noop(); as_void(); static_assert(noexcept(noop())); From 37721ce33fab362d9489543128d0d3b7912ea43c Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 1 Dec 2020 16:11:08 -0800 Subject: [PATCH 8/8] Consistently validate that coroutine_handle<>'s conversion to bool is noexcept --- tests/std/tests/P0912R5_coroutine/test.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/std/tests/P0912R5_coroutine/test.cpp b/tests/std/tests/P0912R5_coroutine/test.cpp index 4763c915998..0aa48651cb6 100644 --- a/tests/std/tests/P0912R5_coroutine/test.cpp +++ b/tests/std/tests/P0912R5_coroutine/test.cpp @@ -102,6 +102,11 @@ void test_noop_handle() { // Validate noop_coroutine_handle 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())); @@ -109,7 +114,6 @@ void test_noop_handle() { // Validate noop_coroutine_handle assert(noop); assert(as_void); - static_assert(noexcept(static_cast(noop))); noop(); as_void(); static_assert(noexcept(noop()));