title: Undefined behaviour during evaluation of a potential constant expression
body: <p>Consider this program:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;limits.h&gt;
  
  extern int i;
  
  struct S {
      S() {
          if (i == 0) {
              puts("Hello, world!");
              exit(0);
          }
      }
  };
  
  S s;
  
  int i = 1 + 2 * INT_MIN;
  
  int main() { }
  </code></pre>
  
  <p>As I understood the evaluation of expressions, this is a strictly conforming program, that prints "Hello, world!", then exits, and never actually evaluates the initialiser for <code>i</code>:</p>
  
  <blockquote>
    <p><strong>3.6.2 Initialization of non-local variables [basic.start.init]</strong></p>
    
    <p>[...]</p>
    
    <p>Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place.</p>
    
    <p>Constant initialization is performed:</p>
    
    <p>-- [...]</p>
    
    <p>-- if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.</p>
    
    <p>Together, zero-initialization and constant initialization are called <em>static initialization</em>; all other initialization is <em>dynamic initialization</em>. Static initialization shall be performed before any dynamic initialization takes place. Dynamic initialization of a non-local variable with static storage duration is either ordered or unordered. [...] Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. [...]</p>
    
    <p><strong>5.19 Constant expressions [expr.const]</strong></p>
    
    <p>A conditional-expression is a <em>core constant expression</em> unless it involves one of the
    following as a potentially evaluated subexpression (3.2) [...]:</p>
    
    <p>-- [...]</p>
    
    <p>-- a result that is not mathematically defined or not in the range of representable values for its type;</p>
    
    <p>[...]</p>
    
    <p>A <em>literal constant expression</em> is a prvalue core constant expression of literal type, but not pointer type. [...] Collectively, literal constant expressions, reference constant expressions, and address constant expressions are called <em>constant expressions</em>.</p>
  </blockquote>
  
  <p>Because the expression <code>1 + 2 * INT_MIN</code> has signed integer overflow, it is not a core constant expression, thus not a literal constant expression, thus not a constant expression. Because the initialiser for <code>i</code> is not a constant expression, dynamic initialisation is performed. The initialisation for <code>s</code> is also dynamic, and because its definition precedes that of <code>i</code>, its constructor runs first. At that point, only zero-initialisation has been performed, so the check <code>i == 0</code> should evaluate as true.</p>
  
  <p>However, GCC and clang agree that <code>i</code> can be statically initialised to <code>1</code>. My experience when those two agree is that they are correct, so I am left wondering... is any part of my analysis incorrect?</p>