Surprisingly, this is not undefined behavior.
Static initialization [basic.start.static]
Constant initialization is performed if a variable or temporary object
with static or thread storage duration is constant-initialized. If
constant initialization is not performed, a variable with static
storage duration or thread storage duration is zero-initialized.
Together, zero-initialization and constant initialization are called
static initialization; all other initialization is dynamic
initialization. All static initialization strongly happens before any
dynamic initialization.
Important parts bold-faced. “Static initialization” includes global variable initialization, “static storage duration” includes global variables, and the above clause is applicable here:
int i = i;
This is not constant-initialization. Therefore, zero-initialization is done according to the above clause (for basic integer types zero-initialization means, unsurprising, that it’s set to 0). The above clause also specifies that zero initialization must take place before dynamic initialization.
So, what happens here:
iis initialized to 0.iis then dynamically initialized, from itself, so it still remains 0.