Skip to content

Commit 47b8424

Browse files
committed
Correct the diagnostic behavior for unreachable _Generic associations in C++
New diagnostics were added for unreachable generic selection expression associations in ca75ac5, but it did not account for a difference in behavior between C and C++ regarding lvalue to rvalue conversions. So we would issue diagnostics about a selection being unreachable and then reach it. This corrects the diagnostic behavior in that case. Differential Revision: https://reviews.llvm.org/D125882
1 parent 087ef34 commit 47b8424

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

clang/lib/Sema/SemaExpr.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1692,11 +1692,20 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
16921692
// reached. We will warn about this so users are less surprised by
16931693
// the unreachable association. However, we don't have to handle
16941694
// function types; that's not an object type, so it's handled above.
1695+
//
1696+
// The logic is somewhat different for C++ because C++ has different
1697+
// lvalue to rvalue conversion rules than C. [conv.lvalue]p1 says,
1698+
// If T is a non-class type, the type of the prvalue is the cv-
1699+
// unqualified version of T. Otherwise, the type of the prvalue is T.
1700+
// The result of these rules is that all qualified types in an
1701+
// association in C are unreachable, and in C++, only qualified non-
1702+
// class types are unreachable.
16951703
unsigned Reason = 0;
16961704
QualType QT = Types[i]->getType();
16971705
if (QT->isArrayType())
16981706
Reason = 1;
1699-
else if (QT.hasQualifiers())
1707+
else if (QT.hasQualifiers() &&
1708+
(!LangOpts.CPlusPlus || !QT->isRecordType()))
17001709
Reason = 2;
17011710

17021711
if (Reason)

clang/test/Sema/generic-selection.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ void GH50227(void) {
5858
), int : 0);
5959
}
6060

61-
void unreachable_associations(const int i) {
61+
struct Test {
62+
int i;
63+
};
64+
65+
void unreachable_associations(const int i, const struct Test t) {
6266
_Static_assert( // ext-warning {{'_Static_assert' is a C11 extension}}
6367
_Generic(i, // ext-warning {{'_Generic' is a C11 extension}}
6468
const int : 1, // expected-warning {{due to lvalue conversion of the controlling expression, association of type 'const int' will never be selected because it is qualified}}
@@ -67,4 +71,10 @@ void unreachable_associations(const int i) {
6771
int : 4,
6872
default : 5
6973
) == 4, "we had better pick int!");
74+
_Static_assert( // ext-warning {{'_Static_assert' is a C11 extension}}
75+
_Generic(t, // ext-warning {{'_Generic' is a C11 extension}}
76+
struct Test : 1,
77+
const struct Test : 2, // expected-warning {{due to lvalue conversion of the controlling expression, association of type 'const struct Test' will never be selected because it is qualified}}
78+
default : 3
79+
) == 1, "we had better pick struct Test, not const struct Test!"); // C-specific result
7080
}

clang/test/SemaCXX/generic-selection.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,28 @@ template <class... Args> struct TypeMask {
4444
static_assert(TypeMask<int, long, short>::result == 7, "fail");
4545
static_assert(TypeMask<float, short>::result == 12, "fail");
4646
static_assert(TypeMask<int, float, float>::result == 9, "fail");
47+
48+
49+
struct Test {
50+
int i;
51+
};
52+
53+
void unreachable_associations(const int i, const Test t) {
54+
// FIXME: it's not clear to me whether we intended to deviate from the C
55+
// semantics in terms of how qualifiers are handled, so this documents the
56+
// existing behavior but perhaps not the desired behavior.
57+
static_assert(
58+
_Generic(i,
59+
const int : 1, // expected-warning {{due to lvalue conversion of the controlling expression, association of type 'const int' will never be selected because it is qualified}}
60+
volatile int : 2, // expected-warning {{due to lvalue conversion of the controlling expression, association of type 'volatile int' will never be selected because it is qualified}}
61+
int[12] : 3, // expected-warning {{due to lvalue conversion of the controlling expression, association of type 'int[12]' will never be selected because it is of array type}}
62+
int : 4,
63+
default : 5
64+
) == 4, "we had better pick int, not const int!");
65+
static_assert(
66+
_Generic(t,
67+
Test : 1,
68+
const Test : 2, // Ok in C++, warned in C
69+
default : 3
70+
) == 2, "we had better pick const Test, not Test!"); // C++-specific result
71+
}

0 commit comments

Comments
 (0)