<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="pandoc" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="author" content="Alex Gilding (Perforce UK)" />
  <meta name="author" content="Jens Gustedt (INRIA France)" />
  <meta name="dcterms.date" content="2022-04-08" />
  <title>The constexpr specifier for object definitions</title>
  <style type="text/css">
      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%;}
  </style>
  <!-- (A) TOGGLE PROPERTY WITH JAVASCRIPT -->
  <script>
  function hideDel () {
      var block = document.getElementsByTagName("del");
      let fLen = block.length;
      for (let i = 0; i < fLen; i++) {
          block[i].style.display = "none";
      }
  }
  function hideIns () {
      var block = document.getElementsByTagName("ins");
      let fLen = block.length;
      for (let i = 0; i < fLen; i++) {
          block[i].style.display = "none";
      }
  }
  function showDel () {
      var block = document.getElementsByTagName("del");
      let fLen = block.length;
      for (let i = 0; i < fLen; i++) {
          block[i].style.display = "";
      }
  }
  function showIns () {
      var block = document.getElementsByTagName("ins");
      let fLen = block.length;
      for (let i = 0; i < fLen; i++) {
          block[i].style.display = "";
      }
  }
  function showOrig () {
      hideIns();
      showDel();
  }
  function showNew () {
      showIns();
      hideDel();
  }
  function showBoth () {
      showIns();
      showDel();
  }
  function toggleToc () {
      var block = document.getElementById("TOC");
      let fLen = block.length;
      if (block.style.display == "") {
          block.style.display = "none";
      } else {
          block.style.display = "";
      }
  }
  </script>
  <!-- (B) TEST BLOCK OF TEXT -->
  <table id="diffToggles" style="position: fixed; top: 0; right: 0; z-index: 1"/>
  <tbody>
  <tr><td><input type="button" value="toggle toc" onclick="toggleToc()"/></td><tr>
  <tr><td><input type="button" value="show orig" onclick="showOrig()"/></td><tr>
  <tr><td><input type="button" value="show new" onclick="showNew()"/></td><tr>
  <tr><td><input type="button" value="show both" onclick="showBoth()"/></td><tr>
  </tbody>
  </table>
  <style>
    /*
      Buttondown
      A Markdown/MultiMarkdown/Pandoc HTML output CSS stylesheet
      Author: Ryan Gray
      Date: 15 Feb 2011
      Revised: 21 Feb 2012
     
      General style is clean, with minimal re-definition of the defaults or 
      overrides of user font settings. The body text and header styles are 
      left alone except title, author and date classes are centered. A Pandoc TOC 
      is not printed, URLs are printed after hyperlinks in parentheses. 
      Block quotes are italicized. Tables are lightly styled with lines above 
      and below the table and below the header with a boldface header. Code 
      blocks are line wrapped. 
  
      All elements that Pandoc and MultiMarkdown use should be listed here, even 
      if the style is empty so you can easily add styling to anything.
      
      There are some elements in here for HTML5 output of Pandoc, but I have not 
      gotten around to testing that yet.
  */
  
  /* NOTES:
  
      Stuff tried and failed:
      
      It seems that specifying font-family:serif in Safari will always use 
      Times New Roman rather than the user's preferences setting.
      
      Making the font size different or a fixed value for print in case the screen 
      font size is making the print font too big: Making font-size different for 
      print than for screen causes horizontal lines to disappear in math when using 
      MathJax under Safari.
  */
  
  /* ---- Front Matter ---- */
  
  /* Pandoc header DIV. Contains .title, .author and .date. Comes before div#TOC. 
     Only appears if one of those three are in the document.
  */
  
  body {counter-reset: h2}
    h2 {counter-reset: h3}
    h2 {counter-reset: h3}
    h3 {counter-reset: h4}
    h4 {counter-reset: h5}
    h5 {counter-reset: h6}
  
    h2:before {counter-increment: h2; content: counter(h2) ". "}
    h3:before {counter-increment: h3; content: counter(h2) "." counter(h3) ". "}
    h4:before {counter-increment: h4; content: counter(h2) "." counter(h3) "." counter(h4) ". "}
    h5:before {counter-increment: h5; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) ". "}
    h6:before {counter-increment: h6; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) ". "}
  
    h2.nocount:before, h3.nocount:before, h4.nocount:before, h5.nocount:before, h6.nocount:before { content: ""; counter-increment: none }
    
  div#header, header
      {
      /* Put border on bottom. Separates it from TOC or body that comes after it. */
      border-bottom: 1px solid #aaa;
      margin-bottom: 0.5em;
      }
  
  .title /* Pandoc title header (h1.title) */
      {
      text-align: center;
      }
  
  .author, .date /* Pandoc author(s) and date headers (h2.author and h3.date) */
  {
      font-size: 3ex;
      text-align: center;
      }
  
  /* Pandoc table of contents DIV when using the --toc option.
     NOTE: this doesn't support Pandoc's --id-prefix option for #TOC and #header. 
     Probably would need to use div[id$='TOC'] and div[id$='header'] as selectors.
  */
  
  div#TOC, nav#TOC
      {
      /* Put border on bottom to separate it from body. */
      border-bottom: 1px solid #aaa;
      margin-bottom: 0.5em;
      }
  
  ins {
      color: green
  }
  
  del {
      color: red
  }
  
  #diffToggles {
      display: none
  }
  
  @media screen
  {
      #TOC
      {
          width: 35%;
  	float: left;
  	overflow: hidden;
      }
      #diffToggles {
          display: block
      }
  }
  
  @media print
      {
      div#TOC, nav#TOC
          {
          /* Don't display TOC in print */
          display: none;
          }
      }
  
  /* ---- Headers and sections ---- */
  
  h1, h2, h3, h4, h5, h6
  {
      font-family: "Helvetica Neue", Helvetica, "Liberation Sans", Calibri, Arial, sans-serif; /* Sans-serif headers */
  
      /* font-family: "Liberation Serif", "Georgia", "Times New Roman", serif; /* Serif headers */
  
      page-break-after: avoid; /* Firefox, Chrome, and Safari do not support the property value "avoid" */
  }
  
  /* Pandoc with --section-divs option */
  
  div div, section section /* Nested sections */
      {
      margin-left: 2em; /* This will increasingly indent nested header sections */
      }
  
  p {}
  
  blockquote
      { 
      font-style: italic;
      }
  
  li /* All list items */
      {
      }
  
  li > p /* Loosely spaced list item */
      {
      margin-top: 1em; /* IE: lack of space above a <li> when the item is inside a <p> */
      }
  
  ul /* Whole unordered list */
      {
      }
  
  ul li /* Unordered list item */
      {
      }
  
  ol /* Whole ordered list */
      {
      }
  
  ol li /* Ordered list item */
      {
      }
  
  hr {}
  
  /* ---- Some span elements --- */
  
  sub /* Subscripts. Pandoc: H~2~O */
      {
      }
  
  sup /* Superscripts. Pandoc: The 2^nd^ try. */
      {
      }
      
  em /* Emphasis. Markdown: *emphasis* or _emphasis_ */
      {
      }
      
  em > em /* Emphasis within emphasis: *This is all *emphasized* except that* */
      {
      font-style: normal;
      }
  
  blockquote > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */
      {
      font-style: normal;
      }
  
  blockquote > * > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */
      {
      font-style: normal;
      }
  
  blockquote > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */
      {
      font-style: normal;
      }
  
  blockquote > * > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */
      {
      font-style: normal;
      }
  
  /* ---- Links (anchors) ---- */
  
  a /* All links */
      {
      /* Keep links clean. On screen, they are colored; in print, they do nothing anyway. */
      text-decoration: none;
      }
  
  @media screen
      {
      a:hover
          {
          /* On hover, we indicate a bit more that it is a link. */
          text-decoration: underline;
          }
      }
  
  @media print
      {
      a   {
          /* In print, a colored link is useless, so un-style it. */
          color: black;
          background: transparent;
          }
          
      a[href^="http://"]:after, a[href^="https://"]:after
          {
          /* However, links that go somewhere else, might be useful to the reader,
             so for http and https links, print the URL after what was the link 
             text in parens
          */
          content: " (" attr(href) ") ";
          font-size: 90%;
          }
      }
  
  /* ---- Images ---- */
  
  img
      {
      /* Let it be inline left/right where it wants to be, but verticality make 
         it in the middle to look nicer, but opinions differ, and if in a multi-line 
         paragraph, it might not be so great. 
      */
      vertical-align: middle;
      }
  
  div.figure /* Pandoc figure-style image */
      {
      /* Center the image and caption */
      margin-left: auto;
      margin-right: auto;
      text-align: center;
      font-style: italic;
      }
  
  p.caption /* Pandoc figure-style caption within div.figure */
      {
      /* Inherits div.figure props by default */
      }
  
  /* ---- Code blocks and spans ---- */
  
  pre, code 
      {
      background-color: #fdf7ee;
      /* BEGIN word wrap */
      /* Need all the following to word wrap instead of scroll box */
      /* This will override the overflow:auto if present */
      white-space: pre-wrap; /* css-3 */
      white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
      white-space: -pre-wrap; /* Opera 4-6 */
      white-space: -o-pre-wrap; /* Opera 7 */
      word-wrap: break-word; /* Internet Explorer 5.5+ */
      /* END word wrap */
      }
  
  pre /* Code blocks */
      {
      /* Distinguish pre blocks from other text by more than the font with a background tint. */
      padding: 0.5em; /* Since we have a background color */
      border-radius: 5px; /* Softens it */
      /* Give it a some definition */
      border: 1px solid #aaa;
      /* Set it off left and right, seems to look a bit nicer when we have a background */
      margin-left:  0.5em;
      margin-right: 0.5em;
      }
  
  @media screen
      {
      pre
          {
          /* On screen, use an auto scroll box for long lines, unless word-wrap is enabled */
          white-space: pre;
          overflow: auto;
          /* Dotted looks better on screen and solid seems to print better. */
          border: 1px dotted #777;
          }
      }
  
  code /* All inline code spans */
      {
      }
  
  p > code, li > code /* Code spans in paragraphs and tight lists */
      {
      /* Pad a little from adjacent text */
      padding-left:  2px;
      padding-right: 2px;
      }
      
  li > p code /* Code span in a loose list */
      {
      /* We have room for some more background color above and below */
      padding: 2px;
      }
  
  span.option
      {
          color: blue;
          text-decoration: underline;
      }
  
  
  /* ---- Math ---- */
  
  span.math /* Pandoc inline math default and --jsmath inline math */
      {
      /* Tried font-style:italic here, and it messed up MathJax rendering in some browsers. Maybe don't mess with at all. */
      }
      
  div.math /* Pandoc --jsmath display math */
      {
      }
      
  span.LaTeX /* Pandoc --latexmathml math */
      {
      } 
  
  eq /* Pandoc --gladtex math */
      {
      } 
  
  /* ---- Tables ---- */
  
  /*  A clean textbook-like style with horizontal lines above and below and under 
      the header. Rows highlight on hover to help scanning the table on screen.
  */
  
  table
      {
      border-collapse: collapse;
      border-spacing: 0; /* IE 6 */
  
      border-bottom: 2pt solid #000;
      border-top: 2pt solid #000; /* The caption on top will not have a bottom-border */
  
      /* Center */
      margin-left: auto;
      margin-right: auto;
      }
      
  thead /* Entire table header */
      {
      border-bottom: 1pt solid #000;
      background-color: #eee; /* Does this BG print well? */
      }
  
  tr.header /* Each header row */
      {
      } 
  
  tbody /* Entire table  body */
      {
      }
  
  /* Table body rows */
  
  tr  {
      }
  tr.odd:hover, tr.even:hover /* Use .odd and .even classes to avoid styling rows in other tables */
      {
      background-color: #eee;
      }
      
  /* Odd and even rows */
  tr.odd {}
  tr.even {}
  
  td, th /* Table cells and table header cells */
      { 
      vertical-align: top; /* Word */
      vertical-align: baseline; /* Others */
      padding-left:   0.5em;
      padding-right:  0.5em;
      padding-top:    0.2em;
      padding-bottom: 0.2em;
      }
      
  /* Removes padding on left and right of table for a tight look. Good if thead has no background color*/
  /*
  tr td:last-child, tr th:last-child
      {
      padding-right: 0;
      }
  tr td:first-child, tr th:first-child 
      {
      padding-left: 0;
      }
  */
  
  th /* Table header cells */
      {
      font-weight: bold; 
      }
  
  tfoot /* Table footer (what appears here if caption is on top?) */
      {
      }
  
  caption /* This is for a table caption tag, not the p.caption Pandoc uses in a div.figure */
      {
      caption-side: top;
      border: none;
      font-size: 0.9em;
      font-style: italic;
      text-align: center;
      margin-bottom: 0.3em; /* Good for when on top */
      padding-bottom: 0.2em;
      }
  
  /* ---- Definition lists ---- */
  
  dl /* The whole list */
      {
      border-top: 2pt solid black;
      padding-top: 0.5em;
      border-bottom: 2pt solid black;
      }
  
  dt /* Definition term */
      {
      font-weight: bold;
      }
  
  dd+dt /* 2nd or greater term in the list */
      {
      border-top: 1pt solid black;
      padding-top: 0.5em;
      }
      
  dd /* A definition */
      {
      margin-bottom: 0.5em;
      }
  
  dd+dd /* 2nd or greater definition of a term */
      {
      border-top: 1px solid black; /* To separate multiple definitions */
      }
      
  /* ---- Footnotes ---- */
  
  a.footnote, a.footnoteRef { /* Pandoc, MultiMarkdown footnote links */
      font-size: small; 
      vertical-align: text-top;
  }
  
  a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown, ?? footnote back links */
      {
      }
  
  @media print
      {
      a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown */
          {
          /* Don't display these at all in print since the arrow is only something to click on */
          display: none;
          }
      }
      
  div.footnotes /* Pandoc footnotes div at end of the document */
      {
      }
      
  div.footnotes li[id^="fn"] /* A footnote item within that div */
      {
      }
  
  /* You can class stuff as "noprint" to not print. 
     Useful since you can't set this media conditional inside an HTML element's 
     style attribute (I think), and you don't want to make another stylesheet that 
     imports this one and adds a class just to do this.
  */
  
  @media print
      {
      .noprint
          {
          display:none;
          }
      }
  
  </style>
