It?
int main() { int foo = foo; }
The foo object exists after = , according to [basic.scope.pdecl] :
The declaration point for the name immediately after its full declaration (section 8) and before its initializer (if any).
However, the program as a whole is undefined because you are using (on RHS) an uninitialized value:
int x = x; Here [..] x initialized with its own (undefined) value.
and
Although the default value is "output and poorly specified", the lvalue-to-rvalue conversion is performed in the RHS foo expression .
And ( [conv.lval] ):
The value (3.10) of non-function, type without array T can be converted to rvalue. If T is an incomplete type, a program that requires this conversion is poorly formed. If the object to which the lvalue value belongs is not an object of type T and is not an object of a type derived from T, or if the object is not initialized, the program that requires this conversion is undefined.
With appropriate warning levels, they will tell you about it ; however, programs that cause undefined Behavior are allowed to compile. They just can do something when you run them.
Or how about this?
int foo = foo; int main() {}
Note that foo is "global." They are initialized to zero as the first step according to [basic.start.init] :
Objects with a static storage duration (3.7.1) must be initialized with zeros (8.5) before any other initialization occurs .
So you get int foo with a value of 0; it is valid at this moment, according to [basic.scope.pdecl] above, and according to [stmt.decl] :
Zero initialization (8.5) of all local objects with static storage duration (3.7.1) is performed until any other initialization takes place. [..]
Then you initialize it with the value foo (itself), i.e. 0.
It's well defined ... if a little cryptic.
In the interest of thoroughness, here is the third and final case:
int foo = 42; int main() { int foo = foo; }
Unfortunately, this is the same as in the first case . Since local foo has already been declared and is evaluated in the region at the time of initialization, the initializer uses local foo , and you still adhere to undefined behavior. Global foo not used.