Index: test/Sema/switch.c
===================================================================
--- test/Sema/switch.c	(revision 156821)
+++ test/Sema/switch.c	(working copy)
@@ -9,7 +9,7 @@
   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,33 @@
                         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' and 'TEST19MACRO' both equal '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'}}
+
+    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'}}
+
+    case 4: // expected-note {{previous case}}
+    case 2 + 2: // expected-error {{duplicate case value: '4' and '2 + 2' both equal '4'}}
+      break;
+  }
+}
Index: test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- test/SemaCXX/constant-expression-cxx11.cpp	(revision 156821)
+++ test/SemaCXX/constant-expression-cxx11.cpp	(working copy)
@@ -93,7 +93,7 @@
   void f(int n) {
     switch (n) {
     case MemberZero().zero: // expected-error {{did you mean to call it with no arguments?}} expected-note {{previous}}
-    case id(0): // expected-error {{duplicate case value '0'}}
+    case id(0): // expected-error {{duplicate case value}}
       return;
     }
   }
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 156821)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -5223,6 +5223,8 @@
   "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: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp	(revision 156821)
+++ lib/Sema/SemaStmt.cpp	(working copy)
@@ -768,8 +768,39 @@
 
         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, grab the textual representations of the case statements.
+          SourceManager &SrcMgr = getSourceManager();
+          SourceRange SrcRngPrev =
+                               CaseVals[i-1].second->getLHS()->getSourceRange();
+          SourceRange SrcRngCurr =
+                               CaseVals[i].second->getLHS()->getSourceRange();
+          SrcRngPrev.setEnd(
+                    getPreprocessor().getLocForEndOfToken(SrcRngPrev.getEnd()));
+          SrcRngCurr.setEnd(
+                    getPreprocessor().getLocForEndOfToken(SrcRngCurr.getEnd()));
+          if (SrcRngPrev.getBegin().isMacroID() ||
+              SrcRngPrev.getEnd().isMacroID())
+            SrcRngPrev.setBegin(SrcMgr.getExpansionLoc(SrcRngPrev.getBegin()));
+          if (SrcRngCurr.getBegin().isMacroID() ||
+              SrcRngCurr.getEnd().isMacroID())
+            SrcRngCurr.setBegin(SrcMgr.getExpansionLoc(SrcRngCurr.getBegin()));
+          const char *PrevBegin =
+                                SrcMgr.getCharacterData(SrcRngPrev.getBegin());
+          const char *PrevEnd = SrcMgr.getCharacterData(SrcRngPrev.getEnd());
+          const char *CurrBegin =
+                                SrcMgr.getCharacterData(SrcRngCurr.getBegin());
+          const char *CurrEnd = SrcMgr.getCharacterData(SrcRngCurr.getEnd());
+          StringRef PrevString(PrevBegin, PrevEnd - PrevBegin);
+          StringRef CurrString(CurrBegin, CurrEnd - CurrBegin);
+
+          if (PrevString == CurrString)
+            Diag(CaseVals[i].second->getLHS()->getLocStart(),
+                 diag::err_duplicate_case) << PrevString;
+          else
+            Diag(CaseVals[i].second->getLHS()->getLocStart(),
+                 diag::err_duplicate_case_differing_expr) <<
+                 PrevString << CurrString << CaseVals[i].first.toString(10);
+
           Diag(CaseVals[i-1].second->getLHS()->getLocStart(),
                diag::note_duplicate_case_prev);
           // FIXME: We really want to remove the bogus case stmt from the
