<html><head>
    <title>P2014R2: Proposed resolution for US061+US063 - aligned allocation of coroutine frames</title>
    <meta content="text/html; charset=UTF-8" http-equiv="content-type"><style type="text/css">.lst-kix_w8u4e98an00u-3>li:before{content:"\0025cf  "}.lst-kix_mkcfyz15qrg4-5>li:before{content:"\0025a0  "}.lst-kix_mkcfyz15qrg4-6>li:before{content:"\0025cf  "}.lst-kix_w8u4e98an00u-2>li:before{content:"\0025a0  "}.lst-kix_w8u4e98an00u-4>li:before{content:"\0025cb  "}.lst-kix_w8u4e98an00u-1>li:before{content:"\0025cb  "}.lst-kix_w8u4e98an00u-5>li:before{content:"\0025a0  "}ul.lst-kix_w8u4e98an00u-6{list-style-type:none}ul.lst-kix_w8u4e98an00u-5{list-style-type:none}.lst-kix_mkcfyz15qrg4-3>li:before{content:"\0025cf  "}.lst-kix_mkcfyz15qrg4-7>li:before{content:"\0025cb  "}ul.lst-kix_w8u4e98an00u-8{list-style-type:none}ul.lst-kix_w8u4e98an00u-7{list-style-type:none}ul.lst-kix_w8u4e98an00u-2{list-style-type:none}ul.lst-kix_w8u4e98an00u-1{list-style-type:none}ul.lst-kix_w8u4e98an00u-4{list-style-type:none}ul.lst-kix_w8u4e98an00u-3{list-style-type:none}.lst-kix_mkcfyz15qrg4-4>li:before{content:"\0025cb  "}ul.lst-kix_w8u4e98an00u-0{list-style-type:none}.lst-kix_w8u4e98an00u-0>li:before{content:"\0025cf  "}.lst-kix_mkcfyz15qrg4-8>li:before{content:"\0025a0  "}.lst-kix_hwhcrsn1mpsp-2>li:before{content:"\0025a0  "}.lst-kix_hwhcrsn1mpsp-3>li:before{content:"\0025cf  "}.lst-kix_hwhcrsn1mpsp-4>li:before{content:"\0025cb  "}.lst-kix_w8u4e98an00u-7>li:before{content:"\0025cb  "}.lst-kix_w8u4e98an00u-6>li:before{content:"\0025cf  "}.lst-kix_w8u4e98an00u-8>li:before{content:"\0025a0  "}.lst-kix_hwhcrsn1mpsp-5>li:before{content:"\0025a0  "}.lst-kix_hwhcrsn1mpsp-7>li:before{content:"\0025cb  "}.lst-kix_hwhcrsn1mpsp-6>li:before{content:"\0025cf  "}.lst-kix_im5jkoids01l-7>li:before{content:"\0025cb  "}.lst-kix_im5jkoids01l-6>li:before{content:"\0025cf  "}.lst-kix_im5jkoids01l-8>li:before{content:"\0025a0  "}.lst-kix_7ii1gkby2gax-1>li:before{content:"\0025cb  "}.lst-kix_7ii1gkby2gax-3>li:before{content:"\0025cf  "}.lst-kix_ok2ok8u5e296-7>li:before{content:"\0025cb  "}.lst-kix_im5jkoids01l-5>li:before{content:"\0025a0  "}.lst-kix_ok2ok8u5e296-6>li:before{content:"\0025cf  "}.lst-kix_7ii1gkby2gax-2>li:before{content:"\0025a0  "}.lst-kix_hwhcrsn1mpsp-8>li:before{content:"\0025a0  "}ul.lst-kix_im5jkoids01l-6{list-style-type:none}ul.lst-kix_im5jkoids01l-5{list-style-type:none}ul.lst-kix_im5jkoids01l-8{list-style-type:none}ul.lst-kix_im5jkoids01l-7{list-style-type:none}.lst-kix_7ii1gkby2gax-5>li:before{content:"\0025a0  "}ul.lst-kix_im5jkoids01l-2{list-style-type:none}ul.lst-kix_im5jkoids01l-1{list-style-type:none}.lst-kix_ok2ok8u5e296-8>li:before{content:"\0025a0  "}ul.lst-kix_im5jkoids01l-4{list-style-type:none}ul.lst-kix_im5jkoids01l-3{list-style-type:none}.lst-kix_7ii1gkby2gax-4>li:before{content:"\0025cb  "}ul.lst-kix_im5jkoids01l-0{list-style-type:none}.lst-kix_bihn80uvctfn-8>li:before{content:"\0025a0  "}.lst-kix_7ii1gkby2gax-0>li:before{content:"\0025cf  "}ul.lst-kix_9q1ypfu9szbg-1{list-style-type:none}ul.lst-kix_9q1ypfu9szbg-2{list-style-type:none}ul.lst-kix_9q1ypfu9szbg-0{list-style-type:none}ul.lst-kix_9q1ypfu9szbg-7{list-style-type:none}ul.lst-kix_9q1ypfu9szbg-8{list-style-type:none}ul.lst-kix_9q1ypfu9szbg-5{list-style-type:none}ul.lst-kix_9q1ypfu9szbg-6{list-style-type:none}.lst-kix_ok2ok8u5e296-0>li:before{content:"\0025cf  "}ul.lst-kix_9q1ypfu9szbg-3{list-style-type:none}ul.lst-kix_9q1ypfu9szbg-4{list-style-type:none}.lst-kix_ok2ok8u5e296-1>li:before{content:"\0025cb  "}.lst-kix_im5jkoids01l-0>li:before{content:"\0025cf  "}.lst-kix_ok2ok8u5e296-3>li:before{content:"\0025cf  "}.lst-kix_im5jkoids01l-1>li:before{content:"\0025cb  "}.lst-kix_ok2ok8u5e296-2>li:before{content:"\0025a0  "}.lst-kix_7ii1gkby2gax-6>li:before{content:"\0025cf  "}.lst-kix_ok2ok8u5e296-5>li:before{content:"\0025a0  "}.lst-kix_im5jkoids01l-3>li:before{content:"\0025cf  "}.lst-kix_im5jkoids01l-2>li:before{content:"\0025a0  "}.lst-kix_im5jkoids01l-4>li:before{content:"\0025cb  "}.lst-kix_7ii1gkby2gax-7>li:before{content:"\0025cb  "}.lst-kix_ok2ok8u5e296-4>li:before{content:"\0025cb  "}.lst-kix_7ii1gkby2gax-8>li:before{content:"\0025a0  "}.lst-kix_n3gxb73xbd6z-8>li:before{content:"\0025a0  "}.lst-kix_n3gxb73xbd6z-5>li:before{content:"\0025a0  "}.lst-kix_n3gxb73xbd6z-7>li:before{content:"\0025cb  "}.lst-kix_n3gxb73xbd6z-6>li:before{content:"\0025cf  "}ul.lst-kix_mkcfyz15qrg4-2{list-style-type:none}ul.lst-kix_mkcfyz15qrg4-1{list-style-type:none}ul.lst-kix_mkcfyz15qrg4-4{list-style-type:none}ul.lst-kix_mkcfyz15qrg4-3{list-style-type:none}ul.lst-kix_mkcfyz15qrg4-0{list-style-type:none}ul.lst-kix_7ii1gkby2gax-8{list-style-type:none}ul.lst-kix_7ii1gkby2gax-7{list-style-type:none}ul.lst-kix_7ii1gkby2gax-6{list-style-type:none}ul.lst-kix_7ii1gkby2gax-5{list-style-type:none}ul.lst-kix_7ii1gkby2gax-4{list-style-type:none}ul.lst-kix_mkcfyz15qrg4-6{list-style-type:none}ul.lst-kix_7ii1gkby2gax-3{list-style-type:none}ul.lst-kix_mkcfyz15qrg4-5{list-style-type:none}ul.lst-kix_7ii1gkby2gax-2{list-style-type:none}ul.lst-kix_mkcfyz15qrg4-8{list-style-type:none}ul.lst-kix_7ii1gkby2gax-1{list-style-type:none}ul.lst-kix_mkcfyz15qrg4-7{list-style-type:none}ul.lst-kix_7ii1gkby2gax-0{list-style-type:none}.lst-kix_bihn80uvctfn-3>li:before{content:"\0025cf  "}.lst-kix_bihn80uvctfn-5>li:before{content:"\0025a0  "}.lst-kix_bihn80uvctfn-0>li:before{content:"\0025cf  "}.lst-kix_bihn80uvctfn-4>li:before{content:"\0025cb  "}.lst-kix_bihn80uvctfn-7>li:before{content:"\0025cb  "}ul.lst-kix_hwhcrsn1mpsp-2{list-style-type:none}ul.lst-kix_hwhcrsn1mpsp-1{list-style-type:none}.lst-kix_bihn80uvctfn-6>li:before{content:"\0025cf  "}ul.lst-kix_hwhcrsn1mpsp-0{list-style-type:none}ul.lst-kix_hwhcrsn1mpsp-6{list-style-type:none}ul.lst-kix_hwhcrsn1mpsp-5{list-style-type:none}ul.lst-kix_hwhcrsn1mpsp-4{list-style-type:none}.lst-kix_n3gxb73xbd6z-1>li:before{content:"\0025cb  "}.lst-kix_n3gxb73xbd6z-3>li:before{content:"\0025cf  "}ul.lst-kix_hwhcrsn1mpsp-3{list-style-type:none}ul.lst-kix_hwhcrsn1mpsp-8{list-style-type:none}.lst-kix_n3gxb73xbd6z-0>li:before{content:"\0025cf  "}.lst-kix_n3gxb73xbd6z-4>li:before{content:"\0025cb  "}ul.lst-kix_hwhcrsn1mpsp-7{list-style-type:none}ul.lst-kix_bihn80uvctfn-1{list-style-type:none}ul.lst-kix_bihn80uvctfn-0{list-style-type:none}.lst-kix_bihn80uvctfn-1>li:before{content:"\0025cb  "}.lst-kix_bihn80uvctfn-2>li:before{content:"\0025a0  "}.lst-kix_n3gxb73xbd6z-2>li:before{content:"\0025a0  "}.lst-kix_9q1ypfu9szbg-8>li:before{content:"\0025a0  "}ul.lst-kix_bihn80uvctfn-7{list-style-type:none}ul.lst-kix_bihn80uvctfn-6{list-style-type:none}ul.lst-kix_bihn80uvctfn-8{list-style-type:none}.lst-kix_9q1ypfu9szbg-6>li:before{content:"\0025cf  "}ul.lst-kix_bihn80uvctfn-3{list-style-type:none}ul.lst-kix_bihn80uvctfn-2{list-style-type:none}.lst-kix_9q1ypfu9szbg-7>li:before{content:"\0025cb  "}ul.lst-kix_bihn80uvctfn-5{list-style-type:none}ul.lst-kix_bihn80uvctfn-4{list-style-type:none}.lst-kix_9q1ypfu9szbg-4>li:before{content:"\0025cb  "}.lst-kix_9q1ypfu9szbg-5>li:before{content:"\0025a0  "}.lst-kix_9q1ypfu9szbg-0>li:before{content:"\0025cf  "}.lst-kix_hwhcrsn1mpsp-1>li:before{content:"\0025cb  "}.lst-kix_9q1ypfu9szbg-2>li:before{content:"\0025a0  "}ul.lst-kix_n3gxb73xbd6z-2{list-style-type:none}ul.lst-kix_n3gxb73xbd6z-1{list-style-type:none}.lst-kix_9q1ypfu9szbg-3>li:before{content:"\0025cf  "}ul.lst-kix_n3gxb73xbd6z-0{list-style-type:none}.lst-kix_hwhcrsn1mpsp-0>li:before{content:"\0025cf  "}ul.lst-kix_n3gxb73xbd6z-6{list-style-type:none}ul.lst-kix_n3gxb73xbd6z-5{list-style-type:none}ul.lst-kix_n3gxb73xbd6z-4{list-style-type:none}ul.lst-kix_n3gxb73xbd6z-3{list-style-type:none}.lst-kix_9q1ypfu9szbg-1>li:before{content:"\0025cb  "}ul.lst-kix_n3gxb73xbd6z-8{list-style-type:none}ul.lst-kix_n3gxb73xbd6z-7{list-style-type:none}ul.lst-kix_ok2ok8u5e296-6{list-style-type:none}ul.lst-kix_ok2ok8u5e296-5{list-style-type:none}ul.lst-kix_ok2ok8u5e296-8{list-style-type:none}ul.lst-kix_ok2ok8u5e296-7{list-style-type:none}ul.lst-kix_ok2ok8u5e296-2{list-style-type:none}ul.lst-kix_ok2ok8u5e296-1{list-style-type:none}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}ul.lst-kix_ok2ok8u5e296-4{list-style-type:none}ul.lst-kix_ok2ok8u5e296-3{list-style-type:none}ul.lst-kix_ok2ok8u5e296-0{list-style-type:none}.lst-kix_mkcfyz15qrg4-1>li:before{content:"\0025cb  "}.lst-kix_mkcfyz15qrg4-2>li:before{content:"\0025a0  "}.lst-kix_mkcfyz15qrg4-0>li:before{content:"\0025cf  "}ol{margin:0;padding:0}table td,table th{padding:0}.c46{border-right-style:solid;padding-top:0pt;border-top-width:0pt;border-right-width:0pt;padding-left:0pt;padding-bottom:12pt;line-height:1.38;border-left-width:0pt;border-top-style:solid;border-left-style:solid;border-bottom-width:0pt;border-bottom-style:solid;orphans:2;widows:2;text-align:left;padding-right:0pt}.c31{border-right-style:solid;padding:2pt 2pt 2pt 2pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:55.5pt;border-top-color:#000000;border-bottom-style:solid}.c42{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:43.1pt;border-top-color:#000000;border-bottom-style:solid}.c37{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:44.2pt;border-top-color:#000000;border-bottom-style:solid}.c15{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:49.6pt;border-top-color:#000000;border-bottom-style:solid}.c24{border-right-style:solid;padding:2pt 2pt 2pt 2pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:150pt;border-top-color:#000000;border-bottom-style:solid}.c39{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:48.5pt;border-top-color:#000000;border-bottom-style:solid}.c29{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:45.3pt;border-top-color:#000000;border-bottom-style:solid}.c32{margin-left:45pt;padding-top:0pt;padding-left:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left}.c8{margin-left:36pt;padding-top:0pt;padding-left:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left}.c30{color:#434343;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:14pt;font-family:"Arial";font-style:normal}.c11{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.c5{margin-left:18pt;padding-top:0pt;padding-bottom:0pt;line-height:1.38;orphans:2;widows:2;text-align:left}.c10{padding-top:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left;height:11pt}.c13{color:#24292e;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:10.5pt;font-family:"Arial";font-style:normal}.c3{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:8pt;font-family:"Arial";font-style:normal}.c12{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:16pt;font-family:"Arial";font-style:normal}.c7{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:10pt;font-family:"Courier New";font-style:normal}.c23{padding-top:0pt;padding-bottom:0pt;line-height:1.2;orphans:2;widows:2;text-align:left}.c2{padding-top:18pt;padding-bottom:6pt;line-height:1.38;orphans:2;widows:2;text-align:left}.c6{padding-top:0pt;padding-bottom:0pt;line-height:1.38;orphans:2;widows:2;text-align:left}.c18{font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.c34{padding-top:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left}.c41{padding-top:20pt;padding-bottom:6pt;line-height:1.38;orphans:2;widows:2;text-align:left}.c44{font-weight:400;text-decoration:none;vertical-align:baseline;font-size:19pt;font-family:"Arial";font-style:normal}.c14{padding-top:16pt;padding-bottom:4pt;line-height:1.38;orphans:2;widows:2;text-align:left}.c0{border-spacing:0;border-collapse:collapse;margin-right:auto}.c22{text-decoration:none;vertical-align:baseline;font-size:11pt;font-style:normal}.c36{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.c28{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.c25{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#ff0000;text-decoration:line-through}.c45{border-spacing:0;border-collapse:collapse;margin-right:auto}.c33{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.c17{padding:0;margin:0}.c9{font-family:"Courier New";font-weight:400}.c40{color:inherit;text-decoration:inherit}.c43{font-size:10.5pt;color:#24292e}.c26{color:#000000}.c20{font-style:italic}.c1{height:22.6pt}.c38{height:15pt}.c35{background-color:#ffffff}.c21{height:24pt}.c27{height:11pt}.c16{margin-left:36pt}.c4{color:#57d157}.c19{font-size:8pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.15;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c33 doc-content"><p class="c10"><span class="c11"></span></p><a id="t.3dbff851de6f9bd00f37fb103b295d548d6d1856"></a><a id="t.0"></a><table class="c0"><tr class="c38"><td class="c31" colspan="1" rowspan="1"><p class="c23"><span class="c3">Document</span></p></td><td class="c24" colspan="1" rowspan="1"><p class="c23"><span class="c3">P2014R2</span></p></td></tr><tr class="c38"><td class="c31" colspan="1" rowspan="1"><p class="c23"><span class="c3">Date</span></p></td><td class="c24" colspan="1" rowspan="1"><p class="c23"><span class="c3">2023-02-08</span></p></td></tr><tr class="c21"><td class="c31" colspan="1" rowspan="1"><p class="c23"><span class="c3">Reply To</span></p></td><td class="c24" colspan="1" rowspan="1"><p class="c23"><span class="c19">Lewis Baker &lt;</span><span class="c36 c19">lewissbaker@gmail.com</span><span class="c3">&gt;,</span></p><p class="c23"><span class="c19">Gor Nishanov &lt;</span><span class="c19 c36">gorn@microsoft.com</span><span class="c3">&gt;</span></p></td></tr><tr class="c38"><td class="c31" colspan="1" rowspan="1"><p class="c23"><span class="c3">Audience</span></p></td><td class="c24" colspan="1" rowspan="1"><p class="c23"><span class="c3">CWG</span></p></td></tr><tr class="c38"><td class="c31" colspan="1" rowspan="1"><p class="c23"><span class="c3">Target</span></p></td><td class="c24" colspan="1" rowspan="1"><p class="c23"><span class="c3">C++26</span></p></td></tr></table><h1 class="c41" id="h.f7hubs6d20l3"><span class="c26 c44">Proposed resolution for US061+US063 - aligned allocation of coroutine frames</span></h1><p class="c34"><span class="c11">This paper contains the proposed resolution to NB comments US06 and US063 raised during C++20, which requested the addition of support for align_val_t overloads of operator new() when the compiler needs to allocate storage for the coroutine state.</span></p><p class="c10"><span class="c11"></span></p><p class="c34"><span class="c11">R0 of this paper contained 2 proposed options for the design of this behaviour.</span></p><p class="c10"><span class="c11"></span></p><p class="c34"><span class="c11">R1 added a third option, but this was not published in a mailing at the time.</span></p><p class="c10"><span class="c11"></span></p><p class="c34"><span class="c11">R2 updates the paper to indicate the preference of EWG for to adopt the behaviour descripted in option 1, based on the vote in Kona 2022.</span></p><p class="c10"><span class="c11"></span></p><p class="c34"><span class="c20">Forward Option 1 from P2014R0 (Prefer align_val_t overload only if overaligned) to CWG for inclusion in C++26.</span></p><a id="t.4722b3a82067094388726a770c58faf3016964e2"></a><a id="t.1"></a><table class="c16 c45"><tr class="c1"><td class="c37" colspan="1" rowspan="1"><p class="c28"><span class="c11">SF</span></p></td><td class="c29" colspan="1" rowspan="1"><p class="c28"><span class="c11">F</span></p></td><td class="c42" colspan="1" rowspan="1"><p class="c28"><span class="c11">N</span></p></td><td class="c39" colspan="1" rowspan="1"><p class="c28"><span class="c11">A</span></p></td><td class="c15" colspan="1" rowspan="1"><p class="c28"><span class="c11">SA</span></p></td></tr><tr class="c1"><td class="c37" colspan="1" rowspan="1"><p class="c28"><span class="c11">4</span></p></td><td class="c29" colspan="1" rowspan="1"><p class="c28"><span class="c11">12</span></p></td><td class="c42" colspan="1" rowspan="1"><p class="c28"><span class="c11">1</span></p></td><td class="c39" colspan="1" rowspan="1"><p class="c28"><span class="c11">0</span></p></td><td class="c15" colspan="1" rowspan="1"><p class="c28"><span class="c11">0</span></p></td></tr></table><p class="c10 c16"><span class="c11"></span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span>The selected option</span><span>&nbsp;for the proposed wording attempts to maintain behaviour consistent with [expr.new] and [expr.delete] with regards to only preferring </span><span class="c9">std::align_val_t</span><span class="c11">&nbsp;overloads when the storage to be allocated has new-extended alignment. This results in a more complicated set of rules for lookup, including needing to perform two lookups and then delaying the choice of which one to call until later in the compilation phases when the coroutine-frame layout requirements are known.</span></p><h2 class="c2" id="h.xhrj56fngjfm"><span class="c12">US061</span></h2><p class="c35 c46"><span class="c43">Coroutine allocation does not consider </span><span class="c9 c43">std::align_val_t</span><span class="c13">&nbsp;overloads introduced in C++17</span></p><p class="c6 c35"><span class="c13">Proposed change:</span></p><p class="c6 c35"><span class="c13">Add them to the sequence of operator new calls that are attempted using wording similar to 7.6.2.7/18</span></p><h2 class="c2" id="h.3z43pz111la3"><span class="c12">US063</span></h2><p class="c6"><span>The construction of the argument list for the call to the allocation function to allocate the &#39;coroutine state&#39; does not call the overload of </span><span class="c9">operator new()</span><span>&nbsp;that accepts a </span><span class="c9">std::align_val_t</span><span class="c11">&nbsp;in the case that the allocation required for the coroutine has &#39;new-extended alignment&#39;. This means that allocations of coroutine frames may not be correctly aligned in cases where the coroutine state contains overaligned types.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Proposed change:</span></p><p class="c6"><span class="c11">Apply similar wording from [expr.new]p18:</span></p><p class="c6"><span class="c11">Insert &quot;If the coroutine state has new-extended alignment then the next argument is std::align_val_t.&quot; after &quot;has type size_t.&quot;</span></p><p class="c6 c27"><span class="c11"></span></p><p class="c6"><span class="c11">Insert at end of paragraph:</span></p><p class="c6"><span class="c11">If no matching function is found and the allocated coroutine state has new-extended alignment, the alignment argument is removed from the argument list, and overload resolution is performed again.</span></p><h2 class="c2" id="h.89ticxebztlg"><span>Current wording (</span><span class="c36"><a class="c40" href="https://www.google.com/url?q=https://wg21.link/N4835&amp;sa=D&amp;source=editors&amp;ust=1675896829640906&amp;usg=AOvVaw2BTD3f6KgJJWOF0yJ59pc_">N4835</a></span><span class="c12">):</span></h2><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">[dcl.fct.def.coroutine] p9</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">An implementation may need to allocate additional storage for a coroutine. This storage is known as the coroutine state and is obtained by calling a non-array allocation function (6.7.5.4.1). The allocation function&rsquo;s name is looked up in the scope of the promise type. If this lookup fails, the allocation function&rsquo;s name is looked up in the global scope. If the lookup finds an allocation function in the scope of the promise type, overload resolution is performed on a function call created by assembling an argument list. The first argument is the amount of space requested, and has type std::size_t. The lvalues p1 . . . pn are the succeeding arguments. If no viable function is found (12.4.2), overload resolution is performed again on a function call created by passing just the amount of space required as an argument of type std::size_t.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">[dcl.fct.def.coroutine] p12</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">The deallocation function&rsquo;s name is looked up in the scope of the promise type. If this lookup fails, the deallocation function&rsquo;s name is looked up in the global scope. If deallocation function lookup finds both a usual deallocation function with only a pointer parameter and a usual deallocation function with both a pointer parameter and a size parameter, then the selected deallocation function shall be the one with two parameters. Otherwise, the selected deallocation function shall be the function with one parameter. If no usual deallocation function is found, the program is ill-formed. The selected deallocation function shall be called with the address of the block of storage to be reclaimed as its first argument. If a deallocation function with a parameter of type std::size_t is used, the size of the block is passed as the corresponding argument.</span></p><p class="c10"><span class="c11"></span></p><h3 class="c14" id="h.j2zn7kydx4tg"><span class="c30">Reference (other related sections)</span></h3><p class="c6"><span class="c11">[expr.new] p18</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Overload resolution is performed on a function call created by assembling an argument list. The first argument is the amount of space requested, and has type std::size_t. If the type of the allocated object has new-extended alignment, the next argument is the type&rsquo;s alignment, and has type std::align_val_t. If the new-placement syntax is used, the initializer-clauses in its expression-list are the succeeding arguments. If no matching function is found and the allocated object type has new-extended alignment, the alignment argument is removed from the argument list, and overload resolution is performed again.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">[basic.stc.dynamic.deallocation] p3</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Each deallocation function shall return void. If the function is a destroying operator delete declared in class type C, the type of its first parameter shall be C*; otherwise, the type of its first parameter shall be void*. A deallocation function may have more than one parameter. A usual deallocation function is a deallocation function whose parameters after the first are</span></p><ul class="c17 lst-kix_bihn80uvctfn-0 start"><li class="c8 li-bullet-0"><span class="c11">optionally, a parameter of type std::destroying_delete_t, then</span></li><li class="c8 li-bullet-0"><span class="c11">optionally, a parameter of type std::size_t, then</span></li><li class="c8 li-bullet-0"><span class="c11">optionally, a parameter of type std::align_val_t.</span></li></ul><p class="c6"><span class="c11">A destroying operator delete shall be a usual deallocation function. A deallocation function may be an instance of a function template. Neither the first parameter nor the return type shall depend on a template parameter. A deallocation function template shall have two or more function parameters. A template instance is never a usual deallocation function, regardless of its signature.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">[expr.delete] p10</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">If deallocation function lookup finds more than one usual deallocation function, the function to be called is selected as follows:</span></p><ul class="c17 lst-kix_n3gxb73xbd6z-0 start"><li class="c8 li-bullet-0"><span class="c11">If any of the deallocation functions is a destroying operator delete, all deallocation functions that are not destroying operator deletes are eliminated from further consideration.</span></li><li class="c8 li-bullet-0"><span class="c11">If the type has new-extended alignment, a function with a parameter of type std::align_val_t is preferred; otherwise a function without such a parameter is preferred. If any preferred functions are found, all non-preferred functions are eliminated from further consideration.</span></li><li class="c8 li-bullet-0"><span class="c11">If exactly one function remains, that function is selected and the selection process terminates.</span></li><li class="c8 li-bullet-0"><span class="c11">If the deallocation functions have class scope, the one without a parameter of type std::size_t is selected.</span></li><li class="c8 li-bullet-0"><span class="c11">If the type is complete and if, for an array delete expression only, the operand is a pointer to a class type with a non-trivial destructor or a (possibly multi-dimensional) array thereof, the function with a parameter of type std::size_t is selected.</span></li><li class="c8 li-bullet-0"><span class="c11">Otherwise, it is unspecified whether a deallocation function with a parameter of type std::size_t is selected.</span></li></ul><p class="c10"><span class="c11"></span></p><h2 class="c2" id="h.gxjym9q8dhrn"><span class="c12">Proposed wording:</span></h2><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Modify [dcl.fct.def.coroutine] p9 as follows:</span></p><p class="c10"><span class="c11"></span></p><p class="c5"><span>An implementation may need to allocate additional storage for a coroutine. This storage is known as the coroutine state and is obtained by calling a non-array allocation function (6.7.5.4.1). The allocation function&rsquo;s name is looked up in the scope of the promise type. If the lookup finds an allocation function in the scope of the promise type,</span><span class="c18 c4">&nbsp;then;</span></p><ul class="c17 lst-kix_9q1ypfu9szbg-0 start"><li class="c32 li-bullet-0"><span class="c4">A first overload resolution is performed on a function call created by assembling an argument list. The first argument is the amount of space requested and has type </span><span class="c4 c9">std::size_t</span><span class="c4">. The second argument is the coroutine state&#39;s alignment and has type </span><span class="c9 c4">std::align_val_t</span><span class="c4">. The lvalues p1 ... pn are the succeeding arguments. If a viable function is found (12.4.2), and the type of the second parameter is </span><span class="c9 c4">std::align_val_t</span><span class="c4">&nbsp;and is not a dependent type then then let the found overload be the </span><span class="c20 c4">overaligned-allocation-function</span><span class="c4">, otherwise overload resolution is performed again on a function call created by passing just the first two arguments. If a viable function is found (12.4.2), and the type of the second parameter is </span><span class="c9 c4">std::align_val_t</span><span class="c4">&nbsp;and is not a dependent type then let the found overload be the </span><span class="c20 c4">overaligned-allocation-function</span><span class="c18 c4">.</span></li><li class="c32 li-bullet-0"><span class="c4">A second </span><span>overload resolution is performed on a function call created by assembling an argument list. The first argument is the amount of space requested and has type </span><span class="c9">std::size_t</span><span>. The lvalues p1 ... pn are the succeeding arguments.</span><span class="c4">&nbsp;</span><span>If</span><span class="c4">&nbsp;</span><span class="c25">no</span><span class="c4">a </span><span>viable function is found (12.4.2)</span><span class="c4">, then let the found overload be the </span><span class="c20 c4">normal-allocation-function</span><span class="c4">, otherwise </span><span>overload resolution is performed again on a function call created by passing just the amount of space required as an argument of type </span><span class="c9">std::size_t</span><span>.</span><span class="c4">&nbsp;If a viable function is found (12.4.2), then let the found overload be the </span><span class="c20 c4">normal-allocation-function</span><span class="c18 c4">.</span></li></ul><p class="c5"><span class="c18 c4">Otherwise;</span></p><ul class="c17 lst-kix_7ii1gkby2gax-0 start"><li class="c32 li-bullet-0"><span class="c4">Let the </span><span class="c20 c4">overaligned-allocation-function</span><span class="c4">&nbsp;be </span><span class="c9 c4">::operator new(std::size_t, std::align_val_t)</span><span class="c4">&nbsp;and let the </span><span class="c20 c4">normal-allocation-function</span><span class="c4">&nbsp;be </span><span class="c9 c4 c22">::operator new(std::size_t)</span></li></ul><p class="c10"><span class="c11"></span></p><p class="c5"><span class="c4">If the coroutine state has </span><span class="c20 c4">new-extended alignment</span><span class="c4">&nbsp;and an </span><span class="c20 c4">overaligned-allocation-function</span><span class="c4">&nbsp;was found then the coroutine state is allocated by a call to the </span><span class="c4 c20">overaligned-allocation-function</span><span class="c4">. Otherwise, if the </span><span class="c20 c4">normal-allocation-function</span><span class="c4">&nbsp;was found then the coroutine state is allocated by a call to the </span><span class="c20 c4">normal-allocation-function</span><span class="c18 c4">. Otherwise, the program is ill-formed.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Modify [dcl.fct.def.coroutine] p10 as follows:</span></p><p class="c5"><span>The unqualified-id get_return_object_on_allocation_failure is looked up in the scope of the promise type by class member access lookup (6.5.5). If any declarations are found, then the result of a call to an allocation function used to obtain storage for the coroutine state is assumed to return nullptr if it fails to obtain storage, and if a global allocation function is selected,</span><span class="c4">&nbsp;then if the coroutine frame has new-extended alignment</span><span>&nbsp;the ::operator new(size_t,</span><span class="c4">&nbsp;align_val_t, const</span><span>&nbsp;nothrow_t</span><span class="c4">&amp;</span><span>) form is used</span><span class="c4">, otherwise the ::operator new(size_t, const nothrow_t&amp;) form is used</span><span class="c11">. The allocation function used in this case shall have a non-throwing noexcept-specification. If the allocation function returns nullptr, the coroutine returns control to the caller of the coroutine and the return value is obtained by a call to T::get_return_object_on_allocation_failure(), where T is the promise type.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Modify [dcl.fct.def.coroutine] p12 as follows:</span></p><p class="c10"><span class="c11"></span></p><p class="c5"><span>The deallocation function&rsquo;s name is looked up in the scope of the promise type. If this lookup fails, the deallocation function&rsquo;s name is looked up in the global scope. If deallocation function lookup finds </span><span class="c18 c4">more than one usual deallocation function, the function to be called is selected as follows:</span></p><ul class="c17 lst-kix_ok2ok8u5e296-0 start"><li class="c8 li-bullet-0"><span class="c18 c4">If any deallocation functions found in the scope of the promise type are a destroying operator delete, the program is ill-formed.</span></li><li class="c8 li-bullet-0"><span class="c4">If the coroutine state has new-extended alignment, a function with a parameter of type </span><span class="c9 c4">std::align_val_t</span><span class="c18 c4">&nbsp;is preferred; otherwise a function without such a parameter is preferred. If any preferrred functions are found, all non-preferred functions are eliminated from further consideration.</span></li><li class="c8 li-bullet-0"><span class="c18 c4">If exactly one function remains, that function is selected and the selection process terminates.</span></li><li class="c8 li-bullet-0"><span class="c4">Otherwise, a function with a parameter of type </span><span class="c9 c4">std::size_t</span><span class="c4">&nbsp;is preferred to a function without a parameter of type </span><span class="c9 c4">std::size_t</span><span class="c18 c4">.</span></li></ul><p class="c5"><span class="c25">both a usual deallocation function with only a pointer parameter and a usual deallocation function with both a pointer parameter and a size parameter, then the selected deallocation function shall be the one with two parameters. Otherwise, the selected deallocation function shall be the function with one parameter.</span><span>&nbsp;If no usual deallocation function is found, the program is ill-formed. The selected deallocation function shall be called with the address of the block of storage to be reclaimed as its first argument. If a deallocation function with a parameter of type </span><span class="c9">std::size_t</span><span>&nbsp;is used, the size of the block is passed as the corresponding argument. </span><span class="c4">If a deallocation function with a parameter of type </span><span class="c9 c4">std::align_val_t</span><span class="c4 c18">&nbsp;is used, the requested alignment of the block is passed as the corresponding argument.</span></p><p class="c10"><span class="c11"></span></p><h2 class="c2" id="h.qgpndpamcyxl"><span class="c12">Discussion</span></h2><h3 class="c14" id="h.ps5jgcfgpdqe"><span class="c30">Issue #1 - Potential ambiguity with interpretation of templated operator new() overload</span></h3><p class="c6"><span class="c11">[basic.stc.dynamic.allocation]/3.1</span></p><p class="c6"><span class="c11">If the allocation function takes an argument of type std::align_val_t, the storage will have the alignment specified by the value of this argument.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span>This paragraph has some potentially interesting interactions with coroutine frame allocation which allows an overload of </span><span class="c9">promise_type::operator new()</span><span class="c11">&nbsp;to be defined that will receive the arguments to the coroutine function.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">This means that if I have:</span></p><p class="c6"><span class="c22 c9 c26">struct task {</span></p><p class="c6"><span class="c22 c9 c26">&nbsp; struct promise_type {</span></p><p class="c6"><span class="c22 c9 c26">&nbsp; &nbsp; template&lt;typename... Args&gt;</span></p><p class="c6"><span class="c22 c9 c26">&nbsp; &nbsp; static void* operator new(std::size_t, Args...);</span></p><p class="c6 c27"><span class="c22 c9 c26"></span></p><p class="c6"><span class="c22 c9 c26">&nbsp; &nbsp; ...</span></p><p class="c6"><span class="c22 c9 c26">&nbsp; };</span></p><p class="c6"><span class="c22 c9 c26">};</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c22 c9 c26">task foo(std::align_val_t x) {</span></p><p class="c6"><span class="c22 c9 c26">&nbsp; co_return;</span></p><p class="c6"><span class="c22 c9 c26">}</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c22 c9 c26">foo(std::align_val_t(1&#39;000&#39;000));</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span>Then the compiler will generate a call to </span><span class="c9">promise_type::operator new(std::size_t, std::align_val_t)</span><span class="c11">&nbsp;if needed to allocate storage for the coroutine frame.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span>Does this mean that the implementation of this </span><span class="c9">operator new()</span><span class="c11">&nbsp;needs to ensure that the allocation is required to have an alignment of 1&#39;000&#39;000 bytes? Will compilers make any assumptions about this? ie. if the align_val_t argument was not injected by the compiler?</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span>The proposed wording above tries to avoid this case being considered a valid overload for the </span><span class="c9">std::align_val_t</span><span class="c11">&nbsp;case by requiring that the found overload not have a parameter in the alignment position that is a dependent-type.</span></p><h3 class="c14" id="h.h9htq7m9tku0"><span class="c30">Issue #2 - Destroying operator delete does not make sense</span></h3><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Need to exclude destroying operator delete from being considered for operator delete overloads found within the scope of the promise type.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">When destroying the coroutine state we are not actually destroying an object. The coroutine state has no type and so we cannot pass a pointer to the coroutine state type as required by destroying operator delete calls.</span></p><h3 class="c14" id="h.yekpk2h2kdnr"><span class="c30">Issue #3 - Alignment requirements not known by compiler front-end</span></h3><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">The alignment and size of the coroutine state is not known at template instantiation time and can depend on the result of optimisation passes that run in later compilation phases.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Optimisation passes of the compiler may end up eliding storage of some overaligned local-variables if it determines that the construction of those variables is never reachable (ie. dead-code), thus potentially reducing the alignment requirements of the coroutine state compared to what an analysis by a compiler-front end could determine.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Conversely, it&#39;s possible that the compiler might inline the allocation of a nested coroutine frame into the caller, which itself may contain overaligned variables, thus potentially increasing the alignment requirement of the coroutine state compared to what an analysis by a compiler-front end could determine.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">This means that the choice of whether to call the new-extended alignment allocation function or the normal allocation function will typically be made by the compiler middle/back-end once the coroutine frame layout has been determined, long after template instantiation has completed.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Thus a compiler front-end will typically need to perform lookup, and instantiate if necessary, both flavours of allocation functions, and if both are found, defer the decision about which one to call until after the coroutine frame layout has been calculated.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">The proposed wording above attempts to describe this process of performing two allocation function overload resolutions, one for new-extended alignment and one for normal alignment.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">While, in some cases, it may be possible for the compiler front-end to determine which one will be called, there is no obvious way to normatively specify when this should occur. Thus even in this situation the compiler should be forced to instantiate both allocation function flavours so that the validity of the program is not determined by some unspecified property of the coroutine being compiled. eg. one of the allocation functions may have been ill-formed were it to be instantiated.</span></p><p class="c6 c27"><span class="c11"></span></p><p class="c6"><span class="c11">If a particular compiler skipped instantiating the allocation function in cases where it could determine that it was never going to be called then this might mean the difference between a program being valid on one compiler and one being ill-formed on another compiler that did not have this ability to skip the instantiation.</span></p><p class="c10"><span class="c11"></span></p><h3 class="c14" id="h.bjz889lk42yt"><span class="c30">Issue #4 - Order of resolution (Option 1)</span></h3><p class="c6"><span>When resolving the overloads of </span><span class="c9">operator new()</span><span>&nbsp;and </span><span class="c9">operator delete()</span><span class="c11">&nbsp;to call when allocating/deallocating a coroutine frame, the overload resolution order is different depending on whether the coroutine frame is overaligned or not.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">This is how the current wording of option 1 is intended to be interpreted with regards to order of preference of different overloads.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">If the coroutine frame has new-extended alignment then the order of preference for overload resolution of the allocation function is:</span></p><ul class="c17 lst-kix_hwhcrsn1mpsp-0 start"><li class="c8 li-bullet-0"><span class="c7">promise_type::operator new(std::size_t, std::align_val_t, Args...)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator new(std::size_t, std::align_val_t)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator new(std::size_t, Args...)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator new(std::size_t)</span></li><li class="c8 li-bullet-0"><span class="c7">::operator new(std::size_t, std::align_val_t)</span></li></ul><p class="c6"><span class="c11">and the order of resolution of the deallocation function is:</span></p><ul class="c17 lst-kix_mkcfyz15qrg4-0 start"><li class="c8 li-bullet-0"><span class="c7">promise_type::operator delete(void*, std::size_t, std::align_val_t)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator delete(void*, std::align_val_t)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator delete(void*, std::size_t)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator delete(void*)</span></li><li class="c8 li-bullet-0"><span class="c7">::operator delete(void*, std::size_t, std::align_val_t)</span></li></ul><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">Otherwise, if the coroutine frame has normal (non-extended) alignment then the order of preference for overload resolution is:</span></p><ul class="c17 lst-kix_w8u4e98an00u-0 start"><li class="c8 li-bullet-0"><span class="c7">promise_type::operator new(std::size_t, Args...)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator new(std::size_t)</span></li><li class="c8 li-bullet-0"><span class="c7">::operator new(std::size_t)</span></li></ul><p class="c6"><span class="c11">and the order of resolution of the deallocation function is:</span></p><ul class="c17 lst-kix_im5jkoids01l-0 start"><li class="c8 li-bullet-0"><span class="c7">promise_type::operator delete(void*, std::size_t)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator delete(void*)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator delete(void*, std::size_t, std::align_val_t)</span></li><li class="c8 li-bullet-0"><span class="c7">promise_type::operator delete(void*, std::align_val_t)</span></li><li class="c8 li-bullet-0"><span class="c7">::operator delete(void*, std::size_t)</span></li></ul><p class="c10"><span class="c11"></span></p><p class="c6"><span>Note that there is a slight inconsistency between </span><span class="c9">operator new()</span><span>&nbsp;and </span><span class="c9">operator delete()</span><span>&nbsp;here. If the coroutine frame is not overaligned then the overloads of </span><span class="c9">operator new()</span><span>&nbsp;that contain </span><span class="c9">std::align_val_t </span><span>are not considered. However, for deallocation function, it still considers </span><span class="c9">std::align_val_t </span><span>overloads, it just prefers the overloads without </span><span class="c9">std::align_val_t</span><span class="c11">.</span></p><p class="c10"><span class="c11"></span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span>Also, there is not currently a requirement to also provide a class-member deallocation function if you provide a class-member allocation function. It will fall-back to global </span><span class="c9">operator delete()</span><span>&nbsp;if you only provide a </span><span class="c9">promise_type::operator new()</span><span class="c11">.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span>Similarly, if you provide only a </span><span class="c9">promise_type::operator delete()</span><span>, it will still fall back to </span><span class="c9">::operator new()</span><span class="c11">&nbsp;for the allocation-function.</span></p><p class="c10"><span class="c11"></span></p><p class="c6"><span class="c11">This seems to be consistent with the behaviour of ordinary class allocation functions, however.</span></p><p class="c10"><span class="c11"></span></p><p class="c10"><span class="c11"></span></p></body></html>
