Hi
Apparently, I had a brainstorm when posting patches to cover the
cases with await expressions in do {} while; and while {} ; and
omitted the for loop case.
Fixed thus.
tested on x86_64-darwin, x86_64-linux-gnu and with cppcoro and
folly/coroutines.
OK for master / 10.x?
thanks
Iain
gcc/cp/ChangeLog:
* coroutines.cc (replace_continue): Rewrite continue into
'goto label'.
(await_statement_walker): Handle await expressions in the
initializer, condition and iteration expressions of for
loops.
gcc/testsuite/ChangeLog:
* g++.dg/coroutines/pr98480.C: New test.
* g++.dg/coroutines/torture/co-await-24-for-init.C: New test.
* g++.dg/coroutines/torture/co-await-25-for-condition.C: New test.
* g++.dg/coroutines/torture/co-await-26-for-iteration-expr.C: New test.
---
gcc/cp/coroutines.cc | 126 ++
gcc/testsuite/g++.dg/coroutines/pr98480.C | 20 +++
.../coroutines/torture/co-await-24-for-init.C | 101 ++
.../torture/co-await-25-for-condition.C | 94 +
.../torture/co-await-26-for-iteration-expr.C | 87
5 files changed, 428 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/coroutines/pr98480.C
create mode 100644
gcc/testsuite/g++.dg/coroutines/torture/co-await-24-for-init.C
create mode 100644
gcc/testsuite/g++.dg/coroutines/torture/co-await-25-for-condition.C
create mode 100644
gcc/testsuite/g++.dg/coroutines/torture/co-await-26-for-iteration-expr.C
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 712431583d5..438538a0b4f 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -3431,6 +3431,50 @@ coro_build_add_if_not_cond_break (tree cond)
finish_if_stmt (if_stmt);
}
+/* Tree walk callback to replace continue statements with goto label. */
+static tree
+replace_continue (tree *stmt, int *do_subtree, void *d)
+{
+ tree expr = *stmt;
+ if (TREE_CODE (expr) == CLEANUP_POINT_EXPR)
+expr = TREE_OPERAND (expr, 0);
+ if (CONVERT_EXPR_P (expr) && VOID_TYPE_P (expr))
+expr = TREE_OPERAND (expr, 0);
+ STRIP_NOPS (expr);
+ if (!STATEMENT_CLASS_P (expr))
+return NULL_TREE;
+
+ switch (TREE_CODE (expr))
+{
+ /* Unless it's a special case, just walk the subtrees as usual. */
+ default: return NULL_TREE;
+
+ case CONTINUE_STMT:
+ {
+ tree *label = (tree *)d;
+ location_t loc = EXPR_LOCATION (expr);
+ /* re-write a continue to goto label. */
+ *stmt = build_stmt (loc, GOTO_EXPR, *label);
+ *do_subtree = 0;
+ return NULL_TREE;
+ }
+
+ /* Statements that do not require recursion. */
+ case DECL_EXPR:
+ case BREAK_STMT:
+ case GOTO_EXPR:
+ case LABEL_EXPR:
+ case CASE_LABEL_EXPR:
+ case ASM_EXPR:
+ /* These must break recursion. */
+ case FOR_STMT:
+ case WHILE_STMT:
+ case DO_STMT:
+ *do_subtree = 0;
+ return NULL_TREE;
+}
+}
+
/* Tree walk callback to analyze, register and pre-process statements that
contain await expressions. */
@@ -3534,6 +3578,88 @@ await_statement_walker (tree *stmt, int *do_subtree,
void *d)
return res;
}
break;
+ case FOR_STMT:
+ {
+ /* for loops only need special treatment if the condition or the
+ iteration expression contain a co_await. */
+ tree for_stmt = *stmt;
+ /* Sanity check. */
+ if ((res = cp_walk_tree (_INIT_STMT (for_stmt),
+ analyze_expression_awaits, d, )))
+ return res;
+ gcc_checking_assert (!awpts->saw_awaits);
+
+ if ((res = cp_walk_tree (_COND (for_stmt),
+ analyze_expression_awaits, d, )))
+ return res;
+ bool for_cond_await = awpts->saw_awaits != 0;
+ unsigned save_awaits = awpts->saw_awaits;
+
+ if ((res = cp_walk_tree (_EXPR (for_stmt),
+ analyze_expression_awaits, d, )))
+ return res;
+ bool for_expr_await = awpts->saw_awaits > save_awaits;
+
+ /* If the condition has an await, then we will need to rewrite the
+ loop as
+ for (init expression;true;iteration expression) {
+ condition = await expression;
+ if (condition)
+ break;
+ ...
+ }
+ */
+ if (for_cond_await)
+ {
+ tree insert_list = push_stmt_list ();
+ /* This will be expanded when the revised body is handled. */
+ coro_build_add_if_not_cond_break (FOR_COND (for_stmt));
+ /* .. add the original for body. */
+ add_stmt (FOR_BODY (for_stmt));
+ /* To make the new for body. */
+ FOR_BODY (for_stmt) = pop_stmt_list (insert_list);
+ FOR_COND (for_stmt)