diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 31ec1bcc4..22896f42b 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -577,11 +577,6 @@ namespace winrt::impl auto final_suspend() noexcept { - if (winrt_suspend_handler) - { - winrt_suspend_handler(this); - } - return final_suspend_awaiter{ this }; } @@ -606,14 +601,23 @@ namespace winrt::impl } template - auto await_transform(Expression&& expression) + Expression&& await_transform(Expression&& expression) { if (Status() == AsyncStatus::Canceled) { throw winrt::hresult_canceled(); } - return notify_awaiter{ static_cast(expression), m_propagate_cancellation ? &m_cancellable : nullptr }; + if constexpr (std::is_convertible_v&, enable_await_cancellation&>) + { + if (m_propagate_cancellation) + { + static_cast(expression).set_cancellable_promise(&m_cancellable); + expression.enable_cancellation(&m_cancellable); + } + } + + return std::forward(expression); } cancellation_token await_transform(get_cancellation_token_t) noexcept diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index ae77512d7..415857850 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -133,26 +133,6 @@ namespace winrt::impl resume_apartment_sync(context.m_context, handle, failure); } } - - template - class awaiter_finder - { - template static constexpr bool find_awaitable_member(...) { return false; } - template static constexpr bool find_co_await_member(...) { return false; } - template static constexpr bool find_co_await_free(...) { return false; } - -#ifdef WINRT_IMPL_COROUTINES - template ().await_ready())> static constexpr bool find_awaitable_member(int) { return true; } - template ().operator co_await())> static constexpr bool find_co_await_member(int) { return true; } - template ()))> static constexpr bool find_co_await_free(int) { return true; } -#endif - - public: - - static constexpr bool has_awaitable_member = find_awaitable_member(0); - static constexpr bool has_co_await_member = find_co_await_member(0); - static constexpr bool has_co_await_free = find_co_await_free(0); - }; } WINRT_EXPORT namespace winrt @@ -226,76 +206,6 @@ WINRT_EXPORT namespace winrt }; } -namespace winrt::impl -{ - template - decltype(auto) get_awaiter(T&& value) noexcept - { -#ifdef WINRT_IMPL_COROUTINES - if constexpr (awaiter_finder::has_co_await_member) - { - static_assert(!awaiter_finder::has_co_await_free, "Ambiguous operator co_await (as both member and free function)."); - return static_cast(value).operator co_await(); - } - else if constexpr (awaiter_finder::has_co_await_free) - { - return operator co_await(static_cast(value)); - } - else - { - static_assert(awaiter_finder::has_awaitable_member, "Not an awaitable type"); - return static_cast(value); - } -#else - return static_cast(value); -#endif - } - - template - struct notify_awaiter - { - decltype(get_awaiter(std::declval())) awaitable; - - notify_awaiter(T&& awaitable_arg, [[maybe_unused]] cancellable_promise* promise = nullptr) : awaitable(get_awaiter(static_cast(awaitable_arg))) - { - if constexpr (std::is_convertible_v&, enable_await_cancellation&>) - { - if (promise) - { - static_cast(awaitable).set_cancellable_promise(promise); - awaitable.enable_cancellation(promise); - } - } - } - - bool await_ready() - { - if (winrt_suspend_handler) - { - winrt_suspend_handler(this); - } - - return awaitable.await_ready(); - } - - template - auto await_suspend(coroutine_handle handle) - { - return awaitable.await_suspend(handle); - } - - decltype(auto) await_resume() - { - if (winrt_resume_handler) - { - winrt_resume_handler(this); - } - - return awaitable.await_resume(); - } - }; -} - WINRT_EXPORT namespace winrt { [[nodiscard]] inline auto resume_background() noexcept @@ -728,11 +638,6 @@ namespace std::experimental suspend_never final_suspend() const noexcept { - if (winrt_suspend_handler) - { - winrt_suspend_handler(this); - } - return{}; } @@ -740,12 +645,6 @@ namespace std::experimental { winrt::terminate(); } - - template - auto await_transform(Expression&& expression) - { - return winrt::impl::notify_awaiter{ static_cast(expression) }; - } }; }; } diff --git a/strings/base_extern.h b/strings/base_extern.h index b4e3eeed0..52b72bea5 100644 --- a/strings/base_extern.h +++ b/strings/base_extern.h @@ -2,8 +2,6 @@ __declspec(selectany) int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {}; __declspec(selectany) winrt::hstring(__stdcall* winrt_to_message_handler)(void* address) {}; __declspec(selectany) void(__stdcall* winrt_throw_hresult_handler)(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {}; -__declspec(selectany) void(__stdcall* winrt_suspend_handler)(void const* token) noexcept {}; -__declspec(selectany) void(__stdcall* winrt_resume_handler)(void const* token) noexcept {}; __declspec(selectany) int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {}; extern "C" diff --git a/test/old_tests/UnitTests/async.cpp b/test/old_tests/UnitTests/async.cpp index 08253a385..4544979d0 100644 --- a/test/old_tests/UnitTests/async.cpp +++ b/test/old_tests/UnitTests/async.cpp @@ -22,7 +22,7 @@ namespace IAsyncAction NoSuspend_IAsyncAction() { - co_await resume_after(0s); + co_await 0s; auto cancel = co_await get_cancellation_token(); @@ -34,7 +34,7 @@ namespace IAsyncActionWithProgress NoSuspend_IAsyncActionWithProgress() { - co_await resume_after(0s); + co_await 0s; auto cancel = co_await get_cancellation_token(); @@ -46,7 +46,7 @@ namespace IAsyncOperation NoSuspend_IAsyncOperation() { - co_await resume_after(0s); + co_await 0s; auto cancel = co_await get_cancellation_token(); @@ -60,7 +60,7 @@ namespace IAsyncOperationWithProgress NoSuspend_IAsyncOperationWithProgress() { - co_await resume_after(0s); + co_await 0s; auto cancel = co_await get_cancellation_token(); diff --git a/test/test/async_ref_result.cpp b/test/test/async_ref_result.cpp deleted file mode 100644 index 31cd1ce29..000000000 --- a/test/test/async_ref_result.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ -#ifdef __cpp_lib_coroutine - using std::suspend_never; -#else - using std::experimental::suspend_never; -#endif - - // - // Checks that references returned by awaitables - // are not accidentally decayed. - // - // This test "runs" at compile time via static_assert. - - template - struct awaitable : suspend_never - { - std::decay_t value; - T await_resume() { return static_cast(value); } - }; - - template - struct awaitable_member_awaiter : suspend_never - { - decltype(auto) get_awaiter() { return *this; } - std::decay_t value; - T await_resume() { return static_cast(value); } - }; - - template - struct awaitable_free_awaiter : suspend_never - { - std::decay_t value; - T await_resume() { return static_cast(value); } - }; - template - decltype(auto) get_awaiter(awaitable_free_awaiter&& value) { return std::move(value); } - - template typename A, typename T> - IAsyncAction Check() - { - decltype(auto) value = co_await A(); - static_assert(std::is_same_v); - } - - template typename A> - IAsyncAction Check() - { - co_await Check(); - co_await Check(); - co_await Check(); - co_await Check(); - } - - IAsyncAction Test() - { - co_await Check(); - co_await Check(); - co_await Check(); - } -} - -TEST_CASE("async_ref_result") -{ - Test().get(); -} diff --git a/test/test/async_throw.cpp b/test/test/async_throw.cpp index 779351439..88e38d323 100644 --- a/test/test/async_throw.cpp +++ b/test/test/async_throw.cpp @@ -12,26 +12,26 @@ namespace IAsyncAction Action() { - co_await resume_after(10ms); + co_await 10ms; throw hresult_invalid_argument(L"Async"); } IAsyncActionWithProgress ActionWithProgress() { - co_await resume_after(10ms); + co_await 10ms; throw hresult_invalid_argument(L"Async"); } IAsyncOperation Operation() { - co_await resume_after(10ms); + co_await 10ms; throw hresult_invalid_argument(L"Async"); co_return 1; } IAsyncOperationWithProgress OperationWithProgress() { - co_await resume_after(10ms); + co_await 10ms; throw hresult_invalid_argument(L"Async"); co_return 1; } diff --git a/test/test/disconnected.cpp b/test/test/disconnected.cpp index 13fcad601..8c7e30e49 100644 --- a/test/test/disconnected.cpp +++ b/test/test/disconnected.cpp @@ -16,7 +16,7 @@ namespace IAsyncActionWithProgress ActionProgress() { - co_await resume_after(500ms); + co_await 500ms; auto progress = co_await get_progress_token(); progress(123); co_return; @@ -29,7 +29,7 @@ namespace IAsyncOperationWithProgress OperationProgress() { - co_await resume_after(500ms); + co_await 500ms; auto progress = co_await get_progress_token(); progress(123); co_return 123; diff --git a/test/test/notify_awaiter.cpp b/test/test/notify_awaiter.cpp deleted file mode 100644 index 0305e5a23..000000000 --- a/test/test/notify_awaiter.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ -#ifdef __cpp_lib_coroutine - using std::suspend_never; -#else - using std::experimental::suspend_never; -#endif - - // Never suspends. - // Allows copying, but asserts if you try. - struct suspend_never_but_assert_if_copied : suspend_never - { - suspend_never_but_assert_if_copied() = default; - suspend_never_but_assert_if_copied(suspend_never_but_assert_if_copied const&) - { - REQUIRE(false); - } - }; - - // The bad_awaiter asserts if it ever gets used. - // Use it for ambiguous alternatives we don't want to pick. - struct bad_awaiter : suspend_never - { - void await_resume() const noexcept - { - REQUIRE(false); - } - }; - - // If the only awaitable is the member awaitable, then use it. - struct member_awaitable : suspend_never_but_assert_if_copied - { - }; - - // Should pick the free operator co_await over the member awaitable. - struct free_operator_awaitable : bad_awaiter - { - }; - auto operator co_await(free_operator_awaitable) - { - return suspend_never_but_assert_if_copied{}; - } - - // Should pick the member operator co_await over the member awaitable. - struct member_operator_awaitable : bad_awaiter - { - auto operator co_await() - { - return suspend_never_but_assert_if_copied{}; - } - }; - - // Verify that we can await non-copyable objects. - struct no_copy_awaitable : suspend_never - { - no_copy_awaitable() = default; - no_copy_awaitable(no_copy_awaitable const&) = delete; - }; - - // operator co_await takes precedence over member awaitable. - struct ambiguous_awaitable1 : bad_awaiter - { - auto operator co_await() - { - return suspend_never_but_assert_if_copied{}; - } - }; - - // This awaitable supports both member co_await - // and free co_await, and the free co_await is a - // better match if invoked on an lvalue. We don't try - // to support this case. We just declare it as ambiguous. - struct ambiguous_awaitable2 : bad_awaiter - { - auto operator co_await() const - { - return bad_awaiter{}; - } - }; - suspend_never_but_assert_if_copied operator co_await(ambiguous_awaitable2&) - { - return {}; - } - - // We invoke this on an lvalue, so the member co_await is unavailable. - // Verify that the unavailable co_await is ignored. - struct ambiguous_awaitable3 : suspend_never_but_assert_if_copied - { - auto operator co_await()&& - { - return bad_awaiter{}; - } - }; - - IAsyncAction AsyncAction() - { - co_return; - } - IAsyncActionWithProgress AsyncActionWithProgress() - { - co_return; - } - IAsyncOperation AsyncOperation() - { - co_return 0; - } - IAsyncOperationWithProgress AsyncOperationWithProgress() - { - co_return 0; - } - - enum class notification - { - suspend, - resume, - }; - - static std::vector> watcher; - static handle start_racing{ CreateEventW(nullptr, true, false, nullptr) }; - constexpr size_t test_suspension_points = 13; - - IAsyncAction Async() - { - co_await resume_on_signal(start_racing.get()); - co_await resume_background(); - co_await resume_background(); - co_await member_awaitable{}; - co_await free_operator_awaitable{}; - co_await member_operator_awaitable{}; - co_await no_copy_awaitable{}; - co_await ambiguous_awaitable1{}; - // co_await ambiguous_awaitable2{}; // does not compile - ambiguous_awaitable3 awaitable3; - co_await awaitable3; - co_await AsyncAction(); - co_await AsyncActionWithProgress(); - co_await AsyncOperation(); - co_await AsyncOperationWithProgress(); - } -} - -// GNUC does not support MSVC extension lambda call convention conversion -// https://devblogs.microsoft.com/oldnewthing/20150220-00/?p=44623 -#if defined(__GNUC__) -#define LAMBDA_STDCALL __attribute__((stdcall)) -#else -#define LAMBDA_STDCALL -#endif - -TEST_CASE("notify_awaiter") -{ - // Everything works fine when nobody is watching. - - REQUIRE(!winrt_suspend_handler); - REQUIRE(!winrt_resume_handler); - SetEvent(start_racing.get()); - Async().get(); - ResetEvent(start_racing.get()); - - // Hook up some watchers. - - winrt_suspend_handler = [](void const* token) LAMBDA_STDCALL noexcept - { - watcher.push_back({ token, notification::suspend }); - }; - - winrt_resume_handler = [](void const* token) LAMBDA_STDCALL noexcept - { - auto last = watcher.back(); - REQUIRE(last.first == token); - REQUIRE(last.second == notification::suspend); - watcher.push_back({ token, notification::resume }); - }; - - // Prepare a coroutine. - REQUIRE(watcher.empty()); - auto async = Async(); - - // Give coroutine a moment to get to the starting line. - Sleep(1000); - - // Coroutine should have suspended once. - REQUIRE(watcher.size() == 1); - REQUIRE(watcher.back().second == notification::suspend); - - // And the race is on! - SetEvent(start_racing.get()); - async.get(); - - // Each suspension point should have been recorded plus one for each final_suspend. - REQUIRE(watcher.size() == 2 * test_suspension_points + 5); - - // Remove watchers. - - winrt_suspend_handler = nullptr; - winrt_resume_handler = nullptr; -} diff --git a/test/test/test.vcxproj b/test/test/test.vcxproj index 69c307ebf..bb33508a2 100644 --- a/test/test/test.vcxproj +++ b/test/test/test.vcxproj @@ -280,7 +280,6 @@ - @@ -402,7 +401,6 @@ - diff --git a/test/test_win7/async_throw.cpp b/test/test_win7/async_throw.cpp index bca1e9b26..1cdcf7ffc 100644 --- a/test/test_win7/async_throw.cpp +++ b/test/test_win7/async_throw.cpp @@ -12,26 +12,26 @@ namespace IAsyncAction Action() { - co_await resume_after(10ms); + co_await 10ms; throw hresult_invalid_argument(L"Async"); } IAsyncActionWithProgress ActionWithProgress() { - co_await resume_after(10ms); + co_await 10ms; throw hresult_invalid_argument(L"Async"); } IAsyncOperation Operation() { - co_await resume_after(10ms); + co_await 10ms; throw hresult_invalid_argument(L"Async"); co_return 1; } IAsyncOperationWithProgress OperationWithProgress() { - co_await resume_after(10ms); + co_await 10ms; throw hresult_invalid_argument(L"Async"); co_return 1; } diff --git a/test/test_win7/disconnected.cpp b/test/test_win7/disconnected.cpp index 1757937d0..a69a210d5 100644 --- a/test/test_win7/disconnected.cpp +++ b/test/test_win7/disconnected.cpp @@ -13,7 +13,7 @@ namespace IAsyncActionWithProgress ActionProgress() { - co_await resume_after(500ms); + co_await 500ms; auto progress = co_await get_progress_token(); progress(123); co_return; @@ -26,7 +26,7 @@ namespace IAsyncOperationWithProgress OperationProgress() { - co_await resume_after(500ms); + co_await 500ms; auto progress = co_await get_progress_token(); progress(123); co_return 123;