<!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="2024-04-16" />
  <title>Less transient constexpr allocation (and more consteval
relaxation)</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.csl-block{margin-left: 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; }
      .sourceCode { overflow: visible; }
      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: 83%;
}
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: 75%;
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: 75%;
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: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
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>
  <style type="text/css">a {
color : #4183C4;
text-decoration: underline;
}
a.marginalized {
text-decoration: none;
}
a.self-link {
text-decoration: none;
}
h1#toctitle {
border-bottom: 1px solid #cccccc;
}
#TOC li {
margin-top: 1px;
margin-bottom: 1px;
}
#TOC ul>li:before { display: none; }
h3.subtitle { margin-top: -15px; }
h1:target { background-color: transparent; }
h2:target { background-color: transparent; }
h3:target { background-color: transparent; }
h4:target { background-color: transparent; }
h5:target { background-color: transparent; }
h6:target { background-color: transparent; }
code span.co { font-family: monospace; }
table tr {
background-color: white;
}
table tr:nth-child(2n) {
background-color: #f6f8fa;
}
#title-block-header > table tr:nth-child(2n) {
background-color: white;
}
td > div.sourceCode {
background-color: inherit;
}
table {
border-collapse: collapse;
}
table td, table th {
border: 1px solid #cccccc;
}
table th {
border-bottom: 1px solid black;
text-align: center;
}
table tr:first-child th {
border-top: 0;
}
table tr:last-child td {
border-bottom: 0;
}
table tr td:first-child,
table tr th:first-child {
border-left: 0;
}
table tr td:last-child,
table tr th:last-child {
border-right: 0;
}
table tbody tr:first-child td {
border-top: 1px solid black;
}
#title-block-header td { border: 0; }
@media all {
body {
margin: 2em;
}
}
@media screen and (min-width: 480px) {
body {
margin: 5em;
}
}
#refs code{padding-left: 0px; text-indent: 0px;}
:root {
--diff-ins: #C9FBC9;
--diff-strongins: #acf2bd;
--diff-del: #ffdddd;
--diff-strongdel: #ff8888;
}
span.diffins {
background-color: var(--diff-strongins);
}
span.diffdel {
background-color: var(--diff-strongdel);
}
div.rm { text-decoration: line-through; }
div.rm code.sourceCode { text-decoration: line-through; }
div.addu, span.addu {
color: #006e28;
background-color: var(--diff-ins);
}

