Skip to content

Commit f4e14bf

Browse files
authored
[Sema] Warn about omitting deprecated enumerator in switch (#138562)
This undoes part of 3e4e3b1 which added the "Omitting a deprecated constant is ok; it should never materialize." logic. That seems wrong: deprecated means the enumerator is likely to be removed in future versions, not that it cannot materialize. Also move warnings about the use of deprecated enumerators in switch cases behind a separate flag, -Wdeprecated-switch-case, for users who wish to handle such enums explicitly and suppress the warning.
1 parent be50ada commit f4e14bf

File tree

8 files changed

+78
-6
lines changed

8 files changed

+78
-6
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,33 @@ Improvements to Clang's diagnostics
565565

566566
- Clang now suggests corrections for unknown attribute names.
567567

568+
- ``-Wswitch`` will now diagnose unhandled enumerators in switches also when
569+
the enumerator is deprecated. Warnings about using deprecated enumerators in
570+
switch cases have moved behind a new ``-Wdeprecated-switch-case`` flag.
571+
572+
For example:
573+
574+
.. code-block:: c
575+
576+
enum E {
577+
Red,
578+
Green,
579+
Blue [[deprecated]]
580+
};
581+
void example(enum E e) {
582+
switch (e) {
583+
case Red: // stuff...
584+
case Green: // stuff...
585+
}
586+
}
587+
588+
will result in a warning about ``Blue`` not being handled in the switch.
589+
590+
The warning can be fixed either by adding a ``default:``, or by adding
591+
``case Blue:``. Since the enumerator is deprecated, the latter approach will
592+
trigger a ``'Blue' is deprecated`` warning, which can be turned off with
593+
``-Wno-deprecated-switch-case``.
594+
568595
Improvements to Clang's time-trace
569596
----------------------------------
570597

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@ def DeprecatedCopyWithDtor : DiagGroup<"deprecated-copy-with-dtor", [DeprecatedC
234234
def DeprecatedLiteralOperator : DiagGroup<"deprecated-literal-operator">;
235235
// For compatibility with GCC.
236236
def : DiagGroup<"deprecated-copy-dtor", [DeprecatedCopyWithDtor]>;
237-
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
237+
def DeprecatedSwitchCase : DiagGroup<"deprecated-switch-case">;
238+
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations", [DeprecatedSwitchCase]>;
238239
def DeprecatedRedundantConstexprStaticDef : DiagGroup<"deprecated-redundant-constexpr-static-def">;
239240
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
240241
def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6038,6 +6038,8 @@ def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to th
60386038
def err_undeclared_use : Error<"use of undeclared %0">;
60396039
def warn_deprecated : Warning<"%0 is deprecated">,
60406040
InGroup<DeprecatedDeclarations>;
6041+
def warn_deprecated_switch_case : Warning<warn_deprecated.Summary>,
6042+
InGroup<DeprecatedSwitchCase>;
60416043
def note_from_diagnose_if : Note<"from 'diagnose_if' attribute on %0:">;
60426044
def warn_property_method_deprecated :
60436045
Warning<"property access is using %0 method which is deprecated">,

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6761,6 +6761,9 @@ class Sema final : public SemaBase {
67616761
/// example, in a for-range initializer).
67626762
bool InLifetimeExtendingContext = false;
67636763

6764+
/// Whether evaluating an expression for a switch case label.
6765+
bool IsCaseExpr = false;
6766+
67646767
/// Whether we should rebuild CXXDefaultArgExpr and CXXDefaultInitExpr.
67656768
bool RebuildDefaultArgOrDefaultInit = false;
67666769

clang/lib/Parse/ParseExpr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ ExprResult Parser::ParseArrayBoundExpression() {
169169
ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
170170
EnterExpressionEvaluationContext ConstantEvaluated(
171171
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
172+
Actions.currentEvaluationContext().IsCaseExpr = true;
173+
172174
ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr, false,
173175
TypeCastState::NotTypeCast));
174176
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));

clang/lib/Sema/SemaAvailability.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,13 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
547547
return;
548548
}
549549
case AR_Deprecated:
550-
diag = !ObjCPropertyAccess ? diag::warn_deprecated
551-
: diag::warn_property_method_deprecated;
550+
if (ObjCPropertyAccess)
551+
diag = diag::warn_property_method_deprecated;
552+
else if (S.currentEvaluationContext().IsCaseExpr)
553+
diag = diag::warn_deprecated_switch_case;
554+
else
555+
diag = diag::warn_deprecated;
556+
552557
diag_message = diag::warn_deprecated_message;
553558
diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
554559
property_note_select = /* deprecated */ 0;

clang/lib/Sema/SemaStmt.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1667,8 +1667,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
16671667
// Don't warn about omitted unavailable EnumConstantDecls.
16681668
switch (EI->second->getAvailability()) {
16691669
case AR_Deprecated:
1670-
// Omitting a deprecated constant is ok; it should never materialize.
1670+
// Deprecated enumerators need to be handled: they may be deprecated,
1671+
// but can still occur.
1672+
break;
1673+
16711674
case AR_Unavailable:
1675+
// Omitting an unavailable enumerator is ok; it should never occur.
16721676
continue;
16731677

16741678
case AR_NotYetIntroduced:

clang/test/Sema/switch-availability.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_cc1 -verify -Wswitch -triple x86_64-apple-macosx10.12 %s
1+
// RUN: %clang_cc1 -verify -Wswitch -Wreturn-type -triple x86_64-apple-macosx10.12 %s
2+
// RUN: %clang_cc1 -verify -Wswitch -Wreturn-type -Wno-deprecated-switch-case -DNO_DEPRECATED_CASE -triple x86_64-apple-macosx10.12 %s
23

34
enum SwitchOne {
45
Unavail __attribute__((availability(macos, unavailable))),
@@ -15,7 +16,7 @@ enum SwitchTwo {
1516
};
1617

1718
void testSwitchTwo(enum SwitchTwo st) {
18-
switch (st) {} // expected-warning{{enumeration values 'Vim' and 'Emacs' not handled in switch}}
19+
switch (st) {} // expected-warning{{enumeration values 'Ed', 'Vim', and 'Emacs' not handled in switch}}
1920
}
2021

2122
enum SwitchThree {
@@ -25,3 +26,30 @@ enum SwitchThree {
2526
void testSwitchThree(enum SwitchThree st) {
2627
switch (st) {} // expected-warning{{enumeration value 'New' not handled in switch}}
2728
}
29+
30+
enum SwitchFour {
31+
Red,
32+
Green,
33+
#ifndef NO_DEPRECATED_CASE
34+
// expected-note@+2{{'Blue' has been explicitly marked deprecated here}}
35+
#endif
36+
Blue [[deprecated]]
37+
};
38+
39+
int testSwitchFour(enum SwitchFour e) {
40+
switch (e) { // expected-warning{{enumeration value 'Blue' not handled in switch}}
41+
case Red: return 1;
42+
case Green: return 2;
43+
}
44+
} // expected-warning{{non-void function does not return a value in all control paths}}
45+
46+
int testSwitchFourCovered(enum SwitchFour e) {
47+
switch (e) {
48+
case Red: return 1;
49+
case Green: return 2;
50+
#ifndef NO_DEPRECATED_CASE
51+
// expected-warning@+2{{'Blue' is deprecated}}
52+
#endif
53+
case Blue: return 3;
54+
} // no warning
55+
}

0 commit comments

Comments
 (0)