This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4358. §[exec.as.awaitable] is using "Preconditions:" when it should probably be described in the constraint

Section: 33.13.1 [exec.as.awaitable] Status: New Submitter: Lewis Baker Opened: 2025-08-27 Last modified: 2025-09-14

Priority: Not Prioritized

View other active issues in [exec.as.awaitable].

View all other issues in [exec.as.awaitable].

View all issues with New status.

Discussion:

In 33.13.1 [exec.as.awaitable] bullet 7.2 it states:

  1. (7.2) — Otherwise, (void(p), expr) if is-awaitable<Expr, U> is true, where U is an unspecified class type that is not Promise and that lacks a member named await_transform.

    Preconditions: is-awaitable<Expr, Promise> is true and the expression co_await expr in a coroutine with promise type U is expression-equivalent to the same expression in a coroutine with promise type Promise.

The "Preconditions:" sentence there refers to static properties of the program and so seems like a better fit for a Mandates: element or for folding into the constraint.

Also, in the part of the precondition above which says "… and the expression co_await expr in a coroutine with promise type U is expression-equivalent to the same expression in a coroutine with promise type Promise" it is unclear how this can be satisfied, as the types involved are different and therefore the expression cannot be expression-equivalent.

I think perhaps what is intended here is something along the lines of the first expression having "effects equivalent to" the second expression, instead of "expression-equivalent to"?

However, I think there is a more direct way to express the intent here, by instead just requiring that decltype(GET-AWAITER(expr)) satisfies is-awaiter<Promise>. This checks whether expr would be a valid type to return from a Promise::await_transform() function.

Proposed resolution:

This wording is relative to N5014.

  1. Modify 33.13.1 [exec.as.awaitable] as indicated:

    -7- as_awaitable is a customization point object. For subexpressions expr and p where p is an lvalue, Expr names the type decltype((expr)) and Promise names the type decay_t<decltype((p))>, as_awaitable(expr, p) is expression-equivalent to, except that the evaluations of expr and p are indeterminately sequenced:

    1. (7.1) — expr.as_awaitable(p) if that expression is well-formed.

      Mandates: is-awaitable<A, Promise> is true, where A is the type of the expression above.

    2. (7.2) — Otherwise, (void(p), expr) if decltype(GET-AWAITER(expr)) satisfies is-awaiter<Promise>.is-awaitable<Expr, U> is true, where U is an unspecified class type that is not Promise and that lacks a member named await_transform.

      Preconditions: is-awaitable<Expr, Promise> is true and the expression co_await expr in a coroutine with promise type U is expression-equivalent to the same expression in a coroutine with promise type Promise.

    3. (7.3) — […]

    4. (7.4) — […]

    5. (7.5) — […]