It can't be undefined because the char there might have a trap representation, because 6.2.6.1p5 says that accessing anything with a character type is well defined.
It could be undefined because of 6.3.2.1p2
An lvalue designating an object of automatic storage duration that
could have been declared with the register storage class is used in a
context that requires the value of the designated object, but the
object is uninitialized.
so the question is, could the array have been declared with the register storage class?
The answer to that is no, it couldn't have, because you're indexing it. Indexing is defined according to 6.5.2.1p2
(
A postfix expression followed by an expression in square brackets []
is a subscripted designation of an element of an array object. The
definition of the subscript operator [] is that E1[E2] is identical to
(*((E1)+(E2))). Because of the conversion rules that apply to the
binary + operator, if E1 is an array object (equivalently, a pointer
to the initial element of an array object) and E2 is an integer,
E1[E2] designates the E2-th element of E1 (counting from zero).
)
in terms of the array coverting to the address of its first element, but for a register-classified array, such conversion would have been undefined as per bullet point:
An lvalue having array type is converted to a pointer to the initial
element of the array, and the array object has register storage class
(6.3.2.1).
in appendix J.2 Undefined behavior, which means the array couldn't have been declared register
.
Footnote 121 in 6.7.1 Storage class specifiers further elaborates this:
the address of any part of an object declared with storage-class
specifier register cannot be computed, either explicitly (by use of
the unary & operator as discussed in 6.5.3.2) or implicitly (by
converting an array name to a pointer as discussed in 6.3.2.1). Thus,
the only operators that can be applied to an array declared with
storage-class specifier register are sizeof and _Alignof
(In other words, while the language allows register arrays, they're essentially unusable).
Consequently, code like:
char unspecified(void){ char s[1]; return s[0]; }
will return an unspecified value but will not render your program's behavior undefined.