Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -8188,6 +8188,8 @@ def err_default_not_in_switch : Error< "'default' statement not in switch statement">; def err_case_not_in_switch : Error<"'case' statement not in switch statement">; +def warn_unreachable_stmt_in_switch : Warning< + "statement will be never executed">, InGroup>; def warn_bool_switch_condition : Warning< "switch condition has boolean value">, InGroup; def warn_case_value_overflow : Warning< Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -723,7 +723,8 @@ /// Check the specified case value is in range for the given unpromoted switch /// type. static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val, - unsigned UnpromotedWidth, bool UnpromotedSign) { + unsigned UnpromotedWidth, bool UnpromotedSign, + bool &CaseListIsErroneous) { // In C++11 onwards, this is checked by the language rules. if (S.getLangOpts().CPlusPlus11) return; @@ -738,9 +739,11 @@ // FIXME: Use different diagnostics for overflow in conversion to promoted // type versus "switch expression cannot have this value". Use proper // IntRange checking rather than just looking at the unpromoted type here. - if (ConvVal != Val) - S.Diag(Loc, diag::warn_case_value_overflow) << Val.toString(10) - << ConvVal.toString(10); + if (ConvVal != Val) { + CaseListIsErroneous = true; + S.Diag(Loc, diag::warn_case_value_overflow) + << Val.toString(10) << ConvVal.toString(10); + } } } @@ -819,6 +822,19 @@ if (!BodyStmt) return StmtError(); SS->setBody(BodyStmt, SwitchLoc); + if (const auto *CS = dyn_cast(BodyStmt)) { + for (const auto *S : CS->body()) { + if (isa(S)) + continue; + if (isa(S) || isa(S) || isa(S)) + break; + Diag(S->getBeginLoc(), diag::warn_unreachable_stmt_in_switch); + } + } else if (!isa(BodyStmt) && !isa(BodyStmt) && + !isa(BodyStmt) && !isa(BodyStmt)) { + Diag(BodyStmt->getBeginLoc(), diag::warn_unreachable_stmt_in_switch); + } + Expr *CondExpr = SS->getCond(); if (!CondExpr) return StmtError(); @@ -900,7 +916,7 @@ // Check the unconverted value is within the range of possible values of // the switch expression. checkCaseValue(*this, Lo->getBeginLoc(), LoVal, CondWidthBeforePromotion, - CondIsSignedBeforePromotion); + CondIsSignedBeforePromotion, CaseListIsErroneous); // FIXME: This duplicates the check performed for warn_not_in_enum below. checkEnumTypesInSwitchStmt(*this, CondExprBeforePromotion, @@ -1003,7 +1019,8 @@ // Check the unconverted value is within the range of possible values of // the switch expression. checkCaseValue(*this, Hi->getBeginLoc(), HiVal, - CondWidthBeforePromotion, CondIsSignedBeforePromotion); + CondWidthBeforePromotion, CondIsSignedBeforePromotion, + CaseListIsErroneous); // Convert the value to the same width/sign as the condition. AdjustAPSInt(HiVal, CondWidth, CondIsSigned); Index: test/Sema/implicit-decl-c90.c =================================================================== --- test/Sema/implicit-decl-c90.c +++ test/Sema/implicit-decl-c90.c @@ -15,7 +15,7 @@ void t1(int x) { int (*p)(); switch (x) { - g(); + g(); // expected-warning {{statement will be never executed}} case 0: x = h() + 1; break; Index: test/SemaCXX/array-bounds.cpp =================================================================== --- test/SemaCXX/array-bounds.cpp +++ test/SemaCXX/array-bounds.cpp @@ -164,6 +164,7 @@ static enum enumB myVal = enumB_X; void test_nested_switch() { switch (enumA_E) { // expected-warning {{no case matching constant}} + // expected-warning@+1 {{statement will be never executed}} switch (myVal) { // expected-warning {{enumeration values 'enumB_X' and 'enumB_Z' not handled in switch}} case enumB_Y: ; } Index: test/SemaCXX/warn-unreachable-stmt-switch.cpp =================================================================== --- test/SemaCXX/warn-unreachable-stmt-switch.cpp +++ test/SemaCXX/warn-unreachable-stmt-switch.cpp @@ -0,0 +1,152 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wswitch-unreachable %s +// RUN: %clang_cc1 -x c -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -Wswitch-unreachable %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -verify %s + +void g(int x); + +void foo(int x) { + int b = 0; + switch (x) { + label: + case 4: + break; + default: + return; + } + + switch (x) { + x++; // expected-warning {{statement will be never executed}} + label2: + case 4: + break; + default: + return; + } + + switch (x) { + label3: + x++; + case 4: + break; + default: + return; + } + + switch (x) { + case 4: + return; + } + + switch (x) { + b = x; // expected-warning {{statement will be never executed}} + case 7: + g(b); + break; + } + + switch (x) { + ; + case 7: + g(b); + break; + } + + switch (x) { + break; // expected-warning {{statement will be never executed}} + case 7: + break; + } + + switch (x) { + return; // expected-warning {{statement will be never executed}} + case 7: + break; + } + + switch (x) { + x++; // expected-warning {{statement will be never executed}} + g(x); // expected-warning {{statement will be never executed}} + case 7: + break; + } + + switch (x) { + x++; // expected-warning {{statement will be never executed}} + label4: + g(x); + case 7: + break; + } + + switch (x) { + g(x); // expected-warning {{statement will be never executed}} + case 1: + break; + case 2: + break; + } + + switch (x) { + g(x); // expected-warning {{statement will be never executed}} + case 1: + case 2: + case 3: + break; + } + + switch (x) { + case 1: + break; + case 2: + break; + } + + switch (x) { + case 1: + break; + default: + break; + } + + switch (x) { + b = x; // expected-warning {{statement will be never executed}} + } + + switch (x) { + g(x); // expected-warning {{statement will be never executed}} + } + + switch (x) + b = x; // expected-warning {{statement will be never executed}} + + switch (x) + g(x); // expected-warning {{statement will be never executed}} + + switch (x) + label5: + g(x); + + switch (x) { + label6: + g(x); + } + + switch (x) + case 5: + g(x); + + switch (x) { + case 5: + g(x); + } + + switch (x) + default: + g(x); + + switch (x) { + default: + g(x); + } +}