<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2021-10-25" />
  <title>Allow programmer to control and detect coroutine elision by static constexpr bool must\_elide() and coroutine\_handle::elided()</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span. { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 100%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 100%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 100%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: normal;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: normal; line-height: 0; }
.footnote {
font-size: normal;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Allow programmer to control and detect coroutine elision by static constexpr bool must_elide() and coroutine_handle::elided()</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2477R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2021-10-25</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      Evolution Working Group, Library Evolution Working Group<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Chuanqi Xu<br>&lt;<a href="mailto:chuanqi.xcq@alibaba-inc.com" class="email">chuanqi.xcq@alibaba-inc.com</a>&gt;<br>
    </td>
  </tr>
</table>

</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#abstract"><span class="toc-section-number">1</span> Abstract<span></span></a></li>
<li><a href="#change-log"><span class="toc-section-number">2</span> Change Log<span></span></a></li>
<li><a href="#background-and-motivation"><span class="toc-section-number">3</span> Background and Motivation<span></span></a></li>
<li><a href="#terminology"><span class="toc-section-number">4</span> Terminology<span></span></a>
<ul>
<li><a href="#halo-and-coroutine-elision"><span class="toc-section-number">4.1</span> HALO and Coroutine elision<span></span></a></li>
<li><a href="#constexpr-time-and-compile-time"><span class="toc-section-number">4.2</span> constexpr time and compile time<span></span></a></li>
<li><a href="#coroutine-status-and-corotuine-frame"><span class="toc-section-number">4.3</span> Coroutine status and Corotuine frame<span></span></a></li>
<li><a href="#ramp-function"><span class="toc-section-number">4.4</span> Ramp function<span></span></a></li>
</ul></li>
<li><a href="#the-storage-lifetime-of-elided-coroutine-frame"><span class="toc-section-number">5</span> The storage lifetime of elided coroutine frame<span></span></a></li>
<li><a href="#design"><span class="toc-section-number">6</span> Design<span></span></a>
<ul>
<li><a href="#must_elide"><span class="toc-section-number">6.1</span> must_elide<span></span></a>
<ul>
<li><a href="#necessity"><span class="toc-section-number">6.1.1</span> Necessity<span></span></a></li>
<li><a href="#risks"><span class="toc-section-number">6.1.2</span> Risks<span></span></a></li>
<li><a href="#design-ideas"><span class="toc-section-number">6.1.3</span> Design Ideas<span></span></a></li>
<li><a href="#why-in-promise_type"><span class="toc-section-number">6.1.4</span> Why in promise_type?<span></span></a></li>
</ul></li>
<li><a href="#elided"><span class="toc-section-number">6.2</span> elided<span></span></a>
<ul>
<li><a href="#support-both"><span class="toc-section-number">6.2.1</span> Support both<span></span></a></li>
<li><a href="#suppot-coroutine_handlepromisetypeelided-only"><span class="toc-section-number">6.2.2</span> Suppot coroutine_handle&lt;PromiseType&gt;::elided() only<span></span></a></li>
<li><a href="#giving-up-to-support-elided"><span class="toc-section-number">6.2.3</span> Giving up to support elided<span></span></a></li>
<li><a href="#summarize"><span class="toc-section-number">6.2.4</span> Summarize<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#examples"><span class="toc-section-number">7</span> Examples<span></span></a>
<ul>
<li><a href="#always-enabledisable-coroutine-elision"><span class="toc-section-number">7.1</span> Always Enable/Disable coroutine elision<span></span></a></li>
<li><a href="#no-guarantee-to-coroutine-elision"><span class="toc-section-number">7.2</span> No guarantee to coroutine elision<span></span></a></li>
<li><a href="#controlling-the-elision-at-callsite"><span class="toc-section-number">7.3</span> Controlling the elision at callsite<span></span></a></li>
</ul></li>
<li><a href="#limitations"><span class="toc-section-number">8</span> Limitations<span></span></a>
<ul>
<li><a href="#indirect-call"><span class="toc-section-number">8.1</span> Indirect Call<span></span></a></li>
<li><a href="#elision-cross-translation-unit"><span class="toc-section-number">8.2</span> Elision cross translation unit<span></span></a></li>
<li><a href="#use-out-of-the-scope-of-definition"><span class="toc-section-number">8.3</span> Use out of the scope of definition<span></span></a></li>
<li><a href="#summary"><span class="toc-section-number">8.4</span> Summary<span></span></a></li>
</ul></li>
<li><a href="#implementation"><span class="toc-section-number">9</span> Implementation<span></span></a>
<ul>
<li><a href="#current-implementation-issue"><span class="toc-section-number">9.1</span> Current Implementation issue<span></span></a></li>
<li><a href="#implementation-in-gcc"><span class="toc-section-number">9.2</span> Implementation in GCC<span></span></a></li>
</ul></li>
<li><a href="#qa"><span class="toc-section-number">10</span> Q&amp;A<span></span></a>
<ul>
<li><a href="#how-does-the-compiler-guarantee-coroutine-elision-if-must_elide-evaluates-to-true-at-constexpr-time"><span class="toc-section-number">10.1</span> How does the compiler guarantee coroutine elision if must_elide evaluates to true at constexpr time<span></span></a></li>
<li><a href="#is-elided-a-constexpr-function"><span class="toc-section-number">10.2</span> Is elided() a constexpr function?<span></span></a></li>
<li><a href="#does-the-semantics-of-guaranteed-copy-elision-matter"><span class="toc-section-number">10.3</span> Does the semantics of guaranteed copy-elision matter?<span></span></a></li>
</ul></li>
<li><a href="#conclusion"><span class="toc-section-number">11</span> Conclusion<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>It is a well-known problem that coroutine needs dynamic allocation to work. Although there is an optimization in the compiler, programmers couldn’t control coroutine elision in a well-defined way. And there is not a good method that a programmer to use to detect whether the elision happened or not. So I proposed two methods. One for controlling the coroutine elision. And one for detecting it. Both of them wouldn’t break any existing codes.</p>
<h1 data-number="2" id="change-log"><span class="header-section-number">2</span> Change Log<a href="#change-log" class="self-link"></a></h1>
<ul>
<li>Adding more examples. Many thanks for Lewis Baker offering these examples!</li>
<li>Rename <code class="sourceCode default">should_elide</code> to <code class="sourceCode default">must_elide</code>.</li>
<li>Discussing the semantics of the storage lifetime of elided coroutine frame.</li>
<li>Adding more words about necessity, risks, and design ideas.</li>
<li>Correcting that <code class="sourceCode default">coroutine_handle&lt;&gt;::elided</code> and <code class="sourceCode default">coroutine_handle&lt;PromiseType&gt;::elided()</code> should be a runtime constant instead of a compile constant.</li>
<li>Discussing how should we support <code class="sourceCode default">coroutine_handle&lt;&gt;::elided</code>.</li>
<li>Raising the problem that indirect calls couldn’t be elided.</li>
<li>Discussing the relation of object and coroutine frame.</li>
<li>Add a conclusion section.</li>
</ul>
<h1 data-number="3" id="background-and-motivation"><span class="header-section-number">3</span> Background and Motivation<a href="#background-and-motivation" class="self-link"></a></h1>
<p>A coroutine needs space to store information (coroutine status) when it suspends. Generally, a coroutine would use <code class="sourceCode default">promise_type::operator new</code> (if existing) or <code class="sourceCode default">::operator new</code> to allocate coroutine status. However, it is expensive to allocate memory dynamically. Even we could use user-provided allocators, it is not easy (or very hard) to implement a safe and effective allocator. And dynamic allocation wouldn’t be cheap than static allocation after all.</p>
<p>To mitigate the expenses, Richard Smith and Gor Nishanov designed <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0981r0.html">HALO</a> (which is called <code class="sourceCode default">coroutine elision</code> nowadays) to allocate coroutine on the stack when the compiler finds it is safe to do so. And there is a corresponding optimization called <code class="sourceCode default">CoroElide</code> in Clang/LLVM. But there is no word in the C++ specification about <code class="sourceCode default">coroutine elision</code>. It only says:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb1-1"><a href="#cb1-1"></a>[dcl.fct.def.coroutine]p9</span>
<span id="cb1-2"><a href="#cb1-2"></a>An implementation **may** need to allocate additional storage for a coroutine.</span></code></pre></div>
<p>So it leaves the space for the compiler to do optimization. But it doesn’t make any promise for programmers. So programmers couldn’t find a well-defined method to control coroutine elision nor detect whether the coroutine elision happened. And <code class="sourceCode default">coroutine elision</code> doesn’t like other compiler optimization since programmers could feel strongly about the dynamic allocation. So I feel it is necessary to support it.</p>
<p>Except for the general need to avoid dynamic allocation to speed up. I heard from Niall Douglas that it is needed to disable <code class="sourceCode default">coroutine elision</code> in an embedded system. In the resource-limited system, we could use <code class="sourceCode default">promise_type::operator new</code> to allocate space from a big static-allocated bytes array. And the feature to disable <code class="sourceCode default">coroutine elision</code> is not present in the standard too.</p>
<h1 data-number="4" id="terminology"><span class="header-section-number">4</span> Terminology<a href="#terminology" class="self-link"></a></h1>
<p>This section aims at explaining the terminologies in this proposal to avoid misunderstanding. This aim is not to discuss the words used in the specification formally. That should be discussed in the wording stage.</p>
<h2 data-number="4.1" id="halo-and-coroutine-elision"><span class="header-section-number">4.1</span> HALO and Coroutine elision<a href="#halo-and-coroutine-elision" class="self-link"></a></h2>
<p>The two terminologies refer to the same thing in this proposal. I found that people on the language side prefer to use the term <code class="sourceCode default">HALO</code>. And the people on the compiler side prefer to use the term <code class="sourceCode default">Corotuine elision</code>. I like the term <code class="sourceCode default">Coroutine elision</code> more personally. We could discuss what’s the preferred name later.</p>
<h2 data-number="4.2" id="constexpr-time-and-compile-time"><span class="header-section-number">4.2</span> constexpr time and compile time<a href="#constexpr-time-and-compile-time" class="self-link"></a></h2>
<p>Generally, these two terms refer to the same thing. But it’s not the case for coroutine. For example, the layout of coroutine status is built at compile time. But the programmer couldn’t see it. Informally, if a value is a constexpr-time constant, it could participate in the template/if-constexpr evaluation. And if a value is a compile-time constant, it needn’t be evaluated at runtime. So simply, a constexpr-time constant is a compile-time constant. But a compile-time constant may not be a constexpr-time constant.</p>
<h2 data-number="4.3" id="coroutine-status-and-corotuine-frame"><span class="header-section-number">4.3</span> Coroutine status and Corotuine frame<a href="#coroutine-status-and-corotuine-frame" class="self-link"></a></h2>
<p>Coroutine status is an abstract concept used in the language standard to refer to all the information the coroutine should keep. And the coroutine frame refers to the data structure generated by the compiler to keep the information needed. We could think coroutine frame is a derived class of coroutine status : ).</p>
<h2 data-number="4.4" id="ramp-function"><span class="header-section-number">4.4</span> Ramp function<a href="#ramp-function" class="self-link"></a></h2>
<p>The compiler would split a coroutine function into several parts: ramp function, resume function and destroy function. Both the resume function and destroy function contain a compiler-generated state machine to make the coroutine work correctly. And the ramp function is the initial function that would initialize the coroutine frame.</p>
<h1 data-number="5" id="the-storage-lifetime-of-elided-coroutine-frame"><span class="header-section-number">5</span> The storage lifetime of elided coroutine frame<a href="#the-storage-lifetime-of-elided-coroutine-frame" class="self-link"></a></h1>
<p>Simply, the semantics of the storage lifetime of a coroutine state is just like a corresponding local variable in the place of the callsite. In another word, the lifetime of the elided coroutine frame would end at the end of the enclosing block. For example:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a>NormalTask example1(<span class="dt">int</span> count) {</span>
<span id="cb1-2"><a href="#cb1-2"></a>  <span class="dt">int</span> sum = <span class="dv">0</span>;</span>
<span id="cb1-3"><a href="#cb1-3"></a>  <span class="cf">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; count; ++i)</span>
<span id="cb1-4"><a href="#cb1-4"></a>    sum += <span class="kw">co_await</span> coroutine_func();</span>
<span id="cb1-5"><a href="#cb1-5"></a></span>
<span id="cb1-6"><a href="#cb1-6"></a>  <span class="kw">co_return</span> sum;</span>
<span id="cb1-7"><a href="#cb1-7"></a>}</span></code></pre></div>
<p>Assume <code class="sourceCode default">coroutine_func()</code> would be elided, then the code would look like:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a>AlwaysElideTask an_elided_coroutine<span class="op">()</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
<span id="cb2-2"><a href="#cb2-2"></a></span>
<span id="cb2-3"><a href="#cb2-3"></a>NormalTask example<span class="op">(</span><span class="dt">int</span> count<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-4"><a href="#cb2-4"></a>  <span class="dt">int</span> sum <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb2-5"><a href="#cb2-5"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> count; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-6"><a href="#cb2-6"></a>    coroutine_status_ty coroutine_status;  <span class="co">// for an_elided_coroutine</span></span>
<span id="cb2-7"><a href="#cb2-7"></a>    initializing coroutine_status<span class="op">...</span>      </span>
<span id="cb2-8"><a href="#cb2-8"></a>    any other works in an_elided_coroutine <span class="co">// This is possible if the intial_suspend </span></span>
<span id="cb2-9"><a href="#cb2-9"></a>                                           <span class="co">// of AlwaysElideTask is not suspend_alwyas.</span></span>
<span id="cb2-10"><a href="#cb2-10"></a>    AlwaysElideTask Task <span class="op">=</span> coroutine_status<span class="op">.</span>promise<span class="op">.</span>get_return_object<span class="op">()</span>;</span>
<span id="cb2-11"><a href="#cb2-11"></a>    sum <span class="op">+=</span> <span class="kw">co_await</span> Task;</span>
<span id="cb2-12"><a href="#cb2-12"></a>  <span class="op">}</span> <span class="co">// So the coroutine_status is invalided here.</span></span>
<span id="cb2-13"><a href="#cb2-13"></a></span>
<span id="cb2-14"><a href="#cb2-14"></a>  <span class="kw">co_return</span> sum;</span>
<span id="cb2-15"><a href="#cb2-15"></a><span class="op">}</span></span></code></pre></div>
<p>Before this proposal, the compiler would elide a coroutine frame only if the compiler could prove it is safe to do so.</p>
<h1 data-number="6" id="design"><span class="header-section-number">6</span> Design<a href="#design" class="self-link"></a></h1>
<p>The design consists of 2 parts. One for controlling the elision. One for detecting the elision. Both of them should be easy to understand.</p>
<h2 data-number="6.1" id="must_elide"><span class="header-section-number">6.1</span> must_elide<a href="#must_elide" class="self-link"></a></h2>
<p>If the compiler could find the name <code class="sourceCode default">must_elide</code> in the scope of promise_type, then if the result of <code class="sourceCode default">promise_type::must_elide()</code> evaluates to true at constexpr time, all the coroutine frames generated from the coroutine function are guaranteed to be elided. Or if the result of <code class="sourceCode default">promise_type::must_elide()</code> evaluates to false at constexpr time, all the coroutine frames generated from the coroutine function are guaranteed to not be elided. Otherwise, if the compiler couldn’t find <code class="sourceCode default">must_elide</code> in the scope of promise_type or the result of <code class="sourceCode default">promise_type::must_elide</code> couldn’t be evaluated at constexpr time, the compiler is free to elide every single coroutine frame generated from the coroutine function.</p>
<h3 data-number="6.1.1" id="necessity"><span class="header-section-number">6.1.1</span> Necessity<a href="#necessity" class="self-link"></a></h3>
<p>The necessity of <code class="sourceCode default">must_elide</code> comes from the fact we observed in practice: “There is no way that the programmer could control coroutine elision in a well-defined way.” Different from other compiler optimization, programmers could feel dynamic allocation strongly. So there is a lack of a mechanism that programmers could control coroutine elision.</p>
<p>There is a tip to make the coroutine easier to elide: Make the coroutine type contain a coroutine_handle only. But here are some drawbacks: - It is a hack. There is no reason to do so from the perspective of the standard. And I think programmers couldn’t understand it except the compiler writers. It is hard to understand. - There is no promise that the compiler made to elide coroutine if some observable conditions are met. No. It means that we tested a coroutine is OK to elide under some conditions in a version of the compiler. But nobody knows whether or not it would elide in other versions. - There are coroutine types that couldn’t contain a coroutine_handle only. But we understand that it is Ok to elide from the programmers’ sight. - There is the need to disable coroutine elision in certain circumstances.</p>
<p>The core idea behind this is that we need a mechanism in the language level to specify that we want this coroutine to elide and another coroutine to not elide <strong>explicitly</strong>. And a fact we observed is that there are many coroutine frames that couldn’t be elided but they are safe to elide in fact. I think it is a little bit violates the design principles of C++ for “Pay for what you used”. Now the situation becomes the programmer using coroutine need to pay what they could have avoided.</p>
<h3 data-number="6.1.2" id="risks"><span class="header-section-number">6.1.2</span> Risks<a href="#risks" class="self-link"></a></h3>
<p>The key risk here is that: - It is not always safe to elide a coroutine frame.</p>
<p>Here is an example:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a>Task&lt;<span class="dt">int</span>&gt; example2(<span class="dt">int</span> task_count) {</span>
<span id="cb2-2"><a href="#cb2-2"></a>  <span class="bu">std::</span>vector&lt;ElidedTask&lt;<span class="dt">int</span>&gt;&gt; tasks;</span>
<span id="cb2-3"><a href="#cb2-3"></a>  <span class="cf">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; task_count; i++)</span>
<span id="cb2-4"><a href="#cb2-4"></a>    tasks.empalce_back(coro_task());</span>
<span id="cb2-5"><a href="#cb2-5"></a>    </span>
<span id="cb2-6"><a href="#cb2-6"></a>  <span class="co">// the semantics of whenAll is that it would</span></span>
<span id="cb2-7"><a href="#cb2-7"></a>  <span class="co">// complete after all the tasks completed.</span></span>
<span id="cb2-8"><a href="#cb2-8"></a>  <span class="kw">co_return</span> <span class="kw">co_await</span> whenAll(<span class="bu">std::</span>move(tasks));</span>
<span id="cb2-9"><a href="#cb2-9"></a>}</span></code></pre></div>
<p>If we make <code class="sourceCode default">coro_task()</code> to elide all the time, the code would look like this:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a>Task&lt;<span class="dt">int</span>&gt; example2(<span class="dt">int</span> task_count) {</span>
<span id="cb3-2"><a href="#cb3-2"></a>  <span class="bu">std::</span>vector&lt;coroutine_status_ty *&gt; tasks;</span>
<span id="cb3-3"><a href="#cb3-3"></a>  <span class="cf">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; task_count; i++) {</span>
<span id="cb3-4"><a href="#cb3-4"></a>    coroutine_status_ty coroutine_status;</span>
<span id="cb3-5"><a href="#cb3-5"></a>    tasks.empalce_back(&amp;coroutine_status);</span>
<span id="cb3-6"><a href="#cb3-6"></a>  }</span>
<span id="cb3-7"><a href="#cb3-7"></a>  </span>
<span id="cb3-8"><a href="#cb3-8"></a>  <span class="co">// Now all the pointer in tasks are dangling</span></span>
<span id="cb3-9"><a href="#cb3-9"></a>  <span class="co">// pointer!</span></span>
<span id="cb3-10"><a href="#cb3-10"></a>  <span class="kw">co_return</span> <span class="kw">co_await</span> whenAll(<span class="bu">std::</span>move(tasks));</span>
<span id="cb3-11"><a href="#cb3-11"></a>}</span></code></pre></div>
<p>It should be clear that <code class="sourceCode default">tasks</code> would contain only dangling pointers after the for-loop. And there would be other examples. The answer for this situation is that we shouldn’t make the coroutine frame elide.</p>
<h3 data-number="6.1.3" id="design-ideas"><span class="header-section-number">6.1.3</span> Design Ideas<a href="#design-ideas" class="self-link"></a></h3>
<p>The core design ideas include: - Offer a mechanism that the programmer could control coroutine elision. So that they could avoid cost for dynamic allocation or unwanted elision. - It is not designed as a panacea. There are cases it couldn’t handle. And it is possible to be a risk if the user uses it arbitrarily. But we could solve a lot of problems we couldn’t solve after all. - It is not a forced option. You could avoid using it. So that it wouldn’t break any existing code. It is designed for the programmer who could understand it and willing to pay for the risk. And if you think you don’t understand it or you don’t want to pay that risk, you could refuse to use it simply. - We should support to force a coroutine to elide, to not elide or offloading the judgment to the compiler. Or in another word, the mechanism should return tristate. And this is the reason why I chose constexpr bool function. Since it has a tristate naturally: <code class="sourceCode default">constexpr time true</code>, <code class="sourceCode default">constexpr time false</code> and <code class="sourceCode default">constexpr time unknown</code>.</p>
<h3 data-number="6.1.4" id="why-in-promise_type"><span class="header-section-number">6.1.4</span> Why in promise_type?<a href="#why-in-promise_type" class="self-link"></a></h3>
<p>People may complain that it is too coarse grained to define <code class="sourceCode default">must_elide</code> at the promise_type level. It should be better to annotate at the callsite. I agree with it. But the key problem here is that there is <strong>no mechanism in C++ to annotate an expression</strong>! Although there is attribute in C++ standard. It contains statement level and declaration level only. And it would be a much harder problem to support expression attribute. So it would be a long time to support the expression attribute from my point of view (Or we couldn’t make it actually).</p>
<p>And here are two reasons to define <code class="sourceCode default">must_elide</code> in promise_type: - It is more suit for the current coroutine design. Now the behavior of a coroutine is defined in promise_type and corresponding awaiter. So it is natural to define <code class="sourceCode default">must_elide</code> in promise_type. - It is possible to control the coroutine to elide at the callsite level in the current design.</p>
<p>The second point matters more. For example:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">struct</span> ShouldElideTagT;</span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="kw">struct</span> NoElideTagT;</span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="kw">struct</span> MayElideTagT;</span>
<span id="cb4-4"><a href="#cb4-4"></a></span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="kw">template</span>&lt;<span class="kw">typename</span> T&gt;</span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="kw">concept</span> ElideTag = (<span class="bu">std::</span>same_as&lt;T, ShouldElideTagT&gt; ||</span>
<span id="cb4-7"><a href="#cb4-7"></a>                    <span class="bu">std::</span>same_as&lt;T, NoElideTagT&gt; ||</span>
<span id="cb4-8"><a href="#cb4-8"></a>                    <span class="bu">std::</span>same_as&lt;T, MayElideTagT&gt;);</span>
<span id="cb4-9"><a href="#cb4-9"></a></span>
<span id="cb4-10"><a href="#cb4-10"></a><span class="dt">bool</span> undetermism;</span>
<span id="cb4-11"><a href="#cb4-11"></a><span class="kw">template</span> &lt;ElideTag Tag&gt;</span>
<span id="cb4-12"><a href="#cb4-12"></a><span class="kw">struct</span> TaskPromiseAlternative : <span class="kw">public</span> TaskPromiseBase {</span>
<span id="cb4-13"><a href="#cb4-13"></a>    <span class="at">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> must_elide() {</span>
<span id="cb4-14"><a href="#cb4-14"></a>        <span class="cf">if</span> <span class="kw">constexpr</span> (<span class="bu">std::</span>is_same_v&lt;Tag, ShouldElideTagT&gt;)</span>
<span id="cb4-15"><a href="#cb4-15"></a>            <span class="cf">return</span> <span class="kw">true</span>;</span>
<span id="cb4-16"><a href="#cb4-16"></a>        <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> (<span class="bu">std::</span>is_same_v&lt;Tag, NoElideTagT&gt;)</span>
<span id="cb4-17"><a href="#cb4-17"></a>            <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb4-18"><a href="#cb4-18"></a>        <span class="cf">else</span></span>
<span id="cb4-19"><a href="#cb4-19"></a>            <span class="cf">return</span> undetermism;</span>
<span id="cb4-20"><a href="#cb4-20"></a>    }</span>
<span id="cb4-21"><a href="#cb4-21"></a>};</span>
<span id="cb4-22"><a href="#cb4-22"></a></span>
<span id="cb4-23"><a href="#cb4-23"></a><span class="kw">template</span> &lt;ElideTag Tag = MayElideTagT&gt;</span>
<span id="cb4-24"><a href="#cb4-24"></a><span class="kw">using</span> AlternativeTask = Task&lt;TaskPromiseAlternative&lt;Tag&gt;&gt;;</span>
<span id="cb4-25"><a href="#cb4-25"></a><span class="kw">using</span> Task = AlternativeTask&lt;MayElideTagT&gt;;</span>
<span id="cb4-26"><a href="#cb4-26"></a></span>
<span id="cb4-27"><a href="#cb4-27"></a><span class="kw">template</span> &lt;ElideTag Tag = MayElideTagT&gt;</span>
<span id="cb4-28"><a href="#cb4-28"></a>AlternativeTask&lt;Tag&gt; alternative_task () { <span class="co">/* ... */</span> } <span class="co">// This is a coroutine</span></span>
<span id="cb4-29"><a href="#cb4-29"></a></span>
<span id="cb4-30"><a href="#cb4-30"></a>Task NaturalTask() { <span class="co">/* ... */</span> } <span class="co">// This is a coroutine.</span></span>
<span id="cb4-31"><a href="#cb4-31"></a></span>
<span id="cb4-32"><a href="#cb4-32"></a><span class="dt">int</span> foo() {</span>
<span id="cb4-33"><a href="#cb4-33"></a>  <span class="kw">auto</span> t1 = alternative_task&lt;ShouldElideTagT&gt;();</span>
<span id="cb4-34"><a href="#cb4-34"></a>  <span class="co">// Task::elided would call coroutine_handle::elided</span></span>
<span id="cb4-35"><a href="#cb4-35"></a>  <span class="ot">assert</span> (t1.elided());</span>
<span id="cb4-36"><a href="#cb4-36"></a>  <span class="kw">auto</span> t2 = alternative_task&lt;NoElideTagT&gt;();</span>
<span id="cb4-37"><a href="#cb4-37"></a>  <span class="ot">assert</span> (!t1.elided());</span>
<span id="cb4-38"><a href="#cb4-38"></a>  <span class="co">// The default case, which would be general for most cases</span></span>
<span id="cb4-39"><a href="#cb4-39"></a>  alternative_task();</span>
<span id="cb4-40"><a href="#cb4-40"></a>  <span class="co">// The author of the function don&#39;t want us to control its elision</span></span>
<span id="cb4-41"><a href="#cb4-41"></a>  <span class="co">// or the author think it doesn&#39;t matter to elide or not. After all,</span></span>
<span id="cb4-42"><a href="#cb4-42"></a>  <span class="co">// the compiler would make the decision.</span></span>
<span id="cb4-43"><a href="#cb4-43"></a>  NaturalTask();</span>
<span id="cb4-44"><a href="#cb4-44"></a>}</span></code></pre></div>
<p>In this way, we could control the elision at call site! All cost we need to pay is that we need to type a little more in the definition. I think it is acceptable personally.</p>
<h2 data-number="6.2" id="elided"><span class="header-section-number">6.2</span> elided<a href="#elided" class="self-link"></a></h2>
<p>Add a non-static member bool function <code class="sourceCode default">elided</code> to <code class="sourceCode default">std::coroutine_handle&lt;&gt;</code> and <code class="sourceCode default">std::coroutine_handle&lt;PromiseType&gt;</code> .</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2"></a>  <span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb3-3"><a href="#cb3-3"></a>  <span class="kw">struct</span> coroutine_handle<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span></span>
<span id="cb3-4"><a href="#cb3-4"></a>  <span class="op">{</span> </span>
<span id="cb3-5"><a href="#cb3-5"></a>    <span class="co">// ...</span></span>
<span id="cb3-6"><a href="#cb3-6"></a>    <span class="co">// [coroutine.handle.observers], observers</span></span>
<span id="cb3-7"><a href="#cb3-7"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span> <span class="kw">operator</span> <span class="dt">bool</span><span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb3-8"><a href="#cb3-8"></a>    <span class="dt">bool</span> done<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb3-9"><a href="#cb3-9"></a><span class="op">+</span>   <span class="dt">bool</span> elided<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb3-10"><a href="#cb3-10"></a>    <span class="co">// ...</span></span>
<span id="cb3-11"><a href="#cb3-11"></a>  <span class="op">}</span>;</span>
<span id="cb3-12"><a href="#cb3-12"></a></span>
<span id="cb3-13"><a href="#cb3-13"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Promise<span class="op">&gt;</span></span>
<span id="cb3-14"><a href="#cb3-14"></a>  <span class="kw">struct</span> coroutine_handle</span>
<span id="cb3-15"><a href="#cb3-15"></a>  <span class="op">{</span></span>
<span id="cb3-16"><a href="#cb3-16"></a>    <span class="co">// ...</span></span>
<span id="cb3-17"><a href="#cb3-17"></a>    <span class="co">// [coroutine.handle.observers], observers</span></span>
<span id="cb3-18"><a href="#cb3-18"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span> <span class="kw">operator</span> <span class="dt">bool</span><span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb3-19"><a href="#cb3-19"></a>    <span class="dt">bool</span> done<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb3-20"><a href="#cb3-20"></a><span class="op">+</span>       <span class="dt">bool</span> elided<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb3-21"><a href="#cb3-21"></a>        <span class="co">// ...</span></span>
<span id="cb3-22"><a href="#cb3-22"></a>  <span class="op">}</span>;</span>
<span id="cb3-23"><a href="#cb3-23"></a><span class="op">}</span></span></code></pre></div>
<p>And the semantic are clear. If the corresponding coroutine is elided, then <code class="sourceCode default">elided</code> would return true. And if the corresponding coroutine is not elided, then <code class="sourceCode default">elided</code> would return false.</p>
<p>Here are two reasons I want to introduce <code class="sourceCode default">elided</code>:</p>
<ul>
<li>For the language side, if we introduce the concept of coroutine elision in the language. It is odd that the user couldn’t observe it.</li>
<li>For the engineering side, as a new feature, the developer should write tests if they want to introduce this feature into their codebases. But they couldn’t make it until <code class="sourceCode default">elided</code> is provided.</li>
</ul>
<p>But introducing <code class="sourceCode default">elided</code> would introduce overhead. Since it would require the coroutine status to store extra information.</p>
<p>And here is 3 direction:</p>
<ul>
<li>Support both <code class="sourceCode default">coroutine_handle&lt;&gt;::elided()</code> and <code class="sourceCode default">coroutine_handle&lt;PromiseType&gt;::elided()</code>.</li>
<li>Support <code class="sourceCode default">coroutine_handle&lt;PromiseType&gt;::elided()</code> only.</li>
<li>Giving up to support <code class="sourceCode default">elided()</code>.</li>
</ul>
<h3 data-number="6.2.1" id="support-both"><span class="header-section-number">6.2.1</span> Support both<a href="#support-both" class="self-link"></a></h3>
<p>If we want to support both <code class="sourceCode default">coroutine_handle&lt;&gt;::elided()</code> and <code class="sourceCode default">coroutine_handle&lt;PromiseType&gt;::elided()</code>, we must refactor the ABI for coroutine into the following form:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">struct</span> CoroutineFrame {</span>
<span id="cb5-2"><a href="#cb5-2"></a>  <span class="dt">void</span> (*resume_func)(CoroutineFrame*);</span>
<span id="cb5-3"><a href="#cb5-3"></a>  <span class="dt">void</span> (*destroy_func)(CoroutineFrame*);</span>
<span id="cb5-4"><a href="#cb5-4"></a>  <span class="dt">bool</span> Elided;</span>
<span id="cb5-5"><a href="#cb5-5"></a>  <span class="dt">promise_type</span>;</span>
<span id="cb5-6"><a href="#cb5-6"></a>  <span class="co">// any other information needed</span></span>
<span id="cb5-7"><a href="#cb5-7"></a>};</span></code></pre></div>
<p>[Note: The current coroutine ABI is:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">struct</span> CoroutineFrame {</span>
<span id="cb6-2"><a href="#cb6-2"></a>  <span class="dt">void</span> (*resume_func)(CoroutineFrame*);</span>
<span id="cb6-3"><a href="#cb6-3"></a>  <span class="dt">void</span> (*destroy_func)(CoroutineFrame*);</span>
<span id="cb6-4"><a href="#cb6-4"></a>  <span class="dt">promise_type</span>;</span>
<span id="cb6-5"><a href="#cb6-5"></a>  <span class="co">// any other information needed</span></span>
<span id="cb6-6"><a href="#cb6-6"></a>};</span></code></pre></div>
<p>]</p>
<p>There are several drawbacks:</p>
<ul>
<li>It breaks the ABI.</li>
<li>It would enlarge the coroutine frame. Due to the alignment requirement, it may introduce more space than 1 bit for every coroutine frame.</li>
<li>It would introduce an extra store instruction for every coroutine.</li>
</ul>
<p>For the ABI problem, I am not sure if it matters so much. There are some reasons:</p>
<ul>
<li>Coroutine is a new feature so the historical dependent problem may not be so large.</li>
<li>Now, the different compilers would generate different ABI. The type for the resume_func, destroy_func, and the index for the state machine are not the same in different compilers.</li>
<li>For the same compiler, the different versions of the compilers may generate different coroutine frames although their headers are the same. The remainder of the frame may be different.</li>
<li>The coroutine ABI is not standardized as far as I know.</li>
</ul>
<p>And for the second and the third drawbacks, they are the price we must pay to enable this feature.</p>
<p>And the implementation demo implements this strategy.</p>
<h3 data-number="6.2.2" id="suppot-coroutine_handlepromisetypeelided-only"><span class="header-section-number">6.2.2</span> Suppot coroutine_handle&lt;PromiseType&gt;::elided() only<a href="#suppot-coroutine_handlepromisetypeelided-only" class="self-link"></a></h3>
<p>If we decided to not support <code class="sourceCode default">coroutine_handle&lt;&gt;::elided()</code>, we could move the <code class="sourceCode default">Elided</code> bit in the back of <code class="sourceCode default">promise_type</code>:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">struct</span> CoroutineFrame {</span>
<span id="cb7-2"><a href="#cb7-2"></a>  <span class="dt">void</span> (*resume_func)(CoroutineFrame*),</span>
<span id="cb7-3"><a href="#cb7-3"></a>  <span class="dt">void</span> (*destroy_func)(CoroutineFrame*),</span>
<span id="cb7-4"><a href="#cb7-4"></a>  <span class="dt">promise_type</span>,</span>
<span id="cb7-5"><a href="#cb7-5"></a>  <span class="dt">bool</span> Elided,</span>
<span id="cb7-6"><a href="#cb7-6"></a>  <span class="co">// any other information needed</span></span>
<span id="cb7-7"><a href="#cb7-7"></a>};</span></code></pre></div>
<p>So that we could avoid the ABI problems. But I feel odd for giving up to support <code class="sourceCode default">coroutine_handle&lt;&gt;::elided</code>. Since <code class="sourceCode default">coroutine_handle&lt;&gt;</code> is a generic abstract for coroutine and <code class="sourceCode default">elided</code> should be a generic feature for all the coroutine.</p>
<h3 data-number="6.2.3" id="giving-up-to-support-elided"><span class="header-section-number">6.2.3</span> Giving up to support elided<a href="#giving-up-to-support-elided" class="self-link"></a></h3>
<p>This is simple. We wouldn’t need to pay anything in implementation and language wording.</p>
<h3 data-number="6.2.4" id="summarize"><span class="header-section-number">6.2.4</span> Summarize<a href="#summarize" class="self-link"></a></h3>
<p>I prefer to support both and pay for the price for more space needed and the extra store instruction. But I am not so sure since the use cases for <code class="sourceCode default">elided</code> I got now are in the test only. And for the codes which are actually running in production, I couldn’t imagine the use cases for <code class="sourceCode default">elided</code>. So in another word, the people who use coroutine in production would pay for the price that they don’t use. This violates the principle of C++ that “Pay for what you use”. But as I said, it is really odd that people could control coroutine elision without observing it.</p>
<p>So I am not sure about this. Any opinion is welcome.</p>
<h1 data-number="7" id="examples"><span class="header-section-number">7</span> Examples<a href="#examples" class="self-link"></a></h1>
<p>A set of examples could be found at <a href="https://github.com/ChuanqiXu9/llvm-project/tree/CoroMustElide/MustElide">Examples</a>. Example-1~6 mimic the use of loop, select operator, goto statement, function default argument, the initializer of an if-block, and the initializer of a class data-member. All of them are simple and easy to understand. Here talks about the basic usage for <code class="sourceCode default">must_elide</code> only.</p>
<h2 data-number="7.1" id="always-enabledisable-coroutine-elision"><span class="header-section-number">7.1</span> Always Enable/Disable coroutine elision<a href="#always-enabledisable-coroutine-elision" class="self-link"></a></h2>
<p>We could enable/disable coroutine elision for a kind of coroutine like:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">struct</span> TaskPromiseAlwaysElide : <span class="kw">public</span> TaskPromiseBase {</span>
<span id="cb8-2"><a href="#cb8-2"></a>    <span class="at">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> must_elide() {</span>
<span id="cb8-3"><a href="#cb8-3"></a>        <span class="cf">return</span> <span class="kw">true</span>;</span>
<span id="cb8-4"><a href="#cb8-4"></a>    }</span>
<span id="cb8-5"><a href="#cb8-5"></a>};</span>
<span id="cb8-6"><a href="#cb8-6"></a></span>
<span id="cb8-7"><a href="#cb8-7"></a><span class="kw">struct</span> TaskPromiseNeverElide : <span class="kw">public</span> TaskPromiseBase {</span>
<span id="cb8-8"><a href="#cb8-8"></a>    <span class="at">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> must_elide() {</span>
<span id="cb8-9"><a href="#cb8-9"></a>        <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb8-10"><a href="#cb8-10"></a>    }</span>
<span id="cb8-11"><a href="#cb8-11"></a>};</span></code></pre></div>
<p>Then for the coroutine like:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> PromiseType<span class="op">&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="kw">class</span> Task <span class="op">:</span> <span class="kw">public</span> TaskBase<span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb4-4"><a href="#cb4-4"></a>    <span class="kw">using</span> promise_type <span class="op">=</span> PromiseType;</span>
<span id="cb4-5"><a href="#cb4-5"></a>    <span class="kw">using</span> HandleType <span class="op">=</span> std<span class="op">::</span>experimental<span class="op">::</span>coroutine_handle<span class="op">&lt;</span>promise_type<span class="op">&gt;</span>;</span>
<span id="cb4-6"><a href="#cb4-6"></a>    <span class="co">// ...</span></span>
<span id="cb4-7"><a href="#cb4-7"></a><span class="op">}</span>; <span class="co">// end of Task</span></span>
<span id="cb4-8"><a href="#cb4-8"></a><span class="kw">using</span> AlwaysElideTask <span class="op">=</span> Task<span class="op">&lt;</span>TaskPromiseAlwaysElide<span class="op">&gt;</span>;</span>
<span id="cb4-9"><a href="#cb4-9"></a><span class="kw">using</span> NeverElideTask <span class="op">=</span> Task<span class="op">&lt;</span>TaskPromiseNeverElide<span class="op">&gt;</span>;</span>
<span id="cb4-10"><a href="#cb4-10"></a></span>
<span id="cb4-11"><a href="#cb4-11"></a>AlwaysElideTask always_elide_task <span class="op">()</span> <span class="op">{</span></span>
<span id="cb4-12"><a href="#cb4-12"></a>    <span class="co">// ... contain coroutine keywords</span></span>
<span id="cb4-13"><a href="#cb4-13"></a><span class="op">}</span></span>
<span id="cb4-14"><a href="#cb4-14"></a>NeverElideTask never_elide_task <span class="op">()</span> <span class="op">{</span></span>
<span id="cb4-15"><a href="#cb4-15"></a>    <span class="co">// ... contain coroutine keywords</span></span>
<span id="cb4-16"><a href="#cb4-16"></a><span class="op">}</span></span></code></pre></div>
<p>Then every coroutine frame generated from <code class="sourceCode default">always_elide_task()</code> would be elided. And every coroutine frame generated from <code class="sourceCode default">never_elide_task</code> wouldn’t be elided.</p>
<h2 data-number="7.2" id="no-guarantee-to-coroutine-elision"><span class="header-section-number">7.2</span> No guarantee to coroutine elision<a href="#no-guarantee-to-coroutine-elision" class="self-link"></a></h2>
<p>If the compiler couldn’t infer the result of <code class="sourceCode default">promise_type::must_elide</code> at compile time, then the compiler is free to do elision or not. And the behavior would be the same with <code class="sourceCode default">must_elide</code> is not exist in <code class="sourceCode default">promise_type</code>.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="dt">bool</span> undertermism;</span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="kw">struct</span> TaskPromiseMeaningless <span class="op">:</span> <span class="kw">public</span> TaskPromiseBase <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> must_elide<span class="op">()</span> <span class="op">{</span></span>
<span id="cb5-4"><a href="#cb5-4"></a>        <span class="cf">return</span> undertermism;</span>
<span id="cb5-5"><a href="#cb5-5"></a>    <span class="op">}</span></span>
<span id="cb5-6"><a href="#cb5-6"></a><span class="op">}</span>;</span></code></pre></div>
<p>Then <code class="sourceCode default">TaskPromiseMeaningless</code> would be the same as <code class="sourceCode default">TaskPromiseBase</code> for every case.</p>
<h2 data-number="7.3" id="controlling-the-elision-at-callsite"><span class="header-section-number">7.3</span> Controlling the elision at callsite<a href="#controlling-the-elision-at-callsite" class="self-link"></a></h2>
<p>It is possible that we could control coroutine elision for specific call. Here is my demo,</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">using</span> NormalTask <span class="op">=</span> Task<span class="op">&lt;</span>TaskPromiseBase<span class="op">&gt;</span>;</span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="kw">using</span> AlwaysElideTask <span class="op">=</span> Task<span class="op">&lt;</span>TaskPromiseAlwaysElide<span class="op">&gt;</span>;</span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="kw">using</span> NeverElideTask <span class="op">=</span> Task<span class="op">&lt;</span>TaskPromiseNeverElide<span class="op">&gt;</span>;</span>
<span id="cb6-4"><a href="#cb6-4"></a></span>
<span id="cb6-5"><a href="#cb6-5"></a><span class="kw">struct</span> ShouldElideTagT;</span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="kw">struct</span> NoElideTagT;</span>
<span id="cb6-7"><a href="#cb6-7"></a><span class="kw">struct</span> MayElideTagT;</span>
<span id="cb6-8"><a href="#cb6-8"></a></span>
<span id="cb6-9"><a href="#cb6-9"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb6-10"><a href="#cb6-10"></a><span class="kw">concept</span> ElideTag <span class="op">=</span> <span class="op">(</span>std<span class="op">::</span>same_as<span class="op">&lt;</span>T, ShouldElideTagT<span class="op">&gt;</span> <span class="op">||</span></span>
<span id="cb6-11"><a href="#cb6-11"></a>                    std<span class="op">::</span>same_as<span class="op">&lt;</span>T, NoElideTagT<span class="op">&gt;</span> <span class="op">||</span></span>
<span id="cb6-12"><a href="#cb6-12"></a>                    std<span class="op">::</span>same_as<span class="op">&lt;</span>T, MayElideTagT<span class="op">&gt;)</span>;</span>
<span id="cb6-13"><a href="#cb6-13"></a></span>
<span id="cb6-14"><a href="#cb6-14"></a><span class="dt">bool</span> undetermism;</span>
<span id="cb6-15"><a href="#cb6-15"></a><span class="kw">template</span> <span class="op">&lt;</span>ElideTag Tag<span class="op">&gt;</span></span>
<span id="cb6-16"><a href="#cb6-16"></a><span class="kw">struct</span> TaskPromiseAlternative <span class="op">:</span> <span class="kw">public</span> TaskPromiseBase <span class="op">{</span></span>
<span id="cb6-17"><a href="#cb6-17"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> must_elide<span class="op">()</span> <span class="op">{</span></span>
<span id="cb6-18"><a href="#cb6-18"></a>        <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span>Tag, ShouldElideTagT<span class="op">&gt;)</span></span>
<span id="cb6-19"><a href="#cb6-19"></a>            <span class="cf">return</span> <span class="kw">true</span>;</span>
<span id="cb6-20"><a href="#cb6-20"></a>        <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span>Tag, NoElideTagT<span class="op">&gt;)</span></span>
<span id="cb6-21"><a href="#cb6-21"></a>            <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb6-22"><a href="#cb6-22"></a>        <span class="cf">else</span></span>
<span id="cb6-23"><a href="#cb6-23"></a>            <span class="cf">return</span> undetermism;</span>
<span id="cb6-24"><a href="#cb6-24"></a>    <span class="op">}</span></span>
<span id="cb6-25"><a href="#cb6-25"></a><span class="op">}</span>;</span>
<span id="cb6-26"><a href="#cb6-26"></a></span>
<span id="cb6-27"><a href="#cb6-27"></a><span class="kw">template</span> <span class="op">&lt;</span>ElideTag Tag <span class="op">=</span> MayElideTagT<span class="op">&gt;</span></span>
<span id="cb6-28"><a href="#cb6-28"></a><span class="kw">using</span> AlternativeTask <span class="op">=</span> Task<span class="op">&lt;</span>TaskPromiseAlternative<span class="op">&lt;</span>Tag<span class="op">&gt;&gt;</span>;</span>
<span id="cb6-29"><a href="#cb6-29"></a></span>
<span id="cb6-30"><a href="#cb6-30"></a><span class="kw">template</span> <span class="op">&lt;</span>ElideTag Tag <span class="op">=</span> MayElideTagT<span class="op">&gt;</span></span>
<span id="cb6-31"><a href="#cb6-31"></a>AlternativeTask<span class="op">&lt;</span>Tag<span class="op">&gt;</span> alternative_task <span class="op">()</span> <span class="op">{</span> <span class="co">/* ... */</span> <span class="op">}</span> <span class="co">// This is a coroutine</span></span>
<span id="cb6-32"><a href="#cb6-32"></a></span>
<span id="cb6-33"><a href="#cb6-33"></a><span class="dt">int</span> foo<span class="op">()</span> <span class="op">{</span></span>
<span id="cb6-34"><a href="#cb6-34"></a>  <span class="kw">auto</span> t1 <span class="op">=</span> alternative_task<span class="op">&lt;</span>ShouldElideTagT<span class="op">&gt;()</span>;</span>
<span id="cb6-35"><a href="#cb6-35"></a>  <span class="co">// Task::elided would call coroutine_handle::elided</span></span>
<span id="cb6-36"><a href="#cb6-36"></a>  <span class="ot">assert</span> <span class="op">(</span>t1<span class="op">.</span>elided<span class="op">())</span>;</span>
<span id="cb6-37"><a href="#cb6-37"></a>  <span class="kw">auto</span> t2 <span class="op">=</span> alternative_task<span class="op">&lt;</span>NoElideTagT<span class="op">&gt;()</span>;</span>
<span id="cb6-38"><a href="#cb6-38"></a>  <span class="ot">assert</span> <span class="op">(!</span>t1<span class="op">.</span>elided<span class="op">())</span>;</span>
<span id="cb6-39"><a href="#cb6-39"></a>  <span class="co">// The default case, which would be general for most cases</span></span>
<span id="cb6-40"><a href="#cb6-40"></a>  alternative_task<span class="op">()</span>; </span>
<span id="cb6-41"><a href="#cb6-41"></a><span class="op">}</span> </span></code></pre></div>
<p>From the example in <code class="sourceCode default">foo</code>, we could find that we get the ability to control elision at callsite finally! Although it looks tedious to add <code class="sourceCode default">template &lt;ElideTag Tag&gt;</code> alone the way. But I believe the cases that we need to control wouldn’t be too much. We only need to control some of the coroutines in a project.</p>
<h1 data-number="8" id="limitations"><span class="header-section-number">8</span> Limitations<a href="#limitations" class="self-link"></a></h1>
<p>This section describes the limitations of this proposal. It contains 2 situations that we couldn’t elide a coroutine even if the <code class="sourceCode default">promise_type::must_elide</code> evaluates to true at compile time and a situation that is beyond the current elision design.</p>
<h2 data-number="8.1" id="indirect-call"><span class="header-section-number">8.1</span> Indirect Call<a href="#indirect-call" class="self-link"></a></h2>
<p>An indirect call is the call which the compiler couldn’t find the corresponding callee at compile time. The most common indirect call is virtual functions. For example:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a>Class A <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="kw">virtual</span> CoroType CoroFunc<span class="op">()</span> <span class="op">{</span> <span class="co">/*...*/</span> <span class="op">}</span></span>
<span id="cb7-4"><a href="#cb7-4"></a><span class="op">}</span>;</span>
<span id="cb7-5"><a href="#cb7-5"></a><span class="kw">class</span> B <span class="op">:</span> <span class="kw">public</span> A <span class="op">{</span></span>
<span id="cb7-6"><a href="#cb7-6"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb7-7"><a href="#cb7-7"></a>CoroType CoroFunc<span class="op">()</span> <span class="op">{</span> <span class="co">/*...*/</span> <span class="op">}</span></span>
<span id="cb7-8"><a href="#cb7-8"></a><span class="op">}</span>;</span>
<span id="cb7-9"><a href="#cb7-9"></a>CoroType foo<span class="op">(</span>A<span class="op">*</span> a<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-10"><a href="#cb7-10"></a>    <span class="kw">co_await</span> a<span class="op">-&gt;</span>CoroFunc<span class="op">()</span>; <span class="co">// The compiler couldn&#39;t know which function CoroFunc refers to.</span></span>
<span id="cb7-11"><a href="#cb7-11"></a><span class="op">}</span>;</span></code></pre></div>
<p>Another example is function pointers:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb8-1"><a href="#cb8-1"></a>// coro_func is a global variable</span>
<span id="cb8-2"><a href="#cb8-2"></a>std::function&lt;Task()&gt; coro_func;</span>
<span id="cb8-3"><a href="#cb8-3"></a>// ... many operations to fulfill coro_func</span>
<span id="cb8-4"><a href="#cb8-4"></a>// in another function</span>
<span id="cb8-5"><a href="#cb8-5"></a>co_await coro_func(); </span></code></pre></div>
<p>Although we could see from the signature the function that <code class="sourceCode default">coro_func</code> refers to should elide all the way. But the compiler couldn’t elide it actually since it can’t know the coroutine <code class="sourceCode default">coro_func</code> refers to usually. The compiler couldn’t know if <code class="sourceCode default">coro_func</code> refers to a coroutine actually. And the compiler couldn’t do too much even if we could use any hack possible.</p>
<p>The internal reason is that the compiler needs to know how many bits we need to allocate the coroutine status if we want to elide a coroutine. And the compiler couldn’t infer that if it couldn’t see the body of the coroutine.</p>
<h2 data-number="8.2" id="elision-cross-translation-unit"><span class="header-section-number">8.2</span> Elision cross translation unit<a href="#elision-cross-translation-unit" class="self-link"></a></h2>
<p>Another issue is that we couldn’t elide a coroutine into a function in another translation unit. For example:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a><span class="co">// CoroType.h</span></span>
<span id="cb9-2"><a href="#cb9-2"></a>AlwaysElideTask may_be_a_coroutine<span class="op">()</span>;      <span class="co">// We couldn&#39;t see if this is a coroutine</span></span>
<span id="cb9-3"><a href="#cb9-3"></a>                                           <span class="co">// from the signature.</span></span>
<span id="cb9-4"><a href="#cb9-4"></a><span class="co">// A.cpp</span></span>
<span id="cb9-5"><a href="#cb9-5"></a>AlwaysElideTask may_be_a_coroutine<span class="op">()</span> <span class="op">{</span>     <span class="co">// It is a coroutine indeed.</span></span>
<span id="cb9-6"><a href="#cb9-6"></a>  <span class="kw">co_await</span> std<span class="op">::</span>suspend_always<span class="op">{}</span>;</span>
<span id="cb9-7"><a href="#cb9-7"></a>  <span class="co">// ... Other works needed.</span></span>
<span id="cb9-8"><a href="#cb9-8"></a><span class="op">}</span></span>
<span id="cb9-9"><a href="#cb9-9"></a><span class="co">// B.cpp</span></span>
<span id="cb9-10"><a href="#cb9-10"></a>AlwaysElideTask CoroA<span class="op">()</span> <span class="op">{</span></span>
<span id="cb9-11"><a href="#cb9-11"></a>  <span class="kw">co_return</span> <span class="kw">co_await</span> may_be_a_coroutine<span class="op">()</span>; <span class="co">// Is it a coroutine?</span></span>
<span id="cb9-12"><a href="#cb9-12"></a><span class="op">}</span></span></code></pre></div>
<p>The reason why the compiler couldn’t elide it is similar to the above question. If the compiler couldn’t know the callee, it couldn’t do optimization.</p>
<p>From the perspective of a compiler, this issue is potentially solvable by enabling LTO (Link Time Optimization). In LTO, the compiler could see every translation unit. But since we are talking about the language standard. I feel like that is not possible that we could add the concept LTO in the standard nor we could change the compilation model.</p>
<h2 data-number="8.3" id="use-out-of-the-scope-of-definition"><span class="header-section-number">8.3</span> Use out of the scope of definition<a href="#use-out-of-the-scope-of-definition" class="self-link"></a></h2>
<p>There is an example above to address the problem:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a>Task&lt;<span class="dt">int</span>&gt; example2(<span class="dt">int</span> task_count) {</span>
<span id="cb9-2"><a href="#cb9-2"></a>  <span class="bu">std::</span>vector&lt;ElidedTask&lt;<span class="dt">int</span>&gt;&gt; tasks;</span>
<span id="cb9-3"><a href="#cb9-3"></a>  <span class="cf">for</span> (<span class="dt">int</span> i = <span class="dv">0</span>; i &lt; task_count; i++)</span>
<span id="cb9-4"><a href="#cb9-4"></a>    tasks.empalce_back(coro_task());</span>
<span id="cb9-5"><a href="#cb9-5"></a>    </span>
<span id="cb9-6"><a href="#cb9-6"></a>  <span class="co">// the semantics of whenAll is that it would</span></span>
<span id="cb9-7"><a href="#cb9-7"></a>  <span class="co">// complete after all the tasks completed.</span></span>
<span id="cb9-8"><a href="#cb9-8"></a>  <span class="kw">co_return</span> <span class="kw">co_await</span> whenAll(<span class="bu">std::</span>move(tasks));</span>
<span id="cb9-9"><a href="#cb9-9"></a>}</span></code></pre></div>
<p>We shouldn’t make <code class="sourceCode default">coro_task()</code> to elide since it would be problematic when we use <code class="sourceCode default">tasks</code>. The reason behind this is that the storage lifetime of elided coroutine would end at the enclosing braces, but it is possible to use after the lifetime ends!</p>
<p>This is unsolvable in the current design. Since the compiler needs to know the stack frame size for each function statically at compile time. But the compiler couldn’t know the value of <code class="sourceCode default">task_count</code> at compile time, so the compiler won’t know the space needed for the function.</p>
<h2 data-number="8.4" id="summary"><span class="header-section-number">8.4</span> Summary<a href="#summary" class="self-link"></a></h2>
<p>The two limitations here exist since the compiler needs to know the callee at compile time. And another limitation exists since the compiler need to know the frame size statically. I think all three are unable to solve.</p>
<p>For the last limitation, I think it is OK to leave it in the future to resolve (if possible). And for the other limitations, I think there are two methods: - Make the program ill-formed once the compiler found the situations. - Define that the <code class="sourceCode default">must_elide</code> doesn’t work for virtual functions and functions in another translation unit explicitly.</p>
<p>I think the latter is better. Although it is constrained, the semantics are well-defined.</p>
<h1 data-number="9" id="implementation"><span class="header-section-number">9</span> Implementation<a href="#implementation" class="self-link"></a></h1>
<p>An implementation could be found here: <a href="https://github.com/ChuanqiXu9/llvm-project/tree/CoroMustElide">CoroMustElide</a>.</p>
<h2 data-number="9.1" id="current-implementation-issue"><span class="header-section-number">9.1</span> Current Implementation issue<a href="#current-implementation-issue" class="self-link"></a></h2>
<p>An issue in the current implementation is that: it could work only if we turned optimization on. In other words, if we define this in the specification, it should work correctly under O0.</p>
<p>The reason is the internal pass ordering problem in the compiler. I definitely believe it could be solved if we get in consensus on this proposal.</p>
<h2 data-number="9.2" id="implementation-in-gcc"><span class="header-section-number">9.2</span> Implementation in GCC<a href="#implementation-in-gcc" class="self-link"></a></h2>
<p>Mathias Stearn points out that there is no coroutine elision optimization in GCC now. So it would be harder to implement this proposal in GCC since it would require GCC to implement coroutine elision first.</p>
<h1 data-number="10" id="qa"><span class="header-section-number">10</span> Q&amp;A<a href="#qa" class="self-link"></a></h1>
<p>This section includes the questions had been asked and the corresponding answer.</p>
<h2 data-number="10.1" id="how-does-the-compiler-guarantee-coroutine-elision-if-must_elide-evaluates-to-true-at-constexpr-time"><span class="header-section-number">10.1</span> How does the compiler guarantee coroutine elision if must_elide evaluates to true at constexpr time<a href="#how-does-the-compiler-guarantee-coroutine-elision-if-must_elide-evaluates-to-true-at-constexpr-time" class="self-link"></a></h2>
<p>Here talks about the case of clang only. Since the question was raised because clang handles coroutine in two parts, the frontend part and the middle end part. But I think this wouldn’t be a problem for GCC since GCC handles coroutine in the frontend.</p>
<p>Simply, the frontend would pass specified information to the middle end after parsing source codes. So when the frontend sees the value of <code class="sourceCode default">promise_type::must_elide</code> evaluates to true or false, the frontend would pass a special marker to the middle end to inform that the coroutine should be elided or not.</p>
<p>Due to that coroutine elision depends on inlining now. So in the case, the middle end sees an <code class="sourceCode default">always-elide</code> marker, it would mark the ramp function as <code class="sourceCode default">always_inline</code> to ensure it could be inlined as expected.</p>
<h2 data-number="10.2" id="is-elided-a-constexpr-function"><span class="header-section-number">10.2</span> Is elided() a constexpr function?<a href="#is-elided-a-constexpr-function" class="self-link"></a></h2>
<p>No, although it looks like a constexpr function. Even its result isn’t a compile time constant. This doesn’t make much sense. Since we could know that the elision is done at compile time. So it is natural that whether or not a coroutine is elided at runtime. But the point here is that we couldn’t associate any coroutine_hadle with a coroutine at compile time. For example:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a>__attribute__<span class="op">((</span>noinline<span class="op">))</span></span>
<span id="cb10-2"><a href="#cb10-2"></a><span class="dt">bool</span> IsElided<span class="op">(</span>coroutine_handle<span class="op">&lt;&gt;</span> handle<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3"></a>  <span class="cf">return</span> handle<span class="op">.</span>elided<span class="op">()</span>;</span>
<span id="cb10-4"><a href="#cb10-4"></a><span class="op">}</span></span></code></pre></div>
<p>The compiler couldn’t connect the handle with a coroutine clearly. So it must read information somewhere.</p>
<h2 data-number="10.3" id="does-the-semantics-of-guaranteed-copy-elision-matter"><span class="header-section-number">10.3</span> Does the semantics of guaranteed copy-elision matter?<a href="#does-the-semantics-of-guaranteed-copy-elision-matter" class="self-link"></a></h2>
<p>Here is an example:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2"></a>ElidedTask<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span> foo_impl<span class="op">(</span>Args<span class="op">...</span> args<span class="op">)</span> <span class="op">{</span> <span class="kw">co_await</span> whatever<span class="op">()</span>; <span class="op">...</span> <span class="op">}</span></span>
<span id="cb11-3"><a href="#cb11-3"></a></span>
<span id="cb11-4"><a href="#cb11-4"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb11-5"><a href="#cb11-5"></a>ElidedTask<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span> foo<span class="op">(</span>std<span class="op">::</span>tuple<span class="op">&lt;</span>Args<span class="op">&gt;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-6"><a href="#cb11-6"></a>  <span class="kw">co_await</span> std<span class="op">::</span>apply<span class="op">([](</span>Args<span class="op">&amp;...</span> args<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> foo_impl<span class="op">(</span>args<span class="op">...)</span>; <span class="op">}</span>, t<span class="op">)</span>;</span>
<span id="cb11-7"><a href="#cb11-7"></a><span class="op">}</span></span></code></pre></div>
<p>Due to the guaranteed copy-elision, the return value of foo_impl should be constructed directly at the lambda in <code class="sourceCode default">std::apply</code>. Then the question is: how about the coroutine frame? Where does its lifetime end? Is the code above good? Does it violate the rule guaranteed copy-elision?</p>
<p>First, for the current language specification, coroutine elision should be irrelevant to copy-elision. Since coroutine elision is talk about whether or not to allocate a coroutine status. And copy-elision talks about where we should construct an object.</p>
<p>The key point here is that an object would never be a coroutine status and coroutine status would never be an object. The object could have pointers that points to the coroutine status. And the coroutine status is a special instance created by the compiler in the middle end. So copy elision wouldn’t affect coroutine elision. Now let’s back to the above example and see what would happen.</p>
<p>So <code class="sourceCode default">foo(int)</code> would be elided into foo(). But it doesn’t matter with bar(). So the coroutine status of <code class="sourceCode default">foo(int)</code> would become a local variable to the <code class="sourceCode default">foo()</code>. And if <code class="sourceCode default">foo()</code> exits, the coroutine status is released. And when we co_await foo() in bar, it would try to resume the coroutine <code class="sourceCode default">foo(int)</code> but the coroutine status is released. And it would crash generally (Or an undefined behavior).</p>
<p>People may argue that this is not same with the intuition. But I think the overall behavior is well-defined except what would happen finally is undefined behavior. BTW, the behavior wouldn’t change if foo() would be inlined into bar().</p>
<p>So simply the above example is not good. We couldn’t mark the return type for <code class="sourceCode default">foo_impl</code> as <code class="sourceCode default">ElidedTask&lt;void&gt;</code>.</p>
<h1 data-number="11" id="conclusion"><span class="header-section-number">11</span> Conclusion<a href="#conclusion" class="self-link"></a></h1>
<p>This proposal proposes two components to coroutine. One called <code class="sourceCode default">must_elide</code> allows the user to control the coroutine elision which is impossible before. One called <code class="sourceCode default">elided</code> allows the user to observe the coroutine elision. For <code class="sourceCode default">must_elide</code>, it gives the rights to user but also the risks. But it is an alternative, user who don’t want to pay the risk could avoid to use it and nothing would change. But there are still situations <code class="sourceCode default">must_elide</code> handle, we could only define the condition clearly in the standard. But after all, the situation is much better. For <code class="sourceCode default">elided</code>, it would require another bit in coroutine frame and an additional store instruction at runtime. And the use cases we found now are in tests only. We need more discussion to make a decision.</p>
</div>
</div>
</body>
</html>
