https://gcc.gnu.org/g:d888a8a8dcf391197ae82e2bbf99507effc27950
commit r15-3923-gd888a8a8dcf391197ae82e2bbf99507effc27950 Author: Arsen Arsenović <ar...@aarsen.me> Date: Tue Sep 24 18:16:01 2024 +0200 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. Diff: --- gcc/cp/coroutines.cc | 4 +++- gcc/testsuite/g++.dg/coroutines/pr116793-1.C | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 8e4c55a800e4..86a5ac8999ac 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 000000000000..ed2bdd26996a --- /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); +}