Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 186957)
+++ gcc/c-family/c-common.c	(working copy)
@@ -3479,10 +3479,16 @@ binary_op_error (location_t location, en
   error_at (location,
 	    "invalid operands to binary %s (have %qT and %qT)", opname,
 	    type0, type1);
 }
 
+static tree expr_original_type (tree expr)
+{
+  STRIP_NOPS (expr);
+  return TREE_TYPE (expr);
+}
+
 /* Subroutine of build_binary_op, used for comparison operations.
    See if the operands have both been converted from subword integer types
    and, if so, perhaps change them both back to their original type.
    This function is also responsible for converting the two operands
    to the proper common type for comparison.
@@ -3504,10 +3510,11 @@ shorten_compare (tree *op0_ptr, tree *op
   tree op1 = *op1_ptr;
   int unsignedp0, unsignedp1;
   int real1, real2;
   tree primop0, primop1;
   enum tree_code code = *rescode_ptr;
+  location_t loc = EXPR_LOC_OR_HERE (op0);
 
   /* Throw away any conversions to wider types
      already present in the operands.  */
 
   primop0 = c_common_get_narrower (op0, &unsignedp0);
@@ -3724,13 +3731,15 @@ shorten_compare (tree *op0_ptr, tree *op
 	}
 
       if (TREE_CODE (primop0) != INTEGER_CST)
 	{
 	  if (val == truthvalue_false_node)
-	    warning (OPT_Wtype_limits, "comparison is always false due to limited range of data type");
+	    warning_at (loc, OPT_Wtype_limits,
+			"comparison is always false due to limited range of data type");
 	  if (val == truthvalue_true_node)
-	    warning (OPT_Wtype_limits, "comparison is always true due to limited range of data type");
+	    warning_at (loc, OPT_Wtype_limits,
+			"comparison is always true due to limited range of data type");
 	}
 
       if (val != 0)
 	{
 	  /* Don't forget to evaluate PRIMOP0 if it has side effects.  */
@@ -3793,33 +3802,35 @@ shorten_compare (tree *op0_ptr, tree *op
 
       if (!real1 && !real2 && integer_zerop (primop1)
 	  && TYPE_UNSIGNED (*restype_ptr))
 	{
 	  tree value = 0;
+	  /* All unsigned values are >= 0, so we warn.  However,
+	     if OP0 is a constant that is >= 0, the signedness of
+	     the comparison isn't an issue, so suppress the
+	     warning.  */
+	  bool warn = 
+	    warn_type_limits && !in_system_header
+	    && !(TREE_CODE (primop0) == INTEGER_CST
+		 && !TREE_OVERFLOW (convert (c_common_signed_type (type),
+					     primop0)))
+	    /* Do not warn for enumeration types.  */
+	    && (TREE_CODE (expr_original_type (primop0)) != ENUMERAL_TYPE);
+	  
 	  switch (code)
 	    {
 	    case GE_EXPR:
-	      /* All unsigned values are >= 0, so we warn.  However,
-		 if OP0 is a constant that is >= 0, the signedness of
-		 the comparison isn't an issue, so suppress the
-		 warning.  */
-	      if (warn_type_limits && !in_system_header
-		  && !(TREE_CODE (primop0) == INTEGER_CST
-		       && !TREE_OVERFLOW (convert (c_common_signed_type (type),
-						   primop0))))
-		warning (OPT_Wtype_limits,
-			 "comparison of unsigned expression >= 0 is always true");
+	      if (warn)
+		warning_at (loc, OPT_Wtype_limits,
+			    "comparison of unsigned expression >= 0 is always true");
 	      value = truthvalue_true_node;
 	      break;
 
 	    case LT_EXPR:
-	      if (warn_type_limits && !in_system_header
-		  && !(TREE_CODE (primop0) == INTEGER_CST
-		       && !TREE_OVERFLOW (convert (c_common_signed_type (type),
-						   primop0))))
-		warning (OPT_Wtype_limits,
-			 "comparison of unsigned expression < 0 is always false");
+	      if (warn)
+		warning_at (loc, OPT_Wtype_limits,
+			    "comparison of unsigned expression < 0 is always false");
 	      value = truthvalue_false_node;
 	      break;
 
 	    default:
 	      break;
Index: gcc/testsuite/c-c++-common/pr51712.c
===================================================================
--- gcc/testsuite/c-c++-common/pr51712.c	(revision 0)
+++ gcc/testsuite/c-c++-common/pr51712.c	(revision 0)
@@ -0,0 +1,18 @@
+/* PR c/51712 */
+/* { dg-do compile } */
+/* { dg-options "-Wtype-limits" } */
+
+enum test_enum {
+  FOO,
+  BAR
+};
+
+int valid(enum test_enum arg)
+{
+  return arg >= 0 && arg <= BAR;
+}
+
+int valid2(unsigned int arg2)
+{
+  return arg2 >= FOO && arg2 <= BAR; /* { dg-bogus "comparison of unsigned expression" "" { xfail *-*-* } } */
+}
