Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,10 @@ Bug Fixes in This Version
negatives where the analysis failed to detect unchecked access to guarded
data.

- When passing a qualified rvalue as the controlling expression of a
``_Generic`` selection expression, Clang now properly strips the qualifiers.
Fixes #GH96713

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
26 changes: 17 additions & 9 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1828,18 +1828,26 @@ ExprResult Sema::CreateGenericSelectionExpr(
// Look at the canonical type of the controlling expression in case it was a
// deduced type like __auto_type. However, when issuing diagnostics, use the
// type the user wrote in source rather than the canonical one.
//
// Note: there is an edge case for this in C where you can get a
// qualified rvalue and the qualifiers are not stripped by the lvalue
// conversion applied above. e.g.,
//
// struct { const int i; } foo();
// _Generic(foo().i, ...);
//
// Therefore, in C, we will still ask for the non-atomic, unqualified
// type despite those qualifiers generally being stripped above.
QualType ControllingTypeToUse =
ControllingExpr ? ControllingExpr->getType() : ControllingType->getType();
ControllingTypeToUse = ControllingTypeToUse.getCanonicalType();
if (!getLangOpts().CPlusPlus && ControllingExpr)
ControllingTypeToUse = ControllingTypeToUse.getAtomicUnqualifiedType();
for (unsigned i = 0; i < NumAssocs; ++i) {
if (!Types[i])
DefaultIndex = i;
else if (ControllingExpr &&
Context.typesAreCompatible(
ControllingExpr->getType().getCanonicalType(),
Types[i]->getType()))
CompatIndices.push_back(i);
else if (ControllingType &&
Context.typesAreCompatible(
ControllingType->getType().getCanonicalType(),
Types[i]->getType()))
else if (Context.typesAreCompatible(ControllingTypeToUse,
Types[i]->getType()))
CompatIndices.push_back(i);
}

Expand Down
10 changes: 10 additions & 0 deletions clang/test/Sema/generic-selection.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,13 @@ void GH55562(void) {
struct S s = { 0 };
int i = s.a;
}

struct { const int i; } GH96713_1(void);
void GH96713_2(void) {
_Static_assert( // ext-warning {{'_Static_assert' is a C11 extension}}
_Generic(GH96713_1().i, // ext-warning {{'_Generic' is a C11 extension}}
int : 1,
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}}
), ""
);
}