Skip to content

[Sema] Warn about omitting deprecated enumerator in switch #138562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 23, 2025
Merged
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
27 changes: 27 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,33 @@ Improvements to Clang's diagnostics
- ``-Wreserved-identifier`` now fires on reserved parameter names in a function
declaration which is not a definition.

- ``-Wswitch`` will now diagnose unhandled enumerators in switches also when
the enumerator is deprecated. Warnings about using deprecated enumerators in
switch cases have moved behind a new ``-Wdeprecated-switch-case`` flag.

For example:

.. code-block:: c

enum E {
Red,
Green,
Blue [[deprecated]]
};
void example(enum E e) {
switch (e) {
case Red: // stuff...
case Green: // stuff...
}
}

will result in a warning about ``Blue`` not being handled in the switch.

The warning can be fixed either by adding a ``default:``, or by adding
``case Blue:``. Since the enumerator is deprecated, the latter approach will
trigger a ``'Blue' is deprecated`` warning, which can be turned off with
``-Wno-deprecated-switch-case``.

Improvements to Clang's time-trace
----------------------------------

Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ def DeprecatedCopyWithDtor : DiagGroup<"deprecated-copy-with-dtor", [DeprecatedC
def DeprecatedLiteralOperator : DiagGroup<"deprecated-literal-operator">;
// For compatibility with GCC.
def : DiagGroup<"deprecated-copy-dtor", [DeprecatedCopyWithDtor]>;
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
def DeprecatedSwitchCase : DiagGroup<"deprecated-switch-case">;
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations", [DeprecatedSwitchCase]>;
def DeprecatedRedundantConstexprStaticDef : DiagGroup<"deprecated-redundant-constexpr-static-def">;
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">;
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -6009,6 +6009,8 @@ def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to th
def err_undeclared_use : Error<"use of undeclared %0">;
def warn_deprecated : Warning<"%0 is deprecated">,
InGroup<DeprecatedDeclarations>;
def warn_deprecated_switch_case : Warning<warn_deprecated.Summary>,
InGroup<DeprecatedSwitchCase>;
def note_from_diagnose_if : Note<"from 'diagnose_if' attribute on %0:">;
def warn_property_method_deprecated :
Warning<"property access is using %0 method which is deprecated">,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -6747,6 +6747,9 @@ class Sema final : public SemaBase {
/// example, in a for-range initializer).
bool InLifetimeExtendingContext = false;

/// Whether evaluating an expression for a switch case label.
bool IsCaseExpr = false;

/// Whether we should rebuild CXXDefaultArgExpr and CXXDefaultInitExpr.
bool RebuildDefaultArgOrDefaultInit = false;

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ ExprResult Parser::ParseArrayBoundExpression() {
ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
EnterExpressionEvaluationContext ConstantEvaluated(
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
Actions.currentEvaluationContext().IsCaseExpr = true;

ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr, false,
TypeCastState::NotTypeCast));
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
Expand Down
9 changes: 7 additions & 2 deletions clang/lib/Sema/SemaAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,8 +549,13 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
return;
}
case AR_Deprecated:
diag = !ObjCPropertyAccess ? diag::warn_deprecated
: diag::warn_property_method_deprecated;
if (ObjCPropertyAccess)
diag = diag::warn_property_method_deprecated;
else if (S.currentEvaluationContext().IsCaseExpr)
diag = diag::warn_deprecated_switch_case;
else
diag = diag::warn_deprecated;

diag_message = diag::warn_deprecated_message;
diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
property_note_select = /* deprecated */ 0;
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1667,8 +1667,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// Don't warn about omitted unavailable EnumConstantDecls.
switch (EI->second->getAvailability()) {
case AR_Deprecated:
// Omitting a deprecated constant is ok; it should never materialize.
// Deprecated enumerators need to be handled: they may be deprecated,
// but can still occur.
break;

case AR_Unavailable:
// Omitting an unavailable enumerator is ok; it should never occur.
continue;

case AR_NotYetIntroduced:
Expand Down
32 changes: 30 additions & 2 deletions clang/test/Sema/switch-availability.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -Wswitch -triple x86_64-apple-macosx10.12 %s
// RUN: %clang_cc1 -verify -Wswitch -Wreturn-type -triple x86_64-apple-macosx10.12 %s
// RUN: %clang_cc1 -verify -Wswitch -Wreturn-type -Wno-deprecated-switch-case -DNO_DEPRECATED_CASE -triple x86_64-apple-macosx10.12 %s

enum SwitchOne {
Unavail __attribute__((availability(macos, unavailable))),
Expand All @@ -15,7 +16,7 @@ enum SwitchTwo {
};

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

enum SwitchThree {
Expand All @@ -25,3 +26,30 @@ enum SwitchThree {
void testSwitchThree(enum SwitchThree st) {
switch (st) {} // expected-warning{{enumeration value 'New' not handled in switch}}
}

enum SwitchFour {
Red,
Green,
#ifndef NO_DEPRECATED_CASE
// expected-note@+2{{'Blue' has been explicitly marked deprecated here}}
#endif
Blue [[deprecated]]
};

int testSwitchFour(enum SwitchFour e) {
switch (e) { // expected-warning{{enumeration value 'Blue' not handled in switch}}
case Red: return 1;
case Green: return 2;
}
} // expected-warning{{non-void function does not return a value in all control paths}}

int testSwitchFourCovered(enum SwitchFour e) {
switch (e) {
case Red: return 1;
case Green: return 2;
#ifndef NO_DEPRECATED_CASE
// expected-warning@+2{{'Blue' is deprecated}}
#endif
case Blue: return 3;
} // no warning
}
Loading