diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 918ff952bb2c3..95cff4c138503 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 3c24387630d0c..6f15151e7e07e 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -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">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e5a7cdc14a737..2654348188f24 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; +def warn_deprecated_switch_case : Warning, + InGroup; 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">, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 19343eb0af092..d6113e33e564c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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; diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 4b5d677f4ba87..75e9f8b6afd6d 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -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)); diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 96aa65412906c..04dddaf92e67c 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -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; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index e8c1f8490342a..b841f994601e3 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -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: diff --git a/clang/test/Sema/switch-availability.c b/clang/test/Sema/switch-availability.c index 888edddac463d..517b3f100b24c 100644 --- a/clang/test/Sema/switch-availability.c +++ b/clang/test/Sema/switch-availability.c @@ -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))), @@ -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 { @@ -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 +}