Doc. no. | P0664R8 |
Revises | P0664R7 |
Date: | Revised 2019-02-21 |
Project: | Programming Language C++ |
Reference: | ISO/IEC TS 22277, C++ Extensions for Coroutines |
Audience: | CWG |
Reply to: | Gor Nishanov <gorn@microsoft.com> |
All proposed resolutions wording is relative to N4775.
Previous issue list is P0664R7.
Section: 11.4.4 [dcl.fct.def.coroutine] Status: Ready Submitter: Gor Nishanov Opened: 2018-03-08 Last modified: 2018-05-05
[EWG Approved Rapperswil-2018/06/09]
[San Diego-2018/11/10: Alternative resolution for this issue is proposed. Waiting for details]
[EWG Alternative resolution was not accepted -2019/02/20]
Issue:
Common use of the initial_suspend
point in asynchronous coroutines is to suspend the coroutine
during the initial invocation and post a request to resume the coroutine by a different execution agent.
If an execution agent at a later point cannot resume the coroutine, for example, because it is being shutdown,
an error will be reported to a coroutine by resuming the coroutine
and subsequently throwing an exception from await_resume
.
Currently, the invocation of initial_suspend
is specified in [dcl.fct.def.coroutine] as:
{ P p; co_await p.initial_suspend(); // initial suspend point try { F } catch(...) { p.unhandled_exception(); } final_suspend: co_await p.final_suspend(); // final suspend point }
As specified, an exception from await_resume
of initial_suspend
will be thrown
outside of the try-catch
and will not be captured by p.unhandled_exception()
and
whoever waits for eventual completion of a coroutine will never learn about its completion.
This is a specification defect. The intent is to capture an exception thrown by await_resume
of
an awaitable returned by initial_suspend
within the try-catch
enclosing of
the user authored body F
.
The correct behavior has been implemented in MSVC staring with version 2015 and in clang trunk.
Proposed resolution:
Add underlying text to paragraph 11.4.4/3 as follows:
{ P p; co_await p.initial_suspend(); // initial suspend point try { F } catch(...) { p.unhandled_exception(); } final_suspend: co_await p.final_suspend(); // final suspend point }except that any exception thrown after the initial suspend point and before the flow of execution reaches F also results in entering the handler of the try-block and, where an object denoted as p is the promise object of the coroutine and its type P is the promise type of the coroutine, ...
Section: 11.4.4/11 [dcl.fct.def.coroutine] Status: Ready Submitter: Mathias Stearn Opened: 2018-06-09
[Clarification Requested by CWG - San Diego - 2018/11/07]
[EWG: Yes, we meant it! - Kona - 2019/02/21]
Issue:
The intent is that copies/moves of parameters (if required) are created preserving the exact type (including references, r-references, etc). The wording in 11.4.4[dcl.fct.def.coroutine]/11 does not seem to express that clearly.
Proposed wording:
Modify paragraph 11 of 11.4.4/[dcl.fct.def.coroutine] as follows:When a coroutine is invoked, a copy is created for each coroutine parameter. Each such copy is an object or reference with automatic storage duration and has the same type as the corresponding parameter.thatEach copy is direct-initialized ([dcl.init]) froman lvalue referring tothe corresponding parameterif the parameter is an lvalue reference, and from an xvalue referring to it otherwise. If the type of the copy is an rvalue reference type, then, for the purpose of this initialization the value category of the corresponding parameter is an rvalue. Areference touse of a parameter in the function-body of the coroutine and in the call to the coroutine promise constructor is replaced bya reference toits copy. The initialization and destruction of each parameter copy occurs in the context of the called coroutine. Initializations of parameter copies are sequenced before the call to the coroutine promise constructor and indeterminately sequenced with respect to each other. The lifetime of parameter copies ends immediately after the lifetime of the coroutine promise object ends. [ Note: If a coroutine has a parameter passed by reference, resuming the coroutine after the lifetime of the entity referred to by that parameter has ended is likely to result in undefined behavior. —end note ]
void.
Status: Active Submitter: Gor Nishanov Opened: 2018-01-16
Issue:
Mandate that the return type of return_value
and return_void
customization points to be of type void
to leave room for
possible future evolution.
Proposed wording attempt 1:
Modify the paragraph 2 of [stmt.return.coroutine] as follows:(2.1) -- S is p
.return_value(
expr-or-braced-init-list)
, if the operand is a braced-init-list or an expression of non-void
type;(2.1) -- S is
{
expressionopt; p.return_void(); }
, otherwise;S shall be a prvalue of type void. p
.return_void()
shall be a prvalue of typevoid
.
Proposed wording attempt 2:
Add new paragraph after paragraph 3 of [stmt.return.coroutine]:3. If p
.return_void()
is a valid expression, flowing off the end of a coroutine is equivalent to a co_return with no operand; otherwise flowing off the end of a coroutine results in undefined behavior.4. The return type of
return_void
andreturn_value
shall bevoid
.
await_suspend
Section: 8.3.8 [expr.await] Status: Waiting for more information Submitter: Gor Nishanov Opened: 2018-03-10 Last modified: 2018-11-10
[EWG Approved Rapperswil-2018/06/09]
[San Diego-2018/11/10: Alternative resolution for this issue is proposed. Waiting for details.]
Issue:
One of the implementation strategies for coroutines is to chop
original function into as many functions (parts) as there are suspend points.
In that case, it is possible for a compiler create a unique
per suspend per function coroutine_handle
which
resume
and destroy
members can be direct calls to corresponding
parts of the function.
Though no compiler is doing it now, we can allow implementors
to experiment with this approach by relaxing the requirement
on the coroutine_handle
passed
to await_suspend
.
Proposed wording:
Add underlined text to 8.3.8/3.5:(3.5) — h is an object of a class type that is either std::experimental::coroutine_handle<P> or that has a public and unambiguous base class of type std::experimental::coroutine_handle<P> referring to the enclosing coroutine.
task
and generator
types are available Section: 10.1.7.4 [coroutine.handle] Status: Waiting for paper Submitter: Gor Nishanov Opened: 2018-05-05 Last modified: 2018-05-05
Issue:
We stripped out automatic return type deduction for coroutines from N4499 in 2015. Put back the wording to do it once the appropriate types are available in the standard library.
Section: 11.4.4 [dcl.fct.def.coroutine] Status: Resolved Submitter: Gor Nishanov Opened: 2018-03-10 Last modified: 2018-03-10
Proposed wording:
[[Editor of C++ WD will decide on the stable name during merge]
Status: Adopted Submitter: SG1 Opened: 2018-06-08
Issue:
Add a note warning about thread switching near await and/or coroutine_handle wording
Proposed wording
[LWG Approved Kona-2019/02/19]
[This wording per SG1 also addresses issue 32]
[Incorporated in the working draft]
Modify [coroutine.handle.resumption] as follows:
xx.xx.xx coroutine_handle resumption [coroutine.handle.resumption]
1. Resuming a coroutine via
resume
,operator()
, ordestroy
on an execution agent other than the one it was suspended on has implementation-defined behavior unless each is either an instance ofstd::thread
or the thread that executesmain
.[LWG question for CWG: "thread that executes main" or "thread of execution that executes main"?]
[ Note: A coroutine that is resumed on a different execution agent should avoid relying on consistent thread identity throughout, such as holding a mutex object across a suspend point. — end note ]
[ Note: A concurrent resumption of the coroutine may result in a data race. — end note ]
void operator()() const;
void resume() const;...
[ Note: A concurrent resumption of the coroutine via resume, operator(), or destroy may result in a data race. —end note ]
void destroy() const;
...
[ Note: A concurrent resumption of the coroutine via resume, operator(), or destroy may result in a data race. —end note ]
Status: Resolved Submitter: SG1 Opened: 2018-06-08 Resolved: 2019-01-16
Issue:
Add a normative text making it UB to migrate coroutines between certain kind of execution agents. Clarify that migrating between std::threads is OK. But migrating between CPU and GPU is UB.
[Resolved by the wording offered in issue 31 - 2019/01/16]
for co_await
statement. Status: Adopted Submitter: Gor Nishanov Opened: 2018-01-16
[EWG Approved Kona-2019/02/19]
[Incorporated in the working draft]
Issue:
The wording for co_await
statement makes assumptions of what
future asynchronous generator interface will be. Remove it for now as not to
constraint the design space for asynchronous generators.
Proposed wording change:
Strike sections [stmt.iter] and [stmt.ranged] from Coroutines TS working document.