diff options
author | Bin Cheng <bin.cheng@linux.alibaba.com> | 2020-04-10 12:38:53 +0800 |
---|---|---|
committer | Bin Cheng <bin.cheng@linux.alibaba.com> | 2020-04-10 12:53:00 +0800 |
commit | 6c4a05f251ae8a39fa896524defaf4228328c259 (patch) | |
tree | 760eeb443352afc5155a3ab456efb34a1ba2df3c | |
parent | d79a22eddc694970316992927c669dd801e07557 (diff) | |
download | gcc-6c4a05f251ae8a39fa896524defaf4228328c259.zip gcc-6c4a05f251ae8a39fa896524defaf4228328c259.tar.gz gcc-6c4a05f251ae8a39fa896524defaf4228328c259.tar.bz2 |
Simplify co_await_expander.
gcc/cp
2020-04-10 Bin Cheng <bin.cheng@linux.alibaba.com>
* coroutines.cc (co_await_expander): Simplify.
gcc/testsuite
2020-04-10 Bin Cheng <bin.cheng@linux.alibaba.com>
* g++.dg/coroutines/co-await-syntax-10.C: New test.
* g++.dg/coroutines/co-await-syntax-11.C: New test.
-rw-r--r-- | gcc/cp/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 25 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/co-await-syntax-10.C | 40 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/co-await-syntax-11.C | 205 |
5 files changed, 257 insertions, 22 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 49246e8..38f86cd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2020-04-10 Bin Cheng <bin.cheng@linux.alibaba.com> + + * coroutines.cc (co_await_expander): Simplify. + 2020-04-09 Jason Merrill <jason@redhat.com> PR c++/94523 diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 936be06..ab06c0a 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 d8fa35a..72e0d51 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-04-10 Bin Cheng <bin.cheng@linux.alibaba.com> + + * 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 <foreese@gcc.gnu.org> 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 0000000..8304344 --- /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 0000000..69810ab --- /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 <utility> +#include <type_traits> +#include <tuple> +#include <functional> +#include <coroutine> + +struct any { + template <typename T> any(T &&) noexcept; +}; + +template <typename T> +auto get_awaiter_impl(T &&value, int) noexcept + -> decltype(static_cast<T &&>(value).operator co_await()) { + return static_cast<T &&>(value).operator co_await(); +} +template <typename T, int = 0> +T &&get_awaiter_impl(T &&value, any) noexcept; +template <typename T> +auto get_awaiter(T &&value) noexcept + -> decltype(get_awaiter_impl(static_cast<T &&>(value), 123)) { + return get_awaiter_impl(static_cast<T &&>(value), 123); +} + +template <typename T, typename = void> struct awaitable_traits { + using awaiter_t = decltype(get_awaiter(std::declval<T>())); + using await_result_t = decltype(std::declval<awaiter_t>().await_resume()); +}; + +template <typename TASK_CONTAINER> class when_all_ready_awaitable; +template <typename... TASKS> +class when_all_ready_awaitable<std::tuple<TASKS...>> { +public: + explicit when_all_ready_awaitable(std::tuple<TASKS...> &&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<TASKS...> &&await_resume() noexcept { + return std::move(m_awaitable.m_tasks); + } + when_all_ready_awaitable& m_awaitable; + }; + return awaiter{*this}; + } + std::tuple<TASKS...> m_tasks; +}; + +inline void *operator new(std::size_t, void *__p) noexcept; + +template <typename RESULT> +class when_all_task_promise final{ +public: + using coroutine_handle_t = std::coroutine_handle<when_all_task_promise>; + RESULT &&result() &&; +}; +template <typename RESULT> class when_all_task final { +public: + using promise_type = when_all_task_promise<RESULT>; + 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<decltype(0)>) + ; + else + return std::move(*this).result(); + } + coroutine_handle_t m_coroutine; +}; +class task; +template <typename AWAITABLE, + typename RESULT = + typename awaitable_traits<AWAITABLE &&>::await_result_t, + std::enable_if_t<!std::is_void_v<RESULT>, int> = 0> +when_all_task<RESULT> make_when_all_task(AWAITABLE awaitable); + +template <typename... AWAITABLES> +inline auto when_all_ready(AWAITABLES &&... awaitables) { + return when_all_ready_awaitable< + std::tuple<when_all_task<typename awaitable_traits< + std::remove_reference_t<AWAITABLES>>::await_result_t>...>>( + std::make_tuple( + make_when_all_task(std::forward<AWAITABLES>(awaitables))...)); +} + +template <typename FUNC, typename AWAITABLE> class fmap_awaiter { + using awaiter_t = typename awaitable_traits<AWAITABLE &&>::awaiter_t; + +public: + fmap_awaiter(FUNC &&func, AWAITABLE &&awaitable) noexcept + : m_func(static_cast<FUNC &&>(func)), + m_awaiter(get_awaiter(static_cast<AWAITABLE &&>(awaitable))) {} + decltype(auto) await_ready() noexcept { + return static_cast<awaiter_t &&>(m_awaiter).await_ready(); + } + template <typename PROMISE> + decltype(auto) await_suspend(std::coroutine_handle<PROMISE> coro) noexcept {} + template <typename AWAIT_RESULT = + decltype(std::declval<awaiter_t>().await_resume()), + std::enable_if_t<!std::is_void_v<AWAIT_RESULT>, int> = 0> + decltype(auto) await_resume() noexcept { + return std::invoke(static_cast<FUNC &&>(m_func), + static_cast<awaiter_t &&>(m_awaiter).await_resume()); + } + +private: + FUNC &&m_func; + awaiter_t m_awaiter; +}; +template <typename FUNC, typename AWAITABLE> class fmap_awaitable { +public: + template < + typename FUNC_ARG, typename AWAITABLE_ARG, + std::enable_if_t<std::is_constructible_v<FUNC, FUNC_ARG &&> && + std::is_constructible_v<AWAITABLE, AWAITABLE_ARG &&>, + int> = 0> + explicit fmap_awaitable(FUNC_ARG &&func, AWAITABLE_ARG &&awaitable) noexcept + : m_func(static_cast<FUNC_ARG &&>(func)), + m_awaitable(static_cast<AWAITABLE_ARG &&>(awaitable)) {} + auto operator co_await() && { + return fmap_awaiter(static_cast<FUNC &&>(m_func), + static_cast<AWAITABLE &&>(m_awaitable)); + } + +private: + FUNC m_func; + AWAITABLE m_awaitable; +}; + +template <typename FUNC, typename AWAITABLE> +auto fmap(FUNC &&func, AWAITABLE &&awaitable) { + return fmap_awaitable<std::remove_cv_t<std::remove_reference_t<FUNC>>, + std::remove_cv_t<std::remove_reference_t<AWAITABLE>>>( + std::forward<FUNC>(func), std::forward<AWAITABLE>(awaitable)); +} +template <typename... AWAITABLES> +auto when_all(AWAITABLES &&... awaitables) { + return fmap( + [](auto &&taskTuple) { + decltype(auto) __trans_tmp_1 = std::apply( + [](auto &&... tasks) { + return std::make_tuple( + static_cast<decltype(tasks)>(tasks).non_void_result()...); + }, + static_cast<decltype(taskTuple)>(taskTuple)); + return __trans_tmp_1; + }, + when_all_ready(std::forward<AWAITABLES>(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<promise_type> 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)); + }(); +} |