Re: [PATCH] coroutines : Handle for await expressions in for stmts [PR98480].

2021-03-15 Thread Nathan Sidwell

On 3/14/21 8:22 PM, Iain Sandoe wrote:

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.



ok


--
Nathan Sidwell


[PATCH] coroutines : Handle for await expressions in for stmts [PR98480].

2021-03-14 Thread Iain Sandoe
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)