Skip to content

Commit 5c4426f

Browse files
committed
[C11] Generic selection expressions and qualified rvalues
It is possible to get a qualified rvalue in C. Consider: struct { cont int i; } foo(); _Generic(foo().i, ...); foo() returns an rvalue for the anonymous structure, the member access expression then results in an rvalue of type const int. The lvalue to rvalue conversion we perform on the controlling expression of the generic selection expression then fails to strip any qualifiers because the expression is already an rvalue. Discussion on the WG14 reflectors suggested that the qualifiers should still be stripped from the type of the controlling expression; the standard should be corrected to make this more clear. Fixes llvm#96713
1 parent 86860be commit 5c4426f

File tree

3 files changed

+31
-9
lines changed

3 files changed

+31
-9
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,10 @@ Bug Fixes in This Version
739739
negatives where the analysis failed to detect unchecked access to guarded
740740
data.
741741

742+
- When passing a qualified rvalue as the controlling expression of a
743+
``_Generic`` selection expression, Clang now properly strips the qualifiers.
744+
Fixes #GH96713
745+
742746
Bug Fixes to Compiler Builtins
743747
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
744748

clang/lib/Sema/SemaExpr.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,18 +1828,26 @@ ExprResult Sema::CreateGenericSelectionExpr(
18281828
// Look at the canonical type of the controlling expression in case it was a
18291829
// deduced type like __auto_type. However, when issuing diagnostics, use the
18301830
// type the user wrote in source rather than the canonical one.
1831+
//
1832+
// Note: there is an edge case for this in C where you can get a
1833+
// qualified rvalue and the qualifiers are not stripped by the lvalue
1834+
// conversion applied above. e.g.,
1835+
//
1836+
// struct { const int i; } foo();
1837+
// _Generic(foo().i, ...);
1838+
//
1839+
// Therefore, in C, we will still ask for the non-atomic, unqualified
1840+
// type despite those qualifiers generally being stripped above.
1841+
QualType ControllingTypeToUse =
1842+
ControllingExpr ? ControllingExpr->getType() : ControllingType->getType();
1843+
ControllingTypeToUse = ControllingTypeToUse.getCanonicalType();
1844+
if (!getLangOpts().CPlusPlus && ControllingExpr)
1845+
ControllingTypeToUse = ControllingTypeToUse.getAtomicUnqualifiedType();
18311846
for (unsigned i = 0; i < NumAssocs; ++i) {
18321847
if (!Types[i])
18331848
DefaultIndex = i;
1834-
else if (ControllingExpr &&
1835-
Context.typesAreCompatible(
1836-
ControllingExpr->getType().getCanonicalType(),
1837-
Types[i]->getType()))
1838-
CompatIndices.push_back(i);
1839-
else if (ControllingType &&
1840-
Context.typesAreCompatible(
1841-
ControllingType->getType().getCanonicalType(),
1842-
Types[i]->getType()))
1849+
else if (Context.typesAreCompatible(ControllingTypeToUse,
1850+
Types[i]->getType()))
18431851
CompatIndices.push_back(i);
18441852
}
18451853

clang/test/Sema/generic-selection.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,13 @@ void GH55562(void) {
8686
struct S s = { 0 };
8787
int i = s.a;
8888
}
89+
90+
struct { const int i; } GH96713_1(void);
91+
void GH96713_2(void) {
92+
_Static_assert( // ext-warning {{'_Static_assert' is a C11 extension}}
93+
_Generic(GH96713_1().i, // ext-warning {{'_Generic' is a C11 extension}}
94+
int : 1,
95+
const int : 0 // expected-warning {{due to lvalue conversion of the controlling expression, association of type 'const int' will never be selected because it is qualified}}
96+
), ""
97+
);
98+
}

0 commit comments

Comments
 (0)