Produce more useful 'duplicate case' diagnostics. Fixes PR9243, from Terry Long!
authorDouglas Gregor <dgregor@apple.com>
Wed, 16 May 2012 05:32:58 +0000 (05:32 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 16 May 2012 05:32:58 +0000 (05:32 +0000)
llvm-svn: 156904

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaStmt.cpp
clang/test/Sema/switch.c

index 0865619..4356539 100644 (file)
@@ -5229,6 +5229,8 @@ def warn_case_value_overflow : Warning<
   "overflow converting case value to switch condition type (%0 to %1)">,
   InGroup<DiagGroup<"switch">>;
 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'">;
index 2ea07ef..295068c 100644 (file)
@@ -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<DeclRefExpr>(PrevCase)) {
+            PrevString = DeclRef->getDecl()->getName();
+          }
+          if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(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
index a7a7f60..083ccb7 100644 (file)
@@ -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;
+  }
+}