This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2025-06-02


2563. Initialization of coroutine result object

Section: 9.6.4  [dcl.fct.def.coroutine]     Status: review     Submitter: Tomasz Kamiński     Date: 2022-04-06     Liaison: EWG

Subclause 9.6.4 [dcl.fct.def.coroutine] paragraph 7 specifies:

The expression promise.get_return_object() is used to initialize the returned reference or prvalue result object of a call to a coroutine. The call to get_return_object is sequenced before the call to initial-suspend and is invoked at most once.

It is unclear:

There is implementation divergence.

Note that a user-defined conversion may be involved in the initialization of the coroutine's prvalue result object from get_return_object(). Note also that the return type of get_return_object might be non-copyable and non-movable. However, there are certain programming patterns that would benefit from a late-initialized return value.

See also compiler explorer.

Suggested resolution [SUPERSEDED]:

Change in 9.6.4 [dcl.fct.def.coroutine] paragraph 7 as follows:

The expression promise.get_return_object() is used to initialize the The returned reference or prvalue result object of a call to a coroutine is copy-initialized with promise.get_return_object(). The call to get_return_object initialization is sequenced before the call to initial-suspend and is invoked at most once.

Additional notes (January, 2023)

See also clang bug report #56532.

Forwarded to EWG with paper issue 1414, by decision of the CWG chair.

EWG 2023-02-06

EWG agrees that get_return_object is invoked outside of the try-block and that, if a conversion is needed, the return value of get_return_object is considered an xvalue that is later converted to the result object.

Proposed resolution (May, 2025):

  1. Change in 9.6.4 [dcl.fct.def.coroutine] paragraph 5 as follows:

    A coroutine behaves as if the top-level cv-qualifiers in all parameter-declarations in the declarator of its function-definition were removed and its function-body were replaced by the following replacement body:
      {
        promise-type promise promise-constructor-arguments ;
        get-return-object-invocation ;
        try {
          co_await promise .initial_suspend() ;
          function-body
        } catch ( ... ) {
          if (!initial-await-resume-called )
            throw ;
          promise .unhandled_exception() ;
        }
      final-suspend :
        co_await promise .final_suspend() ;
      }
    
    where
    • ...
    • promise-constructor-arguments is determined as follows: ...
    • get-return-object-invocation is as follows:
      • if the return type R of promise.get_return_object() is cv void, then get-return-object-invocation is promise.get_return_object(), and the return type of the coroutine shall also be cv void;
      • otherwise, if R is the same class type as the return type of the coroutine (ignoring cv-qualification), and the implementation does not create a temporary to hold the result object (6.7.7 [class.temporary]), then get-return-object-invocation initializes the prvalue result object of the call to the coroutine from promise.get_return_object();
      • otherwise, get-return-object-invocation initializes a variable with the exposition-only name gro as if by
          decltype(auto) gro = promise.get_return_object();
        
    • a coroutine is suspended at the initial suspend point if ...
  2. Replace 9.6.4 [dcl.fct.def.coroutine] paragraph 8 as follows:

    The expression promise.get_return_object() is used to initialize the returned reference or prvalue result object of a call to a coroutine. The call to get_return_object is sequenced before the call to initial-suspeend and is invoked at most once.

    If get-return-object-invocation defines a variable gro and the coroutine returns to its caller, whether by suspending (7.6.2.4 [expr.await]) or completing without ever suspending (8.7.5 [stmt.return.coroutine]), it is as if by return gro. This return exits the scope of gro. It exits the scope of promise only if the coroutine completed without suspending. [Note: The operand of the return might be move-eligible (7.5.5.2 [expr.prim.id.unqual]). --end note]

  3. Change in 9.6.4 [dcl.fct.def.coroutine] paragraph 11 as follows:

    ... If the allocation function returns nullptr, the coroutine transfers control to the caller of the coroutine and the return value is obtained by a call to as if by return T::get_return_object_on_allocation_failure();, where T is the promise type. ...