diff --git a/docs/ReleaseNotes.html b/docs/ReleaseNotes.html
index 2a1e62f..1223dfb 100644
--- a/docs/ReleaseNotes.html
+++ b/docs/ReleaseNotes.html
@@ -89,7 +89,8 @@ Clang's support for those languages.</p>
 
 <p>New: <code>-Wdangling-else</code>, <code>-Wstrncat-size</code>, ...</p>
 
-<p>Improved: <code>-Wformat</code>, <code>-Wempty-body</code>, ...</p>
+<p>Improved: <code>-Wformat</code>, <code>-Wempty-body</code>,
+             <code>-Wtautological-compare</code>, ...</p>
 
 <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
 <h3 id="cchanges">C Language Changes in Clang</h3>
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index eded154..d02e844 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3645,11 +3645,8 @@ def err_stmtexpr_file_scope : Error<
 def warn_mixed_sign_comparison : Warning<
   "comparison of integers of different signs: %0 and %1">,
   InGroup<SignCompare>, DefaultIgnore;
-def warn_lunsigned_always_true_comparison : Warning<
-  "comparison of unsigned%select{| enum}2 expression %0 is always %1">,
-  InGroup<TautologicalCompare>;
-def warn_runsigned_always_true_comparison : Warning<
-  "comparison of %0 unsigned%select{| enum}2 expression is always %1">,
+def warn_always_true_comparison : Warning<
+  "comparison of %0 %1 %2 is always %select{false|true}3">,
   InGroup<TautologicalCompare>;
 def warn_comparison_of_mixed_enum_types : Warning<
   "comparison of two values with different enumeration types (%0 and %1)">,
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 3d9f5b3..61c205f 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -3664,7 +3664,7 @@ static bool IsSameFloatAfterCast(const APValue &value,
 
 static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
 
-static bool IsZero(Sema &S, Expr *E) {
+static bool IsIntegerConstant(llvm::APSInt &Value, Sema &S, Expr *E) {
   // Suppress cases where we are comparing against an enum constant.
   if (const DeclRefExpr *DR =
       dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
@@ -3675,42 +3675,57 @@ static bool IsZero(Sema &S, Expr *E) {
   if (E->getLocStart().isMacroID())
     return false;
 
-  llvm::APSInt Value;
-  return E->isIntegerConstantExpr(Value, S.Context) && Value == 0;
+  return E->EvaluateAsInt(Value, S.Context);
 }
 
-static bool HasEnumType(Expr *E) {
-  // Strip off implicit integral promotions.
-  while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
-    if (ICE->getCastKind() != CK_IntegralCast &&
-        ICE->getCastKind() != CK_NoOp)
-      break;
-    E = ICE->getSubExpr();
-  }
+static bool IsNegative(llvm::APSInt &Value, Sema &S, Expr *E) {
+  return IsIntegerConstant(Value, S, E)
+         && Value.isSigned() && Value.isNegative();
 
-  return E->getType()->isEnumeralType();
 }
 
-static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
-  BinaryOperatorKind op = E->getOpcode();
-  if (E->isValueDependent())
-    return;
+static bool IsZero(Sema &S, Expr *E) {
+  llvm::APSInt Value;
+  return IsIntegerConstant(Value, S, E) && Value == 0;
+}
 
-  if (op == BO_LT && IsZero(S, E->getRHS())) {
-    S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
-      << "< 0" << "false" << HasEnumType(E->getLHS())
+static void CheckTrivialComparison(Sema &S, BinaryOperator *E) {
+  BinaryOperatorKind Op = E->getOpcode();
+  const char *OpStr = E->getOpcodeStr();
+  Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
+  Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
+  bool IsLHSUnsigned = LHS->getType()->hasUnsignedIntegerRepresentation();
+  bool IsRHSUnsigned = RHS->getType()->hasUnsignedIntegerRepresentation();
+  if (E->isEqualityOp()) {
+     // We only care about signed equality comparisons, such as
+     // unsigned char == -1, where unsigned char is sign-extended.
+     if (!E->getLHS()->getType()->hasSignedIntegerRepresentation())
+       return;
+     llvm::APSInt Value;
+     if (IsLHSUnsigned && IsNegative(Value, S, RHS)) {
+       S.Diag(E->getOperatorLoc(), diag::warn_always_true_comparison)
+         << LHS->getType() << OpStr << Value.toString(10) << (Op == BO_NE)
+         << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+     } else if (IsNegative(Value, S, LHS) && IsRHSUnsigned) {
+       S.Diag(E->getOperatorLoc(), diag::warn_always_true_comparison)
+         << Value.toString(10) << OpStr << RHS->getType() << (Op == BO_NE)
+         << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+     }
+  } else if (Op == BO_LT && IsLHSUnsigned && IsZero(S, RHS)) {
+    S.Diag(E->getOperatorLoc(), diag::warn_always_true_comparison)
+      << LHS->getType() << OpStr << "0" << 0
       << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
-  } else if (op == BO_GE && IsZero(S, E->getRHS())) {
-    S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
-      << ">= 0" << "true" << HasEnumType(E->getLHS())
+  } else if (Op == BO_GE && IsLHSUnsigned && IsZero(S, RHS)) {
+    S.Diag(E->getOperatorLoc(), diag::warn_always_true_comparison)
+      << LHS->getType() << OpStr << "0" << 1
       << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
-  } else if (op == BO_GT && IsZero(S, E->getLHS())) {
-    S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
-      << "0 >" << "false" << HasEnumType(E->getRHS())
+  } else if (Op == BO_GT && IsZero(S, LHS) && IsRHSUnsigned) {
+    S.Diag(E->getOperatorLoc(), diag::warn_always_true_comparison)
+      << "0" << OpStr << RHS->getType() << 0
       << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
-  } else if (op == BO_LE && IsZero(S, E->getLHS())) {
-    S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
-      << "0 <=" << "true" << HasEnumType(E->getRHS())
+  } else if (Op == BO_LE && IsZero(S, LHS) && IsRHSUnsigned) {
+    S.Diag(E->getOperatorLoc(), diag::warn_always_true_comparison)
+      << "0" << OpStr << RHS->getType() << 1
       << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
   }
 }
@@ -3731,14 +3746,17 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
   assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
          && "comparison with mismatched types");
 
-  // We don't do anything special if this isn't an unsigned integral
-  // comparison:  we're only interested in integral comparisons, and
-  // signed comparisons only happen in cases we don't care to warn about.
-  //
-  // We also don't care about value-dependent expressions or expressions
+  // We don't care about value-dependent expressions or expressions
   // whose result is a constant.
-  if (!T->hasUnsignedIntegerRepresentation()
-      || E->isValueDependent() || E->isIntegerConstantExpr(S.Context))
+  if (E->isValueDependent() || E->isIntegerConstantExpr(S.Context))
+    return AnalyzeImpConvsInComparison(S, E);
+
+  // Fire -Wtautological-compare for trivial comparisons.
+  CheckTrivialComparison(S, E);
+
+  // Don't fire -Wsign-compare if this isn't an unsigned integral
+  // comparison.
+  if (!T->hasUnsignedIntegerRepresentation())
     return AnalyzeImpConvsInComparison(S, E);
 
   Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
@@ -3756,7 +3774,6 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
     signedOperand = RHS;
     unsignedOperand = LHS;
   } else {
-    CheckTrivialUnsignedComparison(S, E);
     return AnalyzeImpConvsInComparison(S, E);
   }
 
@@ -3768,11 +3785,9 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
   AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc());
   AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
 
-  // If the signed range is non-negative, -Wsign-compare won't fire,
-  // but we should still check for comparisons which are always true
-  // or false.
+  // If the signed range is non-negative, -Wsign-compare won't fire.
   if (signedRange.NonNegative)
-    return CheckTrivialUnsignedComparison(S, E);
+    return;
 
   // For (in)equality comparisons, if the unsigned operand is a
   // constant which cannot collide with a overflowed signed operand,
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 03aebb3..a2e601f 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -278,10 +278,23 @@ void test4() {
 
 // PR4807
 int test5(unsigned int x) {
-  return (x < 0) // expected-warning {{comparison of unsigned expression < 0 is always false}}
-    && (0 > x)   // expected-warning {{comparison of 0 > unsigned expression is always false}}
-    && (x >= 0)  // expected-warning {{comparison of unsigned expression >= 0 is always true}}
-    && (0 <= x); // expected-warning {{comparison of 0 <= unsigned expression is always true}}
+  return (x < 0) // expected-warning {{comparison of 'unsigned int' < 0 is always false}}
+    && (0 > x)   // expected-warning {{comparison of 0 > 'unsigned int' is always false}}
+    && (x >= 0)  // expected-warning {{comparison of 'unsigned int' >= 0 is always true}}
+    && (0 <= x); // expected-warning {{comparison of 0 <= 'unsigned int' is always true}}
+}
+
+int uchar(unsigned char x) {
+  return 42
+    + (x < 0)    // expected-warning {{comparison of 'unsigned char' < 0 is always false}}
+    + (0 > x)    // expected-warning {{comparison of 0 > 'unsigned char' is always false}}
+    + (x >= 0)   // expected-warning {{comparison of 'unsigned char' >= 0 is always true}}
+    + (0 <= x)   // expected-warning {{comparison of 0 <= 'unsigned char' is always true}}
+    + (x == -1)  // expected-warning {{comparison of 'unsigned char' == -1 is always false}}
+    + (-1 == x)  // expected-warning {{comparison of -1 == 'unsigned char' is always false}}
+    + (x != -1)  // expected-warning {{comparison of 'unsigned char' != -1 is always true}}
+    + (-1 != x)  // expected-warning {{comparison of -1 != 'unsigned char' is always true}}
+  ;
 }
 
 int test6(unsigned i, unsigned power) {
@@ -308,7 +321,7 @@ int rdar8414119_bar(unsigned x) {
 int rdar8511238() {
   enum A { A_foo, A_bar };
   enum A a;
-  if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+  if (a < 0) // expected-warning {{comparison of 'enum A' < 0 is always false}}
     return 0;
   return 20;
 }
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
index ceef274..3508d88 100644
--- a/test/SemaTemplate/instantiate-function-1.cpp
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -65,7 +65,7 @@ template<typename T, typename U, typename V> struct X6 {
     if (t > 0)
       return u;
     else { 
-      if (t < 0)
+      if (t < 0)  // expected-warning{{comparison of 'bool' < 0 is always false}}
         return v; // expected-error{{cannot initialize return object of type}}
     }
 
