------- Comment #8 from manu at gcc dot gnu dot org  2008-02-15 18:04 -------
This patch fixes this bug but it is an ugly hack. Perhaps such an ugly hack is
the only thing we can do at the moment.

Once bootstrapping + testing finishes, I will submit.

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


-- 

manu at gcc dot gnu dot org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Last reconfirmed|2007-12-13 21:38:26         |2008-02-15 18:04:44
               date|                            |


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34389

Reply via email to