Authors: Joseph Myers
Date: 2026-03-05
Submitted against: C23
Status: Open
Cross-references: 1031
This is an issue previously mentioned in reflector message 28292.
In C23, there is undefined behavior for lvalue conversion of an lvalue with incomplete, non-array type, and for array-to-pointer conversion of an array object with register storage class. (In C2Y, the first of these has become a constraint violation, and the second has become implementation-defined behavior.)
In both cases, it should be understood that the undefined behavior is
translation-time undefined, since it relates to a property of a
translation unit, not a property of a particular execution. In both
cases, there are specific contexts, such as operands of sizeof or
typeof, where the relevant conversion does not occur, and thus the
undefined behavior, constraint violation or implementation-defined
behavior does not occur either.
This raises the question of how those contexts are defined for generic associations in a generic selection other than the one that is the result expression.
struct s *p;
void
f1()
{
typeof(_Generic(1, int: *p)) *q;
}
void
f2()
{
typeof(_Generic(1, int: 0, long: *p)) *q;
}
void
f3()
{
_Generic(1, int: 0, long: *p);
}
In f1, *p is the result expression, and is treated as being the
operand of typeof by common practice (this is a natural consequence
of "It is an lvalue, a function designator, or a void expression if
its result expression is, respectively, an lvalue, a function
designator, or a void expression."; if it is an lvalue, it is to be
expected that conversions do or do not occur based on its context,
although the current text may not be fully clear on this and the
N3722
proposal does not fully address this case either). Thus the code in
f1 is valid.
In f2 and f3, however, *p is not the result expression. This
could be interpreted as meaning that none of the "Except when"
conditions for avoiding lvalue conversion apply, and so undefined
behavior (C23) or a constraint violation (C2Y) occurs. Alternatively,
it could be interpreted as occurring only in f3 because of the
typeof present in f2.
For each of the three examples, there is a question of intent: should lvalue conversion occur in that case? Then, there is the question of whether the standard is sufficiently clear about this or whether it needs amendment to meet the desired intent.
I suggest that all three examples ought to be valid. f1 ought to be
valid because the lvalue is the operand of typeof (via _Generic).
The other two ought to be valid because no lvalue conversion should
occur for generic associations other than the result expression, which
would make it irrelevant what the context surrounding _Generic is.
This would require changes to the standard to add to the "Except when"
conditions.
Changes such as those proposed in
N3809
(to allow arbitrary balanced token sequences rather than properly
typed expressions for generic associations other than the result
expression) would alternatively make f2 and f3 valid, but
introduce incompatibilities regarding scoping of identifiers declared
in such generic associations, which would render it unsuitable to
apply to earlier versions of C.