Issue 1030: Lvalue conversion for generic associations

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.