Commit cd14f288 by Iain Sandoe

coroutines: Update lambda capture handling to n4849.

In the absence of specific comment on the handling of closures I'd
implemented something more than was intended (extending the lifetime
of lambda capture-by-copy vars to the duration of the coro).

After discussion at WG21 in February and by email, the correct handling
is to treat the closure "this" pointer the same way as for a regular one,
and thus it is the user's responsibility to ensure that the lambda capture
object has suitable lifetime for the coroutine.  It is noted that users
frequently get this wrong, so it would be a good thing to revisit for C++23.

This patch removes the additional copying behaviour for lambda capture-by-
copy vars.

gcc/cp/ChangeLog:

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

	* coroutines.cc (struct local_var_info): Adjust to remove the
	reference to the captured var, and just to note that this is a
	lambda capture proxy.
	(transform_local_var_uses): Handle lambda captures specially.
	(struct param_frame_data): Add a visited set.
	(register_param_uses): Also check for param uses in lambda
	capture proxies.
	(struct local_vars_frame_data): Remove captures list.
	(register_local_var_uses): Handle lambda capture proxies by
	noting and bypassing them.
	(morph_fn_to_coro): Update to remove lifetime extension of
	lambda capture-by-copy vars.

gcc/testsuite/ChangeLog:

2020-03-02  Iain Sandoe  <iain@sandoe.co.uk>
	    Jun Ma <JunMa@linux.alibaba.com>

	* g++.dg/coroutines/torture/class-05-lambda-capture-copy-local.C:
	* g++.dg/coroutines/torture/lambda-09-init-captures.C: New test.
	* g++.dg/coroutines/torture/lambda-10-mutable.C: New test.
parent b80cbe2d
2020-03-02 Iain Sandoe <iain@sandoe.co.uk>
* coroutines.cc (struct local_var_info): Adjust to remove the
reference to the captured var, and just to note that this is a
lambda capture proxy.
(transform_local_var_uses): Handle lambda captures specially.
(struct param_frame_data): Add a visited set.
(register_param_uses): Also check for param uses in lambda
capture proxies.
(struct local_vars_frame_data): Remove captures list.
(register_local_var_uses): Handle lambda capture proxies by
noting and bypassing them.
(morph_fn_to_coro): Update to remove lifetime extension of
lambda capture-by-copy vars.
2020-03-02 Iain Sandoe <iain@sandoe.co.uk>
* coroutines.cc (build_co_await): Do not build frame
awaitable proxy vars when the co_await expression is
a function parameter or local var.
......
2020-03-02 Iain Sandoe <iain@sandoe.co.uk>
Jun Ma <JunMa@linux.alibaba.com>
* g++.dg/coroutines/torture/class-05-lambda-capture-copy-local.C:
* g++.dg/coroutines/torture/lambda-09-init-captures.C: New test.
* g++.dg/coroutines/torture/lambda-10-mutable.C: New test.
2020-03-02 Uroš Bizjak <ubizjak@gmail.com>
PR target/93997
......
......@@ -18,7 +18,7 @@ class foo
auto l = [=](T y) -> coro1
{
T x = y;
co_return co_await x + local;
co_return co_await x + y + local;
};
return l;
}
......@@ -43,7 +43,7 @@ int main ()
/* Now we should have the co_returned value. */
int y = x.handle.promise().get_value();
if ( y != 20 )
if ( y != 37 )
{
PRINTF ("main: wrong result (%d).", y);
abort ();
......
// { dg-do run }
// lambda with initialized captures
#include "../coro.h"
// boiler-plate for tests of codegen
#include "../coro1-ret-int-yield-int.h"
int main ()
{
int a_copy = 20;
auto f = [&a_ref = a_copy, a_copy = a_copy + 10]() -> coro1
{
a_ref += 20;
co_return a_ref + a_copy;
};
{
coro1 A = f ();
A.handle.resume();
if (a_copy != 40)
{
PRINT ("main: [a_copy = 40]");
abort ();
}
int y = A.handle.promise().get_value();
if (y != 70)
{
PRINTF ("main: A co-ret = %d, should be 70\n", y);
abort ();
}
}
a_copy = 5;
coro1 B = f ();
B.handle.resume();
if (a_copy != 25)
{
PRINT ("main: [a_copy = 25]");
abort ();
}
int y = B.handle.promise().get_value();
if (y != 55)
{
PRINTF ("main: B co-ret = %d, should be 55\n", y);
abort ();
}
return 0;
}
// { dg-do run }
// lambda with mutable closure object.
#include "../coro.h"
// boiler-plate for tests of codegen
#include "../coro1-ret-int-yield-int.h"
/* Creates a coro lambda with a mutable closure and
suspend-always initial suspend. */
auto make_co_lambda ()
{
return [i = 1] () mutable -> coro1 { co_return i++; };
}
/* We make this behave sequentially for the purposes of testing. */
int main()
{
auto co_l = make_co_lambda ();
auto v1 = co_l ();
auto v2 = co_l ();
auto v3 = co_l ();
v3.handle.resume();
v2.handle.resume();
v1.handle.resume();
int res1 = v1.handle.promise().get_value ();
int res2 = v2.handle.promise().get_value ();
int res3 = v3.handle.promise().get_value ();
PRINTF ("main: co-lambda %d, %d, %d\n",res1, res2, res3);
if ( res1 != 3 || res2 != 2 || res3 != 1)
{
PRINT ("main: bad return value.");
abort ();
}
if (!v1.handle.done() || !v2.handle.done() || !v3.handle.done())
{
PRINT ("main: apparently something was not done...");
abort ();
}
PRINT ("main: done.");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment