Skip to content

with_awaitable_senders should use affine in its await_transform #358

@ericniebler

Description

@ericniebler

with_awaitable_senders is intended to be used as a base class of a coroutine promise type to make senders awaitable in coroutines of that type. E.g.,

struct my_task
{
  struct promise_type
    : std::execution::with_awaitable_senders<promise_type>
  {

with_awaitable_senders gives my_task::promise_type an await_transform member function that turns senders into awaitables by calling the as_awaitable customization point. in [exec.with.awaitable.senders], await_transform(value) is specified as follows:

return as_awaitable(std::forward<Value>(value), static_cast<Promise&>(*this));

this does, indeed, make senders awaitable for my_task, but it doesn't guard against senders that change the current execution context. so for example, co_await sndr will cause the coroutine to resume on whatever context sndr completed on, which could be different from the context at suspension.

this is in contrast to what is done for std::execution::task, whose promise's await_transform is specified to return:

returns as_awaitable(affine(std​::​forward<​Sender>(sndr)), *this)

the use of the affine algorithm here guarantees that after co_await-ing a sender, the coroutine will resume on the same execution context it suspended on. (this is done because we observed in the field that it caught many programmers by surprise that a coroutine could thread-hop at co_awaits, leading to bugs.)

one fix here is for with_awaitable_senders::await_transform to do what task::promise_type::await_transform is doing: wrapping senders in affine before calling as_awaitable. then task::promise_type can be respecified in terms of with_awaitable_senders<task::promise_type>, at which point task::promise_type would no longer need to provide its own await_transform memfn.

Proposed Resolution

TODO

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions