Index: test/Sema/warn-duplicate-enum.c
===================================================================
--- test/Sema/warn-duplicate-enum.c	(revision 0)
+++ test/Sema/warn-duplicate-enum.c	(revision 0)
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wduplicate-enum
+// RUN: %clang_cc1 %s -x c++ -fsyntax-only -verify -Wduplicate-enum
+enum A {
+  A1 = 0,  // expected-note {{element A1 also has value 0}}
+  A2 = -1,
+  A3,  // expected-warning {{element A3 has been implicitly assigned 0 which another element has been assigned}}
+  A4};
+
+enum B {
+  B1 = -1,  // expected-note {{element B1 also has value -1}}
+  B2,       // expected-warning {{element B2 has been implicitly assigned 0 which another element has been assigned}}
+  B3,
+  B4 = -2,
+  B5,  // expected-warning {{element B5 has been implicitly assigned -1 which another element has been assigned}}
+  B6   // expected-note {{element B6 also has value 0}}
+};
+
+enum C { C1, C2 = -1, C3 }; // expected-warning{{element C1 has been implicitly assigned 0 which another element has been assigned}} \
+  // expected-note {{element C3 also has value 0}}
+
+enum D {
+  D1,
+  D2,
+  D3,  // expected-warning{{element D3 has been implicitly assigned 2 which another element has been assigned}}
+  D4 = D2,  // no warning
+  D5 = 2  // expected-note {{element D5 also has value 2}}
+};
+
+enum E {
+  E1,
+  E2 = E1,
+  E3 = E2
+};
+
+enum F {
+  F1,
+  F2,
+  FCount,
+  FMax = FCount - 1
+};
+
+enum G {
+  G1,
+  G2,
+  GMax = G2,
+  GCount = GMax + 1
+};
+
+enum {
+  H1 = 0,
+  H2 = -1,
+  H3,
+  H4};
+
+enum {
+  I1 = -1,
+  I2,
+  I3,
+  I4 = -2,
+  I5,
+  I6
+};
+
+enum { J1, J2 = -1, J3 };
+
+enum { 
+  K1, 
+  K2, 
+  K3,
+  K4 = K2,
+  K5 = 2
+};
+
+enum {
+  L1,
+  L2 = L1,
+  L3 = L2
+};
+
+enum {
+  M1,
+  M2,
+  MCount,
+  MMax = MCount - 1
+};
+
+enum {
+  N1,
+  N2,
+  NMax = N2,
+  NCount = NMax + 1
+};
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 160463)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -26,6 +26,10 @@
 def note_identical_enum_values : Note<
   "initialize the last element with the previous element to silence "
   "this warning">;
+def warn_duplicate_enum_values : Warning<
+  "element %0 has been implicitly assigned %1 which another element has "
+  "been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore;
+def note_duplicate_element : Note<"element %0 also has value %1">;
 
 // Constant expressions
 def err_expr_not_ice : Error<
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 160463)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -10485,6 +10485,147 @@
                                     Next->getName());
 }
 
+// Sort by value, then put the elements without initializers first.
+bool CompEnumConstantDecl(EnumConstantDecl* Constant1,
+                          EnumConstantDecl* Constant2) {
+  const llvm::APSInt &Val1 = Constant1->getInitVal(),
+                     &Val2 = Constant2->getInitVal();
+
+  int64_t Value1 = Val1.isSigned() ? Val1.getSExtValue() : Val1.getZExtValue(),
+          Value2 = Val2.isSigned() ? Val2.getSExtValue() : Val2.getZExtValue();
+
+  if (Value1 != Value2)
+    return Value1 < Value2;
+
+  bool HasInitExpr1 = Constant1->getInitExpr(),
+       HasInitExpr2 = Constant2->getInitExpr();
+
+  if (HasInitExpr1 != HasInitExpr2)
+    return HasInitExpr2;
+
+  return false;
+}
+
+// Returns true when the enum initial expression does not trigger the
+// duplicate enum warning.  A few common cases are exempted as follows:
+// Element2 = Elememt1
+// Element2 = Element1 + 1
+// Element2 = Element1 - 1
+// Where Element2 and Element1 are from the same enum.
+static bool ValidDuplicateEnum(EnumConstantDecl *ECD, EnumDecl *Enum) {
+  Expr *InitExpr = ECD->getInitExpr();
+  if (!InitExpr)
+    return true;
+  InitExpr = InitExpr->IgnoreImpCasts();
+
+  if (BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr)) {
+    if (!BO->isAdditiveOp())
+      return true;
+    IntegerLiteral *IL = dyn_cast<IntegerLiteral>(BO->getRHS());
+    if (!IL)
+      return true;
+    if (IL->getValue() != 1)
+      return true;
+
+    InitExpr = BO->getLHS();
+  }
+
+  // This checks if the elements are from the same enum.
+  DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InitExpr);
+  if (!DRE)
+    return true;
+
+  EnumConstantDecl *EnumConstant = dyn_cast<EnumConstantDecl>(DRE->getDecl());
+  if (!EnumConstant)
+    return true;
+
+  if (cast<EnumDecl>(TagDecl::castFromDeclContext(ECD->getDeclContext())) !=
+      Enum)
+    return true;
+
+  return false;
+}
+
+// Emits a warning when an element is implicitly set a value that
+// a previous element has already been set to.
+static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements,
+                                        unsigned NumElements, EnumDecl *Enum,
+                                        QualType EnumType) {
+  if (S.Diags.getDiagnosticLevel(diag::warn_duplicate_enum_values,
+                                 Enum->getLocation()) ==
+      DiagnosticsEngine::Ignored)
+    return;
+
+  // Avoid anonymous enums
+  if (!Enum->getIdentifier())
+    return;
+
+  // Only check for small enums.
+  if (Enum->getNumPositiveBits() > 63 || Enum->getNumNegativeBits() > 64)
+    return;
+
+  llvm::SmallVector<EnumConstantDecl*, 10> ElementsVector(NumElements);
+
+  for (unsigned i = 0; i < NumElements; ++i) {
+    EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]);
+    if (!ECD)
+      return;
+
+    ElementsVector[i] = ECD;
+  }
+  std::stable_sort(ElementsVector.begin(), ElementsVector.end(),
+                   CompEnumConstantDecl);
+
+  for (llvm::SmallVector<EnumConstantDecl*, 10>::iterator
+           I = ElementsVector.begin(), E = ElementsVector.end();
+       I != E; ++I) {
+    // No more elements to be a duplicate of.
+    if ((I + 1) == E)
+      break;
+
+    // Only use if no value is given.
+    if ((*I)->getInitExpr())
+      continue;
+
+    llvm::APSInt Value = (*I)->getInitVal();
+
+    // Find the first duplicate enum.
+    llvm::SmallVector<EnumConstantDecl*, 10>::iterator Iter = I + 1;
+    for (; Iter != E && llvm::APSInt::isSameValue(Value, (*Iter)->getInitVal());
+         ++Iter) {
+      if (ValidDuplicateEnum(*Iter, Enum))
+        break;
+    }
+
+    if (Iter == E)
+      break;
+
+    if (!llvm::APSInt::isSameValue(Value, (*Iter)->getInitVal())) {
+      I = Iter - 1;
+      continue;
+    }
+
+    // Emit diagnostic for first element.
+    S.Diag((*I)->getLocation(), diag::warn_duplicate_enum_values)
+      << (*I)->getName() << Value.toString(10)
+      << (*I)->getSourceRange();
+
+    // Emit note for every other duplicate value enum.
+    for (; Iter != E && llvm::APSInt::isSameValue(Value, (*Iter)->getInitVal());
+         ++Iter) {
+      if (ValidDuplicateEnum(*Iter, Enum))
+        S.Diag((*Iter)->getLocation(), diag::note_duplicate_element)
+          << (*Iter)->getName() << Value.toString(10)
+          << (*Iter)->getSourceRange();
+    }
+    if (Iter == E)
+      break;
+
+    // After loop increment, I will be Iter.
+    I = Iter - 1;
+  }
+}
+
 void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
                          SourceLocation RBraceLoc, Decl *EnumDeclX,
                          Decl **Elements, unsigned NumElements,
@@ -10709,6 +10850,7 @@
     DeclsInPrototypeScope.push_back(Enum);
 
   CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType);
+  CheckForDuplicateEnumValues(*this, Elements, NumElements, Enum, EnumType);
 }
 
 Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
