<!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="2023-01-12" />
  <title>Emitting messages at compile time</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span. { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
}
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: #e6ffed;
--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); }
</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">Emitting messages at compile time</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2758R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2023-01-12</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="#introduction"><span class="toc-section-number">1</span> Introduction<span></span></a>
<ul>
<li><a href="#static_assert"><span class="toc-section-number">1.1</span> <code class="sourceCode cpp"><span class="kw">static_assert</span></code><span></span></a></li>
<li><a href="#forced-constant-evaluation-failures"><span class="toc-section-number">1.2</span> Forced constant evaluation failures<span></span></a></li>
<li><a href="#general-compile-time-debugging"><span class="toc-section-number">1.3</span> General compile-time debugging<span></span></a></li>
<li><a href="#prior-work"><span class="toc-section-number">1.4</span> Prior Work<span></span></a></li>
</ul></li>
<li><a href="#to-stdformat-or-not-to-stdformat"><span class="toc-section-number">2</span> To <code class="sourceCode cpp">std<span class="op">::</span>format</code> or not to <code class="sourceCode cpp">std<span class="op">::</span>format</code>?<span></span></a></li>
<li><a href="#improving-static_assert"><span class="toc-section-number">3</span> Improving <code class="sourceCode cpp"><span class="kw">static_assert</span></code><span></span></a></li>
<li><a href="#improving-compile-time-diagnostics"><span class="toc-section-number">4</span> Improving compile-time diagnostics<span></span></a>
<ul>
<li><a href="#predictability"><span class="toc-section-number">4.1</span> Predictability<span></span></a></li>
<li><a href="#predictability-of-errors"><span class="toc-section-number">4.2</span> Predictability of Errors<span></span></a></li>
<li><a href="#error-handling-in-general"><span class="toc-section-number">4.3</span> Error-Handling in General<span></span></a></li>
</ul></li>
<li><a href="#proposal"><span class="toc-section-number">5</span> Proposal<span></span></a></li>
<li><a href="#bibliography"><span class="toc-section-number">6</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>Currently, our ability to provide diagnostics to users is pretty limited. There are two kinds of errors I want to talk about here: static assertions and forced constant evaluation failures.</p>
<h2 data-number="1.1" id="static_assert"><span class="header-section-number">1.1</span> <code class="sourceCode cpp"><span class="kw">static_assert</span></code><a href="#static_assert" class="self-link"></a></h2>
<p>We can use <code class="sourceCode cpp"><span class="kw">static_assert</span></code>, but the only message we can provide is a string literal. This is useful (better than nothing), but is frequently insufficient. Consider:</p>
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="dt">void</span> foo<span class="op">(</span>T t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>    <span class="kw">static_assert</span><span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span>T<span class="op">)</span> <span class="op">==</span> <span class="dv">8</span>, <span class="st">&quot;All types must have size 8&quot;</span><span class="op">)</span>;</span>
<span id="cb1-4"><a href="#cb1-4"></a>    <span class="co">// ...</span></span>
<span id="cb1-5"><a href="#cb1-5"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>What happens when I try to call <code class="sourceCode cpp">foo<span class="op">(</span><span class="ch">&#39;c&#39;</span><span class="op">)</span></code>? These are the error messages I get:</p>
<ul>
<li><p>MSVC:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb2-1"><a href="#cb2-1"></a>&lt;source&gt;(6): error C2338: static_assert failed: &#39;All types must have size 8&#39;</span>
<span id="cb2-2"><a href="#cb2-2"></a>&lt;source&gt;(11): note: see reference to function template instantiation &#39;void foo&lt;char&gt;(T)&#39; being compiled</span>
<span id="cb2-3"><a href="#cb2-3"></a>        with</span>
<span id="cb2-4"><a href="#cb2-4"></a>        [</span>
<span id="cb2-5"><a href="#cb2-5"></a>            T=char</span>
<span id="cb2-6"><a href="#cb2-6"></a>        ]</span></code></pre></div></li>
<li><p>GCC:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb3-1"><a href="#cb3-1"></a>&lt;source&gt;: In instantiation of &#39;void foo(T) [with T = char]&#39;:</span>
<span id="cb3-2"><a href="#cb3-2"></a>&lt;source&gt;:11:8:   required from here</span>
<span id="cb3-3"><a href="#cb3-3"></a>&lt;source&gt;:6:29: error: static assertion failed: All types must have size 8</span>
<span id="cb3-4"><a href="#cb3-4"></a>    6 |     static_assert(sizeof(T) == 8, &quot;All types must have size 8&quot;);</span>
<span id="cb3-5"><a href="#cb3-5"></a>      |                   ~~~~~~~~~~^~~~</span>
<span id="cb3-6"><a href="#cb3-6"></a>&lt;source&gt;:6:29: note: the comparison reduces to &#39;(1 == 8)&#39;</span></code></pre></div></li>
<li><p>Clang:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb4-1"><a href="#cb4-1"></a>&lt;source&gt;:6:5: error: static assertion failed due to requirement &#39;sizeof(char) == 8&#39;: All types must have size 8</span>
<span id="cb4-2"><a href="#cb4-2"></a>    static_assert(sizeof(T) == 8, &quot;All types must have size 8&quot;);</span>
<span id="cb4-3"><a href="#cb4-3"></a>    ^             ~~~~~~~~~~~~~~</span>
<span id="cb4-4"><a href="#cb4-4"></a>&lt;source&gt;:11:5: note: in instantiation of function template specialization &#39;foo&lt;char&gt;&#39; requested here</span>
<span id="cb4-5"><a href="#cb4-5"></a>    foo(&#39;c&#39;);</span>
<span id="cb4-6"><a href="#cb4-6"></a>    ^</span>
<span id="cb4-7"><a href="#cb4-7"></a>&lt;source&gt;:6:29: note: expression evaluates to &#39;1 == 8&#39;</span>
<span id="cb4-8"><a href="#cb4-8"></a>    static_assert(sizeof(T) == 8, &quot;All types must have size 8&quot;);</span>
<span id="cb4-9"><a href="#cb4-9"></a>                  ~~~~~~~~~~^~~~</span></code></pre></div></li>
</ul>
<p>In this case, there are two additional useful pieces of information, neither of which I can provide in a string literal: what <code class="sourceCode cpp">T</code> is and what <code class="sourceCode cpp"><span class="kw">sizeof</span><span class="op">(</span>T<span class="op">)</span></code> is. In this case, all three compilers do tell me what <code class="sourceCode cpp">T</code> is (gcc and MSVC explicitly, clang in a way that you can figure out) and two of them also tell me what <code class="sourceCode cpp"><span class="kw">sizeof</span><span class="op">(</span>T<span class="op">)</span></code> is. So that’s not too bad.</p>
<p>But consider this slight variation:</p>
<blockquote>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="dt">void</span> foo<span class="op">(</span>T t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3"></a>    <span class="kw">using</span> U <span class="op">=</span> std<span class="op">::</span>remove_pointer_t<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb5-4"><a href="#cb5-4"></a>    <span class="kw">static_assert</span><span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span>U<span class="op">)</span> <span class="op">==</span> <span class="dv">8</span>, <span class="st">&quot;All types must have size 8&quot;</span><span class="op">)</span>;</span>
<span id="cb5-5"><a href="#cb5-5"></a>    <span class="co">// ...</span></span>
<span id="cb5-6"><a href="#cb5-6"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Think of <code class="sourceCode cpp">std<span class="op">::</span>remove_pointer_t<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as representative of any kind of transformation. With this change, now only clang tells me that <code class="sourceCode cpp">U<span class="op">=</span><span class="dt">char</span></code>.</p>
<p>That’s good of clang and gcc to provide this extra information, but there’s only so much that we can rely on compilers for. Generally speaking, at the point of assertion, the programmer writing it is going to have a better sense of what’s useful than the compiler author - who needs to come up with something general purpose that works well in all cases. That’s a tough line to walk - printing all the information that’s useful without printing so much information that it’s impossible to actually find the useful bits.</p>
<p>The compilers are doing better with every release, but in specific situations, the programmer will know what’s important and can provide more and better information. If only they had any ability to do so.</p>
<h2 data-number="1.2" id="forced-constant-evaluation-failures"><span class="header-section-number">1.2</span> Forced constant evaluation failures<a href="#forced-constant-evaluation-failures" class="self-link"></a></h2>
<p>Consider the example:</p>
<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">auto</span> f<span class="op">()</span> <span class="op">-&gt;</span> std<span class="op">::</span>string <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2"></a>    <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{} {:d}&quot;</span>, <span class="dv">5</span>, <span class="st">&quot;not a number&quot;</span><span class="op">)</span>;</span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>One of the cool things about <code class="sourceCode cpp">std<span class="op">::</span>format</code> is that the format string is checked at compile time. The above is ill-formed: because <code class="sourceCode cpp">d</code> is not a valid format specifier for <code class="sourceCode cpp"><span class="kw">const</span> <span class="dt">char</span><span class="op">*</span></code>. What is the compiler error that you get here?</p>
<ul>
<li><p>MSVC</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb7-1"><a href="#cb7-1"></a>&lt;source&gt;(6): error C7595: &#39;fmt::v9::basic_format_string&lt;char,int,const char (&amp;)[13]&gt;::basic_format_string&#39;: call to immediate function is not a constant expression</span>
<span id="cb7-2"><a href="#cb7-2"></a>C:\data\libraries\installed\x64-windows\include\fmt\core.h(2839): note: failure was caused by call of undefined function or one not declared &#39;constexpr&#39;</span>
<span id="cb7-3"><a href="#cb7-3"></a>C:\data\libraries\installed\x64-windows\include\fmt\core.h(2839): note: see usage of &#39;fmt::v9::detail::error_handler::on_error&#39;</span></code></pre></div></li>
<li><p>GCC</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb8-1"><a href="#cb8-1"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format: In function &#39;std::string f()&#39;:</span>
<span id="cb8-2"><a href="#cb8-2"></a>&lt;source&gt;:6:23:   in &#39;constexpr&#39; expansion of &#39;std::basic_format_string&lt;char, int, const char (&amp;)[13]&gt;(&quot;{} {:d}&quot;)&#39;</span>
<span id="cb8-3"><a href="#cb8-3"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format:3634:19:   in &#39;constexpr&#39; expansion of &#39;__scanner.std::__format::_Checking_scanner&lt;char, int, char [13]&gt;::&lt;anonymous&gt;.std::__format::_Scanner&lt;char&gt;::_M_scan()&#39;</span>
<span id="cb8-4"><a href="#cb8-4"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format:3448:30:   in &#39;constexpr&#39; expansion of &#39;((std::__format::_Scanner&lt;char&gt;*)this)-&gt;std::__format::_Scanner&lt;char&gt;::_M_on_replacement_field()&#39;</span>
<span id="cb8-5"><a href="#cb8-5"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format:3500:15:   in &#39;constexpr&#39; expansion of &#39;((std::__format::_Scanner&lt;char&gt;*)this)-&gt;std::__format::_Scanner&lt;char&gt;::_M_format_arg(__id)&#39;</span>
<span id="cb8-6"><a href="#cb8-6"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format:3572:33:   in &#39;constexpr&#39; expansion of &#39;((std::__format::_Checking_scanner&lt;char, int, char [13]&gt;*)this)-&gt;std::__format::_Checking_scanner&lt;char, int, char [13]&gt;::_M_parse_format_spec&lt;int, char [13]&gt;(__id)&#39;</span>
<span id="cb8-7"><a href="#cb8-7"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format:3589:36:   in &#39;constexpr&#39; expansion of &#39;((std::__format::_Checking_scanner&lt;char, int, char [13]&gt;*)this)-&gt;std::__format::_Checking_scanner&lt;char, int, char [13]&gt;::_M_parse_format_spec&lt;char [13]&gt;((__id - 1))&#39;</span>
<span id="cb8-8"><a href="#cb8-8"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format:3586:40:   in &#39;constexpr&#39; expansion of &#39;__f.std::formatter&lt;char [13], char&gt;::parse(((std::__format::_Checking_scanner&lt;char, int, char [13]&gt;*)this)-&gt;std::__format::_Checking_scanner&lt;char, int, char [13]&gt;::&lt;anonymous&gt;.std::__format::_Scanner&lt;char&gt;::_M_pc)&#39;</span>
<span id="cb8-9"><a href="#cb8-9"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format:1859:26:   in &#39;constexpr&#39; expansion of &#39;((std::formatter&lt;char [13], char&gt;*)this)-&gt;std::formatter&lt;char [13], char&gt;::_M_f.std::__format::__formatter_str&lt;char&gt;::parse((* &amp; __pc))&#39;</span>
<span id="cb8-10"><a href="#cb8-10"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format:823:48: error: call to non-&#39;constexpr&#39; function &#39;void std::__format::__failed_to_parse_format_spec()&#39;</span>
<span id="cb8-11"><a href="#cb8-11"></a>  823 |         __format::__failed_to_parse_format_spec();</span>
<span id="cb8-12"><a href="#cb8-12"></a>      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~</span>
<span id="cb8-13"><a href="#cb8-13"></a>/opt/compiler-explorer/gcc-trunk-20230108/include/c++/13.0.0/format:185:3: note: &#39;void std::__format::__failed_to_parse_format_spec()&#39; declared here</span>
<span id="cb8-14"><a href="#cb8-14"></a>  185 |   __failed_to_parse_format_spec()</span>
<span id="cb8-15"><a href="#cb8-15"></a>      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span></code></pre></div></li>
<li><p>Clang (with libstdc++, libc++ doesn’t implement <code class="sourceCode cpp"><span class="op">&lt;</span>format<span class="op">&gt;</span></code> yet):</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb9-1"><a href="#cb9-1"></a>&lt;source&gt;:6:24: error: call to consteval function &#39;std::basic_format_string&lt;char, int, const char (&amp;)[13]&gt;::basic_format_string&lt;char[8]&gt;&#39; is not a constant expression</span>
<span id="cb9-2"><a href="#cb9-2"></a>    return std::format(&quot;{} {:d}&quot;, 5, &quot;not a number&quot;);</span>
<span id="cb9-3"><a href="#cb9-3"></a>                       ^</span>
<span id="cb9-4"><a href="#cb9-4"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/format:823:2: note: non-constexpr function &#39;__failed_to_parse_format_spec&#39; cannot be used in a constant expression</span>
<span id="cb9-5"><a href="#cb9-5"></a>        __format::__failed_to_parse_format_spec();</span>
<span id="cb9-6"><a href="#cb9-6"></a>        ^</span>
<span id="cb9-7"><a href="#cb9-7"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/format:1859:21: note: in call to &#39;&amp;__f._M_f-&gt;parse(__scanner._Scanner::_M_pc)&#39;</span>
<span id="cb9-8"><a href="#cb9-8"></a>      { return _M_f.parse(__pc); }</span>
<span id="cb9-9"><a href="#cb9-9"></a>                    ^</span>
<span id="cb9-10"><a href="#cb9-10"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/format:3586:35: note: in call to &#39;&amp;__f-&gt;parse(__scanner._Scanner::_M_pc)&#39;</span>
<span id="cb9-11"><a href="#cb9-11"></a>              this-&gt;_M_pc.advance_to(__f.parse(this-&gt;_M_pc));</span>
<span id="cb9-12"><a href="#cb9-12"></a>                                         ^</span>
<span id="cb9-13"><a href="#cb9-13"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/format:3589:6: note: in call to &#39;&amp;__scanner-&gt;_M_parse_format_spec(0)&#39;</span>
<span id="cb9-14"><a href="#cb9-14"></a>            _M_parse_format_spec&lt;_Tail...&gt;(__id - 1);</span>
<span id="cb9-15"><a href="#cb9-15"></a>            ^</span>
<span id="cb9-16"><a href="#cb9-16"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/format:3572:3: note: in call to &#39;&amp;__scanner-&gt;_M_parse_format_spec(1)&#39;</span>
<span id="cb9-17"><a href="#cb9-17"></a>                _M_parse_format_spec&lt;_Args...&gt;(__id);</span>
<span id="cb9-18"><a href="#cb9-18"></a>                ^</span>
<span id="cb9-19"><a href="#cb9-19"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/format:3500:2: note: in call to &#39;&amp;__scanner-&gt;_M_format_arg(1)&#39;</span>
<span id="cb9-20"><a href="#cb9-20"></a>        _M_format_arg(__id);</span>
<span id="cb9-21"><a href="#cb9-21"></a>        ^</span>
<span id="cb9-22"><a href="#cb9-22"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/format:3448:7: note: in call to &#39;&amp;__scanner-&gt;_M_on_replacement_field()&#39;</span>
<span id="cb9-23"><a href="#cb9-23"></a>                    _M_on_replacement_field();</span>
<span id="cb9-24"><a href="#cb9-24"></a>                    ^</span>
<span id="cb9-25"><a href="#cb9-25"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/format:3634:12: note: in call to &#39;&amp;__scanner-&gt;_M_scan()&#39;</span>
<span id="cb9-26"><a href="#cb9-26"></a>        __scanner._M_scan();</span>
<span id="cb9-27"><a href="#cb9-27"></a>                  ^</span>
<span id="cb9-28"><a href="#cb9-28"></a>&lt;source&gt;:6:24: note: in call to &#39;basic_format_string(&quot;{} {:d}&quot;)&#39;</span>
<span id="cb9-29"><a href="#cb9-29"></a>    return std::format(&quot;{} {:d}&quot;, 5, &quot;not a number&quot;);</span>
<span id="cb9-30"><a href="#cb9-30"></a>                       ^</span>
<span id="cb9-31"><a href="#cb9-31"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/format:185:3: note: declared here</span>
<span id="cb9-32"><a href="#cb9-32"></a>  __failed_to_parse_format_spec()</span>
<span id="cb9-33"><a href="#cb9-33"></a>  ^</span></code></pre></div></li>
<li><p>GCC, using <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> trunk instead of libstdc++:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb10-1"><a href="#cb10-1"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h: In function &#39;std::string f()&#39;:</span>
<span id="cb10-2"><a href="#cb10-2"></a>&lt;source&gt;:6:23:   in &#39;constexpr&#39; expansion of &#39;fmt::v9::basic_format_string&lt;char, int, const char (&amp;)[13]&gt;(&quot;{} {:d}&quot;)&#39;</span>
<span id="cb10-3"><a href="#cb10-3"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h:2847:40:   in &#39;constexpr&#39; expansion of &#39;fmt::v9::detail::parse_format_string&lt;true, char, format_string_checker&lt;char, int, char [13]&gt; &gt;(((fmt::v9::basic_format_string&lt;char, int, const char (&amp;)[13]&gt;*)this)-&gt;fmt::v9::basic_format_string&lt;char, int, const char (&amp;)[13]&gt;::str_, fmt::v9::detail::format_string_checker&lt;char, int, char [13]&gt;(fmt::v9::basic_string_view&lt;char&gt;(((const char*)s))))&#39;</span>
<span id="cb10-4"><a href="#cb10-4"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h:2583:44:   in &#39;constexpr&#39; expansion of &#39;fmt::v9::detail::parse_replacement_field&lt;char, format_string_checker&lt;char, int, char [13]&gt;&amp;&gt;((p + -1), end, (* &amp; handler))&#39;</span>
<span id="cb10-5"><a href="#cb10-5"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h:2558:38:   in &#39;constexpr&#39; expansion of &#39;(&amp; handler)-&gt;fmt::v9::detail::format_string_checker&lt;char, int, char [13]&gt;::on_format_specs(adapter.fmt::v9::detail::parse_replacement_field&lt;char, format_string_checker&lt;char, int, char [13]&gt;&amp;&gt;(const char*, const char*, format_string_checker&lt;char, int, char [13]&gt;&amp;)::id_adapter::arg_id, (begin + 1), end)&#39;</span>
<span id="cb10-6"><a href="#cb10-6"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h:2727:51:   in &#39;constexpr&#39; expansion of &#39;((fmt::v9::detail::format_string_checker&lt;char, int, char [13]&gt;*)this)-&gt;fmt::v9::detail::format_string_checker&lt;char, int, char [13]&gt;::parse_funcs_[id](((fmt::v9::detail::format_string_checker&lt;char, int, char [13]&gt;*)this)-&gt;fmt::v9::detail::format_string_checker&lt;char, int, char [13]&gt;::context_)&#39;</span>
<span id="cb10-7"><a href="#cb10-7"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h:2641:17:   in &#39;constexpr&#39; expansion of &#39;f.fmt::v9::formatter&lt;const char*, char, void&gt;::parse&lt;fmt::v9::detail::compile_parse_context&lt;char&gt; &gt;((* &amp; ctx))&#39;</span>
<span id="cb10-8"><a href="#cb10-8"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h:2784:35:   in &#39;constexpr&#39; expansion of &#39;fmt::v9::detail::parse_format_specs&lt;char&gt;((&amp; ctx)-&gt;fmt::v9::detail::compile_parse_context&lt;char&gt;::&lt;anonymous&gt;.fmt::v9::basic_format_parse_context&lt;char&gt;::begin(), (&amp; ctx)-&gt;fmt::v9::detail::compile_parse_context&lt;char&gt;::&lt;anonymous&gt;.fmt::v9::basic_format_parse_context&lt;char&gt;::end(), ((fmt::v9::formatter&lt;const char*, char, void&gt;*)this)-&gt;fmt::v9::formatter&lt;const char*, char, void&gt;::specs_, ctx.fmt::v9::detail::compile_parse_context&lt;char&gt;::&lt;anonymous&gt;, type)&#39;</span>
<span id="cb10-9"><a href="#cb10-9"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h:2468:37:   in &#39;constexpr&#39; expansion of &#39;parse_presentation_type.fmt::v9::detail::parse_format_specs&lt;char&gt;(const char*, const char*, dynamic_format_specs&lt;&gt;&amp;, fmt::v9::basic_format_parse_context&lt;char&gt;&amp;, type)::&lt;unnamed struct&gt;::operator()(fmt::v9::presentation_type::dec, ((int)integral_set))&#39;</span>
<span id="cb10-10"><a href="#cb10-10"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h:2395:49: error: call to non-&#39;constexpr&#39; function &#39;void fmt::v9::detail::throw_format_error(const char*)&#39;</span>
<span id="cb10-11"><a href="#cb10-11"></a> 2395 |       if (!in(arg_type, set)) throw_format_error(&quot;invalid format specifier&quot;);</span>
<span id="cb10-12"><a href="#cb10-12"></a>      |                               ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb10-13"><a href="#cb10-13"></a>/opt/compiler-explorer/libs/fmt/trunk/include/fmt/core.h:646:27: note: &#39;void fmt::v9::detail::throw_format_error(const char*)&#39; declared here</span>
<span id="cb10-14"><a href="#cb10-14"></a>  646 | FMT_NORETURN FMT_API void throw_format_error(const char* message);</span>
<span id="cb10-15"><a href="#cb10-15"></a>      |                           ^~~~~~~~~~~~~~~~~~</span></code></pre></div></li>
</ul>
<p>All the compilers reject the code, which is good. MSVC gives you no information at all. Clang indicates that there’s something wrong with some format spec, but doesn’t show enough information to know what types are involved (is it the <code class="sourceCode cpp"><span class="dv">5</span></code> or the <code class="sourceCode cpp"><span class="st">&quot;not a number&quot;</span></code>?). GCC does the best in that you can actually tell that the problem argument is a <code class="sourceCode cpp"><span class="dt">char</span><span class="op">[</span><span class="dv">13</span><span class="op">]</span></code> (if you really carefully peruse the compile error), but otherwise all you know is that there’s <em>something</em> wrong with the format spec.</p>
<p>This isn’t a standard library implementation problem - the error gcc gives when using <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> isn’t any better. If you carefully browse the message, you can see that it’s the <code class="sourceCode cpp"><span class="kw">const</span> <span class="dt">char</span><span class="op">*</span></code> specifier that’s the problem, but otherwise all you know is that it’s invalid.</p>
<p>The problem here is that the only way to “fail” here is to do something that isn’t valid during constant evaluation time, like throw an exception or invoke an undefined function. And there’s only so much information you can provide that way. You can’t provide the format string, you can’t point to the offending character.</p>
<p>Imagine how much easier this would be for the end-user to determine the problem and then fix if the compiler error you got was something like this:</p>
<blockquote>
<div class="sourceCode" id="cb11"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb11-1"><a href="#cb11-1"></a>format(&quot;{} {:d}&quot;, int, const char*)</span>
<span id="cb11-2"><a href="#cb11-2"></a>             ^         ^</span>
<span id="cb11-3"><a href="#cb11-3"></a>&#39;d&#39; is an invalid type specifier for arguments of type &#39;const char*&#39;</span></code></pre></div>
</blockquote>
<p>That message might not be perfect, but it’s overwhelmingly better than anything that’s possible today. So we should at least make it possible tomorrow.</p>
<h2 data-number="1.3" id="general-compile-time-debugging"><span class="header-section-number">1.3</span> General compile-time debugging<a href="#general-compile-time-debugging" class="self-link"></a></h2>
<p>The above two sections were about the desire to emit a compile error, with a rich diagnostic message. But sometimes we don’t want to emit an <em>error</em>, we just want to emit <em>some information</em>.</p>
<p>When it comes to runtime programming, there are several mechanisms we have for debugging code. For instance, you could use a debugger to step through it or you could litter your code with print statements. When it comes to <em>compile-time</em> programmer, neither option is available. But it would be incredibly useful to be able to litter our code with <em>compile-time</em> print statements. This was the initial selling point of Circle: want compile-time prints? That’s just <code class="sourceCode cpp"><span class="op">@</span>meta printf</code>.</p>
<p>There’s simply no way I’m aware of today to emit messages at compile-time other than forcing a compile error, and even those (as hinted at above) are highly limited.</p>
<h2 data-number="1.4" id="prior-work"><span class="header-section-number">1.4</span> Prior Work<a href="#prior-work" class="self-link"></a></h2>
<p><span class="citation" data-cites="N4433">[<a href="#ref-N4433" role="doc-biblioref">N4433</a>]</span> previously proposed extending <code class="sourceCode cpp"><span class="kw">static_assert</span></code> to support arbitrary constant expressions. That paper was discussed in <a href="https://wiki.edg.com/bin/view/Wg21lenexa/N4433">Lenexa in 2015</a>. The minutes indicate that that there was concern about simply being able to implement a useful <code class="sourceCode cpp">format</code> in <code class="sourceCode cpp"><span class="kw">constexpr</span></code> (<code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> was just v1.1.0 at the time). Nevertheless, the paper was well received, with a vote of 12-3-9-1-0 to continue work on the proposal. Today, we know we can implement a useful <code class="sourceCode cpp">format</code> in <code class="sourceCode cpp"><span class="kw">constexpr</span></code>. We already have it!</p>
<p><span class="citation" data-cites="P0596R1">[<a href="#ref-P0596R1" role="doc-biblioref">P0596R1</a>]</span> previously proposed adding <code class="sourceCode cpp">std<span class="op">::</span>constexpr_trace</code> and <code class="sourceCode cpp">std<span class="op">::</span>constexpr_assert</code> facilities - the former as a useful compile-time print and the latter as a useful compile-time assertion to emit a useful message. That paper was discussed in <a href="https://wiki.edg.com/bin/view/Wg21belfast/SG7notesP0596R1">Belfast in 2019</a>, where these two facilities were very popular (16-8-1-0-0 for compile-time print and 6-14-2-0-0 for compile-time assertion). The rest of the discussion was about broader compilation models that isn’t strictly related to these two.</p>
<p>In short, the kind of facility I’m reviving here were already previously discussed and received <em>extremely favorably</em>. 15-1, 24-0, and 20-0. It’s just that then the papers disappeared, so I’m bringing them back.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="to-stdformat-or-not-to-stdformat"><span class="header-section-number">2</span> To <code class="sourceCode cpp">std<span class="op">::</span>format</code> or not to <code class="sourceCode cpp">std<span class="op">::</span>format</code>?<a href="#to-stdformat-or-not-to-stdformat" class="self-link"></a></h1>
<p>That is the question. Basically, when it comes to emitting some kind of text (via whichever mechanism - whether <code class="sourceCode cpp"><span class="kw">static_assert</span></code> or a compile-time print or a compile-time error), we have to decide whether or not to bake <code class="sourceCode cpp">std<span class="op">::</span>format</code> into the API. The advantage of doing so would be ergonomics, the disadvantage would be that it’s a complex library to potential bake into the language - and some people might want these facilities in a context where they’re not using <code class="sourceCode cpp">std<span class="op">::</span>format</code>, for hwatever reason.</p>
<p>But there’s also a bigger issue: while I said above that we have a useful <code class="sourceCode cpp">format</code> in <code class="sourceCode cpp"><span class="kw">constexpr</span></code>, that wasn’t <em>entirely</em> accurate. The parsing logic is completely <code class="sourceCode cpp"><span class="kw">constexpr</span></code> (to great effect), but the formatting logic currently is not. Neither <code class="sourceCode cpp">std<span class="op">::</span>format</code> nor <code class="sourceCode cpp">fmt<span class="op">::</span>format</code> are declared <code class="sourceCode cpp"><span class="kw">constexpr</span></code> today. In order to be able to even consider the question of using <code class="sourceCode cpp">std<span class="op">::</span>format</code> for generating compile-time strings, we have to first ask to what extent this is even feasible.</p>
<p>I think there are currently two limitations (excluding just adding <code class="sourceCode cpp"><span class="kw">constexpr</span></code> everywhere and possibly dealing with some algorithms that happen to not be <code class="sourceCode cpp"><span class="kw">constexpr</span></code>-friendly):</p>
<ol type="1">
<li>formatting floating-point types is not possible right now (we made the integral part of <code class="sourceCode cpp">std<span class="op">::</span>to_chars<span class="op">()</span></code> <code class="sourceCode cpp"><span class="kw">constexpr</span></code> <span class="citation" data-cites="P2291R3">[<a href="#ref-P2291R3" role="doc-biblioref">P2291R3</a>]</span>, but not the floating point).</li>
<li><code class="sourceCode cpp">fmt<span class="op">::</span>format</code> and <code class="sourceCode cpp">std<span class="op">::</span>format</code> rely on type erasing user-defined types, and that’s currently impossible to do at <code class="sourceCode cpp"><span class="kw">constexpr</span></code> time.</li>
</ol>
<p>I am not in a position to say how hard the first of the two is (it’s probably pretty hard?), but I have a separate paper addressing the second <span class="citation" data-cites="P2747R0">[<a href="#ref-P2747R0" role="doc-biblioref">P2747R0</a>]</span>. If we can do any kind of type erasure at all, then it’s probably not too much work to get the rest of format working - even if we ignore floating point entirely. Without compile-time type erasure, it’s still possible to write just a completely different consteval formatting API - but I doubt people would be too happy about having to redo all that work.</p>
<p>We will eventually have <code class="sourceCode cpp"><span class="kw">constexpr</span> std<span class="op">::</span>format</code>, I’m just hoping that we can do so with as little overhead on the library implementation itself (in terms of lines of code) as possible.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="improving-static_assert"><span class="header-section-number">3</span> Improving <code class="sourceCode cpp"><span class="kw">static_assert</span></code><a href="#improving-static_assert" class="self-link"></a></h1>
<p>There are basically two approaches we can take to generalizing the kinds of output <code class="sourceCode cpp"><span class="kw">static_assert</span></code> can produce.</p>
<p>We can allow any constant expression that is some kind of range of <code class="sourceCode cpp"><span class="dt">char</span></code>, <code class="sourceCode cpp"><span class="dt">wchar_t</span></code>, <code class="sourceCode cpp"><span class="dt">char8_t</span></code>, <code class="sourceCode cpp"><span class="dt">char16_t</span></code>, or <code class="sourceCode cpp"><span class="dt">char32_t</span></code>. Like this one:</p>
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1"></a><span class="kw">static_assert</span><span class="op">(</span>cond, std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;The value is {}&quot;</span>, <span class="dv">42</span><span class="op">))</span>;</span></code></pre></div>
</blockquote>
<p>Or we can embed <code class="sourceCode cpp">std<span class="op">::</span>format</code> into the declaration itself:</p>
<blockquote>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1"></a><span class="kw">static_assert</span><span class="op">(</span>cond, <span class="st">&quot;The value is {}&quot;</span>, <span class="dv">42</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>The latter is definitely more ergonomic than the former, but only because you don’t have to write the call to <code class="sourceCode cpp">std<span class="op">::</span>format</code>. However, it has a couple problems.</p>
<p>One big problem is: what does this mean?</p>
<blockquote>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1"></a><span class="kw">static_assert</span><span class="op">(</span>cond, <span class="st">&quot;T{} must be a valid expression.&quot;</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>Today, that’s a valid declaration. But that isn’t a valid format string without format arguments - you’d have to escape the braces to get the same behavior. We could resolve this issue by saying that:</p>
<ul>
<li><code class="sourceCode cpp"><span class="kw">static_assert</span><span class="op">(</span>cond, <em>string-literal</em><span class="op">)</span></code> is the existing behavior</li>
<li><code class="sourceCode cpp"><span class="kw">static_assert</span><span class="op">(</span>cond, <em>string-literal</em>, <em>expression-list</em><span class="op">...)</span></code> where <code class="sourceCode cpp"><em>expression-list</em></code> contains at least one expression is the new behavior</li>
</ul>
<p>This seems… not great. Rust went this approach before and recently changed it in the 2021 edition. From <a href="https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html">panic macro consistency</a>:</p>
<div class="quote">
<p>The <code class="language-rust">panic!()</code> macro is one of Rust’s most well known macros. However, it has some subtle surprises that we can’t just change due to backwards compatibility.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1"></a><span class="co">// Rust 2018</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="pp">panic!</span>(<span class="st">&quot;{}&quot;</span><span class="op">,</span> <span class="dv">1</span>)<span class="op">;</span> <span class="co">// Ok, panics with the message &quot;1&quot;</span></span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="pp">panic!</span>(<span class="st">&quot;{}&quot;</span>)<span class="op">;</span> <span class="co">// Ok, panics with the message &quot;{}&quot;</span></span></code></pre></div>
<p>[…]</p>
<p>This will especially be a problem once implicit format arguments are stabilized. That feature will make <code class="language-rust">println!(&quot;hello {name}&quot;)</code> a short-hand for <code class="language-rust">println!(&quot;hello {}&quot;, name)</code>. However, <code class="language-rust">panic!(&quot;hello {name}&quot;)</code> would not work as expected, since <code class="language-rust">panic!()</code> doesn’t process a single argument as format string.</p>
<p>To avoid that confusing situation, Rust 2021 features a more consistent <code class="language-rust">panic!()</code> macro. The new <code class="language-rust">panic!()</code> macro will no longer accept arbitrary expressions as the only argument. It will, just like <code class="language-rust">println!()</code>, always process the first argument as format string.</p>
</div>
<p>Generally speaking, probably not a great idea to adopt a language design that another language is explicitly moving away from.</p>
<p>And we, unfortunately, also can’t simply change the meaning of existing <code class="sourceCode cpp"><span class="kw">static_assert</span></code> declarations in order to start treating them uniformly as format strings. If we had some mechanism to break source compatibility in an opt-in way (like, say, Rust editions), then that’s something we could consider. But we don’t, so we can’t.</p>
<p>This approach has another problem, which is tying in a complex library mechanism into a language feature. But I’m not really sure it’s worth dwelling on in light of the fact that we can’t really go this route anyway.</p>
<p>That leaves the other idea - requiring the user to write <code class="sourceCode cpp">std<span class="op">::</span>format</code> themselves:</p>
<blockquote>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1"></a><span class="kw">static_assert</span><span class="op">(</span>cond, std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;The value is {}&quot;</span>, <span class="dv">42</span><span class="op">))</span>;</span></code></pre></div>
</blockquote>
<p>Tedious, but at least it makes a facility possible that currently is not. In order to specify this, we’d need to extend the definition of <code class="sourceCode cpp"><span class="kw">static_assert</span></code>. Currently, it only allows <code class="sourceCode cpp"><em>string-literal</em></code>, but we’d want it to be any range of some character type. We already have some language range wording in the standard, in <span>8.6.5 <a href="https://wg21.link/stmt.ranged">[stmt.ranged]</a></span>, so we’d just refer to that.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="improving-compile-time-diagnostics"><span class="header-section-number">4</span> Improving compile-time diagnostics<a href="#improving-compile-time-diagnostics" class="self-link"></a></h1>
<p>While in <code class="sourceCode cpp"><span class="kw">static_assert</span></code>, I don’t think we can have a <code class="sourceCode cpp">std<span class="op">::</span>format<span class="op">()</span></code>-based API, for compile-time diagnostics, I think we should. In particular, the user-facing API should probably be something like this:</p>
<blockquote>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb16-2"><a href="#cb16-2"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb16-3"><a href="#cb16-3"></a>    <span class="kw">constexpr</span> <span class="dt">void</span> constexpr_print<span class="op">(</span>format_string<span class="op">&lt;</span>Args<span class="op">...&gt;</span> fmt, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span>
<span id="cb16-4"><a href="#cb16-4"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb16-5"><a href="#cb16-5"></a>    <span class="kw">constexpr</span> <span class="dt">void</span> constexpr_error<span class="op">(</span>format_string<span class="op">&lt;</span>Args<span class="op">...&gt;</span> fmt, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span>
<span id="cb16-6"><a href="#cb16-6"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>But we’ll probably still need a lower-level API as well. Something these facilities can be implemented on top of, that we might want to expose to users anyway in case they want to use something other than <code class="sourceCode cpp">std<span class="op">::</span>format</code> for their formatting needs. Perhaps something like this:</p>
<blockquote>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2"></a>  <span class="kw">constexpr</span> <span class="dt">void</span> constexpr_print_str<span class="op">(</span><span class="dt">char</span> <span class="kw">const</span><span class="op">*)</span>;</span>
<span id="cb17-3"><a href="#cb17-3"></a>  <span class="kw">constexpr</span> <span class="dt">void</span> constexpr_print_str<span class="op">(</span><span class="dt">char</span> <span class="kw">const</span><span class="op">*</span>, <span class="dt">size_t</span><span class="op">)</span>;</span>
<span id="cb17-4"><a href="#cb17-4"></a>  <span class="kw">constexpr</span> <span class="dt">void</span> constexpr_error_str<span class="op">(</span><span class="dt">char</span> <span class="kw">const</span><span class="op">*)</span>;</span>
<span id="cb17-5"><a href="#cb17-5"></a>  <span class="kw">constexpr</span> <span class="dt">void</span> constexpr_error_str<span class="op">(</span><span class="dt">char</span> <span class="kw">const</span><span class="op">*</span>, <span class="dt">size_t</span><span class="op">)</span>;</span>
<span id="cb17-6"><a href="#cb17-6"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>That is really the minimum necessary, and the nice <code class="sourceCode cpp">format</code> APIs can then trivially be implemented by invoking <code class="sourceCode cpp">std<span class="op">::</span>format</code> and then passing in the resulting <code class="sourceCode cpp">std<span class="op">::</span>string</code>.</p>
<p>But in order to talk about what these APIs actually do and what their effects are, we need to talk about a fairly complex concept: predictability.</p>
<h2 data-number="4.1" id="predictability"><span class="header-section-number">4.1</span> Predictability<a href="#predictability" class="self-link"></a></h2>
<p><span class="citation" data-cites="P0596R1">[<a href="#ref-P0596R1" role="doc-biblioref">P0596R1</a>]</span> talks about predictability introducing this example:</p>
<div class="quote">
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span><span class="op">&gt;</span> <span class="kw">constexpr</span> <span class="dt">int</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-2"><a href="#cb18-2"></a>    std<span class="op">::</span>__report_constexpr_value<span class="op">(</span>“in g<span class="op">()</span>\n”<span class="op">)</span>;</span>
<span id="cb18-3"><a href="#cb18-3"></a>    <span class="cf">return</span> <span class="dv">42</span>;</span>
<span id="cb18-4"><a href="#cb18-4"></a><span class="op">}</span></span>
<span id="cb18-5"><a href="#cb18-5"></a></span>
<span id="cb18-6"><a href="#cb18-6"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="dt">int</span> f<span class="op">(</span>T<span class="op">(*)[</span>g<span class="op">&lt;</span>T<span class="op">&gt;()])</span>; <span class="co">// (1)</span></span>
<span id="cb18-7"><a href="#cb18-7"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="dt">int</span> f<span class="op">(</span>T<span class="op">*)</span>;           <span class="co">// (2)</span></span>
<span id="cb18-8"><a href="#cb18-8"></a><span class="dt">int</span> r <span class="op">=</span> f<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;(</span><span class="kw">nullptr</span><span class="op">)</span>;</span></code></pre></div>
<p>When the compiler resolves the call to <code class="sourceCode cpp">f</code> in this example, it substitutes <code class="sourceCode cpp"><span class="dt">void</span></code> for <code class="sourceCode cpp">T</code> in both declarations (1) and (2). However, for declaration (1), it is unspecified whether <code class="sourceCode cpp">g<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;()</span></code> will be invoked: The compiler may decide to abandon the substitution as soon as it sees an attempt to create “an array of void” (in which case the call to <code class="sourceCode cpp">g<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span></code> is not evaluated), or it may decide to finish parsing the array declarator and evaluate the call to <code class="sourceCode cpp">g<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span></code> as part of that.</p>
<p>We can think of a few realistic ways to address/mitigate this issue:</p>
<ol type="1">
<li>Make attempts to trigger side-effects in expressions that are “tentatively evaluated” (such as the ones happening during deduction) ill-formed with no diagnostic required (because we cannot really require compilers to re-architect their deduction system to ensure that the side-effect trigger is reached).</li>
<li>Make attempts to trigger side-effects in expressions that are “tentatively evaluated” cause the expression to be non-constant. With our example that would mean that even a call <code class="sourceCode cpp">f<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;(</span><span class="kw">nullptr</span><span class="op">)</span></code> would find (1) to be nonviable because <code class="sourceCode cpp">g<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;()</span></code> doesn’t produce a constant in that context.</li>
<li>Introduce a new special function to let the programmer control whether the side effect takes place anyway. E.g., <code class="sourceCode cpp">std<span class="op">::</span>is_tentatively_constant_evaluated<span class="op">()</span></code>. The specification work for this is probably nontrivial and it would leave it unspecified whether the call to <code class="sourceCode cpp">g<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span></code> is evaluated in our example.</li>
</ol>
<p>We propose to follow option 2. Option 3 remains a possible evolution path in that case, but we prefer to avoid the resulting subtleties if we can get away with it.</p>
</div>
<p>As well as:</p>
<div class="quote">
<p>There is another form of “tentative evaluation” that is worth noting. Consider:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1"></a><span class="kw">constexpr</span> <span class="dt">int</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb19-2"><a href="#cb19-2"></a>    std<span class="op">::</span>__report_constexpr_value<span class="op">(</span><span class="st">&quot;in g()</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">)</span>;</span>
<span id="cb19-3"><a href="#cb19-3"></a>    <span class="cf">return</span> <span class="dv">41</span>;</span>
<span id="cb19-4"><a href="#cb19-4"></a><span class="op">}</span></span>
<span id="cb19-5"><a href="#cb19-5"></a><span class="dt">int</span> i <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb19-6"><a href="#cb19-6"></a><span class="kw">constexpr</span> <span class="dt">int</span> h<span class="op">(</span><span class="dt">int</span> p<span class="op">)</span> <span class="op">{</span></span>
<span id="cb19-7"><a href="#cb19-7"></a>    <span class="cf">return</span> p <span class="op">==</span> <span class="dv">0</span> <span class="op">?</span> i <span class="op">:</span> <span class="dv">1</span>;</span>
<span id="cb19-8"><a href="#cb19-8"></a><span class="op">}</span></span>
<span id="cb19-9"><a href="#cb19-9"></a><span class="dt">int</span> r <span class="op">=</span> g<span class="op">()+</span>h<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="co">// Not manifestly constant-evaluated but</span></span>
<span id="cb19-10"><a href="#cb19-10"></a>                  <span class="co">// g() is typically tentatively evaluated.</span></span>
<span id="cb19-11"><a href="#cb19-11"></a><span class="dt">int</span> s <span class="op">=</span> g<span class="op">()+</span><span class="dv">1</span>;    <span class="co">// To be discussed.</span></span></code></pre></div>
<p>Here <code class="sourceCode cpp">g<span class="op">()+</span>h<span class="op">(</span><span class="dv">0</span><span class="op">)</span></code> is not a constant expression because <code class="sourceCode cpp">i</code> cannot be evaluated at compile time. However, the compiler performs a “trial evaluation” of that expression to discover that. In order to comply with the specification that <code class="sourceCode cpp">__report_constexpr_value</code> only produce the side effect if invoked as part of a “manifestly constant-evaluated expression”, two implementation strategies are natural:</p>
<ol type="1">
<li>“Buffer” the side effects during the trial evaluation and “commit” them only if that evaluation succeeds.</li>
<li>Disable the side effects during the trial evaluation and repeat the evaluation with side effects enabled if the trial evaluation succeeds.</li>
</ol>
<p>The second option is only viable because “output” as a side effect cannot be observed by the trial evaluation. However, further on we will consider another class of side effects that can be observed within the same evaluation that triggers them, and thus we do not consider option 2 a viable general implementation strategy.</p>
<p>The first option is more generally applicable, but it may impose a significant toll on performance if the amount of side effects that have to be “buffered” for a later “commit” is significant.</p>
<p>An alternative, therefore, might be to also consider the context of a non-constexpr variable initialization to be “tentatively evaluated” and deem side-effects to be non-constant in that case (i.e., the same as proposed for evaluations during deduction). In the example above, that means that <code class="sourceCode cpp">g<span class="op">()+</span><span class="dv">1</span></code> would not be a constant expression either (due to the potential side effect by <code class="sourceCode cpp">__report_constexpr_value</code> in an initializer that is allowed to be non-constant) and thus <code class="sourceCode cpp">s</code> would not be statically initialized.</p>
</div>
<p>Now, my guiding principle here is that if we take some code that currently works and does some constant evaluation, and add to that code a <code class="sourceCode cpp">constexpr_print</code> statement, the <em>only</em> change in behavior should be the addition of output during compile time. For instance:</p>
<blockquote>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> f<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">int</span> <span class="op">{</span></span>
<span id="cb20-2"><a href="#cb20-2"></a>    std<span class="op">::</span>constexpr_print<span class="op">(</span><span class="st">&quot;Called f({})</span><span class="sc">\n</span><span class="st">&quot;</span>, i<span class="op">)</span>;</span>
<span id="cb20-3"><a href="#cb20-3"></a>    <span class="cf">return</span> i;</span>
<span id="cb20-4"><a href="#cb20-4"></a><span class="op">}</span></span>
<span id="cb20-5"><a href="#cb20-5"></a></span>
<span id="cb20-6"><a href="#cb20-6"></a><span class="dt">int</span> x <span class="op">=</span> f<span class="op">(</span><span class="dv">2</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>WIthout the <code class="sourceCode cpp">constepr_print</code>, this variable is constant-initialized. WIth it, it should be also. It would be easier to deal with the language if we didn’t have all of these weird rules. For instance, if you want constant initialize, use <code class="sourceCode cpp"><span class="kw">constinit</span></code>, if you don’t, there’s no tentative evaluation. But we can’t change that, so this is the language we have.</p>
<p>I think buffer-then-commit is right approach. But also for the first example, that tentative evaluation in a manifestly constant evaluated context is <em>still</em> manifestly constant evaluated. It’s just unspecified whether the call happens. That is: in the first example, the call <code class="sourceCode cpp">f<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;(</span><span class="kw">nullptr</span><span class="op">)</span></code> may or may not print <code class="sourceCode cpp"><span class="st">&quot;in g()</span><span class="sc">\n</span><span class="st">&quot;</span></code>. It’s unspecified. It may make constexpr output not completely portable, but I don’t think any of the alternatives are palatable.</p>
<h2 data-number="4.2" id="predictability-of-errors"><span class="header-section-number">4.2</span> Predictability of Errors<a href="#predictability-of-errors" class="self-link"></a></h2>
<p>An interesting follow-on is what happens here:</p>
<blockquote>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> f<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">int</span> <span class="op">{</span></span>
<span id="cb21-2"><a href="#cb21-2"></a>    <span class="cf">if</span> <span class="op">(</span>i <span class="op">&lt;</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-3"><a href="#cb21-3"></a>        std<span class="op">::</span>constexpr_error_str<span class="op">(</span><span class="st">&quot;cannot invoke f with a negative number&quot;</span><span class="op">)</span>;</span>
<span id="cb21-4"><a href="#cb21-4"></a>    <span class="op">}</span></span>
<span id="cb21-5"><a href="#cb21-5"></a>    <span class="cf">return</span> i;</span>
<span id="cb21-6"><a href="#cb21-6"></a><span class="op">}</span></span>
<span id="cb21-7"><a href="#cb21-7"></a></span>
<span id="cb21-8"><a href="#cb21-8"></a><span class="kw">constexpr</span> <span class="dt">int</span> a <span class="op">=</span> f<span class="op">(-</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb21-9"><a href="#cb21-9"></a><span class="dt">int</span> b <span class="op">=</span> f<span class="op">(-</span><span class="dv">1</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>Basically the question is: what are the actual semantics of <code class="sourceCode cpp">constexpr_error</code>?</p>
<p>If we just say that evaluation (if manifestly constant-evaluated) causes the evaluation to not be a constant, then <code class="sourceCode cpp">a</code> is ill-formed but <code class="sourceCode cpp">b</code> would be (dynamically) initialized with <code class="sourceCode cpp"><span class="op">-</span><span class="dv">1</span></code>.</p>
<p>That seems undesirable: this is, after all, an error that we have the opportunity to catch. This is the only such case: all other manifestly constant evaluated contexts don’t have this kind of fall-back to runtime. So I think it’s not enough to say that constant evaluation fails, but rather that the entire program is ill-formed in this circumstance: both <code class="sourceCode cpp">a</code> and <code class="sourceCode cpp">b</code> are ill-formed.</p>
<p>We also have to consider the predictability question for error-handling. Here’s that same example again:</p>
<blockquote>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span><span class="op">&gt;</span> <span class="kw">constexpr</span> <span class="dt">int</span> g<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-2"><a href="#cb22-2"></a>    <span class="cf">if</span> <span class="op">(</span>i <span class="op">&lt;</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-3"><a href="#cb22-3"></a>        std<span class="op">::</span>constexpr_error_str<span class="op">(</span><span class="st">&quot;can&#39;t call g with a negative number&quot;</span><span class="op">)</span>;</span>
<span id="cb22-4"><a href="#cb22-4"></a>    <span class="op">}</span></span>
<span id="cb22-5"><a href="#cb22-5"></a>    <span class="cf">return</span> <span class="dv">42</span>;</span>
<span id="cb22-6"><a href="#cb22-6"></a><span class="op">}</span></span>
<span id="cb22-7"><a href="#cb22-7"></a></span>
<span id="cb22-8"><a href="#cb22-8"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="dt">int</span> f<span class="op">(</span>T<span class="op">(*)[</span>g<span class="op">&lt;</span>T<span class="op">&gt;(-</span><span class="dv">1</span><span class="op">)])</span>; <span class="co">// (1)</span></span>
<span id="cb22-9"><a href="#cb22-9"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="dt">int</span> f<span class="op">(</span>T<span class="op">*)</span>;             <span class="co">// (2)</span></span>
<span id="cb22-10"><a href="#cb22-10"></a><span class="dt">int</span> r <span class="op">=</span> f<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;(</span><span class="kw">nullptr</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>If <code class="sourceCode cpp">g<span class="op">&lt;</span>T<span class="op">&gt;(-</span><span class="dv">1</span><span class="op">)</span></code> is called, then it’ll hit the <code class="sourceCode cpp">constexpr_error_str</code> call. But it might not be called. I think saying that if it’s called, then the program is ill-formed, is probably fine. If necessary, we can further tighten the rules for substitution and actually specify one way or another (actually specify that <code class="sourceCode cpp">g</code> is <em>not</em> invoked because by the time we lexically get there we know that this whole type is ill-formed, or specify that <code class="sourceCode cpp">g</code> <em>is</em> invoked because we atomically substitute one type at a time), but it’s probably not worth the effort.</p>
<p>Additionally, we could take a leaf out of the book of speculative evaluation. I think of the tentative evaluation of <code class="sourceCode cpp">g<span class="op">&lt;</span>T<span class="op">&gt;(-</span><span class="dv">1</span><span class="op">)</span></code> is this second example <em>quite</em> differently from the tentative <em>constant</em> evaluation of <code class="sourceCode cpp">f<span class="op">(-</span><span class="dv">1</span><span class="op">)</span></code> in the first example. <code class="sourceCode cpp">f</code> is <em>always</em> evaluated, it’s just that we have this language hack that it ends up potentially being evaluated two different ways. <code class="sourceCode cpp">g</code> isn’t <em>necessarily</em> evaluated. So there is room to treat these different. If <code class="sourceCode cpp">g</code> is tentatively evaluated, then we buffer up our prints and errors - such that if it eventually <em>is</em> evaluated (that overload is selected), we then emit all the prints and errors. Otherwise, there is no output. That is, we specify <em>no</em> output if the function isn’t selected. Because the evaluation model is different here - that <code class="sourceCode cpp">f</code> is always constant-evaluated initially - I don’t think of these as inconsistent decisions.</p>
<h2 data-number="4.3" id="error-handling-in-general"><span class="header-section-number">4.3</span> Error-Handling in General<a href="#error-handling-in-general" class="self-link"></a></h2>
<p>Basically, in all contexts, you probably wouldn’t want to <em>just</em> <code class="sourceCode cpp">std<span class="op">::</span>constexpr_error</code>. Well, in a <code class="sourceCode cpp"><span class="kw">consteval</span></code> function, that’s all you’d have to do. But in a <code class="sourceCode cpp"><span class="kw">constexpr</span></code> function that might be evaluated at runtime, you probably still want to fail.</p>
<p>But the question is, <em>how</em> do you want to fail? There are so many different ways of failing</p>
<ul>
<li>throw an exception (of which kind?)</li>
<li>return some kind of error object (return code, <code class="sourceCode cpp">unexpected</code>, <code class="sourceCode cpp"><span class="kw">false</span></code>, etc.)</li>
<li><code class="sourceCode cpp">std<span class="op">::</span>abort<span class="op">()</span></code></li>
<li><code class="sourceCode cpp">std<span class="op">::</span>terminate<span class="op">()</span></code></li>
<li>etc.</li>
</ul>
<p>Which fallback depends entirely on the circumstance. For <code class="sourceCode cpp">formatter<span class="op">&lt;</span>T<span class="op">&gt;::</span>parse</code>, one of my motivating examples here, we have to throw a <code class="sourceCode cpp">std<span class="op">::</span>format_error</code> in this situation. The right pattern there would probably be:</p>
<blockquote>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1"></a><span class="cf">if</span> <span class="kw">consteval</span> <span class="op">{</span></span>
<span id="cb23-2"><a href="#cb23-2"></a>    std<span class="op">::</span>constexpr_error<span class="op">(</span><span class="st">&quot;Bad specifier {}&quot;</span>, <span class="op">*</span>it<span class="op">)</span>;</span>
<span id="cb23-3"><a href="#cb23-3"></a><span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb23-4"><a href="#cb23-4"></a>    <span class="cf">throw</span> std<span class="op">::</span>format_error<span class="op">(</span>std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;Bad specifier {}&quot;</span>, <span class="op">*</span>it<span class="op">))</span>;</span>
<span id="cb23-5"><a href="#cb23-5"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Which can be easily handled in its own API:</p>
<blockquote>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-2"></a><span class="kw">constexpr</span> <span class="dt">void</span> format_parse_failure<span class="op">(</span>format_string<span class="op">&lt;</span>Args<span class="op">...&gt;</span> fmt, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-3"><a href="#cb24-3"></a>    <span class="cf">if</span> <span class="kw">consteval</span> <span class="op">{</span></span>
<span id="cb24-4"><a href="#cb24-4"></a>        constexpr_error<span class="op">(</span>fmt, args<span class="op">...)</span>;</span>
<span id="cb24-5"><a href="#cb24-5"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb24-6"><a href="#cb24-6"></a>        <span class="cf">throw</span> format_error<span class="op">(</span>format<span class="op">(</span>fmt, args<span class="op">...))</span>;</span>
<span id="cb24-7"><a href="#cb24-7"></a>    <span class="op">}</span></span>
<span id="cb24-8"><a href="#cb24-8"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>So we should probably provide that as well (under whichever name).</p>
<p>But that’s a format-specific solution. But a similar pattern works just fine for other error handling mechanisms, except for wanting to return an object (unless your return object happens to have a string part - since the two cases end up being very dfferent). I think that’s okay though - at least we have the utility.</p>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="proposal"><span class="header-section-number">5</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>This paper proposes the following:</p>
<ol type="1">
<li>Extend <code class="sourceCode cpp"><span class="kw">static_assert</span></code> to take not just a <code class="sourceCode cpp"><em>string-literal</em></code> but any <code class="sourceCode cpp"><em>string-range</em></code> such that you can use a call to <code class="sourceCode cpp">std<span class="op">::</span>format<span class="op">()</span></code> as the message</li>
<li>Introduce new compile-time diagnostic APIs, that only have effect if manifestly constant evaluated: <code class="sourceCode cpp">std<span class="op">::</span>constexpr_print_str<span class="op">(</span>msg<span class="op">)</span></code> and <code class="sourceCode cpp">std<span class="op">::</span>constexpr_print_str<span class="op">(</span>msg, len<span class="op">)</span></code>.</li>
<li>Introduce new compile-time error APIs, that only have effect if manifestly constant evaluated: <code class="sourceCode cpp">std<span class="op">::</span>constexpr_error_str<span class="op">(</span>msg<span class="op">)</span></code> and <code class="sourceCode cpp">std<span class="op">::</span>constexpr_error_str<span class="op">(</span>msg, len<span class="op">)</span></code>.</li>
<li>Pursue <code class="sourceCode cpp"><span class="kw">constexpr</span> std<span class="op">::</span>format<span class="op">(</span>fmt_str, args<span class="op">...)</span></code>, which would then allow us to extend the above API with:
<ol type="a">
<li><code class="sourceCode cpp">std<span class="op">::</span>constexpr_print<span class="op">(</span>fmt_str, args<span class="op">...)</span></code></li>
<li><code class="sourceCode cpp">std<span class="op">::</span>constexpr_error<span class="op">(</span>fmt_str, args<span class="op">...)</span></code></li>
<li>a <code class="sourceCode cpp">format</code>-specific helper <code class="sourceCode cpp">std<span class="op">::</span>format_parse_error<span class="op">(</span>fmt_str, args<span class="op">...)</span></code> that either calls <code class="sourceCode cpp">std<span class="op">::</span>constexpr_error</code> or throws a <code class="sourceCode cpp">std<span class="op">::</span>format_error</code>, depending on context.</li>
</ol></li>
</ol>
<h1 data-number="6" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">6</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-N4433">
<p>[N4433] Michael Price. 2015-04-09. Flexible static_assert messages. <br />
<a href="https://wg21.link/n4433">https://wg21.link/n4433</a></p>
</div>
<div id="ref-P0596R1">
<p>[P0596R1] Daveed Vandevoorde. 2019-10-08. Side-effects in constant evaluation: Output and consteval variables. <br />
<a href="https://wg21.link/p0596r1">https://wg21.link/p0596r1</a></p>
</div>
<div id="ref-P2291R3">
<p>[P2291R3] Daniil Goncharov, Karaev Alexander. 2021-09-23. Add Constexpr Modifiers to Functions to_chars and from_chars for Integral Types in Header. <br />
<a href="https://wg21.link/p2291r3">https://wg21.link/p2291r3</a></p>
</div>
<div id="ref-P2747R0">
<p>[P2747R0] Barry Revzin. 2022-12-16. Limited support for <code class="sourceCode cpp"><span class="kw">constexpr</span> <span class="dt">void</span><span class="op">*</span></code>. <br />
<a href="https://wg21.link/p2747r0">https://wg21.link/p2747r0</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
