C++ Logo

STD-PROPOSALS

Advanced search

Subject: [std-proposals] async coroutines vs. lambdas
From: Avi Kivity (avi_at_[hidden])
Date: 2020-05-14 05:57:32


Coroutines capture parameters passed by value and copy them to the
coroutine frame (all quotes from cppreference):

> When a coroutine begins execution, it performs the following:
>
>      allocates the coroutine state object using operator new (see below)
>      copies all function parameters to the coroutine state: by-value
parameters are moved or copied, by-reference parameters remain
references (and so may become dangling if the coroutine is resumed after
the lifetime of referred object ends)
>

This allows a coroutine's parameters to outlive the point it is launched at:

void foo() {

 Â Â Â  call_some_coroutine(a_temporary_value());

}

Normally, a_temporary_value() would e destroyed at the end of the
expression, which can be before the coroutine completes.

With a lambda coroutine, we have a problem. This is because lambdas are
captured by reference:

> If the coroutine is a non-static member function, such as task<void>
my_class::method1(int x) const;, its Promise type is
std::coroutine_traits<task<void>, const my_class&, int>::promise_type

For a lambda, the non-static member function is
synthetic_lambda_type::operator() const, and so the lambda would be
captured as const synthetic_lambda_type&. Consider this call:

int var;

void foo() {

 Â Â Â  [i = 3] () -> future<> {

 Â Â Â Â Â Â Â  co_await delay(1s);

 Â Â Â Â Â Â Â  var = i;

 Â Â Â  }();

}

Because the lambda is captured by reference, the read of 'i' refers to a
freed stack frame.

I consider this is a serious defect. It can be fixed by changing how
"this" parameters to member functions are captured:

 Â - if the object is an rvalue[1], then it is captured by value (and the
promise type is std::coroutine_traits<task<void>, const my_class,
int>::promise_type

 Â - if the object is a glvalue, then it is captured by reference (and
the promise type is std::coroutine_traits<task<void>, const my_class&,
int>::promise_type

I filed a bug[2] against gcc regarding this, but I now believe gcc to be
innocent.

[1] I'm not up to speed on C++ value categories so I'm not sure if this
is a prvalue, xvalue, rvalue, or something else.

[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95111


STD-PROPOSALS list run by std-proposals-owner@lists.isocpp.org

Standard Proposals Archives on Google Groups