coroutines: Fix handling of conditional statements [PR94288]
authorIain Sandoe <iain@sandoe.co.uk>
Thu, 23 Apr 2020 15:59:00 +0000 (16:59 +0100)
committerIain Sandoe <iain@sandoe.co.uk>
Thu, 23 Apr 2020 19:34:57 +0000 (20:34 +0100)
commit3dbc772128e944819b09e21021d4fcd5dc17f2d4
tree389001201cb096a63933c1499409b7da23303331
parent7291b2edf6f87fba839b0d10c04b2562a5f6bd60
coroutines: Fix handling of conditional statements [PR94288]

Normally, when we find a statement containing an await expression
this will be expanded to a statement list implementing the control
flow implied.  The expansion process successively replaces each
await expression in a statement with the result of its await_resume().

In the case of conditional statements (if, while, do, switch) the
expansion of the condition (or expression in the case of do-while)
cannot take place 'inline', leading to the PR.

The solution is to evaluate the expression separately, and to
transform while and do-while loops into endless loops with a break
on the required condition.

In fixing this, I realised that I'd also made a thinko in the case
of expanding truth-and/or-if expressions, where one arm of the
expression might need to be short-circuited.  The mechanism for
expanding via the tree walk will not work correctly in this case and
we need to pre-expand any truth-and/or-if with an await expression
on its conditionally-taken arm.  This applies to any statement with
truth-and/or-if expressions, so can be handled generically.

gcc/cp/ChangeLog:

2020-04-23  Iain Sandoe  <iain@sandoe.co.uk>

PR c++/94288
* coroutines.cc (await_statement_expander): Simplify cases.
(struct susp_frame_data): Add fields for truth and/or if
cases, rename one field.
(analyze_expression_awaits): New.
(expand_one_truth_if): New.
(add_var_to_bind): New helper.
(coro_build_add_if_not_cond_break): New helper.
(await_statement_walker): Handle conditional expressions,
handle expansion of truth-and/or-if cases.
(bind_expr_find_in_subtree): New, checking-only.
(coro_body_contains_bind_expr_p): New, checking-only.
(morph_fn_to_coro): Ensure that we have a top level bind
expression.

gcc/testsuite/ChangeLog:

2020-04-23  Iain Sandoe  <iain@sandoe.co.uk>

PR c++/94288
* g++.dg/coroutines/torture/co-await-18-if-cond.C: New test.
* g++.dg/coroutines/torture/co-await-19-while-cond.C: New test.
* g++.dg/coroutines/torture/co-await-20-do-while-cond.C: New test.
* g++.dg/coroutines/torture/co-await-21-switch-value.C: New test.
* g++.dg/coroutines/torture/co-await-22-truth-and-of-if.C: New test.
* g++.dg/coroutines/torture/co-ret-16-simple-control-flow.C: New test.
gcc/cp/ChangeLog
gcc/cp/coroutines.cc
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/coroutines/torture/co-await-18-if-cond.C [new file with mode: 0644]
gcc/testsuite/g++.dg/coroutines/torture/co-await-19-while-cond.C [new file with mode: 0644]
gcc/testsuite/g++.dg/coroutines/torture/co-await-20-do-while-cond.C [new file with mode: 0644]
gcc/testsuite/g++.dg/coroutines/torture/co-await-21-switch-value.C [new file with mode: 0644]
gcc/testsuite/g++.dg/coroutines/torture/co-await-22-truth-and-of-if.C [new file with mode: 0644]
gcc/testsuite/g++.dg/coroutines/torture/co-ret-16-simple-control-flow.C [new file with mode: 0644]