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,165 @@
                                     Next->getName());
 }
 
+// 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;
+}
+
+static int64_t GetInt64(const llvm::APSInt& Val) {
+  return  Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue();
+}
+
+struct DenseMapInfoint64_t {
+  static int64_t getEmptyKey() { return 0; }
+  static int64_t getTombstoneKey() { return 1; }
+  static unsigned getHashValue(const int64_t Val) {
+    return (unsigned)(Val * 37);
+  }
+  static bool isEqual(const int64_t& LHS, const int64_t& RHS) {
+    return LHS == RHS;
+  }
+};
+
+// 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;
+
+  typedef llvm::SmallVector<EnumConstantDecl*, 4> SameValueVector;
+  typedef llvm::DenseMap<int64_t, SameValueVector*> ValueToVectorMap;
+  typedef llvm::SmallVector<SameValueVector*, 10> DoubleVector;
+  ValueToVectorMap EnumMap;
+  DoubleVector EnumVector;
+  SameValueVector *ZeroVector = 0, *OneVector = 0;
+
+  for (unsigned i = 0; i < NumElements; ++i) {
+    EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]);
+    if (!ECD) {
+      for (DoubleVector::iterator I = EnumVector.begin(), E = EnumVector.end();
+           I != E; ++I)
+        delete *I;
+      return;
+    }
+
+    if (ECD->getInitExpr())
+      continue;
+
+    int64_t Val = GetInt64(ECD->getInitVal());
+
+    if (Val == 0) {
+      if (ZeroVector) continue;
+      ZeroVector = new SameValueVector();
+      ZeroVector->push_back(ECD);
+      EnumVector.push_back(ZeroVector);
+    } else if (Val == 1) {
+      if (OneVector) continue;
+      OneVector = new SameValueVector();
+      OneVector->push_back(ECD);
+      EnumVector.push_back(OneVector);
+    } else {
+      if (EnumMap.find(Val) != EnumMap.end())
+        continue;
+      SameValueVector *ValueVector = new SameValueVector();
+      ValueVector->push_back(ECD);
+      EnumVector.push_back(ValueVector);
+      EnumMap.insert(std::make_pair(Val, ValueVector));
+    }
+  }
+
+  for (unsigned i = 0; i < NumElements; ++i) {
+    EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]);
+    if (!ValidDuplicateEnum(ECD, Enum))
+      continue;
+
+    int64_t Val = GetInt64(ECD->getInitVal());
+
+    if (Val == 0) {
+      if (!ZeroVector || *ZeroVector->begin() == ECD)
+        continue;
+      ZeroVector->push_back(ECD);
+    } else if (Val == 1) {
+      if (!OneVector || *OneVector->begin() == ECD)
+        continue;
+      OneVector->push_back(ECD);
+    } else {
+      ValueToVectorMap::iterator I = EnumMap.find(Val);
+      if (I == EnumMap.end())
+        continue;
+      SameValueVector *V = I->second;
+      if (*V->begin() == ECD)
+        continue;
+      V->push_back(ECD);
+    }
+  }
+
+  for (DoubleVector::iterator DoubleVectorIter = EnumVector.begin(),
+                              DoubleVectorEnd = EnumVector.end();
+       DoubleVectorIter != DoubleVectorEnd; ++DoubleVectorIter) {
+    SameValueVector *V = *DoubleVectorIter;
+    if (V->size() == 1)
+      continue;
+
+    SameValueVector::iterator I = V->begin();
+    S.Diag((*I)->getLocation(), diag::warn_duplicate_enum_values)
+      << (*I)->getName() << (*I)->getInitVal().toString(10)
+      << (*I)->getSourceRange();
+    ++I;
+    for (SameValueVector::iterator E = V->end(); I != E; ++I)
+      S.Diag((*I)->getLocation(), diag::note_duplicate_element)
+        << (*I)->getName() << (*I)->getInitVal().toString(10)
+        << (*I)->getSourceRange();
+    delete V;
+  }
+}
+
 void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
                          SourceLocation RBraceLoc, Decl *EnumDeclX,
                          Decl **Elements, unsigned NumElements,
@@ -10709,6 +10868,7 @@
     DeclsInPrototypeScope.push_back(Enum);
 
   CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType);
+  CheckForDuplicateEnumValues(*this, Elements, NumElements, Enum, EnumType);
 }
 
 Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
