coroutines: Don't make duplicate frame copies of awaitables.
authorIain Sandoe <iain@sandoe.co.uk>
Mon, 2 Mar 2020 15:35:45 +0000 (15:35 +0000)
committerIain Sandoe <iain@sandoe.co.uk>
Mon, 2 Mar 2020 16:57:40 +0000 (16:57 +0000)
commit005530eb019eb7703534540bdac01e5acc611e78
treef1c25920e5292a40c306aae78a79736766ae4ea3
parenta5879399fc0dcdd6b1ebe9a3b0d03db5ca30150a
coroutines: Don't make duplicate frame copies of awaitables.

In general, we need to manage the lifetime of compiler-
generated awaitable instances in the coroutine frame, since
these must persist across suspension points.

However, it is quite possible that the user might provide the
awaitable instances, either as function params or as a local
variable.  We will already generate a frame entry for these as
required.

At present, under this circumstance, we are duplicating these,
awaitable, initialising a second frame copy for them (which we
then subsequently destroy manually after the suspension point).
That's not efficient - so an undesirable thinko in the first place.
However, there is also an actual bug; if the compiler elects to
elide the copy (which is perfectly legal), it does not have visibility
of the manual management of the post-suspend destruction
- this subsequently leads to double-free errors.

The solution is not to make the second copy (as noted, params
and local vars already have frame copies with managed lifetimes).

gcc/cp/ChangeLog:

2020-03-02  Iain Sandoe  <iain@sandoe.co.uk>

* coroutines.cc (build_co_await): Do not build frame
proxy vars when the co_await expression is a function
parameter or local var.
(co_await_expander): Do not initialise a frame var with
itself.
(transform_await_expr): Only substitute the awaitable
frame var if it's needed.
(register_awaits): Do not make frame copies for param
or local vars that are awaitables.

gcc/testsuite/ChangeLog:

2020-03-02  Iain Sandoe  <iain@sandoe.co.uk>

* g++.dg/coroutines/torture/func-params-09-awaitable-parms.C: New test.
* g++.dg/coroutines/torture/local-var-5-awaitable.C: New test.
gcc/cp/ChangeLog
gcc/cp/coroutines.cc
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/coroutines/torture/func-params-09-awaitable-parms.C [new file with mode: 0644]
gcc/testsuite/g++.dg/coroutines/torture/local-var-5-awaitable.C [new file with mode: 0644]