<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<style>
pre {font-family: "Consolas", "Lucida Console", monospace; margin-left:20pt; }
code {font-family: "Consolas", "Lucida Console", monospace; }
pre > i   { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
code > i  { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
pre > em  { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
code > em { font-family: "Consolas", "Lucida Console", monospace;  font-style:italic; }
dl > dt { font-style:italic; }
body { font-family: "Calibri" }

@media (prefers-color-scheme: dark) {
	body { background: #111; color:  #ccc; }
	a { color:  #38f; }
	a:visited { color:  #a4d; }
	.sect { color:  #ccc; }
    del { text-decoration: line-through; color: #EE9999; }
    ins { text-decoration: underline; color: #99EE99; }
    blockquote.std    { color: #ccc; background-color: #2A2A2A;  border: 1px solid #3A3A3A;  padding-left: 0.5em; padding-right: 0.5em; }
    blockquote.stddel { text-decoration: line-through;  color: #ccc; background-color: #221820;  border: 1px solid #332228;  padding-left: 0.5em; padding-right: 0.5em; ; }
    blockquote.stdins { text-decoration: underline;  color: #ccc; background-color: #182220;  border: 1px solid #223328; padding: 0.5em; }
    table { border: 1px solid #ccc; border-spacing: 0px;  margin-left: auto; margin-right: auto; }
}

@media (prefers-color-scheme: light) {
	body { background:  white; color: black; }
    del { text-decoration: line-through; color: #8B0040; }
    ins { text-decoration: underline; color: #005100; }
    blockquote.std    { color: #000000; background-color: #F1F1F1;  border: 1px solid #D1D1D1;  padding-left: 0.5em; padding-right: 0.5em; }
    blockquote.stddel { text-decoration: line-through;  color: #000000; background-color: #FFEBFF;  border: 1px solid #ECD7EC;  padding-left: 0.5em; padding-right: 0.5em; ; }
    blockquote.stdins { text-decoration: underline;  color: #000000; background-color: #C8FFC8;  border: 1px solid #B3EBB3; padding: 0.5em; }
    table { border: 1px solid black; border-spacing: 1px;  margin-left: auto; margin-right: auto; }
}


.comment em { font-family: "Calibri"; font-style:italic; }
p.example   { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }
div.poll { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract  { margin-left: 2em; background-color: #F5F6A2;  border: 1px solid #E1E28E; }

p.function    { }
.attribute    { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;  padding-right: 1ex; }
.attribute dd { margin-left: 0em; }

.editor { color: #4444BB; font-style: normal; background-color: #DDDDDD; }

tab { padding-left: 4em; }
tab3 { padding-left: 3em; }

.link { float: right; font-family: "Consolas", "Lucida Console", monospace; font-size:80% }


table.header { border: none; border-spacing: 0;  margin-left: 0px; font-style: normal; }
td.header { border: none; border-spacing: 0;  margin-left: 0px; font-style: normal; }
.header { border: none; border-spacing: 0;  margin-left: 0px; font-style: normal; }
table.poll { border: 1px solid black; border-spacing: 0px;  margin-left: 0px; font-style: normal; }

th { text-align: left; vertical-align: top;  padding-left: 0.4em;  /*padding-right: 0.4em; border-bottom:1px dashed;*/ }
td { text-align: left;  padding-left: 0.4em; padding-right: 0.4em; /*border-right:1px dashed; */}
tr { border: solid; border-width: 1px 0; border-bottom:1px solid blue }


.revision   { /*color: #005599;*/ }
.grammar { list-style-type:none }

</style>

<title>Contracts and coroutines</title>

</head>
<body>  

<table class="header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;</th><th> </th><td class="header">P2957R2</td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;</th><th> </th><td class="header">2024-10-14</td>
  </tr>
  <tr>
    <th>Audience:&nbsp;&nbsp;</th><th> </th><td class="header">SG21</td>
  </tr>
  <tr>
    <th>Reply-to:&nbsp;&nbsp;</th><th> </th><td class="header">
        <address>Andrzej Krzemie&#324;ski &lt;akrzemi1 at gmail dot com&gt;</address>
        <address>Iain Sandoe &lt;iain at sandoe dot co dot uk&gt;</address>
        <address>Joshua Berne &lt;jberne4 at bloomberg dot net&gt;</address>
        <address>Timur Doumler &lt;papers at timur dot audio&gt;</address>
    </td>
  </tr>
</tbody></table>



<h1>Contracts and coroutines</h1>


<p> This paper proposes how preconditions and postconditions should interact with
    coroutines. </p>

<p> Coroutines generalise regular functions in a specific manner: control can
    return to the caller even though the function body has not finished executing.
    This gives rise to some doubts as to whether the semantics of postconditions,
    as defined for regular functions, still apply. 
    This paper solves this problem, and therewith addresses one of the concerns of a major
    tool-chain vendor expressed in 
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3173r0.pdf"
       title="Gabriel Dos Reis, &ldquo;P2900R6 May Be Minimal, but It Is Not Viable&rdquo;"
       >[P3173R0]</a>.
    </p>



<h2><a class="sect" id="0">0.</a> Revision History</h2>


<h3><a class="sect" id="0.1">0.1.</a> R0 → R1</h3>

<ul>
    <li>Now proposing that it is unspecified whether preconditions see the function
        parameters before the copying of parameters or the copies of the parameters.</li>
    <li>No longer proposing postconditions on coroutines.</li>
</ul>

<h3><a class="sect" id="0.2">0.2.</a> R1 → R2</h3>

<ul>
    <li>Now requiring that preconditions see the function parameters
        before they are copied to the coroutine frame.</li>
    <li>Now proposing that postconditions on coroutines be allowed, 
        but make it ill-formed when they use non-reference function parameters.</li>
    <li>We now have a reference implementation in GCC.</li>
    <li>Added the proposed wording.</li>
    <li>Reformulated the entire paper in order to highlight the definition of a 
        <em>ramp function</em> and its implications.</li>
    <li>Demonstrated how <em>parameter captures</em> can enable referring 
        to coroutine parameters in postconditions in the future.</li>       
</ul>



<h2><a class="sect" id="1">1.</a> Executive summary</h2>


<p> The key observation is that, in current C++, one cannot tell from a function
    declaration, or call, whether the callee is a coroutine or a 'regular' function.
    </p>

<p> We reformulate the definition of a postcondition so that
    it does not refer to the function body.</p>

<p> We derive the properties for pre- and postconditions on coroutines:</p>

<ul>
    <li> they should be allowed on declarations of functions that are later defined
         as coroutines,</li>
    <li> the program state they describe and the point of their evaluation relate to
         the call site,</li>
    <li> postconditions should not relate to the state of the coroutine or the time
         when it finishes.</li>
</ul>    



<h2><a class="sect" id="2">2.</a> Motivation</h2>


<p> Because the start of a coroutine is conceptually no different than the start of a 
    normal function, also the motivation for expressing a precondition is the same as for
    normal functions:</p>

<pre>
generator&lt;int&gt; sequence(int from, int to)
  pre (from &lt;= to);
  </pre>

<p> But when we return to the caller, the situation is different. The caller doesn't get
    the ultimate result of the operation. Instead, it gets a <em>tool</em> (a generator,
    a callback, an awaitable) for <em>advancing</em> the state of the
    of the suspended operation at a later time.</p>

<p> Thus, there are fewer things to express in the postcondition, less need to access 
    function parameters (as they are often used to match against the returned value),
    no option to inspect the ultimate result. The only practical thing is to inspect the 
    state of the said tool:</p>    

<pre>
awaitable&lt;int&gt; cancelable_session(int id) 
  post (r: is_cancelable(r));
  
void caller()
{
  awaitable&lt;int&gt; s = cancelable_session(1);
  contract_assert (is_cancelable(s));
  global_cancelable_sessions.push(std::move(s));
}
</pre>




<h2><a class="sect" id="3">3.</a> Coroutine properties</h2>


<h3><a class="sect" id="3.1">3.1.</a> The ramp function</h3>


<p> The C++ Standard does not clearly define the <em>ramp function</em>; however,
    this notion is crucial for implementing C++ coroutines in a compiler, for 
    understanding coroutines as a user, and for us to design the semantics of 
    postconditions. </p>

<p> When the compiler encounters a coroutine definition — that is, a function body with
    one of the coroutine keywords — it generates two things:</p>
    
<ol>
    <li>The <em>coroutine state (frame)</em>, possibly heap-allocated, storing the copies 
        of function parameters, and tracking the the progress of the function body.</li>
    <li>The <em>ramp function</em>.</li>
</ol>   
   
<p> The ramp function has the following properties:</p>   

<ul>
    <li>It is a normal (non-coroutine) function.</li>
    <li>It prepares the coroutine state.</li>
    <li>It executes the part of the coroutine body, until the first suspension  
        (or till the end, if no suspension is requested).</li>
    <li>It returns the <em>return object</em> obtained from the coroutine promise object.
        </li> 
    <li>You cannot see its body: it is compiler-generated, based on coroutine
        customization points.</li>
    <li>This is the function that the caller actually calls.</li>
</ul>

<p> The crucial property here is that it is a normal function. Hence, whatever 
    <a href="https://isocpp.org/files/papers/P2900R9.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński et al., &ldquo;Contracts for C++&rdquo;">[P2900R9]</a>
    has to say about pre- and postconditions for normal functions, can also be applied
    to the ramp function.    
    </p>   
   

<h3><a class="sect" id="3.2">3.2.</a> The normal function interface</h3>

<p> There is no hint in a function declaration, whether it is a coroutine or not.
    When you invoke a coroutine, you are invoking a (normal) ramp function. Hence,
    the caller has no way of telling if there is a coroutine involved in the call:
    </p>

<pre>
awaitable&lt;int&gt; session(int id);   <em>// may be a coroutine, may be a function</em>

awaitable&lt;int&gt; default_session()  <em>// definitely a normal function</em>
{
  awaitable&lt;int&gt; s = session(0);  <em>// maybe invoking a coroutine, maybe a function</em>
  return s;
}
</pre>

<p> Even though a function is returning a type that may be indicative of a coroutine 
    implementation — an <em>Awaitable</em> or a <em>generator</em> — these are just types,
    and they can be as well returned by normal functions, such as factories, or forwarding
    functions.
    </p>
  


<h3><a class="sect" id="3">3.3.</a>  Copies of function parameters </h3>


<p> A notable thing, performed by the ramp function, is to <em>copy</em>  
    the function parameters into the coroutine frame
    <a href="http://eel.is/c++draft/dcl.fct.def.coroutine#13">[dcl.fct.def.coroutine]/13</a>:</p> 
    
<blockquote>For a parameter of type <em>cv</em> <code>T</code>, 
    the copy is a variable of type <em>cv</em> <code>T</code> 
    with automatic storage duration that is direct-initialized 
    from an xvalue of type <code>T</code> referring to the parameter.
    </blockquote>
    
<p> Thus defined initialization can end up in performing a <em>move</em>, even if a
    function parameter is declared <code>const</code> by the user. 
    This means that effectively the ramp function behaves as if its function parameters 
    had their <code>const</code> qualification removed from the defining declaration.
    </p>
    



<h2><a class="sect" id="4">4.</a> Redefining postconditions</h2>


<p> Before the addition of coroutines (and fibers), code in a single thread is 
    non-interleaved: a started operation has to finish before the next one can start.
    Therefore, usually the definitions of pre- and postconditions
    make a silent assumption that we are describing a non-interleaved flow.
    In this view, the evaluation of the
    postcondition happens: </p>    
    
<ol>
    <li>After the function body has finished (local automatic objects have been 
        destroyed).</li>
    <li>After the control is returned to the caller (the result object has been
        initialized).</li>
</ol>

<p>In fact, for normal functions these two are the same thing.</p>

<p> In case of coroutines, the above two are potentially different points in time,
    and the "non-interleaving" definition of a postcondition cannot be maintained.
    </p> 

<p> We observe that the first property above bears no relation to the caller, and a 
    postcondition, as part of a function contract, is about describing the relation
    between the caller and the callee. Therefore we argue that the first property can
    be dropped without compromising the goal of a postcondition.
    </p>

<p> We propose the following conceptual model. Any remaining part of the coroutine body,
    after the ramp function returns to the caller, can be treated as a callback 
    <em>C</em> returned to the caller. The caller may call <em>C</em> later or never, but
    is not directly affected by the results of calling <em>C</em>.</p>

<p> An equivalent formulation of our model is that pre- and postconditions should behave
    as if we wrapped the call to a coroutine function into a factory function <em>F</em>,
    declared the same contract in <em>F</em>, and called it instead.
    </p>



<h3><a class="sect" id="4.1">4.1.</a> Postconditions and function bodies</h3>



<p> One effect of the proposed model is that the function body bares no connection
    to the predicate expressed in the postcondition:</p>
    
<pre>
awaitable&lt;int&gt; cancelable_session(int id) 
  post (r: is_cancelable(r))
{
  int ans = co_await communicate(id);
  co_return ans;
}
</pre>

<p> In the above example there is nothing in the function body that would indicate
    that the returned <code>r</code> is made "cancelable". 
    </p>

<p> Occasionally, the function body might give a false impression that it relates to the 
    postcondition assertion:
    </p>

<pre>
task&lt;int&gt; fun(int&amp; obj)
  <em>// postcondition: obj &gt;= 0</em>
{
  <em>// ...</em>
  obj = 1; <em>// evaluated long after the postcondition</em>
  co_return;
}
</pre>

<p> This is behavior is <em>not</em> a consequence of this proposal, but of the coroutine 
    mechanics. Note that the notion of a "postcondition", even though not expressible as
    a language feature in the present C++, does exist. Authors of coroutines must already
    take this effect into account.
    </p>    
    
    
    
<h2><a class="sect" id="5">5.</a> Inspecting coroutine parameters</h2>



<p> The only technical challenge is about inspecting the function parameters in pre-
    and postcondition assertions, given that these parameters are potentially moved to the
    coroutine frame. This problem applies only to non-reference parameters. 
    </p>

<p> Preconditions must be evaluated before this move. This is because function parameters
    may be used in the call to the allocation function that provides the storage for the
    coroutine frame. This may cause a situation surprising to the programmers: a
    precondition assertion sees different 
    objects than the coroutine body. As a result, the same predicate can give different
    results in the two places, when the address of the object is inspected, or when the
    copy/move constructor of the class creates objects in a state that is different than 
    the state of the source object.
    </p>

<p> However, we note that this surprising behavior predates contracts and is inherent to
    the coroutine design in C++. Even in C++23 programmers may be surprised that the 
    parameters the coroutine body sees are not the ones that they passed as arguments.
    </p>
    
<p> The challenge for the postconditions is that at the point they are evaluated,
    the copying of the parameters had already occurred and the parameters are potentially
    in a moved-from state: definitely not the state that the caller intends to inspect.
    </p>
    
<p> We propose to make it ill-formed when a coroutine function has a postcondition 
    that odr-uses a non-reference parameter.
    This decision is a direct consequence of two other decisions already made:</p>

<ol>
    <li><a href="https://isocpp.org/files/papers/P2900R9.pdf"
           title="Joshua Berne, Timur Doumler, Andrzej Krzemieński et al., &ldquo;Contracts for C++&rdquo;"
        >[P2900R9]</a>
        makes the program ill-formed when a postcondition (in a normal function)
        references a non-<code>const</code>, non-reference function parameter.
        </li>
    <li>The present specification of coroutines allows the implementations to move from
        <code>const</code> function parameters, effectively behaving as if the top-level
        cv-qualifications were removed from the parameters.
        </li>
</ol>

<p> The rationale for requiring <code>const</code> for non-reference function parameters
    (for normal functions) has been provided in 
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2466r0.html"
       title="Andrzej Krzemieński, &ldquo;The notes on contract annotations&rdquo;"
    >[P2466R0]</a>. Alternative approaches were considered and rejected as
    worse or unimplementable. They are discussed in 
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2466r0.html"
       title="Andrzej Krzemieński, &ldquo;The notes on contract annotations&rdquo;"
    >[P2466R0]</a>
    and, in the context of coroutines, in
    <a href="https://isocpp.org/files/papers/P3387R0.pdf"
       title="Timur Doumler, Peter Bindels, Joshua Berne, &ldquo;Contract assertions on coroutines&rdquo;">[P3387R0]</a>.
    We only list them here:</p>
    
<ol>
<li>Allow the mutation of parameters, resulting in postconditions observing unintended 
    object state. 
    <ul><li>That would prefer run-time surprises to compile-time surprises.</li></ul>
    </li>
<li>Making silent additional copies of referenced parameters.
    <ul><li>That would only partially solve the problems for some types, while
        still causing run-time surprises.</li></ul>   
    </li>  
<li>Simply disallowing any postcondition whatsoever.
    <ul><li>This seems unnecessarily harsh, given that often we only want
    to inspect the returned object.</li></ul> 
    </li> 
<li>Allow the postconditions to refer to objects, as long as their move constructor is
    trivial or not defined. 
    <ul><li>This would introduce the "spooky action at a distance" effect, where one 
    person changes their class <code>X</code> and unknowingly makes somebody else's
    code fail to compile.</li></ul>
    </li>    
<li>Have the postconditions refer to the copies of function parameters residing in the 
    coroutine frame.
    <ul>
        <li>This is the only one specific to coroutines.</li>
        <li>It is unimplementable in the current coroutine model, where user-defined 
            promise types can choose that the coroutine is scheduled to be finished 
            asynchronously (including the destruction of the coroutine frame) 
            from another thread, before it initially suspends, without any sequencing 
            related to returning from the ramp function. </li>
    </ul>
    </li>
</ol>
    
<p> <a href="https://isocpp.org/files/papers/P3387R0.pdf"
       title="Timur Doumler, Peter Bindels, Joshua Berne, &ldquo;Contract assertions on coroutines&rdquo;">[P3387R0]</a>
    compares trade-offs for all these options, and ultimately reaches
    the same conclusion.
    </p>
  

<p> As a consequence, while for normal functions the programmer can enable a 
    postcondition to odr-use a non-reference parameter via adding the <code>const</code>
    qualification to that 
    parameter in all declarations, this will be impossible for coroutines.
    We expect that the compiler error that the user will see will appear only when the 
    function body is encountered. Parsing the non-defining declarations should compile,
    as at this point the compiler doesn't yet know if it deals with the coroutine or not.
    </p>  

<pre>
generator&lt;int&gt; sequence(const int limit)
  post (g : g.size() == limit);           <em>// OK</em>
  
generator&lt;int&gt; sequence(const int limit)  <em>// ok to skip post-</em>
{
  for (int i = limit; i-- != 0;)
    co_yield i;                           <em>// Error: a coroutine</em>
}
</pre>

<p> Note that this is similar to the case where the definition of a normal function does
    not specify the parameter odr-used in the postcondition as const.</p>

<pre>
generator&lt;int&gt; sequence(const int limit)
  post (g : g.size() == limit);           <em>// OK</em>
  
generator&lt;int&gt; sequence(int limit)        <em>// Error: non-const param</em>
{
  return sequence_impl(limit);
}
</pre>


<h3><a class="sect" id="5.1">5.1</a>  Future directions </h3>



<p> <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2461r1.pdf"
       title="Gašper Ažman, Caleb Sunstrum, Bronek Kozicki, &ldquo;Closure-Based Syntax for Contracts&rdquo;">[P2461R1]</a>
    proposes a future addition to postcondition assertions that would allow the user
    to capture (copy) function parameters upon the function entry, so that these
    copies are available when evaluating the postcondition expression upon
    function return. Referring to such captures is safe, and the copying would
    be explicit. This would enable the postconditions to refer to coroutine
    parameters:</p>

<pre>
generator&lt;int&gt; sequence(int from, int to)
  pre (from &lt;= to)
  post[from, to] (g : g.size() == to - from + 1);
  </pre>

   


<h2><a class="sect" id="6">6.</a>  Coroutine-specific guarantees </h2>


<p>
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2932r3.pdf"
       title="Joshua Berne, &ldquo;A Principled Approach to Open Design Questions for Contracts&rdquo;"
       >[P2932R3]</a>
    argues against integrating pre- and postconditions with coroutines too early:
    </p>


<blockquote>
    <p> Currently, no concrete proposal covers the full breadth of the interface a 
        coroutine has with its callers. Without this complete picture, we cannot yet know
        if <code>pre</code> and <code>post</code> will have a meaning that is correct and 
        useful to those calling into or implementing coroutines.
        </p>
</blockquote>


<p> In the light of a clearer description of a coroutine call as a call to the ramp 
    function, we are confident that the model for pre- and postconditions we described
    is the only one possible.
    </p>

<p> While it is true that one could invent different kinds of correctness checks — like
    constraints on what the returned awaitable yields upon <code>co_await</code>, or
    testing the coroutine state at different time points — this problem is no 
    different from checking the state of regular functions at different points of 
    execution or checking the behavior of callbacks returned from regular
    functions. Yet, SG21 did not decide to hold off contracts on regular functions
    only because there is not a complete picture for regular functions. Any additional
    correctness checks, if needed, can be added on top of what we propose.
    </p>




<h2><a class="sect" id="7">7.</a> Proposal</h2>


<p> We propose that preconditions on coroutines be allowed. Their evaluation is
    sequenced after the function parameters are initialized, and before
<ul>
  <li> the potential allocation of a coroutine frame 
       <a href="http://eel.is/c++draft/dcl.fct.def.coroutine#9">[dcl.fct.def.coroutine]/9</a>,</li>
  <li> the initialization of the coroutine promise object
       <a href="http://eel.is/c++draft/dcl.fct.def.coroutine#5.7">[dcl.fct.def.coroutine]/5.7</a>.</li>
</ul>

<p> Parameter names referenced in the precondition predicate
    refer to the original parameters before the move to the coroutine frame.</p>

<p> We propose that postconditions on coroutines be allowed, and have the
    following properties.</p>

<ul>
    <li>The program is ill-formed when a coroutine postcondition odr-uses a
        non-reference function parameter.</li>
    <li>Postcondition evaluation is sequenced after the value, if any, has been
         returned from the ramp function to the caller, and before the function
         parameters (which are moved-from at that time) have been destroyed. </li>
    <li>The postcondition evaluation is unsequenced with respect to the termination
         of the evaluation of the coroutine body and the destruction of its
         automatic variables.</li>
</ul>


<h2><a class="sect" id="8">8.</a> Wording</h2>

    
<p> The proposed wording is relative to 
    <a href="https://isocpp.org/files/papers/P2900R9.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński et al., &ldquo;Contracts for C++&rdquo;">[P2900R9]</a>.
    It is equivalent to the wording provided in 
    <a href="https://isocpp.org/files/papers/P3387R0.pdf"
       title="Timur Doumler, Peter Bindels, Joshua Berne, &ldquo;Contract assertions on coroutines&rdquo;">[P3387R0]</a>
    and 
    <a href="https://isocpp.org/files/papers/P2900R10.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński et al., &ldquo;Contracts for C++&rdquo;">[P2900R10]</a>.
    </p>

<p> Modify [dcl.contract.func] (a section from <a href="https://isocpp.org/files/papers/P2900R9.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński et al., &ldquo;Contracts for C++&rdquo;">[P2900R9]</a>,
    paragraph 6 as follows.
    </p>

<blockquote class="std">

<p> A <del>coroutine 
    (<a href="https://eel.is/c++draft/dcl.fct.def.coroutine">[dcl.fct.def.coroutine]</a>),
    a </del>deleted function 
    (<a href="https://eel.is/c++draft/dcl.fct.def.delete">[dcl.fct.def.delete]</a>)<del>,</del>
    or a function
    defaulted on its first declaration 
    (<a href="https://eel.is/c++draft/dcl.fct.def.default">[dcl.fct.def.default]</a>) 
    may not have a <em>function-contract-specifier-seq</em>.</p>

</blockquote>

<p> Modify 
    <a href="https://eel.is/c++draft/dcl.fct.def.coroutine">[dcl.fct.def.coroutine]</a>,
    paragraph 5 as follows.
    </p>

<blockquote class="std">

<p> A coroutine behaves as if <ins>the top-level <em>cv</em>-qualifiers in all 
    <em>parameter-declaration</em>s in the
    declarator of its <em>function-definition</em> were removed, and </ins>its 
    <em>function-body</em> were replaced by the
    following <em>replacement body</em>:</p>

<pre>
{
  <em>promise-type</em> <em>promise</em> <em>promise-constructor-arguments</em>;
  try {
    co_await <em>promise</em>.initial_suspend();
    <em>function-body</em>
  } catch ( ... ) {
    if (!<em>initial-await-resume-called</em>)
      throw ;
    <em>promise</em>.unhandled_exception();
  }
<em>final-suspend</em>:
  co_await <em>promise</em>.final_suspend();
}
</pre>

</blockquote>
    
<p> Drafting note: the goal is to highlight that the function non-reference parameters 
    are modified (moved from) even if they are declared <code>const</code>. This, however,
    requires to explicitly say later that <em>cv</em>-qualifiers are nonetheless respected
    in some places.
    </p>

<p> Modify Modify 
    <a href="https://eel.is/c++draft/dcl.fct.def.coroutine">[dcl.fct.def.coroutine]</a>,
    paragraph 9 as follows.</p>
    
<blockquote class="std">

<p> An implementation may need to allocate additional storage for a coroutine. This 
    storage is known as the <em>coroutine state</em> and is obtained by calling a 
    non-array allocation function
    (<a href="https://eel.is/c++draft/basic.stc.dynamic.allocation"
       >[basic.stc.dynamic.allocation]</a>)<ins> as part of the replacement body</ins>.
       The allocation function&apos;s name is looked up by searching for it in the scope of the promise type.
</p>
<ul><li> If the search finds any declarations, overload resolution is performed on a 
    function call created by assembling an argument list. The first argument is the amount
    of space requested, and is a prvalue of type <code>std::size_t</code>. The lvalues
    <code>p</code><sub>1</sub> . . . <code>p</code><sub>n</sub>
    <ins>with their original <em>cv</em>-qualifiers </ins>are the successive arguments. If no viable
    function is found
    (<a href="https://eel.is/c++draft/over.match.viable">[over.match.viable]</a>),
    overload resolution is performed again on a function call created
    by passing just the amount of space required as a prvalue of type
    <code>std::size_t</code>.
</li></ul>

</blockquote>


<p> Modify 
    <a href="https://eel.is/c++draft/dcl.fct.def.coroutine">[dcl.fct.def.coroutine]</a>,
    paragraph 13 as follows.</p>

<blockquote class="std">

<p> When a coroutine is invoked, <del>after initializing its parameters 
    (<a href="https://eel.is/c++draft/expr.call">[expr.call]</a>)</del>
    <ins>at the beginning of the replacement body</ins>,
    a copy is created for each coroutine parameter. For a parameter 
    <ins>whose original declaration was </ins>of type 
    <em>cv</em> <code>T</code><ins>:</ins></p>
<ul>
    <ins><li>If <code>T</code> is a reference type, the copy is a reference of type 
    <em>cv</em> <code>T</code> bound to the same object as the parameter,</li></ins>
    
    <li><ins>Otherwise</ins>, the copy is a variable of type <em>cv</em> <code>T</code> 
    with automatic storage duration that is direct-initialized from an xvalue of type 
    <code>T</code> referring to the parameter. <ins>[<em>Note:</em> An identifier
    in the <em>function-body</em> that
    names one of these parameters refers to the created copy and not the original 
    parameter 
    (<a href="https://eel.is/c++draft/expr.prim.id.unqual">[expr.prim.id.unqual]</a>) 
    <em>— end note</em>]</ins>
    </li>
</ul>

<p> <del>[<em>Note:</em> An original parameter object is never a const or volatile object 
    (<a href="https://eel.is/c++draft/basic.type.qualifier">[basic.type.qualifier]</a>).
    <em>— end note</em>]</del>
    </p>

</blockquote>

    
<p> Modify <a href="https://eel.is/c++draft/intro.execution">[intro.execution]</a>,
    paragraph 11 as follows.
    </p>
 
<blockquote class="std"> 

<p> When invoking a function <code>f</code> (whether or not the function is inline), every
    argument expression and the postfix expression designating <code>f</code> are 
    sequenced before every precondition assertion of <del>f</del><ins>the function call 
    (<a href="https://eel.is/c++draft/expr.call">[expr.call]</a>)</ins>, which in turn are
    sequenced before every expression or statement in the body of <code>f</code><ins>, 
    which in turn are sequenced before every postcondition assertion of the function 
    call</ins>. Several contexts in C++ cause evaluation of a function call, even though
    no corresponding function call syntax appears in the translation unit.
    </p>
   
</blockquote>  

<p> Insert the following new paragraph after 
    <a href="https://eel.is/c++draft/expr.call">[expr.call]</a>, paragraph 8.
    </p>

<blockquote class="stdins">   
<p> When control is transferred back to this function call 
    (<a href="https://eel.is/c++draft/stmt.return">[stmt.return]</a>, 
     <a href="https://eel.is/c++draft/expr.await">[expr.await]</a>), all postcondition
    assertions of the function call are evaluated in sequence ([dcl.contract.func]). 
    [<em>Note:</em> This in turn is sequenced before the destruction of any function 
    parameters. <em>— end note</em>]
    </p>
    
</blockquote>


<p> Drafting note: this captures the return form a normal function call, as well as
    the "return from the ramp-function", and the end of the evaluation of the 
    <em>await-expression</em>.
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4988.pdf"
       title="Thomas Köppe, &ldquo;Working Draft Programming Languages — C++&rdquo;">[N4988]</a>
    has the return from a coroutine call underspecified; this wording doesn't try to fix this.       
    </p>
    

<p> Modify the paragraph inserted by 
    <a href="https://isocpp.org/files/papers/P2900R9.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński et al., &ldquo;Contracts for C++&rdquo;">[P2900R9]</a>
    after <a href="https://eel.is/c++draft/stmt.return">[stmt.return]</a>, paragraph 3,
    as follows.</p>

<blockquote class="std">  

<p> <del>All postcondition assertions ([dcl.contract.func]) of the function call 
    (<a href="https://eel.is/c++draft/expr.call">[expr.call]</a>) are evaluated
    in sequence. The destruction of all local variables within the function body is 
    sequenced before the evaluation of any postcondition assertions.</del>
    
    [<em>Note:</em> Postcondition assertions<ins> of the function call 
    (<a href="https://eel.is/c++draft/expr.call">[expr.call]</a>)</ins>
    are<ins> evaluated in sequence after the destruction of any local variables
    in scopes exited by the return statement, and are</ins>, in turn, sequenced before
    the destruction of function parameters. <em>— end note</em>]
    </p>

</blockquote>

<p> Drafting note: this note excludes the case when the control is returned via 
    suspending a coroutine.
    </p>
    
    

<h2><a class="sect" id="9">9.</a> Implementability</h2>



<p> Currently the only compiler to implement contracts and coroutines is GCC. 
    It implements the <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html"
       title="G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers, B. Stroustrup, &ldquo;Support for contract based programming in C++&rdquo;">[P0542R5]</a>
    version of contracts.
    </p>

<p> The implementation in trunk implements <code>[[assert: _]]</code>
    and <code>[[pre: _]]</code> as proposed in this paper.
    Here is a working example in Compiler Explorer:
    <a href="https://godbolt.org/z/x5bTW5W6o">https://godbolt.org/z/x5bTW5W6o</a>.
    </p>

<p> The implementation of <code>[[post: _]]</code> differs from the proposed
    semantics in one aspect: postconditions are allowed to odr-use non-reference
    function parameters, which results in the assertion expressions observing
    the moved-from state of the parameters. There are no difficulties foreseen with adding
    the additional required check.    
    </p>
    
<p> The GCC implementation uses the ramp function implementation. Adding contracts on
    a coroutine is implemented via adding contracts to the ramp, which is no different
    than on any other normal function.
    Currently, the GCC implementation puts the runtime checks for pre- and post-conditions
    inside the function.  This reflects that the current GCC implementation
    for contracts is callee-only.  On-going work to prototype virtual function
    handling is thought to be adaptable to general caller-side contracts and to
    be compatible with coroutines without any special action.
    </p>


<h2><a class="sect" id="10">10.</a> Acknowledgments</h2>


<p> Lewis Baker, Tom Honermann and Lisa Lippincott 
    offered useful
    feedback and improved the quality of the paper.</p>


<h2><a class="sect" id="11">11.</a> References</h2>


<ul>
<li>[P0542R5] — G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers, B. Stroustrup,
    "Support for contract based programming in C++", <br>
    (<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html">"https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html"</a>).
    </li>
    <!--
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html"
       title="G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers, B. Stroustrup, &ldquo;Support for contract based programming in C++&rdquo;">[P0542R5]</a>
    -->

<li>[P2461R1] — Gašper Ažman, Caleb Sunstrum, Bronek Kozicki, "Closure-Based Syntax for Contracts" <br>
    (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2461r1.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2461r1.pdf</a>).
    </li>
    <!--
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2461r1.pdf"
       title="Gašper Ažman, Caleb Sunstrum, Bronek Kozicki, &ldquo;Closure-Based Syntax for Contracts&rdquo;">[P2461R1]</a>
    -->	
    
<li>[P2466R0] — Andrzej Krzemieński, "The notes on contract annotations" <br>
    (<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2466r0.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2466r0.html</a>).
    </li>
    <!--
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2466r0.html"
       title="Andrzej Krzemieński, &ldquo;The notes on contract annotations&rdquo;">[P2466R0]</a>
    -->	
      
<li>[P2900R9] — Joshua Berne, Timur Doumler, Andrzej Krzemieński et al.,
    "Contracts for C++", <br>
    (<a href="https://isocpp.org/files/papers/P2900R9.pdf">"https://isocpp.org/files/papers/P2900R9.pdf"</a>).
    </li>
    <!--
    <a href="https://isocpp.org/files/papers/P2900R9.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński et al., &ldquo;Contracts for C++&rdquo;">[P2900R9]</a>
    -->
    
<li>[P2900R10] — Joshua Berne, Timur Doumler, Andrzej Krzemieński et al.,
    "Contracts for C++", <br>
    (<a href="https://isocpp.org/files/papers/P2900R10.pdf">"https://isocpp.org/files/papers/P2900R10.pdf"</a>).
    </li>
    <!--
    <a href="https://isocpp.org/files/papers/P2900R10.pdf"
       title="Joshua Berne, Timur Doumler, Andrzej Krzemieński et al., &ldquo;Contracts for C++&rdquo;">[P2900R10]</a>
    -->
    
<li>[P2932R3] — Joshua Berne, "A Principled Approach to Open Design Questions for Contracts" <br>
    (<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2932r3.pdf">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2932r3.pdf</a>).
    </li>
    <!--
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2932r3.pdf"
       title="Joshua Berne, &ldquo;A Principled Approach to Open Design Questions for Contracts&rdquo;">[P2932R3]</a>
    -->	
    
<li>[P3173R0] — Gabriel Dos Reis, "P2900R6 May Be Minimal, but It Is Not Viable" <br>
    (<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3173r0.pdf">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3173r0.pdf</a>).
    </li>
    <!--
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3173r0.pdf"
       title="Gabriel Dos Reis, &ldquo;P2900R6 May Be Minimal, but It Is Not Viable&rdquo;">[P3173R0]</a>
    -->
    
<li>[N4988] — Thomas Köppe, "Working Draft Programming Languages — C++" <br>
    (<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4988.pdf">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4988.pdf</a>).
    </li>
    <!--
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n4988.pdf"
       title="Thomas Köppe, &ldquo;Working Draft Programming Languages — C++&rdquo;">[N4988]</a>
    -->	 
    
<li>[P3387R0] — Timur Doumler, Peter Bindels, Joshua Berne, "Contract assertions on coroutines" <br>
    (<a href="https://isocpp.org/files/papers/P3387R0.pdf">https://isocpp.org/files/papers/P3387R0.pdf</a>).
    </li>
    <!-- 
    <a href="https://isocpp.org/files/papers/P3387R0.pdf"
       title="Timur Doumler, Peter Bindels, Joshua Berne, &ldquo;Contract assertions on coroutines&rdquo;">[P3387R0]</a>
    -->

</ul>



</body></html>
