Issue 1001: Qualified rvalues from structure or union members

Authors: Joseph Myers
Date: 2025-03-06
Submitted against: C23
Status: Open
Cross-references: 0423, 0481

C23 6.7.3.5 (Atomic type specifiers) says "The properties associated with atomic types are meaningful only for expressions that are lvalues." and, similarly, in 6.7.4.1 (Type qualifiers), "The properties associated with qualified types are meaningful only for expressions that are lvalues.". Not being meaningful, however, leaves open the possibility that an rvalue might nevertheless have such a type (with no semantic difference compared to having an unqualified type).

Before C11, it was never possible to observe whether an rvalue had a qualified type. C11 introduced _Generic with the potential to observe more details of the types of rvalues, and C23 introduced typeof, and these features resulted in a series of changes to avoid rvalues having qualified or atomic types or to avoid such types being observable:

In June 2024, Aaron Ballman pointed out in reflector message 26025 that it was still possible to have a qualified rvalue when accessing a qualified member of an rvalue structure or union (the result of a function call, assignment expression, conditional expression or comma expression with structure or union type), leading to a long discussion continuing through July and into August. In that discussion, Alex Celeste pointed out (message 26098) that qualifiers on array element types (which before C23 were not considered to be qualifiers on the array type) should still be preserved.

Consistency with the direction of the sequence of changes listed above would indicate that qualifiers and _Atomic should not be preserved in other cases. That suggests the following would be valid.

struct s1 { const int i; } f1();
struct s2 { const int a[1]; } f2();
struct s1a { _Atomic int i; } f1a();
struct s2a { _Atomic int a[1]; } f2a();

extern int i;
extern const int a[1];
extern _Atomic int aa[1];

extern typeof(f1().i) i;
extern typeof(f2().a) a;
extern typeof(f1a().i) i;
extern typeof(f2a().a) aa;

static_assert(_Generic(f1().i, int: 1, default: 0));
static_assert(_Generic(f2().a, const int *: 1, default: 0));
static_assert(_Generic(f1a().i, int: 1, default: 0));
static_assert(_Generic(f2a().a, _Atomic int *: 1, default: 0));

Suggested correction

In C23 6.5.3.4 (Structure and union members), insert at the end of the first Semantics paragraph:

If the first expression is not an lvalue and the designated member does not have array type, the result has the unqualified, non-atomic version of the type of the designated member.


Comment from Issues list maintainer on 2025-06-27:

In reflector message 29935, Jens Gustedt expresses concern about the removal of _Atomic qualifiers.

The handling of array members in non-lvalue structures and unions may require updates in C2y to either the wording proposed in this issue or the wording for array element access added in the integration of N3517. See reflector message 29936.