From 3940ce83438e2332ba541f4e65e700fbefe0c7a8 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 16 May 2012 05:32:58 +0000 Subject: [PATCH] Produce more useful 'duplicate case' diagnostics. Fixes PR9243, from Terry Long! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156904 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ lib/Sema/SemaStmt.cpp | 25 +++++++++++++++-- test/Sema/switch.c | 31 +++++++++++++++++++++- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 0865619e6d..4356539749 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5229,6 +5229,8 @@ def warn_case_value_overflow : Warning< "overflow converting case value to switch condition type (%0 to %1)">, InGroup>; def err_duplicate_case : Error<"duplicate case value '%0'">; +def err_duplicate_case_differing_expr : Error< + "duplicate case value: '%0' and '%1' both equal '%2'">; def warn_case_empty_range : Warning<"empty case range specified">; def warn_missing_case_for_condition : Warning<"no case matching constant switch condition '%0'">; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 2ea07efde8..295068c9f2 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -768,8 +768,29 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, if (i != 0 && CaseVals[i].first == CaseVals[i-1].first) { // If we have a duplicate, report it. - Diag(CaseVals[i].second->getLHS()->getLocStart(), - diag::err_duplicate_case) << CaseVals[i].first.toString(10); + // First, determine if either case value has a name + StringRef PrevString, CurrString; + Expr *PrevCase = CaseVals[i-1].second->getLHS()->IgnoreParenCasts(); + Expr *CurrCase = CaseVals[i].second->getLHS()->IgnoreParenCasts(); + if (DeclRefExpr *DeclRef = dyn_cast(PrevCase)) { + PrevString = DeclRef->getDecl()->getName(); + } + if (DeclRefExpr *DeclRef = dyn_cast(CurrCase)) { + CurrString = DeclRef->getDecl()->getName(); + } + std::string CaseValStr = CaseVals[i-1].first.toString(10); + + if (PrevString == CurrString) + Diag(CaseVals[i].second->getLHS()->getLocStart(), + diag::err_duplicate_case) << + (PrevString.empty() ? CaseValStr : PrevString.str()); + else + Diag(CaseVals[i].second->getLHS()->getLocStart(), + diag::err_duplicate_case_differing_expr) << + (PrevString.empty() ? CaseValStr : PrevString.str()) << + (CurrString.empty() ? CaseValStr : CurrString.str()) << + CaseValStr; + Diag(CaseVals[i-1].second->getLHS()->getLocStart(), diag::note_duplicate_case_prev); // FIXME: We really want to remove the bogus case stmt from the diff --git a/test/Sema/switch.c b/test/Sema/switch.c index a7a7f60492..083ccb7390 100644 --- a/test/Sema/switch.c +++ b/test/Sema/switch.c @@ -9,7 +9,7 @@ void foo(int X) { switch (X) { case 42: ; // expected-note {{previous case}} case 5000000000LL: // expected-warning {{overflow}} - case 42: // expected-error {{duplicate case value}} + case 42: // expected-error {{duplicate case value '42'}} ; case 100 ... 99: ; // expected-warning {{empty case range}} @@ -320,3 +320,32 @@ void rdar110822110(Ints i) break; } } + +// PR9243 +#define TEST19MACRO 5 +void test19(int i) { + enum { + kTest19Enum1 = 7, + kTest19Enum2 = 7 + }; + const int a = 3; + switch (i) { + case 5: // expected-note {{previous case}} + case TEST19MACRO: // expected-error {{duplicate case value '5'}} + + case 7: // expected-note {{previous case}} + case kTest19Enum1: // expected-error {{duplicate case value: '7' and 'kTest19Enum1' both equal '7'}} \ + // expected-note {{previous case}} + case kTest19Enum1: // expected-error {{duplicate case value 'kTest19Enum1'}} \ + // expected-note {{previous case}} + case kTest19Enum2: // expected-error {{duplicate case value: 'kTest19Enum1' and 'kTest19Enum2' both equal '7'}} \ + // expected-note {{previous case}} + case (int)kTest19Enum2: //expected-error {{duplicate case value 'kTest19Enum2'}} + + case 3: // expected-note {{previous case}} + case a: // expected-error {{duplicate case value: '3' and 'a' both equal '3'}} \ + // expected-note {{previous case}} + case a: // expected-error {{duplicate case value 'a'}} + break; + } +} -- 2.40.0