mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 14:46:07 +00:00
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
This commit is contained in:
parent
71728360ad
commit
ca75ac5f04
@ -210,6 +210,10 @@ Improvements to Clang's diagnostics
|
||||
- ``-Wenum-conversion`` now warns on converting a signed enum of one type to an
|
||||
unsigned enum of a different type (or vice versa) rather than
|
||||
``-Wsign-conversion``.
|
||||
- Added the ``-Wunreachable-code-generic-assoc`` diagnostic flag (grouped under
|
||||
the ``-Wunreachable-code`` flag) which is enabled by default and warns the
|
||||
user about ``_Generic`` selection associations which are unreachable because
|
||||
the type specified is an array type or a qualified type.
|
||||
|
||||
Non-comprehensive list of changes in this release
|
||||
-------------------------------------------------
|
||||
|
@ -843,9 +843,11 @@ def ReservedIdentifier : DiagGroup<"reserved-identifier",
|
||||
//
|
||||
def UnreachableCodeLoopIncrement : DiagGroup<"unreachable-code-loop-increment">;
|
||||
def UnreachableCodeFallthrough : DiagGroup<"unreachable-code-fallthrough">;
|
||||
def UnreachableCodeGenericAssoc : DiagGroup<"unreachable-code-generic-assoc">;
|
||||
def UnreachableCode : DiagGroup<"unreachable-code",
|
||||
[UnreachableCodeLoopIncrement,
|
||||
UnreachableCodeFallthrough]>;
|
||||
UnreachableCodeFallthrough,
|
||||
UnreachableCodeGenericAssoc]>;
|
||||
def UnreachableCodeBreak : DiagGroup<"unreachable-code-break">;
|
||||
def UnreachableCodeReturn : DiagGroup<"unreachable-code-return">;
|
||||
def UnreachableCodeAggressive : DiagGroup<"unreachable-code-aggressive",
|
||||
|
@ -693,6 +693,10 @@ def warn_unreachable_fallthrough_attr : Warning<
|
||||
InGroup<UnreachableCodeFallthrough>, DefaultIgnore;
|
||||
def note_unreachable_silence : Note<
|
||||
"silence by adding parentheses to mark code as explicitly dead">;
|
||||
def warn_unreachable_association : Warning<
|
||||
"due to lvalue conversion of the controlling expression, association of type "
|
||||
"%0 will never be selected because it is %select{of array type|qualified}1">,
|
||||
InGroup<UnreachableCodeGenericAssoc>;
|
||||
|
||||
/// Built-in functions.
|
||||
def ext_implicit_lib_function_decl : ExtWarn<
|
||||
|
@ -1685,6 +1685,25 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
|
||||
D = diag::err_assoc_type_nonobject;
|
||||
else if (Types[i]->getType()->isVariablyModifiedType())
|
||||
D = diag::err_assoc_type_variably_modified;
|
||||
else {
|
||||
// Because the controlling expression undergoes lvalue conversion,
|
||||
// array conversion, and function conversion, an association which is
|
||||
// of array type, function type, or is qualified can never be
|
||||
// reached. We will warn about this so users are less surprised by
|
||||
// the unreachable association. However, we don't have to handle
|
||||
// function types; that's not an object type, so it's handled above.
|
||||
unsigned Reason = 0;
|
||||
QualType QT = Types[i]->getType();
|
||||
if (QT->isArrayType())
|
||||
Reason = 1;
|
||||
else if (QT.hasQualifiers())
|
||||
Reason = 2;
|
||||
|
||||
if (Reason)
|
||||
Diag(Types[i]->getTypeLoc().getBeginLoc(),
|
||||
diag::warn_unreachable_association)
|
||||
<< QT << (Reason - 1);
|
||||
}
|
||||
|
||||
if (D != 0) {
|
||||
Diag(Types[i]->getTypeLoc().getBeginLoc(), D)
|
||||
|
@ -57,3 +57,14 @@ void GH50227(void) {
|
||||
_Generic(n++, int : 0) // expected-error {{cannot increment value of type 'int ()'}} ext-warning {{'_Generic' is a C11 extension}}
|
||||
), int : 0);
|
||||
}
|
||||
|
||||
void unreachable_associations(const int i) {
|
||||
_Static_assert( // ext-warning {{'_Static_assert' is a C11 extension}}
|
||||
_Generic(i, // ext-warning {{'_Generic' is a C11 extension}}
|
||||
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}}
|
||||
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}}
|
||||
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}}
|
||||
int : 4,
|
||||
default : 5
|
||||
) == 4, "we had better pick int!");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user