Consider this program:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
extern int i;
struct S {
S() {
if (i == 0) {
puts("Hello, world!");
exit(0);
}
}
};
S s;
int i = 1 + 2 * INT_MIN;
int main() { }
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 i:
3.6.2 Initialization of non-local variables [basic.start.init]
[...]
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.
Constant initialization is performed:
-- [...]
-- 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.
Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. 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. [...]
5.19 Constant expressions [expr.const]
A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2) [...]:
-- [...]
-- a result that is not mathematically defined or not in the range of representable values for its type;
[...]
A literal constant expression 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 constant expressions.
Because the expression 1 + 2 * INT_MIN 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 i is not a constant expression, dynamic initialisation is performed. The initialisation for s is also dynamic, and because its definition precedes that of i, its constructor runs first. At that point, only zero-initialisation has been performed, so the check i == 0 should evaluate as true.
However, GCC and clang agree that i can be statically initialised to 1. My experience when those two agree is that they are correct, so I am left wondering... is any part of my analysis incorrect?