[dcl.fct.def.coroutine]

# 9 Declarations [[dcl]](./#dcl)

## 9.6 Function definitions [[dcl.fct.def]](dcl.fct.def#coroutine)

### 9.6.4 Coroutine definitions [dcl.fct.def.coroutine]

[1](#1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7211)

A function is a [*coroutine*](#def:coroutine "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") if its [*function-body*](dcl.fct.def.general#nt:function-body "9.6.1 General [dcl.fct.def.general]") encloses a[*coroutine-return-statement*](stmt.return.coroutine#nt:coroutine-return-statement "8.8.5 The co_­return statement [stmt.return.coroutine]") ([[stmt.return.coroutine]](stmt.return.coroutine "8.8.5 The co_­return statement")),
an [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]") ([[expr.await]](expr.await "7.6.2.4 Await")),
or a [*yield-expression*](expr.yield#nt:yield-expression "7.6.17 Yielding a value [expr.yield]") ([[expr.yield]](expr.yield "7.6.17 Yielding a value"))[.](#1.sentence-1)

The [*parameter-declaration-clause*](dcl.fct#nt:parameter-declaration-clause "9.3.4.6 Functions [dcl.fct]") of the coroutine shall not
terminate with an ellipsis that is not part of
a [*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]")[.](#1.sentence-2)

[2](#2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7220)

[*Example [1](#example-1)*: task<int> f();

task<void> g1() {int i = co_await f();
 std::cout << "f() => " << i << std::endl;}template <typename... Args> task<void> g2(Args&&...) { // OK, ellipsis is a pack expansionint i = co_await f();
 std::cout << "f() => " << i << std::endl;} task<void> g3(int a, ...) { // error: variable parameter list not allowedint i = co_await f();
 std::cout << "f() => " << i << std::endl;} â *end example*]

[3](#3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7243)

The [*promise type*](#def:coroutine,promise_type "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") of a coroutine isstd​::​coroutine_traits<R, P1, …, Pn>​::​promise_type,
whereR is the return type of the function, andP1â¦Pn is the sequence of types of the non-object function parameters,
preceded by the type of the object parameter ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))
if the coroutine is a non-static member function[.](#3.sentence-1)

The promise type shall be a class type[.](#3.sentence-2)

[4](#4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7254)

In the following, pi is an lvalue of type Pi,
wherep1 denotes the object parameter andpi+1 denotes the ith non-object function parameter
for an implicit object member function, andpi denotes
the ith function parameter otherwise[.](#4.sentence-1)

For an implicit object member function,q1 is an lvalue that denotes *this;
any other qi is an lvalue
that denotes the parameter copy corresponding to pi,
as described below[.](#4.sentence-2)

[5](#5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7268)

A coroutine behaves as if
the top-level cv-qualifiers in all[*parameter-declaration*](dcl.fct#nt:parameter-declaration "9.3.4.6 Functions [dcl.fct]")*s* in the declarator
of its [*function-definition*](dcl.fct.def.general#nt:function-definition "9.6.1 General [dcl.fct.def.general]") were removed and
its [*function-body*](dcl.fct.def.general#nt:function-body "9.6.1 General [dcl.fct.def.general]") were replaced by
the following [*replacement body*](#def:body,replacement "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]"):

{  
 *promise-type* *promise* *promise-constructor-arguments* ;  
 try {  
 co_await *promise*.initial_suspend() ;  
 [*function-body*](dcl.fct.def.general#nt:function-body "9.6.1 General [dcl.fct.def.general]")  
 } catch ( ... ) {  
 if (!*initial-await-resume-called*)  
 throw ;  
 *promise*.unhandled_exception() ;  
 }  
*final-suspend* :  
 co_await *promise*.final_suspend() ;  
}

where

- [(5.1)](#5.1)

  the [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]") containing
the call to initial_suspend is the [*initial await expression*](#def:await_expression,initial "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]"), and

- [(5.2)](#5.2)

  the [*await-expression*](expr.await#nt:await-expression "7.6.2.4 Await [expr.await]") containing
the call to final_suspend is the [*final await expression*](#def:await_expression,final "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]"), and

- [(5.3)](#5.3)

  *initial-await-resume-called* is initially false and is set to true immediately before the evaluation
of the *await-resume* expression ([[expr.await]](expr.await "7.6.2.4 Await"))
of the initial await expression, and

- [(5.4)](#5.4)

  *promise-type* denotes the promise type, and

- [(5.5)](#5.5)

  the object denoted by the exposition-only name *promise* is the [*promise object*](#def:promise_object "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") of the coroutine, and

- [(5.6)](#5.6)

  the label denoted by the name *final-suspend* is defined for exposition only ([[stmt.return.coroutine]](stmt.return.coroutine "8.8.5 The co_­return statement")), and

- [(5.7)](#5.7)

  *promise-constructor-arguments* is determined as follows:
overload resolution is performed on a promise constructor call created by
assembling an argument list q1â¦qn[.](#5.7.sentence-1)
  If a viable
constructor is found ([[over.match.viable]](over.match.viable "12.2.3 Viable functions")), then*promise-constructor-arguments* is(q1, …, qn), otherwise*promise-constructor-arguments* is empty, and

- [(5.8)](#5.8)

  a coroutine is suspended at the [*initial suspend point*](#def:suspend_point,initial "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") if
it is suspended at the initial await expression, and

- [(5.9)](#5.9)

  a coroutine is suspended at a [*final suspend point*](#def:suspend_point,final "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") if
it is suspended
  * [(5.9.1)](#5.9.1)

at a final await expression or

  * [(5.9.2)](#5.9.2)

due to an exception exiting from unhandled_exception()[.](#5.9.sentence-1)

[6](#6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7340)

[*Note [1](#note-1)*:

An odr-use of a non-reference parameter
in a postcondition assertion
of a coroutine is ill-formed ([[dcl.contract.func]](dcl.contract.func "9.4.1 General"))[.](#6.sentence-1)

â *end note*]

[7](#7)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7347)

If searches for the names return_void and return_value in the scope of the promise type each find any declarations,
the program is ill-formed[.](#7.sentence-1)

[*Note [2](#note-2)*:

If return_void is found, flowing off
the end of a coroutine is equivalent to a co_return with no operand[.](#7.sentence-2)

Otherwise, flowing off the end of a coroutine
results in undefined behavior ([[stmt.return.coroutine]](stmt.return.coroutine "8.8.5 The co_­return statement"))[.](#7.sentence-3)

â *end note*]

[8](#8)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7358)

The expression *promise*.get_return_object() is used
to initialize
the returned reference or prvalue result object of a call to a coroutine[.](#8.sentence-1)

The call to get_return_object is sequenced before
the call to initial_suspend and is invoked at most once[.](#8.sentence-2)

[9](#9)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7367)

A suspended coroutine can be resumed to continue execution by invoking
a resumption member function ([[coroutine.handle.resumption]](coroutine.handle.resumption "17.13.4.6 Resumption"))
of a coroutine handle ([[coroutine.handle]](coroutine.handle "17.13.4 Class template coroutine_­handle"))
that refers to the coroutine[.](#9.sentence-1)

The evaluation that invoked a resumption member function is
called the [*resumer*](#def:coroutine,resumer "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]")[.](#9.sentence-2)

Invoking a resumption member function for a coroutine
that is not suspended results in undefined behavior[.](#9.sentence-3)

[10](#10)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7377)

An implementation may need to allocate additional storage for a coroutine[.](#10.sentence-1)

This storage is known as the [*coroutine state*](#def:coroutine_state "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]") and is obtained by calling
a non-array allocation function ([[basic.stc.dynamic.allocation]](basic.stc.dynamic.allocation "6.8.6.5.2 Allocation functions"))
as part of the replacement body[.](#10.sentence-2)

The allocation function's name is looked up by searching for it in the scope of the promise type[.](#10.sentence-3)

- [(10.1)](#10.1)

  If the search finds any declarations,
overload resolution is performed on a function call created by assembling an
argument list[.](#10.1.sentence-1)
  The first argument is the amount of space requested, and
is a prvalue of type std​::​size_t[.](#10.1.sentence-2)
  The lvalues p1â¦pn with their original types (including cv-qualifiers)
are the successive arguments[.](#10.1.sentence-3)
  If no viable function is found ([[over.match.viable]](over.match.viable "12.2.3 Viable functions")),
overload resolution is performed again
on a function call created by passing just
the amount of space required as a prvalue of type std​::​size_t[.](#10.1.sentence-4)

- [(10.2)](#10.2)

  If the search finds no declarations, a search is performed in the global scope[.](#10.2.sentence-1)
  Overload resolution is performed on a function call created by
passing the amount of space required as a prvalue of type std​::​size_t[.](#10.2.sentence-2)

[11](#11)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7402)

If a search for the name get_return_object_on_allocation_failure in the scope of the promise type ([[class.member.lookup]](class.member.lookup "6.5.2 Member name lookup")) finds
any declarations, then the result
of a call to an allocation function used to obtain storage for the coroutine
state is assumed to return nullptr if it fails to obtain storage,
and if a global allocation function is selected,
the ​::​operator new(size_t, nothrow_t) form is used[.](#11.sentence-1)

The allocation function used in this case shall have a non-throwing[*noexcept-specifier*](except.spec#nt:noexcept-specifier "14.5 Exception specifications [except.spec]")[.](#11.sentence-2)

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 T​::​get_return_object_on_allocation_failure(), where T is the promise type[.](#11.sentence-3)

[*Example [2](#example-2)*: #include <iostream>#include <coroutine>// ​::​operator new(size_t, nothrow_t) will be used if allocation is neededstruct generator {struct promise_type; using handle = std::coroutine_handle<promise_type>; struct promise_type {int current_value; static auto get_return_object_on_allocation_failure() { return generator{nullptr}; }auto get_return_object() { return generator{handle::from_promise(*this)}; }auto initial_suspend() { return std::suspend_always{}; }auto final_suspend() noexcept { return std::suspend_always{}; }void unhandled_exception() { std::terminate(); }void return_void() {}auto yield_value(int value) { current_value = value; return std::suspend_always{}; }}; bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; }int current_value() { return coro.promise().current_value; } generator(generator const&) = delete;
 generator(generator && rhs) : coro(rhs.coro) { rhs.coro = nullptr; }~generator() { if (coro) coro.destroy(); }private: generator(handle h) : coro(h) {} handle coro;};
generator f() { co_yield 1; co_yield 2; }int main() {auto g = f(); while (g.move_next()) std::cout << g.current_value() << std::endl;} â *end example*]

[12](#12)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7456)

The coroutine state is destroyed when control flows off the end of the
coroutine or the destroy member
function ([[coroutine.handle.resumption]](coroutine.handle.resumption "17.13.4.6 Resumption"))
of a coroutine handle ([[coroutine.handle]](coroutine.handle "17.13.4 Class template coroutine_­handle"))
that refers to the coroutine
is invoked[.](#12.sentence-1)

In the latter case,
control in the coroutine is considered
to be transferred out of the function ([[stmt.dcl]](stmt.dcl "8.10 Declaration statement"))[.](#12.sentence-2)

The storage for the coroutine state is released by calling a
non-array deallocation function ([[basic.stc.dynamic.deallocation]](basic.stc.dynamic.deallocation "6.8.6.5.3 Deallocation functions"))[.](#12.sentence-3)

If destroy is called for a coroutine that is not suspended, the
program has undefined behavior[.](#12.sentence-4)

[13](#13)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7471)

The deallocation function's name is looked up by searching for it in the scope of the promise type[.](#13.sentence-1)

If nothing is found, a search is performed in the
global scope[.](#13.sentence-2)

If both a usual deallocation
function with only a pointer parameter and a usual deallocation function with
both a pointer parameter and a size parameter are found, then the selected deallocation
function shall be the one with two parameters[.](#13.sentence-3)

Otherwise, the selected
deallocation function shall be the function with one parameter[.](#13.sentence-4)

If no usual
deallocation function is found, the program is ill-formed[.](#13.sentence-5)

The selected deallocation function shall be called with the address of the
block of storage to be reclaimed as its first argument[.](#13.sentence-6)

If a deallocation
function with a parameter of type std​::​size_t is used, the size of
the block is passed as the corresponding argument[.](#13.sentence-7)

[14](#14)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7485)

When a coroutine is invoked,
a copy is created for each coroutine parameter
at the beginning of the replacement body[.](#14.sentence-1)

For a parameter
whose original declaration specified the type cv T,

- [(14.1)](#14.1)

if T is a reference type,
the copy is a reference of typecv T bound to the same object as a parameter;

- [(14.2)](#14.2)

otherwise, the copy is a variable
of type cv T with automatic storage duration that is direct-initialized
from an xvalue of type T referring to the parameter[.](#14.sentence-2)

[*Note [3](#note-3)*:

An identifier in the [*function-body*](dcl.fct.def.general#nt:function-body "9.6.1 General [dcl.fct.def.general]") that names one of these parameters
refers to the created copy,
not the original parameter ([[expr.prim.id.unqual]](expr.prim.id.unqual "7.5.5.2 Unqualified names"))[.](#14.sentence-3)

â *end note*]

The initialization and destruction of each parameter copy occurs in the
context of the called coroutine[.](#14.sentence-4)

Initializations of parameter copies are sequenced before the call to the
coroutine promise constructor and indeterminately sequenced with respect to
each other[.](#14.sentence-5)

The lifetime of parameter copies ends immediately after the lifetime of the
coroutine promise object ends[.](#14.sentence-6)

[*Note [4](#note-4)*:

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[.](#14.sentence-7)

â *end note*]

[15](#15)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7523)

If the evaluation of the expression*promise*.unhandled_exception() exits via an exception,
the coroutine is considered suspended at the final suspend point
and the exception propagates to the caller or resumer[.](#15.sentence-1)

[16](#16)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7529)

The expression co_await *promise*.final_suspend() shall not be potentially-throwing ([[except.spec]](except.spec "14.5 Exception specifications"))[.](#16.sentence-1)
