Skip to content

Commit ca75ac5

Browse files
committed
Diagnose unreachable generic selection associations
The controlling expression of a _Generic selection expression undergoes lvalue conversion, array conversion, and function conversion before picking the association. This means that array types, function types, and qualified types are all unreachable code if they're used as an association. I've been caught by this twice in the past few months and I figure that if a WG14 member can't seem to remember this rule, users are also likely to struggle with it. So this adds an on-by-default unreachable code diagnostic for generic selection expression associations. Note, we don't have to worry about function types as those are already a constraint violation which generates an error. Differential Revision: https://reviews.llvm.org/D125259
1 parent 7172836 commit ca75ac5

File tree

5 files changed

+41
-1
lines changed

5 files changed

+41
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ Improvements to Clang's diagnostics
210210
- ``-Wenum-conversion`` now warns on converting a signed enum of one type to an
211211
unsigned enum of a different type (or vice versa) rather than
212212
``-Wsign-conversion``.
213+
- Added the ``-Wunreachable-code-generic-assoc`` diagnostic flag (grouped under
214+
the ``-Wunreachable-code`` flag) which is enabled by default and warns the
215+
user about ``_Generic`` selection associations which are unreachable because
216+
the type specified is an array type or a qualified type.
213217

214218
Non-comprehensive list of changes in this release
215219
-------------------------------------------------

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -843,9 +843,11 @@ def ReservedIdentifier : DiagGroup<"reserved-identifier",
843843
//
844844
def UnreachableCodeLoopIncrement : DiagGroup<"unreachable-code-loop-increment">;
845845
def UnreachableCodeFallthrough : DiagGroup<"unreachable-code-fallthrough">;
846+
def UnreachableCodeGenericAssoc : DiagGroup<"unreachable-code-generic-assoc">;
846847
def UnreachableCode : DiagGroup<"unreachable-code",
847848
[UnreachableCodeLoopIncrement,
848-
UnreachableCodeFallthrough]>;
849+
UnreachableCodeFallthrough,
850+
UnreachableCodeGenericAssoc]>;
849851
def UnreachableCodeBreak : DiagGroup<"unreachable-code-break">;
850852
def UnreachableCodeReturn : DiagGroup<"unreachable-code-return">;
851853
def UnreachableCodeAggressive : DiagGroup<"unreachable-code-aggressive",

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,10 @@ def warn_unreachable_fallthrough_attr : Warning<
693693
InGroup<UnreachableCodeFallthrough>, DefaultIgnore;
694694
def note_unreachable_silence : Note<
695695
"silence by adding parentheses to mark code as explicitly dead">;
696+
def warn_unreachable_association : Warning<
697+
"due to lvalue conversion of the controlling expression, association of type "
698+
"%0 will never be selected because it is %select{of array type|qualified}1">,
699+
InGroup<UnreachableCodeGenericAssoc>;
696700

697701
/// Built-in functions.
698702
def ext_implicit_lib_function_decl : ExtWarn<

clang/lib/Sema/SemaExpr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,6 +1685,25 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
16851685
D = diag::err_assoc_type_nonobject;
16861686
else if (Types[i]->getType()->isVariablyModifiedType())
16871687
D = diag::err_assoc_type_variably_modified;
1688+
else {
1689+
// Because the controlling expression undergoes lvalue conversion,
1690+
// array conversion, and function conversion, an association which is
1691+
// of array type, function type, or is qualified can never be
1692+
// reached. We will warn about this so users are less surprised by
1693+
// the unreachable association. However, we don't have to handle
1694+
// function types; that's not an object type, so it's handled above.
1695+
unsigned Reason = 0;
1696+
QualType QT = Types[i]->getType();
1697+
if (QT->isArrayType())
1698+
Reason = 1;
1699+
else if (QT.hasQualifiers())
1700+
Reason = 2;
1701+
1702+
if (Reason)
1703+
Diag(Types[i]->getTypeLoc().getBeginLoc(),
1704+
diag::warn_unreachable_association)
1705+
<< QT << (Reason - 1);
1706+
}
16881707

16891708
if (D != 0) {
16901709
Diag(Types[i]->getTypeLoc().getBeginLoc(), D)

clang/test/Sema/generic-selection.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,14 @@ void GH50227(void) {
5757
_Generic(n++, int : 0) // expected-error {{cannot increment value of type 'int ()'}} ext-warning {{'_Generic' is a C11 extension}}
5858
), int : 0);
5959
}
60+
61+
void unreachable_associations(const int i) {
62+
_Static_assert( // ext-warning {{'_Static_assert' is a C11 extension}}
63+
_Generic(i, // ext-warning {{'_Generic' is a C11 extension}}
64+
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}}
65+
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}}
66+
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}}
67+
int : 4,
68+
default : 5
69+
) == 4, "we had better pick int!");
70+
}

0 commit comments

Comments
 (0)