diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 9c0358041331..ca0ce99c2c2d 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -178,7 +178,8 @@ def InvalidOffsetof : DiagGroup<"invalid-offsetof">; def : DiagGroup<"strict-prototypes">; def StrictSelector : DiagGroup<"strict-selector-match">; def MethodDuplicate : DiagGroup<"duplicate-method-match">; -def SwitchEnum : DiagGroup<"switch-enum">; +def SwitchEnumRedundantDefault : DiagGroup<"switch-enum-redundant-default">; +def SwitchEnum : DiagGroup<"switch-enum", [SwitchEnumRedundantDefault]>; def Switch : DiagGroup<"switch", [SwitchEnum]>; def Trigraphs : DiagGroup<"trigraphs">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f685c9f2b759..3ffd580b83b9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4946,19 +4946,22 @@ def warn_case_empty_range : Warning<"empty case range specified">; def warn_missing_case_for_condition : Warning<"no case matching constant switch condition '%0'">; def warn_missing_case1 : Warning<"enumeration value %0 not handled in switch">, - InGroup >; + InGroup; def warn_missing_case2 : Warning< "enumeration values %0 and %1 not handled in switch">, - InGroup >; + InGroup; def warn_missing_case3 : Warning< "enumeration values %0, %1, and %2 not handled in switch">, - InGroup >; + InGroup; def warn_missing_cases : Warning< "%0 enumeration values not handled in switch: %1, %2, %3...">, - InGroup >; + InGroup; +def warn_unreachable_default : Warning< + "default is unreachable as all enumeration values are accounted for">, + InGroup; def warn_not_in_enum : Warning<"case value not in enumerated type %0">, - InGroup >; + InGroup; def err_typecheck_statement_requires_scalar : Error< "statement requires expression of scalar type (%0 invalid)">; def err_typecheck_statement_requires_integer : Error< diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index a53e397243bf..0be3e43b5a7a 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -924,11 +924,17 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, if (RI == CaseRanges.end() || EI->first < RI->first) { hasCasesNotInSwitch = true; - if (!TheDefaultStmt) - UnhandledNames.push_back(EI->second->getDeclName()); + UnhandledNames.push_back(EI->second->getDeclName()); } } + if (TheDefaultStmt) { + if (UnhandledNames.size() == 0) + Diag(TheDefaultStmt->getDefaultLoc(), diag::warn_unreachable_default); + else + UnhandledNames.clear(); + } + // Produce a nice diagnostic if multiple values aren't handled. switch (UnhandledNames.size()) { case 0: break; diff --git a/clang/test/Sema/switch.c b/clang/test/Sema/switch.c index ef2e4c5d9b7c..63ffed18e312 100644 --- a/clang/test/Sema/switch.c +++ b/clang/test/Sema/switch.c @@ -288,3 +288,12 @@ void test17(int x) { case 0: return; } } + +int test18() { + enum { A, B } a; + switch (a) { + case A: return 0; + case B: return 1; + default: return 2; // expected-warning {{default is unreachable as all enumeration values are accounted for}} + } +} diff --git a/clang/test/Sema/warn-unreachable.c b/clang/test/Sema/warn-unreachable.c index 3ad53c707bae..46a680f0ef86 100644 --- a/clang/test/Sema/warn-unreachable.c +++ b/clang/test/Sema/warn-unreachable.c @@ -1,4 +1,4 @@ -// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code -Wno-unused-value +// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code -Wno-unused-value -Wno-switch-enum-redundant-default int halt() __attribute__((noreturn)); int live(); diff --git a/clang/test/SemaCXX/gnu-case-ranges.cpp b/clang/test/SemaCXX/gnu-case-ranges.cpp index c1c18a89481c..94100d2e83e7 100644 --- a/clang/test/SemaCXX/gnu-case-ranges.cpp +++ b/clang/test/SemaCXX/gnu-case-ranges.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify %s +// RUN: %clang_cc1 -verify -Wno-switch-enum-redundant-default %s enum E { one, diff --git a/clang/test/SemaCXX/return-noreturn.cpp b/clang/test/SemaCXX/return-noreturn.cpp index e06ba403efec..4b1f82dc6a3c 100644 --- a/clang/test/SemaCXX/return-noreturn.cpp +++ b/clang/test/SemaCXX/return-noreturn.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code +// RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-switch-enum-redundant-default +// RUN: %clang_cc1 %s -fsyntax-only -std=c++11 -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -Wno-switch-enum-redundant-default // A destructor may be marked noreturn and should still influence the CFG. void pr6884_abort() __attribute__((noreturn));