public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC] PR34389 -Wconversion produces wrong warning
@ 2008-02-16 17:00 Manuel López-Ibáñez
  2008-02-16 17:05 ` Richard Guenther
  0 siblings, 1 reply; 15+ messages in thread
From: Manuel López-Ibáñez @ 2008-02-16 17:00 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 917 bytes --]

The following patch  fixes PR 34389 in a ugly way, in my own opinion,
but I am not able to come up with any other way to fix this.

A more detailed analysis is in the PR. In summary the problem here is
that fold_unary converts (T)(x & c) into (T)x & (T)c which in this
case is (int) (x & 0x7fff) into ((int)x & 0x7fff). By using
get_unwidened, we could handle the first form. However, get_unwidened
won't handle the latter. Thus, when Wconversion sees that this
expression is assigned to a short, it concludes that there may be a
loss of precision.

Bootstrapped and regression tested in x86_64-unknown-linux-gnu. This
patch only affects Wconversion, which is new in 4.3.

Is this OK to commit? Any suggestions?

Cheers,

Manuel.

2008-02-16  Manuel Lopez-Ibanez  <manu@gcc.gnu.org>

 PR c/34389
 * c-common.c (conversion_warning): Handle '&' expressions correctly.

testsuite/
  * gcc.dg/Wconversion-pr34389.c: New.

[-- Attachment #2: fix-pr34389.diff --]
[-- Type: text/plain, Size: 5336 bytes --]

Index: gcc/testsuite/gcc.dg/Wconversion-pr34389.c
===================================================================
--- gcc/testsuite/gcc.dg/Wconversion-pr34389.c	(revision 0)
+++ gcc/testsuite/gcc.dg/Wconversion-pr34389.c	(revision 0)
@@ -0,0 +1,13 @@
+/* PR 34389 */
+/* { dg-do compile } */
+/* { dg-options "-Wall -Wextra -Wconversion -Wsign-conversion" } */
+short  mask1(short x)
+{
+  short y = 0x7fff;
+  return x & y;
+}
+
+short  mask2(short x)
+{
+  return x & 0x7fff;
+}
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c	(revision 132310)
+++ gcc/c-common.c	(working copy)
@@ -1270,65 +1270,98 @@ conversion_warning (tree type, tree expr
                  "conversion to %qT alters %qT constant value",
                  type, TREE_TYPE (expr));
     }
   else /* 'expr' is not a constant.  */
     {
+      tree expr_type = TREE_TYPE (expr);
+
       /* Warn for real types converted to integer types.  */
-      if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+      if (TREE_CODE (expr_type) == REAL_TYPE
           && TREE_CODE (type) == INTEGER_TYPE)
         give_warning = true;
 
-      else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+      else if (TREE_CODE (expr_type) == INTEGER_TYPE
                && TREE_CODE (type) == INTEGER_TYPE)
         {
 	  /* Don't warn about unsigned char y = 0xff, x = (int) y;  */
 	  expr = get_unwidened (expr, 0);
+	  expr_type = TREE_TYPE (expr);
 
+	  /* Don't warn for short y; short x = ((int)y & 0xff);  */
+	  if (TREE_CODE (expr) == BIT_AND_EXPR
+	      && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST)
+	    {
+	      int unsigned0, unsigned1;
+	      tree arg0, arg1;
+	      tree tmp_type;
+	      tree op0, op1;
+
+	      op0 = convert (expr_type, TREE_OPERAND (expr, 0));
+	      op1 = convert (expr_type, TREE_OPERAND (expr, 1));
+
+	      arg0 = get_narrower (op0, &unsigned0);
+	      arg1 = get_narrower (op1, &unsigned1);
+
+	      /* Handle the case that OP0 (or OP1) does not *contain* a conversion
+		 but it *requires* conversion to TYPE.  */
+	      if ((TYPE_PRECISION (TREE_TYPE (op0))
+		   == TYPE_PRECISION (TREE_TYPE (arg0)))
+		  && TREE_TYPE (op0) != expr_type)
+		unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0));
+	      
+	      if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (expr_type)
+		  && (tmp_type
+		      = c_common_signed_or_unsigned_type (unsigned0,
+							   TREE_TYPE (arg0)))
+		  && !POINTER_TYPE_P (tmp_type)
+		  && int_fits_type_p (arg1, tmp_type))
+		expr_type = tmp_type;
+	    }
           /* Warn for integer types converted to smaller integer types.  */
-          if (formal_prec < TYPE_PRECISION (TREE_TYPE (expr))) 
+          if (formal_prec < TYPE_PRECISION (expr_type)) 
 	    give_warning = true;
 
 	  /* When they are the same width but different signedness,
 	     then the value may change.  */
-	  else if ((formal_prec == TYPE_PRECISION (TREE_TYPE (expr))
-		    && TYPE_UNSIGNED (TREE_TYPE (expr)) != TYPE_UNSIGNED (type))
+	  else if ((formal_prec == TYPE_PRECISION (expr_type)
+		    && TYPE_UNSIGNED (expr_type) != TYPE_UNSIGNED (type))
 		   /* Even when converted to a bigger type, if the type is
 		      unsigned but expr is signed, then negative values
 		      will be changed.  */
-		   || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (TREE_TYPE (expr))))
+		   || (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (expr_type)))
 	    warning (OPT_Wsign_conversion,
 		     "conversion to %qT from %qT may change the sign of the result",
-		     type, TREE_TYPE (expr));
+		     type, expr_type);
         }
 
       /* Warn for integer types converted to real types if and only if
          all the range of values of the integer type cannot be
          represented by the real type.  */
-      else if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+      else if (TREE_CODE (expr_type) == INTEGER_TYPE
                && TREE_CODE (type) == REAL_TYPE)
         {
-          tree type_low_bound = TYPE_MIN_VALUE (TREE_TYPE (expr));
-          tree type_high_bound = TYPE_MAX_VALUE (TREE_TYPE (expr));
+          tree type_low_bound = TYPE_MIN_VALUE (expr_type);
+          tree type_high_bound = TYPE_MAX_VALUE (expr_type);
           REAL_VALUE_TYPE real_low_bound = real_value_from_int_cst (0, type_low_bound);
           REAL_VALUE_TYPE real_high_bound = real_value_from_int_cst (0, type_high_bound);
 
           if (!exact_real_truncate (TYPE_MODE (type), &real_low_bound)
               || !exact_real_truncate (TYPE_MODE (type), &real_high_bound))
             give_warning = true;
         }
 
       /* Warn for real types converted to smaller real types.  */
-      else if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+      else if (TREE_CODE (expr_type) == REAL_TYPE
                && TREE_CODE (type) == REAL_TYPE
-               && formal_prec < TYPE_PRECISION (TREE_TYPE (expr)))
+               && formal_prec < TYPE_PRECISION (expr_type))
         give_warning = true;
 
 
       if (give_warning)
         warning (OPT_Wconversion,
                  "conversion to %qT from %qT may alter its value",
-                 type, TREE_TYPE (expr));
+                 type, expr_type);
     }
 }
 
 /* Produce warnings after a conversion. RESULT is the result of
    converting EXPR to TYPE.  This is a helper function for

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2008-02-18 21:37 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-16 17:00 [RFC] PR34389 -Wconversion produces wrong warning Manuel López-Ibáñez
2008-02-16 17:05 ` Richard Guenther
2008-02-16 17:42   ` Manuel López-Ibáñez
2008-02-16 17:50     ` Richard Guenther
2008-02-16 18:31       ` Manuel López-Ibáñez
2008-02-16 18:53         ` Richard Guenther
2008-02-17 16:44           ` Manuel López-Ibáñez
2008-02-17 17:51             ` Richard Guenther
2008-02-18  1:21   ` Joseph S. Myers
2008-02-18 15:48     ` Manuel López-Ibáñez
2008-02-18 17:10       ` Manuel López-Ibáñez
2008-02-18 17:26         ` Richard Guenther
2008-02-18 20:40           ` Manuel López-Ibáñez
2008-02-18 21:37             ` Jakub Jelinek
2008-02-18 22:11               ` Manuel López-Ibáñez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).