</head>
<body>
<header id="title-block-header">
<h1 class="title">The <code>constexpr</code> specifier for object definitions</h1>
<p class="author">Alex Gilding (Perforce UK)</p>
<p class="author">Jens Gustedt (INRIA France)</p>
<p class="date">2022-04-08</p>
</header>
<nav id="TOC">
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#summary-of-changes">Summary of Changes</a></li>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#rationale">Rationale</a></li>
<li><a href="#proposal">Proposal</a><ul>
<li><a href="#types">Types</a></li>
<li><a href="#aggregate-or-union-types">Aggregate or union types</a></li>
<li><a href="#linkage">Linkage</a></li>
<li><a href="#storage-duration">Storage duration</a></li>
</ul></li>
<li><a href="#alternatives">Alternatives</a></li>
<li><a href="#impact">Impact</a></li>
<li><a href="#implementation-experience">Implementation Experience</a></li>
<li><a href="#wording">Wording</a><ul>
<li><a href="#keywords-6.4.1">Keywords (6.4.1)</a></li>
<li><a href="#declarations-6.7">Declarations (6.7)</a></li>
<li><a href="#storage-class-specifiers-6.7.1">Storage-class specifiers (6.7.1)</a></li>
<li><a href="#constant-expressions-6.6">Constant Expressions (6.6)</a></li>
<li><a href="#linkage-6.2.2">Linkage (6.2.2)</a></li>
</ul></li>
<li><a href="#aknowledgements">Aknowledgements</a></li>
</ul>
</nav>
<table>
<tbody>
<tr class="odd">
<td style="text-align: left;">org:</td>
<td style="text-align: left;">ISO/IEC JCT1/SC22/WG14</td>
<td>document:</td>
<td>N2954</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td style="text-align: left;">… WG21 C and C++ liaison</td>
<td></td>
<td>P2576</td>
</tr>
<tr class="odd">
<td style="text-align: left;">target:</td>
<td style="text-align: left;">IS 9899:2023</td>
<td>version:</td>
<td>3</td>
</tr>
<tr class="even">
<td style="text-align: left;">date:</td>
<td style="text-align: left;">2022-04-08</td>
<td>license:</td>
<td><a href="https://creativecommons.org/licenses/by/4.0/" title="Distributed under a Creative Commons Attribution 4.0 International License">CC BY</a></td>
</tr>
</tbody>
</table>
<hr />
<h3 id="abstract">Abstract</h3>
<p>C++ has supported translation-time definition of first-class named constants for over ten years, while C, for all types besides <code>int</code>, is still limited to using second-class language features, in particular macros, during translation. This puts C at a significant disadvantage in terms of being able to share the same features between runtime and translation, and in being able to assert truths about the program during translation rather than waiting to assert in a runtime debug build.</p>
<h3 id="summary-of-changes">Summary of Changes</h3>
<ul>
<li>N2954
<ul>
<li>Base on N2952</li>
<li>Restrict the feature to object definitions</li>
<li>Split the compound literal feature off to N2955</li>
</ul></li>
<li>N2917
<ul>
<li>recursion limits; no UB in C++; no new ODR; no call before definition; linkage; initializer order</li>
<li>wording for function definitions, avoid VLA side effects</li>
<li>wording for compound literals</li>
<li>split wording for different kinds of constant expression and propagate kind; add wording to null pointer constant</li>
<li>community comments, implementability</li>
</ul></li>
<li>N2851
<ul>
<li>original proposal</li>
</ul></li>
</ul>
<h2 id="introduction">Introduction</h2>
<p>C requires that objects with static storage duration are only initialized with constant expressions. The rules for which kinds of expression may appear as constant expressions are quite restrictive and mostly limit users to using macro names for abstraction of values or operations. Users are also limited to testing their assertions about value behaviour at runtime because static_assert is similarly limited in the kinds of expressions it can evaluate during translation. We propose to add a new (old) specifier to C, <code>constexpr</code>, as introduced to C++ in C++11. We propose to add this specifier to objects, and to intentionally keep the functionality minimal to avoid undue burden on lightweight implementations.</p>
<p>A previous revision also had this feature for functions, but WG14 was not in favor of this for inclusion to C23.</p>
<h2 id="rationale">Rationale</h2>
<p>Because C limits initialization of objects with static storage duration to constant expressions, it can be difficult to create clean abstractions for complicated value generation. Users are forced to use macros, which do not allow for the creation of temporary values and require a different coding style. Such macros - especially if they would use temporaries, but have to use repetition instead because of the constraints of constant expressions - may also be unsuitable for use at runtime because they cannot guarantee clear evaluation of side effects. Macros for use in initializers cannot have their address taken or be used by linkage and are truly second-class language citizens.</p>
<p>The same restriction applies to static_assert: a user cannot prove properties about any expression involving a function call at compile-time, instead having to defer to runtime assertions.</p>
<p>C does provide enumerations which are marginally more useful than macros for defining constant values, but their uses are limited and they do not abstract very much; in practice they are only superior in the sense that they have a concrete type and survive preprocessing. Enumerations are not really intended to be used in this way.</p>
<p>In C++, both objects and functions may be declared as <code>constexpr</code>, allowing them to be used in all constant-expression contexts. This makes function calls available for static initialization and for static assertion-based testing.</p>
<p>The subset of headers which are able to be common between C and C++ is also increased by adding this feature and strictly subsetting it from the C++ feature. Large objects can be initialized and their values and generators asserted against during translation by both languages rather than forcing a user to switch to C++ solely in order to get such assertions.</p>
<h2 id="proposal">Proposal</h2>
<p>We propose adding the new keyword <code>constexpr</code> to the language and making it available as a storage-class specifier for objects.</p>
<p>A scalar object declared with the <code>constexpr</code> storage-class specifier is a constant. It must be fully and explicitly initialized according to the static initialization rules. It still has linkage appropriate to its declaration and it exist at runtime to have its address taken; it simply cannot be modified at runtime in any way, i.e. the compiler can use its knowledge of the object’s fixed value in any other constant expression.</p>
<h3 id="types">Types</h3>
<p>There are some restrictions on the type of an object that can be declared with <code>constexpr</code> storage duration. There is a limited number of constructs that are not allowed:</p>
<dl>
<dt>pointer types:</dt>
<dd>allowing these to use non-trival addresses would delay the deduction of the concrete value from translation to link-time. For most of the use cases, such a feature can already be coded by using a <code>static</code> and <code>const</code> qualified pointer object, we don’t need <code>constexpr</code> for that. Therefore we only allow pointer types if the initializer value is null.
</dd>
<dt>variably modified types:</dt>
<dd>these can only occur if the declaration of an array size is not a constant expression. Since we want the feature to be completely determined at translation-time, <code>constexpr</code> VLA and derived types are non-sensical, here.
</dd>
<dt>atomic types:</dt>
<dd>because objects that are declared with this may temporarily need access (or maybe even modify) an lvalue and impose sequentially consistent synchronization where only a translation-time value should be used and no lvalue should be accessed.
</dd>
<dt><code>volatile</code>:</dt>
<dd>It would not be clear what the sematics of a <code>volatile</code> <code>constexpr</code> object would be, for example if it could possibly change by means that are not under the control of the programmer.
</dd>
<dt><code>restrict</code>:</dt>
<dd>Similarly for <code>restrict</code>. The only pointer types that are allowed are null pointers and for them, <code>restrict</code> is useless.
</dd>
</dl>
<p>Generally, it does not make sense to use any of the currently provided standard qualifiers on a <code>constexpr</code> object. For convenience we only allow <code>const</code> qualification, but which is redundant.</p>
<p>Other qualifiers may be introduced at a later time that might hold more meaning for these objects.</p>
<h3 id="aggregate-or-union-types">Aggregate or union types</h3>
<p>In a previous version of this paper we also proposed relaxing the constant-expression rules to allow access to aggregate members when the object being accessed is declared as a <code>constexpr</code> object and (in the case of arrays) the element index is an integer constant expression. WG14 was not in favor of the proposed text.</p>
<h4 id="structure-or-union-types">Structure or union types</h4>
<p>Nevertheless we observe that the member access operator <code>.</code> is not explicitly excluded from the admissible syntax of constant expressions (see 6.6 for a constraining list of exceptions), and that removing it from there might impact implementations that already allow structure or union types as an extension.</p>
<p>Thus we propose to maintain the status quo and to allow the <code>.</code> operator within constant expressions of all kinds. By the defaults that are already in place, a member of a <code>constexpr</code> structure or union inherits all properties from the structure or union. With the definitions that we propose the name of the member would still be an “identifier declared with <code>constexpr</code>” and thus be a named constant.</p>
<p>Union types here merit special consideration, because we don’t want to add new undefined behavior with this construct. A translator will always be able to deduce if the bit-pattern that is imposed for any union member by the initializer provides a valid value for the named constant.</p>
<p>Since this is a translation-time feature, the constraint in 6.6 p4</p>
<blockquote>
<p>Each constant expression shall evaluate to a constant that is in the range of representable values for its type.</p>
</blockquote>
<p>always kicks in, and forces a diagnostic if and when the implementation is not able to produce a consistent value for any member.</p>
<p>Note that allowing structure types agrees with C++’s policy, whereas also allowing it for union types is less constraining than for them. Here, C++ only allows to access the “active” member of a union in a constant expression. Since C does not have this concept of an active member of a union, and since type-punning through union is a distinguished feature in C, it is not easy to map this restriction to C.</p>
<h4 id="array-types">Array types</h4>
<p>The use of a <code>constexpr</code> array object in a context that requires a constant expression is not possible without special considerations, of which WG14 was not in favor for C23. Nevertheless we maintain the possibility to define such named constants because they still have other advantages over <code>const</code>-qualified arrays of static storage duration:</p>
<ul>
<li>The initializer must be composed of constant expressions. So even if the array elements are not constant expression by themselves, many optimizations will still be applicable to them under the as-if rule.</li>
<li>The base type of the array is enforced to be <code>const</code> qualified and not <code>restrict</code>, <code>volatile</code> or <code>_Atomic</code> qualified.</li>
<li>Each assignment expression in the initializer still has to provide a valid value for the type.</li>
<li>A diagnostic can be expected if the initialization of an element at an excess position is attempted.</li>
<li>The property for character arrays (even wide) being strings is easily maintained by the translator and diagnostics can be issued in circumstances that require strings, for example as arguments to formated IO functions. More generally, diagnostics that are based on the content of such character arrays can be issued.</li>
</ul>
<h3 id="linkage">Linkage</h3>
<p>We do not propose changing the meaning of the <code>const</code> keyword in any way (this differs between C and C++) - an object declared at file scope with <code>const</code> and without <code>static</code> continues to have external linkage; an object declared with static storage duration and <code>const</code> but not <code>constexpr</code> is not considered any kind of constant-expression, barring any implementations that are already taking advantage of the permission given in 6.6 paragraph 10 to add more kinds of supported constant expressions.</p>
<p>The difference between the behaviour of <code>const</code> in C and in C++ is unfortunate but is now cemented in existing practice and well-understood. Since changing the status of existing <code>const</code> qualified variables would implicitly change the status of derived array declarations, we would oppose changing that now.</p>
<p>The <code>constexpr</code> feature itself does not have this problem, because it can only be used through an explicit code change. Nevertheless, <code>constexpr</code> objects will typically be defined in header files, so we have to ensure that they don’t create multiply-defined-symbol conflicts. Therefore, in accordance with C++, file-scope <code>constexpr</code> obtain internal linkage and block-scope no linkage at all.</p>
<h3 id="storage-duration">Storage duration</h3>
<p>For the storage duration of the created objects we go with C++ for compatibility, that is per default we have automatic in block scope and static in file scope. The default for block scope can be overwritten by <code>static</code> or refined by <code>register</code>. It would perhaps be more natural for named constants</p>
<ul>
<li>to be addressless (similar to a <code>register</code> declaration or an enumeration),</li>
<li>to have static storage duration (imply <code>static</code> even in block scope), or</li>
<li>to have no linkage (similar to <code>typedef</code> or block local <code>static</code>)</li>
</ul>
<p>but we decided to go with C++’s choices for compatibility.</p>
<p>Also we don’t allow thread local named constants</p>
<dl>
<dt><code>thread_local</code>:</dt>
<dd>Because we only allow constant expressions as initializers for named constants, a split into one distinct object per thread does not make much sense.
</dd>
</dl>
<h2 id="alternatives">Alternatives</h2>
<p>C currently has only one class of in-language entity that can be defined with a value and then used in a constant context, which is an enumeration. This is limited to providing a C-level name for a single <code>int</code> value, but is extremely limited and is a second-class feature closer to macro constants than to C objects. These cannot be addressed and also cannot be used to help much in the composition of arbitrarily-typed constant expressions during translation.</p>
<h2 id="impact">Impact</h2>
<p>As above, the existing incompatibility of <code>const</code> between C and C++ is preserved because the proposal does not intend to break or change any existing C code. Code that intends to express identical constant semantics for values in both C and C++ should start using <code>constexpr</code> objects instead.</p>
<p>This change improves C’s header compatibility with C++ by allowing the same headers to make use of better compile-time initialization features. This increases the subset of C++ headers which can be used from C and does not impose any new runtime cost on any C program.</p>
<h2 id="implementation-experience">Implementation Experience</h2>
<p>There is widespread implementation experience of <code>constexpr</code> as a C++ feature. Internally to the QAC team, we have experience fitting C++11 ruleset <code>constexpr</code> to the C constant evaluator. Our C frontend does not share this component with the C++ compiler, so we were able to compare and contrast which work was reasonable to import and which was not (i.e. we have implemented <code>constexpr</code> fully before). We felt that full C++20 ruleset <code>constexpr</code> was completely unreasonable (probably not controversial!), but that the C++11 rules, including <code>constexpr</code> functions, designed to buildup from a minimalist perspective, were not difficult for a single-person team to add to a C evaluator. Implementing just the <code>constexpr</code> object part (without functions) as proposed here in this paper even has an implementation complexity that is much lower.</p>
<h2 id="wording">Wording</h2>
<p>The wording changes proposed here are based on N2952 that sets the basis for some of the syntactical specifications.</p>
<h3 id="keywords-6.4.1">Keywords (6.4.1)</h3>
<blockquote>
<p>Add <code>constexpr</code> to the list of keywords in 6.4.1.</p>
</blockquote>
<h3 id="declarations-6.7">Declarations (6.7)</h3>
<p>According to the outcome for N2953 use alternatives 1 or 3 from N2952 to make <code>constexpr</code> declarations underspecified.</p>
<dl>
<dt>Alternatives</dt>
<dd><ins>
A declaration such that the declaration specifiers contain no type specifier or that is declared with <code>constexpr</code> is said to be <em>underspecified</em>.
</ins>
</dd>
<dd><ins>
A declaration with <code>constexpr</code> is said to be <em>underspecified</em>.
</ins>
</dd>
</dl>
<h3 id="storage-class-specifiers-6.7.1">Storage-class specifiers (6.7.1)</h3>
<blockquote>
<p>Add <code>constexpr</code> to the list of storage-class specifiers in 6.7.1 p1.</p>
</blockquote>
<h4 id="constraints">Constraints</h4>
<p>Named constants might possibly have static or automatic storage duration, but no other restrictions to their storage duration should apply.</p>
<dl>
<dt>According to the outcome for N2953 change paragraph 2</dt>
<dd>2 At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except that <code>thread_local</code> may appear with <code>static</code> or <code>extern</code><ins> and <code>constexpr</code> may appear with <code>auto</code>, <code>register</code> or <code>static</code></ins>.<sup>127)</sup>
</dd>
<dd><p>2 At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except that <code>thread_local</code> may appear with <code>static</code> or <code>extern</code><ins> and <code>constexpr</code> may appear with <code>__auto_type</code>, <code>auto</code>, <code>register</code> or <code>static</code></ins>.<sup>127)</sup></p>
</dd>
</dl>
<p>As stated above the possible types for named constants should be constrained. Add a new paragraph and footnote to the end of the <em>Constraints</em> section.</p>
<blockquote>
<ins>
An object declared with storage-class specifier <code>constexpr</code> or any of its members, even recursively, shall not have an atomic type or a type that is <code>volatile</code> or <code>restrict</code> qualified. The declaration shall be a definition, shall have an initializer and shall be such that all expressions<sup>FNT0)</sup>, if any, are either constant expressions or string literals.<sup>FNT1)</sup> If an object or subobject declared with storage-class specifier <code>constexpr</code> has pointer type, the implicit or explicit initializer value for it shall be a null pointer.<sup>FNT2)</sup>
</ins>
</blockquote>
<blockquote>
<ins>
<sup>FNT0)</sup> Such as an assignment expression in an initializer or in an array bound.
</ins>
</blockquote>
<blockquote>
<ins>
<sup>FNT1)</sup> As a consequence a <code>constexpr</code> object does not have a variably modified type.
</ins>
</blockquote>
<blockquote>
<ins>
<sup>FNT2)</sup> The named constant corresponding to an object declared with storage-class specifier <code>constexpr</code> and pointer type is a constant expression with value null, and thus a null pointer and an address constant. Even if it has type <code>void*</code> it is not a null pointer constant.
</ins>
</blockquote>
<h4 id="semantics">Semantics</h4>
<p>Adapt the changed p6 as of N2952</p>
<blockquote>
<p>6 Storage-class specifiers specify various properties of identifiers and declared features; storage duration (<code>static</code> in block scope, <code>thread_local</code>, <code>auto</code>, <code>register</code>), linkage (<code>extern</code>, <code>static</code><ins> and <code>constexpr</code></ins> in file scope, <code>typedef</code>)<ins>, value (<code>constexpr</code>)</ins> and type (<code>typedef</code>). The meanings of the various linkages and storage durations were discussed in 6.2.2 and 6.2.4, <code>typedef</code> is discussed in 6.7.8.</p>
</blockquote>
<p>Then add a new paragraph, a footnote and a note to the end of the <em>Semantics</em> section</p>
<blockquote>
<ins>
An object declared with a storage-class specifier <code>constexpr</code> has its value permanently fixed at translation-time; if not yet present, a <code>const</code>-qualification is implicitly added to the object’s type. The declared identifier is considered a constant expression of the respective kind, see 6.6.
</ins>
</blockquote>
<blockquote>
<ins>
<p>NOTE An object declared in block scope with a storage-class specifier <code>constexpr</code> and without <code>static</code> has automatic storage duration, the identifier has no linkage, and each instance of the object has a unique address obtainable with <code>&amp;</code> (if there also is no <code>register</code> specifier) or no address at all (with <code>register</code>). Such an object in file scope has static storage duration, the corresponding identifier has internal linkage, and each translation unit that sees the same textual definition implements a separate object with an address of its own.</p>
</blockquote>
<h3 id="constant-expressions-6.6">Constant Expressions (6.6)</h3>
<p>To introduce terminology, we stipulate that being a constant expression is a property of the declared identifier, and not of the underlying object. Add a new paragraph 5’ after paragraph 5</p>
<blockquote>
<ins>
<p>5’ An identifier that is an enumeration constant, a predefined constant or that is declared with storage-class specifier constexpr and an object type is a <em>named constant</em>. For enumeration and predefined constants, their value and type are defined in the respective clauses; for <code>constexpr</code> objects, such a named constant is a constant expression with the type and value of the declared object.</p>
</blockquote>
<p>These new kinds of constants then have to be added in the appropriate places. Change the following three paragraphs.</p>
<blockquote>
<p>6 An <em>integer constant expression</em><sup>124)</sup> shall have integer type and shall only have operands that are integer constants, <del>enumeration constants</del><ins>named constants of integer type</ins>, character constants, <del>predefined constants,</del> <code>sizeof</code> expressions whose results are integer constants, <code>alignof</code> expressions, and floating constants<ins> or named constants</ins> that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the <code>sizeof</code> or <code>alignof</code> operator.</p>
</blockquote>
<blockquote>
<p>8 An arithmetic constant expression shall have arithmetic type and shall only have operands that are integer constants, floating constants, <del>enumeration constants</del><ins>named constants of arithmetic type</ins>, character constants, <del>predefined constants,</del> <code>sizeof</code> expressions whose results are integer constants, and <code>alignof</code> expressions. Cast operators in an arithmetic constant expression shall only convert arithmetic types to arithmetic types, except as part of an operand to a <code>sizeof</code> or <code>alignof</code> operator.</p>
</blockquote>
<blockquote>
<p>9 An <em>address constant</em> is a null pointer,<ins><sup>FNT3)</sup></ins> a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary <code>&amp;</code> operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type. The array-subscript <code>[]</code> and member-access <code>.</code> and <code>-&gt;</code> operators, the address <code>&amp;</code> and indirection <code>*</code> unary operators, <ins>integer constant expressions,</ins> and pointer casts may be used in the creation of an address constant, but the value of an object shall <ins>otherwise</ins> not be accessed by use of these operators.<ins><sup>FNT4)</sup></ins></p>
</blockquote>
<blockquote>
<ins>
<sup>FNT3)</sup> A named constant of integer type and value zero is a null pointer constant. A named constant with pointer type and value null is a null pointer.
</ins>
</blockquote>
<blockquote>
<ins>
<sup>FNT4)</sup> Named constants with arithmetic type, including names of <code>constexpr</code> objects, are valid in offset computations such as array-subscripts or in pointer casts, as long as the expressions in which they occur form integer constant expressions. In contrast to that, names of other objects, even if <code>const</code>-qualified and with static storage duration, are not valid.
</ins>
</blockquote>
<h3 id="linkage-6.2.2">Linkage (6.2.2)</h3>
<p>Named constants (<code>constexpr</code> objects) will typically be defined in header files, so we have to ensure that they don’t create multiply-defined-symbol conflicts. Change the following paragraph</p>
<blockquote>
<p>3 If the declaration of a file scope identifier for an object <ins>contains any of the storage-class specifiers <code>static</code> or <code>constexpr</code></ins> or <ins>for</ins> a function contains the storage-class specifier <code>static</code>, the identifier has internal linkage.<sup>31)</sup></p>
</blockquote>
<h2 id="aknowledgements">Aknowledgements</h2>
<p>Additional thanks to Martin Uecker and Joseph Myers for detailed wording improvement suggestions for previous revisions of this paper.</p>
</body>
</html>
