Undefined behaviour during evaluation of a potential constant expression

Viewed 243

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?

1 Answers
Related