Consider the following code:
struct s
{
int x;
int y[sizeof((struct s*)0)->x];
};
When compiled as C++ (26), this code seems to be valid with GCC (g++ -std=c++26 -pedantic -Wall -Wextra
does not complain), though it's invalid with Clang, which produces:
error: member access into incomplete type 'struct s'
Assuming GCC is correct, this may imply that in C++ the result of the ->
operator is not always an lvalue. Which value category does x
have in ((struct s*)0)->x
?
I've already consulted expr.ref and it seems that the case above falls into 7.2. Does it follow that x
is an xvalue?
When compiled as C++, does this code lead to undefined behavior?
In C++ *p
is always an lvalue for pointers. E1->E2
is treated as (*(E1)).E2
, so we are in expr.ref 7.2, and E1
is an lvalue so the whole expression is an lvalue. In C, the analysis is simpler, ->
access is always an lvalue.
In both C1 and C++, sizeof
expression does not evaluate expression, it just determines the size of the static type of that expression, which doesn't involve the value category of the expression.
Whether this is well formed is hard to say.
In C++ ->
member access requires the pointer be to a complete type, unless the access is within the definition of the class [expr.ref#5]. It also requires the rhs to name a member of the class.
The C standard does not require the lhs to be a pointer to a complete type, but, like C++ it does require the rhs to name a member of that struct type.
I don't know if you can ever name a member of an incomplete type. Certainly there are occasions where you can't, because the compiler has no idea what names there are.
In either case, the behaviour is not undefined. Either the program is ill-formed, because x
does not name a member of s
(because it is incomplete) or y
is an int [sizeof int]