div.rm pre, div.add pre { background-color: #f6f8fa; }
div.addu pre { background-color: var(--diff-ins); }
div.add, div.add pre { background-color: var(--diff-ins); }
div.addu blockquote {
border-left: 4px solid #00a000;
padding: 0 15px;
color: #006e28;
text-decoration: none;
}
div.addu blockquote code.sourceCode { text-decoration: none; }
div.addu blockquote pre { text-decoration: none; }
div.addu blockquote pre code { text-decoration: none; }
div.quote {
border-left: 7px solid #ccc;
background: #f9f9f9;
margin: 1.5em 10px;
padding-left: 20px;
}
code.diff span.va { color: #000000; background-color: var(--diff-ins); }
code.diff span.st { color: #000000; background-color: var(--diff-del); }
div.std blockquote { color: #000000; background-color: #F1F1F1;
border: 1px solid #D1D1D1;
padding-left: 0.5em; padding-right: 0.5em; }
div.std.ins blockquote {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.ins > div.example {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.std div.sourceCode { background-color: inherit; margin-left: 1em; }
div.std blockquote del { text-decoration: line-through;
color: #000000; background-color: #FFC8EB;
border: none; }
code del { border: 1px solid #ECB3C7; }
</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">Less transient constexpr
allocation (and more consteval relaxation)</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3032R2</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-04-16</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>
      EWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.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="#revision-history" id="toc-revision-history"><span class="toc-section-number">1</span> Revision
History<span></span></a></li>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">2</span> Introduction<span></span></a>
<ul>
<li><a href="#immediate-escalating-expressions" id="toc-immediate-escalating-expressions"><span class="toc-section-number">2.1</span> Immediate-escalating
expressions<span></span></a></li>
<li><a href="#transient-allocations" id="toc-transient-allocations"><span class="toc-section-number">2.2</span> Transient
allocations<span></span></a>
<ul>
<li><a href="#constant-expression-vs-core-constant-expression" id="toc-constant-expression-vs-core-constant-expression"><span class="toc-section-number">2.2.1</span> Constant Expression vs Core
Constant Expression<span></span></a></li>
<li><a href="#mutation" id="toc-mutation"><span class="toc-section-number">2.2.2</span> Mutation<span></span></a></li>
<li><a href="#is-this-actually-to-preserve-constants" id="toc-is-this-actually-to-preserve-constants"><span class="toc-section-number">2.2.3</span> Is this actually to preserve
constants?<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#proposal" id="toc-proposal"><span class="toc-section-number">3</span> Proposal<span></span></a>
<ul>
<li><a href="#incomplete-prior-wording" id="toc-incomplete-prior-wording"><span class="toc-section-number">3.1</span> Incomplete Prior
Wording<span></span></a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">3.2</span> Wording<span></span></a></li>
<li><a href="#feature-test-macro" id="toc-feature-test-macro"><span class="toc-section-number">3.3</span> Feature-Test
Macro<span></span></a></li>
</ul></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">4</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">5</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="revision-history"><span class="header-section-number">1</span>
Revision History<a href="#revision-history" class="self-link"></a></h1>
<p><span class="citation" data-cites="P3032R2">[<a href="https://wg21.link/p3032r2" role="doc-biblioref">P3032R2</a>]</span>: <span class="citation" data-cites="P3032R1">[<a href="https://wg21.link/p3032r1" role="doc-biblioref">P3032R1</a>]</span> of this paper was actually on
the Straw Polls page in Tokyo. Richard Smith pointed out one issue with
the wording, and then Hubert Tong pointed out a much bigger issue with
the wording - and it was pulled. This revision expands the description
of the problem and addresses the wording issues. R1 also did not address
the question of <a href="#immediate-escalating-expressions">escalating
expressions</a>, but this proposal expands on that too.</p>
<p><span class="citation" data-cites="P3032R1">[<a href="https://wg21.link/p3032r1" role="doc-biblioref">P3032R1</a>]</span>: fixed wording, added
feature-test macro.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">2</span>
Introduction<a href="#introduction" class="self-link"></a></h1>
<p>C++20 introduced constexpr allocation, but in a limited form: any
allocation must be deallocated during that constant evaluation.</p>
<p>The intent of the rule is that no constexpr allocation persists to
runtime. For more on why we currently need to avoid that, see Jeff
Snyder’s <span class="citation" data-cites="P1974R0">[<a href="https://wg21.link/p1974r0" role="doc-biblioref">P1974R0</a>]</span> and also <span class="citation" data-cites="P2670R1">[<a href="https://wg21.link/p2670r1" role="doc-biblioref">P2670R1</a>]</span>.</p>
<p>But the rule cited above does slightly more than prevent constexpr
allocation to persist until runtime. The goal of this paper is to allow
more examples of allocations that <em>do not</em> persist until runtime,
that nevertheless are still rejected by the C++23 rules.</p>
<p>For the purposes of this paper, we’ll consider the example of wanting
to get the number of enumerators of a given enumeration. While the
specific example is using reflection (<span class="citation" data-cites="P2996R1">[<a href="https://wg21.link/p2996r1" role="doc-biblioref">P2996R1</a>]</span>), there isn’t anything
particularly reflection-specific about the example - it just makes for a
good example. All you need to know about reflection to understand the
example is that
<code class="sourceCode cpp"><span class="op">^</span>E</code> gives you
an object of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
and that this function exists:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> info <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">consteval</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> enumerators_of<span class="op">(</span>info<span class="op">)</span>;</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>With that, let’s go through several attempts at trying to get the
<em>number</em> of enumerators of a given enumeration
<code class="sourceCode cpp">E</code> as a constant:</p>
<table>
<tr>
<th></th>
<th>
Attempt
</th>
<th>
Result
</th>
</tr>
<tr>
<td style="text-align: center;vertical-align: middle">
1
</td>
<td>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">int</span> r1 <span class="op">=</span> enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> r1;</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
<td>
✅. This one is valid - because <code class="sourceCode cpp">r1</code>
is a
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variable, it’s initializer starts a constant evaluation - which includes
the entire expression. The temporary
<code class="sourceCode cpp">vector</code> is destroyed at the end of
that expression, so it doesn’t persist outside of any constant
evaluation.
</td>
</tr>
<tr>
<td style="text-align: center;vertical-align: middle">
2
</td>
<td>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">int</span> f2<span class="op">()</span> <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span>;</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">int</span> r2 <span class="op">=</span> f2<span class="op">()</span>;</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> r2;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
<td>
<p>❌. This one is invalid.</p>
<p>The same idea about initializing
<code class="sourceCode cpp">r2</code> as mentioned in the previous
example is valid - but because <code class="sourceCode cpp">f2</code> is
a <code class="sourceCode cpp"><span class="kw">constexpr</span></code>
function, the invocation of <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">)</span></code>
is not in an immediate function context - so it needs to be a constant
expression on its own. That is, we start a new constant evaluation
within the original one - but this constant evaluation is just the
expression <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">)</span></code>.
It is not the full expression <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span></code>.</p>
As a result, the temporary vector returned by <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">)</span></code>
persists outside of its constant expression in order to invoke <code class="sourceCode cpp"><span class="op">.</span>size<span class="op">()</span></code>
on it, which is not allowed.
</td>
</tr>
<tr>
<td style="text-align: center;vertical-align: middle">
3
</td>
<td>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">int</span> f3<span class="op">()</span> <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span>;</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">int</span> r3 <span class="op">=</span> f<span class="op">()</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> r3;</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
<td>
<p>✅. Both this row and the next row are subtle refinements of the
second row that make it valid.</p>
The only difference between this and the previous row is that
<code class="sourceCode cpp">f2</code> was
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
but <code class="sourceCode cpp">f3</code> is
<code class="sourceCode cpp"><span class="kw">consteval</span></code>.
This distinction matters, because now <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">)</span></code>
is no longer an immediate invocation - it is now in an immediate
function context. As a result, the only thing that matters is that the
entire expression <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span></code>
is constant - and the temporary <code class="sourceCode cpp">vector<span class="op">&lt;</span>info<span class="op">&gt;</span></code>
does not persist past that.
</td>
</tr>
<tr>
<td style="text-align: center;vertical-align: middle">
4
</td>
<td>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> E<span class="op">&gt;</span> <span class="kw">constexpr</span> <span class="dt">int</span> f4<span class="op">()</span> <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span>;</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">int</span> r4 <span class="op">=</span> f4<span class="op">&lt;</span>E<span class="op">&gt;()</span>;</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> r4;</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
<td>
✅. Here <code class="sourceCode cpp">f4</code> is a
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
function <em>template</em>, whereas
<code class="sourceCode cpp">f2</code> was a regular
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
function. This matters because of <span class="citation" data-cites="P2564R3">[<a href="https://wg21.link/p2564r3" role="doc-biblioref">P2564R3</a>]</span> - the fact that <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span></code>
isn’t a constant expression now causes
<code class="sourceCode cpp">f4</code> to become a
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
function template - and thus we’re in the same state that we were in
<code class="sourceCode cpp">f3</code>: it’s not <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">)</span></code>
that needs to be a core constant expression but rather all of <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span></code>.
</td>
</tr>
<tr>
<td style="text-align: center;vertical-align: middle">
5
</td>
<td>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">int</span> f5<span class="op">()</span> <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> es <span class="op">=</span> enumerators_of<span class="op">(^</span>E<span class="op">)</span>;</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> es<span class="op">.</span>size<span class="op">()</span>;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">int</span> r5 <span class="op">=</span> f<span class="op">()</span>;</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> r5;</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
<td>
❌. Even though <code class="sourceCode cpp">f5</code> is
<code class="sourceCode cpp"><span class="kw">consteval</span></code>,
we are still explicitly starting a new constant evaluation within
<code class="sourceCode cpp">f5</code> by declaring
<code class="sourceCode cpp">es</code> to be
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>.
That allocation persists past that declaration - <em>even though</em> it
does not persist past <code class="sourceCode cpp">f5</code>, which by
being
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
means that it does not persist until runtime.
</td>
</tr>
</table>
<p>Three of these rows are valid C++23 programs (modulo the fact that
they’re using reflection), but
<code class="sourceCode cpp"><span class="dv">2</span></code> and
<code class="sourceCode cpp"><span class="dv">5</span></code> are
invalid - albeit for different reasons:</p>
<ul>
<li>in the 2nd row, we are required to consider <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">)</span></code>
as a constant expression all by itself - even if <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span></code>
is definitely a constant expression.</li>
<li>in the 5th row, we are required to consider
<code class="sourceCode cpp">es</code> as a non-transient constexpr
allocation - even though it definitely does not persist until runtime,
and thus does not actually cause any of the problems that non-transient
constexpr allocation has to address.</li>
</ul>
<h2 data-number="2.1" id="immediate-escalating-expressions"><span class="header-section-number">2.1</span> Immediate-escalating
expressions<a href="#immediate-escalating-expressions" class="self-link"></a></h2>
<p>The wording in <span class="citation" data-cites="P2564R3">[<a href="https://wg21.link/p2564r3" role="doc-biblioref">P2564R3</a>]</span> introduced the term
<em>immediate-escalating expression</em> in <span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">17</a></span>
An expression or conversion is <em>immediate-escalating</em> if it is
not initially in an immediate function context and it is either</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">(17.1)</a></span>
a potentially-evaluated <em>id-expression</em> that denotes an immediate
function that is not a subexpression of an immediate invocation, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">(17.2)</a></span>
an immediate invocation that is not a constant expression and is not a
subexpression of an immediate invocation.</li>
</ul>
</blockquote>
<p>In the second example:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">int</span> f2<span class="op">()</span> <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span>;</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>The expression <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">)</span></code>
is immediate-escalating - it is an immediate invocation
(<code class="sourceCode cpp">enumerators_of</code> is a
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
function) that is not a constant expression (because the temporary
vector persists outside of this expression). This is what causes
<code class="sourceCode cpp">f4</code> to become a
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
function template.</p>
<p>But <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span></code>
is not an immediate invocation (it simply has a subexpression that is an
immediate invocation). However, if we were to define it as an immediate
invocation - then it would not be an immediate-escalating expression
anymore because it is actually a constant expression. And that would be
enough to fix this example (as well as
<code class="sourceCode cpp">f4</code> which would then itself not
escalate to
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
since it wouldn’t need to).</p>
<p>Put differently: instead of escalating <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">)</span></code>
up to the nearest function, which we then try to make
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
(and fail in the case of <code class="sourceCode cpp">f2</code> because
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
functions are not <em>immediate-escalating</em>), we only need to
escalate up to the nearest enclosing expression that could be a constant
expression.</p>
<h2 data-number="2.2" id="transient-allocations"><span class="header-section-number">2.2</span> Transient allocations<a href="#transient-allocations" class="self-link"></a></h2>
<p>The wording in <span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span> for
rejecting non-transient allocations rejects an expression
<code class="sourceCode cpp">E</code> as being a core constant
expressions if <code class="sourceCode cpp">E</code> evaluates:</p>
<blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">(5.18)</a></span>
a <em>new-expression</em> ([expr.new]), unless the selected allocation
function is a replaceable global allocation function
([new.delete.single], [new.delete.array]) and the allocated storage is
deallocated within the evaluation of
<code class="sourceCode cpp">E</code>;</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">(5.20)</a></span>
a call to an instance of <code class="sourceCode cpp">std​<span class="op">::</span>​allocator<span class="op">&lt;</span>T<span class="op">&gt;</span>​<span class="op">::</span>​allocate</code>
([allocator.members]), unless the allocated storage is deallocated
within the evaluation of <code class="sourceCode cpp">E</code>;</li>
</ul>
</blockquote>
<p>That is - an allocation within <code class="sourceCode cpp">E</code>
has to be transient to <code class="sourceCode cpp">E</code>. However,
the rule we really want is that a constant allocation is transient to
constant evaluation. In the fifth example:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">int</span> f5<span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> es <span class="op">=</span> enumerators_of<span class="op">(^</span>E<span class="op">)</span>;</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> es<span class="op">.</span>size<span class="op">()</span>;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>The allocation in <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">)</span></code>
isn’t transient to that expression, but it is definitely destroyed
within <code class="sourceCode cpp">f5</code>, which is
<code class="sourceCode cpp"><span class="kw">consteval</span></code>.
That’s important: if <code class="sourceCode cpp">f5</code> were
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>,
we’d have access to that allocation at runtime.</p>
<p>We can loosen the restriction such that an allocation within
<code class="sourceCode cpp">E</code> must be deallocated within
<code class="sourceCode cpp">E</code> or, if
<code class="sourceCode cpp">E</code> is in an immediate function
context, the end of that context. This would be the end of the <code class="sourceCode cpp"><span class="cf">if</span> <span class="kw">consteval</span> <span class="op">{</span> <span class="op">}</span></code>
block or the end of the
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
function. Such a loosening would allow
<code class="sourceCode cpp">f5</code> above, but not if it’s
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>,
and not if <code class="sourceCode cpp">es</code> were also declared
<code class="sourceCode cpp"><span class="kw">static</span></code>.</p>
<p>Now, allowing the declaration of
<code class="sourceCode cpp">es</code> here has numerous other issues
that are worth considering.</p>
<h3 data-number="2.2.1" id="constant-expression-vs-core-constant-expression"><span class="header-section-number">2.2.1</span> Constant Expression vs Core
Constant Expression<a href="#constant-expression-vs-core-constant-expression" class="self-link"></a></h3>
<p>Right before plenary in Tokyo, Hubert Tong pointed out an important
omission in the wording of this paper: it completely failed to solve the
problem.</p>
<p>While the wording relaxes the rules for a <em>core constant
expression</em>, it did not touch two other important rules: the
definition of a <em>constant expression</em> and the requirements for
the initialization of a
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variable.</p>
<p>Specifically, the existing rule in <span>9.2.6 <a href="https://wg21.link/dcl.constexpr">[dcl.constexpr]</a></span>/6
requires that:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">6</a></span>
… In any constexpr variable declaration, the full-expression of the
initialization shall be a constant expression ([expr.const]).</p>
</blockquote>
</div>
<p>where the term “constant expression” is defined in <span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>/14:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">14</a></span>
A <em>constant expression</em> is either a glvalue core constant
expression that refers to an entity that is a permitted result of a
constant expression (as defined below), or a prvalue core constant
expression whose value satisfies the following constraints:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">(14.1)</a></span>
if the value is an object of class type, each non-static data member of
reference type refers to an entity that is a permitted result of a
constant expression,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_9" id="pnum_9">(14.2)</a></span>
if the value is an object of scalar type, it does not have an
indeterminate value ([basic.indet]),</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">(14.3)</a></span>
if the value is of pointer type, it contains the address of an object
with static storage duration, the address past the end of such an object
([expr.add]), the address of a non-immediate function, or a null pointer
value,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">(14.4)</a></span>
if the value is of pointer-to-member-function type, it does not
designate an immediate function, and</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">(14.5)</a></span>
if the value is an object of class or array type, each subobject
satisfies these constraints for the value.</li>
</ul>
<p>An entity is a <em>permitted result of a constant expression</em> if
it is an object with static storage duration that either is not a
temporary object or is a temporary object whose value satisfies the
above constraints, or if it is a non-immediate function.</p>
</blockquote>
</div>
<p>Attempting to declare a local
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variable to point to some allocation would violate this rule - we do not
meet the requirements set out above.</p>
<p>However, before we go about trying to figure out how to relax the
rule to allow allocations in automatic storage duration
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variables in immediate function contexts - Richard Smith pointed out
another issue. This time not so much a <em>mistake</em> as a missed
opportunity: allocations aren’t the only example of results that are not
permitted today but could be allowed if they’re entirely within an
immediate function context. For instance, taking a pointer to an
immediate function. We have to prevent that from leaking to runtime, but
if we’re in a
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
function - there’s nothing to prevent:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> f<span class="op">()</span> <span class="op">{}</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Ought to be valid, but isn&#39;t a constant expression, because</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">// compile-time-only state escapes... into a compile-time-only context.</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="op">*</span>p <span class="op">=</span> f;</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  p<span class="op">()</span>;</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>So now we have multiple ways in which we need to relax this rule. How
do we go about doing it? We could be very precise in carving out
specifically what we need - but this has a cost. We could fail to carve
out enough, and have to keep refining the rule. But more importantly,
the status quo is that we have two clear terms with clear usage:
<em>core constant expression</em> and <em>constant expression</em>. Any
attempt to introduce a third term in between them simply adds
complexity. Is it worth doing so?</p>
<p>Let’s say that instead we go all the way. If an automatic storage
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variable is declared in an immediate function context, its initializer
does <em>not</em> have to be a constant expression - it only has to be a
core constant expression. This allows the allocation examples that were
the original motivation of the paper, and this allows the immediate
function example that Richard brought up. It does also allow some weird
cases:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">int</span> f<span class="op">(</span><span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">int</span> <span class="op">&amp;</span>r <span class="op">=</span> n; <span class="co">// ill-formed, becomes well-formed</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> r;</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> S <span class="op">{</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> S<span class="op">()</span> <span class="op">{}</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> i;</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> S s; <span class="co">// ill-formed, becomes well-formed</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Both of these cases are… odd. They are rejected today for being an
invalid permitted result (<code class="sourceCode cpp">n</code> doesn’t
have static storage duration) and indeterminate
(<code class="sourceCode cpp">s<span class="op">.</span>i</code> isn’t
initialized), respectively. And allowing them isn’t great. But also any
attempt to actually use <code class="sourceCode cpp">r</code> and
<code class="sourceCode cpp">s</code> here in a constant expression
won’t work anyway. So we’re not losing anything in terms of
correctness.</p>
<p>I think on the whole it’s better to stick with the simpler and
easier-to-understand rule, even as it allows some odd and pointless
code.</p>
<h3 data-number="2.2.2" id="mutation"><span class="header-section-number">2.2.2</span> Mutation<a href="#mutation" class="self-link"></a></h3>
<p>Consider the following example:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> f<span class="op">(</span><span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">int</span><span class="op">*</span> a <span class="op">=</span> <span class="kw">new</span> <span class="dt">int</span><span class="op">(</span>n<span class="op">)</span>; <span class="co">// ill-formed</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">int</span><span class="op">*</span> b <span class="op">=</span> <span class="kw">new</span> <span class="dt">int</span><span class="op">(</span><span class="dv">1</span><span class="op">)</span>; <span class="co">// #1</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> c<span class="op">[*</span>b<span class="op">]</span>;                     <span class="co">// #2</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">++*</span>b;                          <span class="co">// #3</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> d<span class="op">[*</span>b<span class="op">]</span>;                     <span class="co">// #4</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">delete</span> b;</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>The declaration of <code class="sourceCode cpp">a</code> is already
ill-formed, so we don’t have to do anything here.</p>
<p>Now, if the declaration of <code class="sourceCode cpp">c</code> is
ill-formed (at
<code class="sourceCode cpp"><span class="pp">#2</span></code>), then we
lose the point of declaring the local
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variable. We really do want it to be usable as a constant
expression.</p>
<p>However, at the very least the declaration of
<code class="sourceCode cpp">d</code> has to be ill-formed - this cannot
be valid code that both declares an <code class="sourceCode cpp"><span class="dt">int</span><span class="op">[</span><span class="dv">1</span><span class="op">]</span></code>
and an <code class="sourceCode cpp"><span class="dt">int</span><span class="op">[</span><span class="dv">2</span><span class="op">]</span></code>.
There are two ways we can get there:</p>
<ol type="1">
<li>We can reject
<code class="sourceCode cpp"><span class="pp">#1</span></code> as being
insufficiently constant. This gets into the issues that
<code class="sourceCode cpp">propconst</code> was trying to solve <span class="citation" data-cites="P1974R0">[<a href="https://wg21.link/p1974r0" role="doc-biblioref">P1974R0</a>]</span>.</li>
<li>We can reject
<code class="sourceCode cpp"><span class="pp">#3</span></code> for doing
mutation.</li>
</ol>
<p>It would be nice to not have to go full
<code class="sourceCode cpp">propconst</code> just to solve this
particular issue. We’re entirely within the realm of the constant
evaluator, so this problem is just simpler than having to deal with
constexpr allocation that leaks to runtime. And we very nearly already
have wording to reject
<code class="sourceCode cpp"><span class="pp">#3</span></code>, that’s
<span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>/5.16:</p>
<div class="std">
<blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">(5.16)</a></span>
a modification of an object ([expr.ass], [expr.post.incr],
[expr.pre.incr]) unless it is applied to a non-volatile lvalue of
literal type that refers to a non-volatile object whose lifetime began
within the evaluation of <code class="sourceCode cpp">E</code>;</li>
</ul>
</blockquote>
</div>
<p>It’s just that here,
<code class="sourceCode cpp"><span class="op">*</span>b</code> did
actually begin its lifetime within <code class="sourceCode cpp">E</code>
(the call to <code class="sourceCode cpp">f</code>), so we don’t violate
this rule. We should simply extend this rule to be able to reject this
case.</p>
<h3 data-number="2.2.3" id="is-this-actually-to-preserve-constants"><span class="header-section-number">2.2.3</span> Is this actually to preserve
constants?<a href="#is-this-actually-to-preserve-constants" class="self-link"></a></h3>
<p>This was the original motivating example presented in this paper:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">int</span> f5<span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> es <span class="op">=</span> enumerators_of<span class="op">(^</span>E<span class="op">)</span>;</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> es<span class="op">.</span>size<span class="op">()</span>;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Here we don’t actually need <code class="sourceCode cpp">es<span class="op">.</span>size<span class="op">()</span></code>
to be a <em>constant expression</em> - it is enough for it to be a
<em>core constant expression</em>. So is it worth going through extra
hoops to make it so that <code class="sourceCode cpp">es</code> is
usable in constant expressions (i.e. have <code class="sourceCode cpp">es<span class="op">.</span>size<span class="op">()</span></code>
and <code class="sourceCode cpp">es<span class="op">[</span><span class="dv">0</span><span class="op">]</span></code>
both be constants) or is it sufficient for it to simply be a core
constant expression?</p>
<p>I think it’s worth it.</p>
<p>One problem is how to have constant data. Let’s say you have a
function that produces some data that you want to keep around at runtime
as a lookup table:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> get_useful_data<span class="op">()</span> <span class="op">-&gt;</span> std<span class="op">::</span>vector<span class="op">&lt;</span>Data<span class="op">&gt;</span>;</span></code></pre></div>
</blockquote>
</div>
<p>We don’t have non-transient constexpr allocation, so we cannot
declare a global <code class="sourceCode cpp"><span class="kw">constexpr</span> std<span class="op">::</span>vector<span class="op">&lt;</span>Data<span class="op">&gt;</span></code>
to hold onto that. We need to hold it as an array. Specifically a <code class="sourceCode cpp">std<span class="op">::</span>array<span class="op">&lt;</span>Data, N<span class="op">&gt;</span></code>,
since <code class="sourceCode cpp">Data<span class="op">[</span>N<span class="op">]</span></code>
isn’t something you can return from a function. But how do you get
<code class="sourceCode cpp">N</code>? One option is this:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> get_useful_data_as_array<span class="op">()</span> <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">size_t</span> N <span class="op">=</span> get_useful_data<span class="op">().</span>size<span class="op">()</span>;</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">// let&#39;s just assume for simplicity that Data is regular</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>array<span class="op">&lt;</span>Data, N<span class="op">&gt;</span> data;</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>ranges<span class="op">::</span>copy<span class="op">(</span>get_useful_data<span class="op">()</span>, data<span class="op">.</span>begin<span class="op">())</span>;</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> data;</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>This works, but relies on calling <code class="sourceCode cpp">get_useful_data<span class="op">()</span></code>
twice. What if it’s computationally expensive? Sure it’s not expensive
at <em>runtime</em>, but build times matter too. Attempting to avoid
that double invocation leads to some elaborate solutions (e.g. <a href="https://www.youtube.com/watch?v=ABg4_EV5L3w">this one</a>). And
it’d be nice if we could just avoid that entirely:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> get_useful_data_as_array<span class="op">()</span> <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">// ill-formed today, proposed OK</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> std<span class="op">::</span>vector<span class="op">&lt;</span>Data<span class="op">&gt;</span> v <span class="op">=</span> get_useful_data<span class="op">()</span>;</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">// okay, because v is a constant</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>array<span class="op">&lt;</span>Data, v<span class="op">.</span>size<span class="op">()&gt;</span> data;</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>ranges<span class="op">::</span>copy<span class="op">(</span>v, data<span class="op">.</span>begin<span class="op">())</span>;</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> data;</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>This is arguably the obvious solution to this problem (well, aside
from being able to have non-transient constexpr allocation). You can see
a concrete example of this in <span class="citation" data-cites="P2996R2">[<a href="https://wg21.link/p2996r2" role="doc-biblioref">P2996R2</a>]</span>:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> S<span class="op">&gt;</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> get_layout<span class="op">()</span> <span class="op">{</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> members <span class="op">=</span> nonstatic_data_members_of<span class="op">(^</span>S<span class="op">)</span>;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>array<span class="op">&lt;</span>member_descriptor, members<span class="op">.</span>size<span class="op">()&gt;</span> layout;</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></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> members<span class="op">.</span>size<span class="op">()</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>      layout<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> <span class="op">{.</span>offset<span class="op">=</span>offset_of<span class="op">(</span>members<span class="op">[</span>i<span class="op">])</span>, <span class="op">.</span>size<span class="op">=</span>size_of<span class="op">(</span>members<span class="op">[</span>i<span class="op">])}</span>;</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> layout;</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="proposal"><span class="header-section-number">3</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>There are two separate potential changes here, that would each make
one of the attempts above well-formed:</p>
<ol type="1">
<li>we could <a href="#immediate-escalating-expressions">escalate</a>
expressions to larger expressions, so that <code class="sourceCode cpp">enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span></code>
becomes a constant expression, or</li>
<li>we could extend the notation of <a href="#transient-allocations">transient allocation</a> to include the
full immediate context instead of just the constant evaluation</li>
</ol>
<p>The second of these is straightforward to word and provides a lot of
value - since now particularly in the context of reflection you can
declare a <code class="sourceCode cpp"><span class="kw">constexpr</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span></code>
inside a
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
function and use those contents as a constant expression.</p>
<p>The first of these is a little more complicated and doesn’t provide
as much value. It’s a limitation that is fairly easy to work around:
either declare a local
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variable, or change the function to be
<code class="sourceCode cpp"><span class="kw">consteval</span></code> or
a template. However, it is pretty annoying to have to do so - and it
would be nice if we kept pushing
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
evaluation more in the direction of “it just works.” Following <span class="citation" data-cites="P2564R3">[<a href="https://wg21.link/p2564r3" role="doc-biblioref">P2564R3</a>]</span>, the rules here are already
pretty complicated - but the advantage of that is that users simply
don’t have to learn them if more things just work.</p>
<p>This paper proposes solving both problems. That is, all five examples
in the <a href="#introduction">intro</a> will be valid.</p>
<h2 data-number="3.1" id="incomplete-prior-wording"><span class="header-section-number">3.1</span> Incomplete Prior Wording<a href="#incomplete-prior-wording" class="self-link"></a></h2>
<p>Also pointed out by Richard, the original wording changing <span>7.7
<a href="https://wg21.link/expr.const">[expr.const]</a></span>/5 as
follows:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">(5.18)</a></span>
a <em>new-expression</em> ([expr.new]), unless the selected allocation
function is a replaceable global allocation function
([new.delete.single], [new.delete.array]) and the allocated storage is
deallocated <span class="addu">either</span> within the evaluation of
<code class="sourceCode cpp">E</code> <span class="addu">or, if
<code class="sourceCode cpp">E</code> is in an immediate function
context, within that context</span>;</p>
</blockquote>
</div>
<p>Richard pointed out this example, asking if it’s valid:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> f<span class="op">(</span><span class="dt">bool</span> b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">int</span> <span class="op">*</span>p <span class="op">=</span> <span class="kw">new</span> <span class="dt">int</span>;</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>b<span class="op">)</span> <span class="kw">delete</span> p;</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Noting that it’s impossible to tell - it depends on
<code class="sourceCode cpp">b</code>, which the constant evaluator does
not know. Instead he suggests this wording:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">(5.18)</a></span>
a <em>new-expression</em> ([expr.new]), unless the selected allocation
function is a replaceable global allocation function
([new.delete.single], [new.delete.array]) and <span class="addu">either</span> the allocated storage is deallocated within
the evaluation of <code class="sourceCode cpp">E</code><span class="addu">, or <code class="sourceCode cpp">E</code> is in an
immediate function context</span>;</p>
</blockquote>
</div>
<p>He points out that the actual call to
<code class="sourceCode cpp">f</code> still has to be a constant
expression, and so this leak rule still applies there. Neither
leaks-to-runtime nor compile-time leaks are possible. So this wording
change is more correct.</p>
<p>Richard also points out that this allows this nonsensical function,
but if you can’t observe a leak, does it really leak?</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> f<span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span><span class="kw">false</span><span class="op">)</span> <span class="op">{</span> <span class="kw">constexpr</span> <span class="dt">int</span> <span class="op">*</span>p <span class="op">=</span> <span class="kw">new</span> <span class="dt">int</span>; <span class="op">}</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<h2 data-number="3.2" id="wording"><span class="header-section-number">3.2</span> Wording<a href="#wording" class="self-link"></a></h2>
<p>Change <span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>/5:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">5</a></span>
An expression E is a <em>core constant expression</em> unless the
evaluation of <code class="sourceCode cpp">E</code>, following the rules
of the abstract machine ([intro.execution]), would evaluate one of the
following:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_17" id="pnum_17">(5.1)</a></span>
[…]</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_18" id="pnum_18">(5.16)</a></span>
a modification of an object ([expr.ass], [expr.post.incr],
[expr.pre.incr]) unless it is applied to a non-volatile lvalue of
literal type that refers to a non-volatile object whose lifetime began
within the evaluation of <code class="sourceCode cpp">E</code>;</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_19" id="pnum_19">(5.16b)</a></span>
<span class="addu">a modification of an object ([expr.ass],
[expr.post.incr], [expr.pre.incr]) whose lifetime began within the
evaluation of the initializer for a constexpr variable
<code class="sourceCode cpp">V</code>, unless
<code class="sourceCode cpp">E</code> occurs within the initialization
or destruction of <code class="sourceCode cpp">V</code> or of a
temporary object whose lifetime is extended to that of
<code class="sourceCode cpp">V</code>;</span></li>
</ul>
<div class="ins">
<div class="example">
<span>[ <em>Example 1:</em> </span>
<div class="sourceCode" id="cb19"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>constexpr int f(int n) {</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>    constexpr int* p = new int(1); // #1</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>    ++n;      // ok, lifetime of n began within E</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>    ++*p;     // error: modification of object whose lifetime began within</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>              // initializer of constexpr variable at #1</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>    delete p; // ok</span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>    constexpr int q = []{ // #2</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>        int i = 0;</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>        ++i;  // ok: modification of an object whose lifetime begin within E</span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>              // this E occurs within the initialization of constexpr variable</span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a>              // declared at #2</span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>        return i;</span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a>    }();</span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a>    return n + q;</span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
</div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_20" id="pnum_20">(5.17)</a></span>
[…]</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_21" id="pnum_21">(5.18)</a></span>
a <em>new-expression</em> ([expr.new]), unless the selected allocation
function is a replaceable global allocation function
([new.delete.single], [new.delete.array]) and <span class="addu">either
<code class="sourceCode cpp">E</code> is in an immediate function
context or</span> the allocated storage is deallocated within the
evaluation of <code class="addu">E</code>;</li>
</ul>
<div class="ins">
<div class="example">
<span>[ <em>Example 2:</em> </span>
<div class="sourceCode" id="cb20"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>constexpr int f() {</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>    constexpr int* i = new int(1);  // error: allocation is neither deallocated within this</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>    return *i;                      // evaluation nor within an immediate function context</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>consteval int o() {</span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>    constexpr int* n = new int(21); // ok, #1</span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>    int a = *n;</span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>    delete n;                       // #2</span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>    return a;</span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a>consteval int e() {</span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a>    constexpr int* r = new int(2022); // ok, #3</span>
<span id="cb20-15"><a href="#cb20-15" aria-hidden="true" tabindex="-1"></a>    return *r;</span>
<span id="cb20-16"><a href="#cb20-16" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a>static_assert(o() == 21);   // ok, because allocation at #1 is deallocated at #2</span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a>static_assert(e() == 2022); // error: allocation at #3 is not deallocated</span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
</div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_22" id="pnum_22">(5.19)</a></span>
a <em>delete-expression</em> ([expr.delete]), unless it deallocates a
region of storage allocated within the evaluation of
<code class="sourceCode cpp">E</code>;</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_23" id="pnum_23">(5.20)</a></span>
a call to an instance of <code class="sourceCode cpp">std​<span class="op">::</span>​allocator<span class="op">&lt;</span>T<span class="op">&gt;</span>​<span class="op">::</span>​allocate</code>
([allocator.members]), unless <span class="addu">either
<code class="sourceCode cpp">E</code> is in an immediate function
context or</span> the allocated storage is deallocated within the
evaluation of <code class="sourceCode cpp">E</code>;</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_24" id="pnum_24">(5.21)</a></span>
a call to an instance of <code class="sourceCode cpp">std​<span class="op">::</span>​allocator<span class="op">&lt;</span>T<span class="op">&gt;</span>​<span class="op">::</span>​deallocate</code>
([allocator.members]), unless it deallocates a region of storage
allocated within the evaluation of
<code class="sourceCode cpp">E</code>;</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_25" id="pnum_25">(5.22)</a></span>
[…]</li>
</ul>
</blockquote>
</div>
<p>Change <span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>/16-18:</p>
<p>::: std <span class="marginalizedparent"><a class="marginalized" href="#pnum_26" id="pnum_26">16</a></span>
An expression or conversion is in an <em>immediate function context</em>
if it is potentially evaluated and either:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_27" id="pnum_27">(16.1)</a></span>
its innermost enclosing non-block scope is a function parameter scope of
an immediate function,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_28" id="pnum_28">(16.2)</a></span>
it is a subexpression of a manifestly constant-evaluated expression or
conversion, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_29" id="pnum_29">(16.3)</a></span>
its enclosing statement is enclosed ([stmt.pre]) by the
compound-statement of a consteval if statement ([stmt.if]).</li>
</ul>
<p>An invocation is an <em>immediate invocation</em> if it is a
potentially-evaluated explicit or implicit invocation of an immediate
function and is not in an immediate function context. An aggregate
initialization is an immediate invocation if it evaluates a default
member initializer that has a subexpression that is an
immediate-escalating expression. <span class="addu">An expression is an
immediate invocation if it is a constant expression, has a subexpression
that would otherwise be immediate-escalating (see below), and does not
have a subexpression that would also meet these criteria.</span></p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_30" id="pnum_30">17</a></span>
An expression or conversion is <em>immediate-escalating</em> if it is
not initially in an immediate function context and it is either</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_31" id="pnum_31">(17.1)</a></span>
a potentially-evaluated <em>id-expression</em> that denotes an immediate
function that is not a subexpression of an immediate invocation, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_32" id="pnum_32">(17.2)</a></span>
an immediate invocation that is not a constant expression and is not a
subexpression of an immediate invocation.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_33" id="pnum_33">18</a></span>
An <em>immediate-escalating</em> function is</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_34" id="pnum_34">(18.1)</a></span>
the call operator of a lambda that is not declared with the consteval
specifier,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_35" id="pnum_35">(18.2)</a></span>
a defaulted special member function that is not declared with the
consteval specifier, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_36" id="pnum_36">(18.3)</a></span>
a function that results from the instantiation of a templated entity
defined with the constexpr specifier.</li>
</ul>
<p>An immediate-escalating expression shall appear only in an
immediate-escalating function.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_37" id="pnum_37">19</a></span>
An immediate function is a function or constructor that is</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_38" id="pnum_38">(19.1)</a></span>
declared with the consteval specifier, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_39" id="pnum_39">(19.2)</a></span>
an immediate-escalating function F whose function body contains an
immediate-escalating expression E such that E’s innermost enclosing
non-block scope is F’s function parameter scope.</li>
</ul>
<p><span class="note11"><span>[ <em>Note 11:</em> </span> Default member
initializers used to initialize a base or member subobject
([class.base.init]) are considered to be part of the function body
([dcl.fct.def.general]).<span> — <em>end note</em> ]</span></span></p>
<div class="example9">
<span>[ <em>Example 9:</em> </span>
<div>
<div class="sourceCode" id="cb21"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a>  consteval int id(int i) { return i; }</span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>  constexpr char id(char c) { return c; }</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>  template&lt;class T&gt;</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>  constexpr int f(T t) {</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>    return t + id(t);</span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a>  auto a = &amp;f&lt;char&gt;;              // OK, f&lt;char&gt; is not an immediate function</span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>  auto b = &amp;f&lt;int&gt;;               // error: f&lt;int&gt; is an immediate function</span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a>  static_assert(f(3) == 6);       // OK</span>
<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a>  template&lt;class T&gt;</span>
<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a>  constexpr int g(T t) {          // g&lt;int&gt; is not an immediate function</span>
<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a>    return t + id(42);            // because id(42) is already a constant</span>
<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a>  template&lt;class T, class F&gt;</span>
<span id="cb21-20"><a href="#cb21-20" aria-hidden="true" tabindex="-1"></a>  constexpr bool is_not(T t, F f) {</span>
<span id="cb21-21"><a href="#cb21-21" aria-hidden="true" tabindex="-1"></a>    return not f(t);</span>
<span id="cb21-22"><a href="#cb21-22" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb21-23"><a href="#cb21-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-24"><a href="#cb21-24" aria-hidden="true" tabindex="-1"></a>  consteval bool is_even(int i) { return i % 2 == 0; }</span>
<span id="cb21-25"><a href="#cb21-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-26"><a href="#cb21-26" aria-hidden="true" tabindex="-1"></a>  static_assert(is_not(5, is_even));      // OK</span>
<span id="cb21-27"><a href="#cb21-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-28"><a href="#cb21-28" aria-hidden="true" tabindex="-1"></a>  int x = 0;</span>
<span id="cb21-29"><a href="#cb21-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-30"><a href="#cb21-30" aria-hidden="true" tabindex="-1"></a>  template&lt;class T&gt;</span>
<span id="cb21-31"><a href="#cb21-31" aria-hidden="true" tabindex="-1"></a>  constexpr T h(T t = id(x)) {    // h&lt;int&gt; is not an immediate function</span>
<span id="cb21-32"><a href="#cb21-32" aria-hidden="true" tabindex="-1"></a>                                  // id(x) is not evaluated when parsing the default argument ([dcl.fct.default], [temp.inst])</span>
<span id="cb21-33"><a href="#cb21-33" aria-hidden="true" tabindex="-1"></a>      return t;</span>
<span id="cb21-34"><a href="#cb21-34" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb21-35"><a href="#cb21-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-36"><a href="#cb21-36" aria-hidden="true" tabindex="-1"></a>  template&lt;class T&gt;</span>
<span id="cb21-37"><a href="#cb21-37" aria-hidden="true" tabindex="-1"></a>  constexpr T hh() {              // hh&lt;int&gt; is an immediate function because of the invocation</span>
<span id="cb21-38"><a href="#cb21-38" aria-hidden="true" tabindex="-1"></a>    return h&lt;T&gt;();                // of the immediate function id in the default argument of h&lt;int&gt;</span>
<span id="cb21-39"><a href="#cb21-39" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb21-40"><a href="#cb21-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-41"><a href="#cb21-41" aria-hidden="true" tabindex="-1"></a>  int i = hh&lt;int&gt;();              // error: hh&lt;int&gt;() is an immediate-escalating expression</span>
<span id="cb21-42"><a href="#cb21-42" aria-hidden="true" tabindex="-1"></a>                                  // outside of an immediate-escalating function</span>
<span id="cb21-43"><a href="#cb21-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-44"><a href="#cb21-44" aria-hidden="true" tabindex="-1"></a>  struct A {</span>
<span id="cb21-45"><a href="#cb21-45" aria-hidden="true" tabindex="-1"></a>    int x;</span>
<span id="cb21-46"><a href="#cb21-46" aria-hidden="true" tabindex="-1"></a>    int y = id(x);</span>
<span id="cb21-47"><a href="#cb21-47" aria-hidden="true" tabindex="-1"></a>  };</span>
<span id="cb21-48"><a href="#cb21-48" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-49"><a href="#cb21-49" aria-hidden="true" tabindex="-1"></a>  template&lt;class T&gt;</span>
<span id="cb21-50"><a href="#cb21-50" aria-hidden="true" tabindex="-1"></a>  constexpr int k(int) {          // k&lt;int&gt; is not an immediate function because A(42) is a</span>
<span id="cb21-51"><a href="#cb21-51" aria-hidden="true" tabindex="-1"></a>    return A(42).y;               // constant expression and thus not immediate-escalating</span>
<span id="cb21-52"><a href="#cb21-52" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb21-53"><a href="#cb21-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-54"><a href="#cb21-54" aria-hidden="true" tabindex="-1"></a><span class="va">+ consteval std::vector&lt;int&gt; get_data();</span></span>
<span id="cb21-55"><a href="#cb21-55" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb21-56"><a href="#cb21-56" aria-hidden="true" tabindex="-1"></a><span class="va">+ constexpr int get_size1() {</span></span>
<span id="cb21-57"><a href="#cb21-57" aria-hidden="true" tabindex="-1"></a><span class="va">+   constexpr auto v = get_data(); // error: get_data() is an immediate-escalating expression</span></span>
<span id="cb21-58"><a href="#cb21-58" aria-hidden="true" tabindex="-1"></a><span class="va">+                                  // outside of an immediate-escalating function</span></span>
<span id="cb21-59"><a href="#cb21-59" aria-hidden="true" tabindex="-1"></a><span class="va">+   return v.size();</span></span>
<span id="cb21-60"><a href="#cb21-60" aria-hidden="true" tabindex="-1"></a><span class="va">+ }</span></span>
<span id="cb21-61"><a href="#cb21-61" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb21-62"><a href="#cb21-62" aria-hidden="true" tabindex="-1"></a><span class="va">+ constexpr int get_size2() {</span></span>
<span id="cb21-63"><a href="#cb21-63" aria-hidden="true" tabindex="-1"></a><span class="va">+   return get_data().size();      // OK, get_data().size() is an immediate invocation that is</span></span>
<span id="cb21-64"><a href="#cb21-64" aria-hidden="true" tabindex="-1"></a><span class="va">+                                  // a constant expression</span></span>
<span id="cb21-65"><a href="#cb21-65" aria-hidden="true" tabindex="-1"></a><span class="va">+ }</span></span></code></pre></div>
</div>
<span> — <em>end example</em> ]</span>
</div>
<p>Change <span>9.2.6 <a href="https://wg21.link/dcl.constexpr">[dcl.constexpr]</a></span>/6:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_40" id="pnum_40">6</a></span>
A <code class="sourceCode cpp"><span class="kw">constexpr</span></code>
specifier used in an object declaration declares the object as const.
Such an object shall have literal type and shall be initialized. In any
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variable declaration, <span class="addu">either</span></p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_41" id="pnum_41">(6.1)</a></span>
the full-expression of the initialization shall be a constant expression
([expr.const]) <span class="addu">, or</span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_42" id="pnum_42">(6.2)</a></span>
<span class="addu">the variable shall have automatic storage duration,
be declared within an immediate function context, and the
full-expression of the initialization shall be a core constant
expression ([expr.const])</span>.</li>
</ul>
<p><span class="addu">Except for an automatic storage duration variable
declared in an immediate function context, a</span> <span class="rm" style="color: #bf0303"><del>A</del></span>
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variable that is an object, as well as any temporary to which a
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
reference is bound, shall have constant destruction.</p>
<div class="example4">
<span>[ <em>Example 4:</em> </span>
<div>
<div class="sourceCode" id="cb22"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>  struct pixel {</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>    int x, y;</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>  };</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>  constexpr pixel ur = { 1294, 1024 };    // OK</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>  constexpr pixel origin;                 // error: initializer missing</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a><span class="va">+ consteval int f() {</span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a><span class="va">+   constexpr pixel* q = new pixel{3, 4}; // ok</span></span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a><span class="va">+   int result = q-&gt;x + q-&gt;y;</span></span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a><span class="va">+   delete q;</span></span>
<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a><span class="va">+   return result;</span></span>
<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a><span class="va">+ }</span></span>
<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a><span class="va">+ constexpr void g() {</span></span>
<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a><span class="va">+   constexpr pixel* p = new pixel{1, 2}; // error: not a constant expression</span></span>
<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a><span class="va">+   delete p;</span></span>
<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a><span class="va">+   constexpr auto pf = f; // error: not a constant expression</span></span>
<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a><span class="va">+ }</span></span>
<span id="cb22-19"><a href="#cb22-19" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb22-20"><a href="#cb22-20" aria-hidden="true" tabindex="-1"></a><span class="va">+ consteval int h() {</span></span>
<span id="cb22-21"><a href="#cb22-21" aria-hidden="true" tabindex="-1"></a><span class="va">+   constexpr auto pf = f; // ok</span></span>
<span id="cb22-22"><a href="#cb22-22" aria-hidden="true" tabindex="-1"></a><span class="va">+   return pf();</span></span>
<span id="cb22-23"><a href="#cb22-23" aria-hidden="true" tabindex="-1"></a><span class="va">+ }</span></span></code></pre></div>
</div>
<span> — <em>end example</em> ]</span>
</div>
</blockquote>
</div>
<h2 data-number="3.3" id="feature-test-macro"><span class="header-section-number">3.3</span> Feature-Test Macro<a href="#feature-test-macro" class="self-link"></a></h2>
<p>Bump the value of <code class="sourceCode cpp">__cpp_constexpr</code>
in <span>15.11 <a href="https://wg21.link/cpp.predefined">[cpp.predefined]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb23"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="st">- __cpp_constexpr <span class="diffdel">202306L</span></span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="va">+ __cpp_constexpr <span class="diffins">2024XXL</span></span></span></code></pre></div>
</div>
</blockquote>
</div>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="acknowledgements"><span class="header-section-number">4</span>
Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Thank you to Peter Dimov for being Peter Dimov and coming up with all
of these examples.</p>
<p>Thank you to Hubert Tong for noticing that the wording was wrong and
Richard Smith for helping to fix it. Thanks to Jason Merrill for help
with phrasing the immediate-escalating wording.</p>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">5</span>
References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-P1974R0" class="csl-entry" role="doc-biblioentry">
[P1974R0] Jeff Snyder, Louis Dionne, Daveed Vandevoorde. 2020-05-15.
Non-transient constexpr allocation using propconst. <a href="https://wg21.link/p1974r0"><div class="csl-block">https://wg21.link/p1974r0</div></a>
</div>
<div id="ref-P2564R3" class="csl-entry" role="doc-biblioentry">
[P2564R3] Barry Revzin. 2022-11-11. consteval needs to propagate up. <a href="https://wg21.link/p2564r3"><div class="csl-block">https://wg21.link/p2564r3</div></a>
</div>
<div id="ref-P2670R1" class="csl-entry" role="doc-biblioentry">
[P2670R1] Barry Revzin. 2023-02-03. Non-transient constexpr allocation.
<a href="https://wg21.link/p2670r1"><div class="csl-block">https://wg21.link/p2670r1</div></a>
</div>
<div id="ref-P2996R1" class="csl-entry" role="doc-biblioentry">
[P2996R1] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton,
Faisal Vali, Daveed Vandevoorde. 2023-12-18. Reflection for C++26. <a href="https://wg21.link/p2996r1"><div class="csl-block">https://wg21.link/p2996r1</div></a>
</div>
<div id="ref-P2996R2" class="csl-entry" role="doc-biblioentry">
[P2996R2] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton,
Faisal Vali, Daveed Vandevoorde, Dan Katz. 2024-02-15. Reflection for
C++26. <a href="https://wg21.link/p2996r2"><div class="csl-block">https://wg21.link/p2996r2</div></a>
</div>
<div id="ref-P3032R1" class="csl-entry" role="doc-biblioentry">
[P3032R1] Barry Revzin. 2023-03-21. Less transient constexpr allocation.
<a href="https://wg21.link/p3032r1"><div class="csl-block">https://wg21.link/p3032r1</div></a>
</div>
<div id="ref-P3032R2" class="csl-entry" role="doc-biblioentry">
[P3032R2] Barry Revzin. 2024-04-16. Less transient constexpr allocation
(and more consteval relaxation). <a href="https://wg21.link/p3032r2"><div class="csl-block">https://wg21.link/p3032r2</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
