178 lines
4.8 KiB
Diff
178 lines
4.8 KiB
Diff
In the current implementation, statement expressions were intentionally
|
|
unsupported (as a C++ extension). However since they are quite heavily
|
|
used by end-users and also now emitted by the compiler in some cases
|
|
we are now working to add them. This first patch ensures that we
|
|
recurse into statement expressions (and therefore handle coroutine
|
|
keywords that might appear inside them).
|
|
|
|
PR c++/115851
|
|
PR c++/116914
|
|
PR c++/117231
|
|
|
|
gcc/cp/ChangeLog:
|
|
|
|
* coroutines.cc (await_statement_expander): Walk into
|
|
statement expressions.
|
|
(await_statement_walker): Likewise.
|
|
|
|
gcc/testsuite/ChangeLog:
|
|
|
|
* g++.dg/coroutines/pr115851.C: New test.
|
|
* g++.dg/coroutines/pr116914.C: New test.
|
|
* g++.dg/coroutines/pr117231.C: New test.
|
|
|
|
Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
|
|
---
|
|
gcc/cp/coroutines.cc | 22 ++++++++++++
|
|
gcc/testsuite/g++.dg/coroutines/pr115851.C | 35 +++++++++++++++++++
|
|
gcc/testsuite/g++.dg/coroutines/pr116914.C | 40 ++++++++++++++++++++++
|
|
gcc/testsuite/g++.dg/coroutines/pr117231.C | 21 ++++++++++++
|
|
4 files changed, 118 insertions(+)
|
|
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr115851.C
|
|
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr116914.C
|
|
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr117231.C
|
|
|
|
--- gcc/cp/coroutines.cc
|
|
+++ gcc/cp/coroutines.cc
|
|
@@ -2128,6 +2128,14 @@ await_statement_expander (tree *stmt, int *do_subtree, void *d)
|
|
}
|
|
else if (EXPR_P (*stmt))
|
|
{
|
|
+ /* Look for ({}) at the top level - just recurse into these. */
|
|
+ if (TREE_CODE (*stmt) == EXPR_STMT)
|
|
+ {
|
|
+ tree inner = EXPR_STMT_EXPR (*stmt);
|
|
+ if (TREE_CODE (inner) == STATEMENT_LIST
|
|
+ || TREE_CODE (inner) == BIND_EXPR)
|
|
+ return NULL_TREE; // process contents
|
|
+ }
|
|
process_one_statement (stmt, d);
|
|
*do_subtree = 0; /* Done subtrees. */
|
|
}
|
|
@@ -3857,6 +3865,20 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d)
|
|
if (!(cp_walk_tree (stmt, find_any_await, &await_ptr, &visited)))
|
|
return NULL_TREE; /* Nothing special to do here. */
|
|
|
|
+ /* Handle statement expressions. */
|
|
+ if (TREE_CODE (expr) == EXPR_STMT)
|
|
+ {
|
|
+ tree inner = EXPR_STMT_EXPR (expr);
|
|
+ if (TREE_CODE (inner) == STATEMENT_LIST
|
|
+ || TREE_CODE (inner) == BIND_EXPR)
|
|
+ {
|
|
+ res = cp_walk_tree (&EXPR_STMT_EXPR (expr),
|
|
+ await_statement_walker, d, NULL);
|
|
+ *do_subtree = 0;
|
|
+ return res;
|
|
+ }
|
|
+ }
|
|
+
|
|
visited.empty ();
|
|
awpts->saw_awaits = 0;
|
|
hash_set<tree> truth_aoif_to_expand;
|
|
--- gcc/testsuite/g++.dg/coroutines/pr115851.C
|
|
+++ gcc/testsuite/g++.dg/coroutines/pr115851.C
|
|
@@ -0,0 +1,35 @@
|
|
+// { dg-additional-options "-Wno-pedantic " }
|
|
+#include <coroutine>
|
|
+
|
|
+struct SuspendNever {
|
|
+ bool await_ready() noexcept;
|
|
+ void await_suspend(std::coroutine_handle<>) noexcept;
|
|
+ void await_resume() noexcept;
|
|
+};
|
|
+
|
|
+struct Coroutine;
|
|
+
|
|
+struct PromiseType {
|
|
+ Coroutine get_return_object();
|
|
+ SuspendNever initial_suspend();
|
|
+ SuspendNever final_suspend() noexcept;
|
|
+ void unhandled_exception () {}
|
|
+};
|
|
+
|
|
+struct Coroutine {
|
|
+ using promise_type = PromiseType;
|
|
+};
|
|
+
|
|
+struct ErrorOr {
|
|
+ int release_error();
|
|
+};
|
|
+
|
|
+void warnln(int const&);
|
|
+
|
|
+Coroutine __async_test_input_basic() {
|
|
+ ({
|
|
+ co_await SuspendNever{};
|
|
+ ErrorOr _temporary_result2;
|
|
+ warnln(_temporary_result2.release_error());
|
|
+ });
|
|
+}
|
|
--- gcc/testsuite/g++.dg/coroutines/pr116914.C
|
|
+++ gcc/testsuite/g++.dg/coroutines/pr116914.C
|
|
@@ -0,0 +1,40 @@
|
|
+// { dg-additional-options "-std=gnu++20 -fpreprocessed" }
|
|
+
|
|
+namespace std {
|
|
+template <typename a, typename> struct coroutine_traits : a {};
|
|
+template <typename = void> struct coroutine_handle {
|
|
+ static coroutine_handle from_address(void *);
|
|
+ operator coroutine_handle<>();
|
|
+ void *address();
|
|
+};
|
|
+struct b {
|
|
+ int await_ready() noexcept;
|
|
+ void await_suspend(coroutine_handle<>) noexcept;
|
|
+ void await_resume() noexcept;
|
|
+};
|
|
+} // namespace std
|
|
+struct c;
|
|
+struct d {
|
|
+ c get_return_object();
|
|
+ std::b initial_suspend();
|
|
+ std::b final_suspend() noexcept;
|
|
+ void unhandled_exception();
|
|
+ std::b yield_value(int);
|
|
+};
|
|
+struct e {
|
|
+ void operator++();
|
|
+ int operator*();
|
|
+ int operator!=(e);
|
|
+};
|
|
+struct c {
|
|
+ using promise_type = d;
|
|
+ e begin();
|
|
+ e end();
|
|
+ c f() {
|
|
+ c g;
|
|
+ for (auto h : g) {
|
|
+ auto i = 1;
|
|
+ co_yield i;
|
|
+ }
|
|
+ }
|
|
+};
|
|
--- gcc/testsuite/g++.dg/coroutines/pr117231.C
|
|
+++ gcc/testsuite/g++.dg/coroutines/pr117231.C
|
|
@@ -0,0 +1,21 @@
|
|
+// { dg-additional-options "-std=c++23 " }
|
|
+// { dg-do run }
|
|
+#include <generator>
|
|
+//#include <print>
|
|
+#include <vector>
|
|
+
|
|
+std::generator<int> get_seq()
|
|
+{
|
|
+ std::vector<int> data_{1, 2, 3};
|
|
+ for (auto item : data_)
|
|
+ co_yield item;
|
|
+}
|
|
+
|
|
+int main()
|
|
+{
|
|
+ int res = 0;
|
|
+ for (auto item : get_seq())
|
|
+ res = item; //std::println("{}", item);
|
|
+ if (res != 3)
|
|
+ __builtin_abort ();
|
|
+}
|