<div style="text-align: right">
<b>Date:</b> 2019-07-18<br>
<b>Reply to:</b> Eric Fiselier &lt;eric@efcs.ca&gt;
</div>

<h1>P1143R2 Adding the <code>constinit</code> keyword</h1>

<pre><code>const char *g() { return "dynamic initialization"; }
constexpr const char *f(bool p) { return p ? "constant initializer" : g(); }

constinit const char *c = f(true); // OK.
constinit const char *d = f(false); // ill-formed
</code></pre>

<h2>Introduction</h2>

<p>We're all familar with the Static Initialization Order Fiasco. Static storage duration variables with dynamic
initializers cause hard-to-find bugs caused by the indeterminate order of dynamic initialization.</p>

<p>However, static variables with constant initializers avoid these pitfalls by causing the initialization to take
place at compile time. These variables can be safely used during dynamic initialization across translation units.</p>

<p>Unfortunatly the rules for constant initialization are complex and change dialect to dialect. This makes it
non-obvious what form of initialization is taking place simply by inspecting the code. We need a way to
enforce that constant initialization is truely taking place. It’s important to be able to fail fast instead
of silently falling back on dynamic initialization.</p>

<p>This paper proposes the <code>constinit</code> keyword.</p>

<p>The keyword can be applied to variable declarations with static storage duration. It requires that the variable have a "constant initializer". For example:</p>

<pre><code>// Compiled as C++14
struct T {
  constexpr T(int) {}
  ~T(); // non-trivial
};
constinit T x = {42}; // Initialization OK. Doesn't check destructor.
constinit T y = 42; // error: variable does not have a constant initializer
// copy initialization is not a constant expression on a non-literal type in C++14.
</code></pre>

<h2>Previous Discussions</h2>

<h3><code>constinit</code> as an attribute.</h3>

<p>in r0 of this paper <code>constinit</code> was proposed as an attribute. When this idea was presented, there was general concencious that this feature would be better suited as a keyword. First, <code>constinit</code> enforces correctness and if compilers were allowed to ignore it as they can attributes, it would allow "ill-formed" programs to compile. Second, there was some discussion about the behavior of <code>[[constinit]]</code> being out-of-scope for attributes (I don't believe this to be the case). </p>

<h3>Applying <code>constinit</code> to declarations or just definitions?</h3>

<p><code>constinit</code> communicates the intention of the programmer to both the compiler
and other programmers.  In order for the compiler to inforce the intent, the
specifier need only be present on the initializing declaration, and not any
other declarations.  However, to express the intent to other programmers there
is value in allowing the <code>constinit</code> specifier to appear on non-defining
declarations. For example:</p>

<pre><code>// Foo.h
struct Foo {
  constinit static int x;
};
// Foo.cpp
int Foo::x = 42;
</code></pre>

<p><code>constinit</code> can also be useful to compilers for non-initializing declarations
of <code>thread_local</code> variables:</p>

<pre><code>extern thread_local constinit x;
int f() { return x; }
</code></pre>

<p>Without <code>constinit</code>, runtime code must be executed to perform a check of a
guard variable and conditionally initialize <code>x</code> each time it is used. (Other
techniques exist, but this approach is common.) If the variable is known to
have constant initialization, this can be avoided.</p>

<p>After EWG discussion, <code>constinit</code> is permitted on any declarations of a
variable; if it is present on some declaration but not on the initializing
declaration, the program is ill-formed, no diagnostic required.</p>

<h2>Wording</h2>

<p>Modify <code>[dcl.spec]</code> as described below.</p>

<h4>5.11 Keywords [lex.key]</h4>

<p>Add <code>constinit</code> to Table 5 (Keywords).</p>

<h4>9.1 Specifiers [dcl.spec]</h4>

<ol>
<li><p>The specifiers that can be used in a declaration are:</p>

<blockquote>
  <p><em>decl-specifier</em>:<br></p>

<blockquote>
  <p>...<br>
<ins><code>constinit</code></ins></p>
</blockquote>

<p></blockquote></p></li>
<li><p>Each decl-specifier shall appear at most once in a complete decl-specifier-seq, except that long may appear twice. <del>The constexpr and consteval decl-specifiers shall not both appear in a decl-specifier-seq.</del><ins>At most one of the <code>constexpr</code>, <code>consteval</code>, and <code>constinit</code> keywords shall appear in a decl-specifier-seq.</ins></p></li>
</ol>

<h4>9.1.X The <code>constinit</code> specifier  [dcl.constinit]</h4>

<p>Add the new subclause under <code>[dcl.spec]</code> with the following wording.</p>

<ol>
<li>The <code>constinit</code> specifier shall be applied only to a declaration of a variable with static or thread storage duration. If the specifier is applied to any declaration of a variable, it shall be applied to the initializing declaration. No diagnostic is required if no <code>constinit</code> declaration is reachable at the point of the initializing declaration.</li>
<li>If a variable declared with the <code>constinit</code> specifier has dynamic initialization ([basic.start.dynamic]), the program is ill-formed. [<em>Note</em>: The <code>constinit</code> specifier ensures that the variable is initialized during static initialization ([basic.start.static]). --- <em>end note</em>]</li>
<li><p>[<em>Example</em>:</p>

<pre><code>const char *g() { return "dynamic initialization"; }
constexpr const char *f(bool p) { return p ? "constant initializer" : g(); }


constinit const char *c = f(true); // OK.
constinit const char *d = f(false); // ill-formed
</code></pre>

<p>--- <em>end example</em>]</p></li>
</ol>

<h4>15.10 Predefined macro names [cpp.predefined]</h4>

<p>Add a feature test macro <code>__cpp_constinit</code> with a suitable value to Table 17 (Feature-test macros).</p>

<h4>C.5.1 Clause 5: lexical conventions [diff.cpp17.lex]</h4>

<p>Add a bullet to the "New keywords" change in paragraph 2:</p>

<blockquote>
  <ul><li><ins>The <tt>constinit</tt> keyword is added to prevent unintended dynamic initialization.</ins></li></ul>
</blockquote>

<h2>References</h2>

<ul>
<li><p><a href="https://clang.llvm.org/docs/AttributeReference.html#require-constant-initialization-clang-require-constant-initialization">Clang's <code>[[require_constant_initialization]]</code> documentation</a></p></li>
<li><p><a href="https://github.com/efcs/clang/tree/fix-const-init">A Clang implementation of the r0 proposal</a></p></li>
<li><p><a href="http://eel.is/c++draft/basic.start#static-2">Definition of <em>Constant Initialization</em> from <code>[basic.start.static]</code></a></p></li>
</ul>
