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.
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)
{
--- /dev/null
+// 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);
+}