From 6c4a05f251ae8a39fa896524defaf4228328c259 Mon Sep 17 00:00:00 2001 From: Bin Cheng Date: Fri, 10 Apr 2020 12:38:53 +0800 Subject: [PATCH] Simplify co_await_expander. gcc/cp 2020-04-10 Bin Cheng * coroutines.cc (co_await_expander): Simplify. gcc/testsuite 2020-04-10 Bin Cheng * g++.dg/coroutines/co-await-syntax-10.C: New test. * g++.dg/coroutines/co-await-syntax-11.C: New test. --- gcc/cp/ChangeLog | 4 + gcc/cp/coroutines.cc | 25 +-- gcc/testsuite/ChangeLog | 5 + .../g++.dg/coroutines/co-await-syntax-10.C | 40 ++++ .../g++.dg/coroutines/co-await-syntax-11.C | 205 ++++++++++++++++++ 5 files changed, 257 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-10.C create mode 100644 gcc/testsuite/g++.dg/coroutines/co-await-syntax-11.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 49246e8fa2d..38f86cd3e87 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2020-04-10 Bin Cheng + + * coroutines.cc (co_await_expander): Simplify. + 2020-04-09 Jason Merrill PR c++/94523 diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 936be06c336..ab06c0aef54 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1389,34 +1389,13 @@ co_await_expander (tree *stmt, int * /*do_subtree*/, void *d) return NULL_TREE; coro_aw_data *data = (coro_aw_data *) d; - enum tree_code stmt_code = TREE_CODE (*stmt); tree stripped_stmt = *stmt; - - /* Look inside <(void) (expr)> cleanup */ - if (stmt_code == CLEANUP_POINT_EXPR) - { - stripped_stmt = TREE_OPERAND (*stmt, 0); - stmt_code = TREE_CODE (stripped_stmt); - if (stmt_code == EXPR_STMT - && (TREE_CODE (EXPR_STMT_EXPR (stripped_stmt)) == CONVERT_EXPR - || TREE_CODE (EXPR_STMT_EXPR (stripped_stmt)) == CAST_EXPR) - && VOID_TYPE_P (TREE_TYPE (EXPR_STMT_EXPR (stripped_stmt)))) - { - stripped_stmt = TREE_OPERAND (EXPR_STMT_EXPR (stripped_stmt), 0); - stmt_code = TREE_CODE (stripped_stmt); - } - } - tree *buried_stmt = NULL; tree saved_co_await = NULL_TREE; enum tree_code sub_code = NOP_EXPR; - if (stmt_code == EXPR_STMT - && TREE_CODE (EXPR_STMT_EXPR (stripped_stmt)) == CO_AWAIT_EXPR) - saved_co_await - = EXPR_STMT_EXPR (stripped_stmt); /* hopefully, a void exp. */ - else if (stmt_code == MODIFY_EXPR || stmt_code == INIT_EXPR) + if (stmt_code == MODIFY_EXPR || stmt_code == INIT_EXPR) { sub_code = TREE_CODE (TREE_OPERAND (stripped_stmt, 1)); if (sub_code == CO_AWAIT_EXPR) @@ -1435,6 +1414,8 @@ co_await_expander (tree *stmt, int * /*do_subtree*/, void *d) else if ((stmt_code == CONVERT_EXPR || stmt_code == NOP_EXPR) && TREE_CODE (TREE_OPERAND (stripped_stmt, 0)) == CO_AWAIT_EXPR) saved_co_await = TREE_OPERAND (stripped_stmt, 0); + else if (stmt_code == CO_AWAIT_EXPR) + saved_co_await = stripped_stmt; if (!saved_co_await) return NULL_TREE; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d8fa35aca9c..72e0d519bb9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-04-10 Bin Cheng + + * g++.dg/coroutines/co-await-syntax-10.C: New test. + * g++.dg/coroutines/co-await-syntax-11.C: New test. + 2020-04-09 Fritz Reese PR fortran/87923 diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-10.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-10.C new file mode 100644 index 00000000000..8304344c826 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-10.C @@ -0,0 +1,40 @@ +// { dg-additional-options "-std=c++17 -w" } + +#include "coro.h" + +class await { +public: + class promise_type { + public: + std::suspend_always initial_suspend() const noexcept { return {}; } + std::suspend_always final_suspend() const noexcept { return {}; } + void unhandled_exception() noexcept { } + await get_return_object() { return await{}; } + void return_void() {} + }; + bool await_ready() const noexcept { return false; } + bool await_suspend(std::coroutine_handle<>) noexcept {return true;} + void await_resume() { } +}; + +class mycoro { +public: + class promise_type { + public: + std::suspend_always initial_suspend() const noexcept { return {}; } + std::suspend_always final_suspend() const noexcept { return {}; } + void unhandled_exception() noexcept { } + mycoro get_return_object() { return mycoro{}; } + void return_void() {} + }; +}; +mycoro foo(await awaitable) { + co_return co_await awaitable; +} + +mycoro bar() +{ + auto t = [&]() -> await { co_return; }(); + return foo (t); +} + diff --git a/gcc/testsuite/g++.dg/coroutines/co-await-syntax-11.C b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-11.C new file mode 100644 index 00000000000..69810ab5caa --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/co-await-syntax-11.C @@ -0,0 +1,205 @@ +// { dg-additional-options "-std=c++17 -w" } + +#include +#include +#include +#include +#include + +struct any { + template any(T &&) noexcept; +}; + +template +auto get_awaiter_impl(T &&value, int) noexcept + -> decltype(static_cast(value).operator co_await()) { + return static_cast(value).operator co_await(); +} +template +T &&get_awaiter_impl(T &&value, any) noexcept; +template +auto get_awaiter(T &&value) noexcept + -> decltype(get_awaiter_impl(static_cast(value), 123)) { + return get_awaiter_impl(static_cast(value), 123); +} + +template struct awaitable_traits { + using awaiter_t = decltype(get_awaiter(std::declval())); + using await_result_t = decltype(std::declval().await_resume()); +}; + +template class when_all_ready_awaitable; +template +class when_all_ready_awaitable> { +public: + explicit when_all_ready_awaitable(std::tuple &&tasks) noexcept + : m_tasks(std::move(tasks)) {} + auto operator co_await() &&noexcept { + struct awaiter { + awaiter(when_all_ready_awaitable &awaitable) noexcept + : m_awaitable(awaitable) {} + bool await_ready() const noexcept { return false; } + bool await_suspend() noexcept { return false; } + std::tuple &&await_resume() noexcept { + return std::move(m_awaitable.m_tasks); + } + when_all_ready_awaitable& m_awaitable; + }; + return awaiter{*this}; + } + std::tuple m_tasks; +}; + +inline void *operator new(std::size_t, void *__p) noexcept; + +template +class when_all_task_promise final{ +public: + using coroutine_handle_t = std::coroutine_handle; + RESULT &&result() &&; +}; +template class when_all_task final { +public: + using promise_type = when_all_task_promise; + using coroutine_handle_t = typename promise_type::coroutine_handle_t; + decltype(auto) result() &; + decltype(auto) result() && { + return std::move(m_coroutine.promise()).result(); + } + decltype(auto) non_void_result() && { + if constexpr (std::is_void_v) + ; + else + return std::move(*this).result(); + } + coroutine_handle_t m_coroutine; +}; +class task; +template ::await_result_t, + std::enable_if_t, int> = 0> +when_all_task make_when_all_task(AWAITABLE awaitable); + +template +inline auto when_all_ready(AWAITABLES &&... awaitables) { + return when_all_ready_awaitable< + std::tuple>::await_result_t>...>>( + std::make_tuple( + make_when_all_task(std::forward(awaitables))...)); +} + +template class fmap_awaiter { + using awaiter_t = typename awaitable_traits::awaiter_t; + +public: + fmap_awaiter(FUNC &&func, AWAITABLE &&awaitable) noexcept + : m_func(static_cast(func)), + m_awaiter(get_awaiter(static_cast(awaitable))) {} + decltype(auto) await_ready() noexcept { + return static_cast(m_awaiter).await_ready(); + } + template + decltype(auto) await_suspend(std::coroutine_handle coro) noexcept {} + template ().await_resume()), + std::enable_if_t, int> = 0> + decltype(auto) await_resume() noexcept { + return std::invoke(static_cast(m_func), + static_cast(m_awaiter).await_resume()); + } + +private: + FUNC &&m_func; + awaiter_t m_awaiter; +}; +template class fmap_awaitable { +public: + template < + typename FUNC_ARG, typename AWAITABLE_ARG, + std::enable_if_t && + std::is_constructible_v, + int> = 0> + explicit fmap_awaitable(FUNC_ARG &&func, AWAITABLE_ARG &&awaitable) noexcept + : m_func(static_cast(func)), + m_awaitable(static_cast(awaitable)) {} + auto operator co_await() && { + return fmap_awaiter(static_cast(m_func), + static_cast(m_awaitable)); + } + +private: + FUNC m_func; + AWAITABLE m_awaitable; +}; + +template +auto fmap(FUNC &&func, AWAITABLE &&awaitable) { + return fmap_awaitable>, + std::remove_cv_t>>( + std::forward(func), std::forward(awaitable)); +} +template +auto when_all(AWAITABLES &&... awaitables) { + return fmap( + [](auto &&taskTuple) { + decltype(auto) __trans_tmp_1 = std::apply( + [](auto &&... tasks) { + return std::make_tuple( + static_cast(tasks).non_void_result()...); + }, + static_cast(taskTuple)); + return __trans_tmp_1; + }, + when_all_ready(std::forward(awaitables)...)); +} +class async_mutex_scoped_lock_operation; +class async_mutex { +public: + async_mutex() noexcept; + async_mutex_scoped_lock_operation scoped_lock_async() noexcept; +}; +class async_mutex_lock { +public: + explicit async_mutex_lock(); + ~async_mutex_lock(); + +private: + async_mutex *m_mutex; +}; +class async_mutex_scoped_lock_operation { +public: + async_mutex_lock await_resume() const noexcept; +}; +class task { +public: + class promise_type { + public: + auto initial_suspend() noexcept { return std::suspend_always{}; } + auto final_suspend() noexcept { return std::suspend_always{}; } + task get_return_object() noexcept { return task{}; } + void unhandled_exception() noexcept {} + void return_value(int value) noexcept { v = value; } + int result(){ return v; } + int v = 0; + }; +public: + task() noexcept {} + auto operator co_await() const &noexcept { + struct awaitable { + std::coroutine_handle m_coroutine; + decltype(auto) await_resume() { + return this->m_coroutine.promise().result(); + } + }; + return awaitable{}; + } +}; +void foo() { + (void) []() -> task { + auto makeTask = [](int x) -> task { co_return x; }; + async_mutex_scoped_lock_operation op; + co_await when_all(std::move(op), makeTask(123)); + }(); +} -- 2.30.2