Issue 1031: Generic selection controlling expression lvalue of incomplete non-array type

Authors: Jay Ghiron
Date: 2026-03-06
Submitted against: C23
Status: Open
Cross-references: 1030

In C23 the type a generic selection uses is defined as such:

The type of the controlling expression is the type of the expression as if it had undergone an lvalue conversion, array to pointer conversion, or function to pointer conversion.

(C23 6.5.2.1 "Generic selection" paragraph 2.)

However, lvalue conversions are defined as such:

Except when it is the operand of the sizeof operator, or the typeof operators, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion.

(C23 6.3.3.1 "Lvalues, arrays, and function designators" paragraph 2.)

There is no exemption here for expressions that are the controlling expression of a generic selection, so it appears that lvalue conversions will happen in controlling expressions of generic associations. Given this, it appears that the "as if it had undergone an lvalue conversion" is redundant since the expression must have already undergone lvalue conversions if it were an lvalue of non-array type. I do not think this was the intent, however. An example of where this difference matters is:

extern struct incomplete s;
int main(){
_Generic(s,default:0);
}

Question 1

Does this program actually do lvalue conversion, and cause undefined behavior? In C2Y this has been changed to a constraint.

Question 2

If it should not actually do lvalue conversion, does the hypothetical lvalue conversion cause undefined behavior? In C2Y this has been changed to a constraint.

A correction should consider that C2Y has changed the constraints on generic associations to allow for incomplete types.