aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArsen Arsenović <arsen@aarsen.me>2024-09-24 18:16:01 +0200
committerArsen Arsenović <arsen@gcc.gnu.org>2024-09-27 13:37:38 +0200
commitd888a8a8dcf391197ae82e2bbf99507effc27950 (patch)
tree615de535d4f71f9d93f7cfb46419bbe3c512874a
parentde03ef6337b0a368d61c74b790313b4216c7ed6e (diff)
downloadgcc-d888a8a8dcf391197ae82e2bbf99507effc27950.zip
gcc-d888a8a8dcf391197ae82e2bbf99507effc27950.tar.gz
gcc-d888a8a8dcf391197ae82e2bbf99507effc27950.tar.bz2
c++/coro: ignore cleanup_point_exprs while expanding awaits [PR116793]
If we reach a CLEANUP_POINT_EXPR while trying to walk statements, we actually care about the statement or statement list contained within it. Indeed, such a construction started happening with r15-3513-g964577c31df206, after temporary promotion. In the test case presented in PR116793, the compiler generated: <<cleanup_point { struct _cleanup_task Aw0 [value-expr: frame_ptr->Aw0_2_3]; int T002 [value-expr: frame_ptr->T002_2_3]; int T002 [value-expr: frame_ptr->T002_2_3]; <<cleanup_point <<< Unknown tree: expr_stmt (void) (T002 = TARGET_EXPR <D.20994, 3>) >>>>>; struct _cleanup_task Aw0 [value-expr: frame_ptr->Aw0_2_3]; <<cleanup_point <<< Unknown tree: expr_stmt (void) (Aw0 = TARGET_EXPR <D.20995, func ((int &) &T002)>) >>>>>; <<cleanup_point <<< Unknown tree: expr_stmt (void) (D.22450 = <<< Unknown tree: co_await TARGET_EXPR <D.20995, func ((int &) &T002)> Aw0 {_cleanup_task::await_ready (&Aw0), _cleanup_task::await_suspend<_task1::promise_type> (&Aw0, TARGET_EXPR <D.21078, _Coro_self_handle>), <<< Unknown tree: aggr_init_expr 4 await_resume D.22443 &Aw0 >>>} 0 >>>) >>>>>; <<cleanup_point <<< Unknown tree: expr_stmt (void) (D.20991 = (struct tuple &) &D.22450) >>>>>; } D.22467 = 1; int & i [value-expr: frame_ptr->i_1_2]; <<cleanup_point <<< Unknown tree: expr_stmt (void) (i = std::get<0, int&> (NON_LVALUE_EXPR <D.20991>)) >>>>>;>>; ... i.e. a statement list within a cleanup point. In such a case, we don't actually care about the cleanup point, but we do care about the statement inside, so, we can just walk down into the CLEANUP_POINT_EXPR. PR c++/116793 gcc/cp/ChangeLog: * coroutines.cc (await_statement_expander): Just process subtrees if encountering a CLEANUP_POINT_EXPR. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr116793-1.C: New test.
-rw-r--r--gcc/cp/coroutines.cc4
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr116793-1.C26
2 files changed, 29 insertions, 1 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 8e4c55a..86a5ac8 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -2063,7 +2063,9 @@ await_statement_expander (tree *stmt, int *do_subtree, void *d)
tree res = NULL_TREE;
/* Process a statement at a time. */
- if (STATEMENT_CLASS_P (*stmt) || TREE_CODE (*stmt) == BIND_EXPR)
+ if (STATEMENT_CLASS_P (*stmt)
+ || TREE_CODE (*stmt) == BIND_EXPR
+ || TREE_CODE (*stmt) == CLEANUP_POINT_EXPR)
return NULL_TREE; /* Just process the sub-trees. */
else if (TREE_CODE (*stmt) == STATEMENT_LIST)
{
diff --git a/gcc/testsuite/g++.dg/coroutines/pr116793-1.C b/gcc/testsuite/g++.dg/coroutines/pr116793-1.C
new file mode 100644
index 0000000..ed2bdd2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr116793-1.C
@@ -0,0 +1,26 @@
+// https://gcc.gnu.org/PR116793
+#include <tuple>
+#include <coroutine>
+struct _cleanup_task {
+ bool await_ready() const noexcept;
+ template <typename Promise>
+ bool await_suspend(std::coroutine_handle<Promise> parent) noexcept;
+ std::tuple<int &> await_resume() noexcept;
+};
+struct _task1 {
+ struct promise_type final {
+ std::suspend_always initial_suspend() noexcept;
+ _task1 get_return_object() noexcept;
+ void unhandled_exception() noexcept;
+ struct awaiter final {
+ bool await_ready() noexcept;
+ void await_resume() noexcept;
+ void await_suspend(std::coroutine_handle<promise_type> h) noexcept;
+ };
+ awaiter final_suspend() noexcept;
+ };
+};
+_cleanup_task func(int &&);
+_task1 g() {
+ auto &&[i] = co_await func(3);
+}