Hi!

As discussed in the PR, on the following testcase we've regressed with the
introduction of c_fully_fold, when the C FE normally warns the argument
isn't folded yet.  Fixed by also warning in c_fully_fold_internal, if before
that function the shift count wasn't INTEGER_CST and after it it is.

The testcase also revealed a regression on the C++ FE side, caused by
SIZEOF_EXPR folding deferral.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2013-01-08  Jakub Jelinek  <ja...@redhat.com>

        PR c/48418
        * c-common.c (c_fully_fold_internal): Warn for LSHIFT_EXPR and
        RSHIFT_EXPR, if orig_op1 isn't INTEGER_CST, op1 is INTEGER_CST
        and is either negative or bigger or equal to type precision
        of the first operand.

        * typeck.c (cp_build_binary_op): For LSHIFT_EXPR and RSHIFT_EXPR,
        call maybe_constant_value for the negative or too big shift
        count warnings.

        * c-c++-common/pr48418.c: New test.

--- gcc/c-family/c-common.c.jj  2012-12-31 15:05:45.000000000 +0100
+++ gcc/c-family/c-common.c     2013-01-08 15:15:47.019347593 +0100
@@ -1269,6 +1269,25 @@ c_fully_fold_internal (tree expr, bool i
          && !TREE_OVERFLOW_P (op0)
          && !TREE_OVERFLOW_P (op1))
        overflow_warning (EXPR_LOCATION (expr), ret);
+      if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR)
+         && TREE_CODE (orig_op1) != INTEGER_CST
+         && TREE_CODE (op1) == INTEGER_CST
+         && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+             || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE)
+         && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE
+         && c_inhibit_evaluation_warnings == 0)
+       {
+         if (tree_int_cst_sgn (op1) < 0)
+           warning_at (loc, 0, (code == LSHIFT_EXPR
+                                ? "left shift count is negative"
+                                : "right shift count is negative"));
+         else if (compare_tree_int (op1,
+                                    TYPE_PRECISION (TREE_TYPE (orig_op0)))
+                  >= 0)
+           warning_at (loc, 0, (code == LSHIFT_EXPR
+                                ? "left shift count >= width of type"
+                                : "right shift count >= width of type"));
+       }
       goto out;
 
     case INDIRECT_REF:
--- gcc/cp/typeck.c.jj  2013-01-07 14:14:44.000000000 +0100
+++ gcc/cp/typeck.c     2013-01-08 15:30:20.202388635 +0100
@@ -4095,10 +4095,13 @@ cp_build_binary_op (location_t location,
        }
       else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
+         tree const_op1 = maybe_constant_value (op1);
+         if (TREE_CODE (const_op1) != INTEGER_CST)
+           const_op1 = op1;
          result_type = type0;
-         if (TREE_CODE (op1) == INTEGER_CST)
+         if (TREE_CODE (const_op1) == INTEGER_CST)
            {
-             if (tree_int_cst_lt (op1, integer_zero_node))
+             if (tree_int_cst_lt (const_op1, integer_zero_node))
                {
                  if ((complain & tf_warning)
                      && c_inhibit_evaluation_warnings == 0)
@@ -4106,7 +4109,7 @@ cp_build_binary_op (location_t location,
                }
              else
                {
-                 if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0
+                 if (compare_tree_int (const_op1, TYPE_PRECISION (type0)) >= 0
                      && (complain & tf_warning)
                      && c_inhibit_evaluation_warnings == 0)
                    warning (0, "right shift count >= width of type");
@@ -4138,16 +4141,20 @@ cp_build_binary_op (location_t location,
        }
       else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
+         tree const_op1 = maybe_constant_value (op1);
+         if (TREE_CODE (const_op1) != INTEGER_CST)
+           const_op1 = op1;
          result_type = type0;
-         if (TREE_CODE (op1) == INTEGER_CST)
+         if (TREE_CODE (const_op1) == INTEGER_CST)
            {
-             if (tree_int_cst_lt (op1, integer_zero_node))
+             if (tree_int_cst_lt (const_op1, integer_zero_node))
                {
                  if ((complain & tf_warning)
                      && c_inhibit_evaluation_warnings == 0)
                    warning (0, "left shift count is negative");
                }
-             else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
+             else if (compare_tree_int (const_op1,
+                                        TYPE_PRECISION (type0)) >= 0)
                {
                  if ((complain & tf_warning)
                      && c_inhibit_evaluation_warnings == 0)
--- gcc/testsuite/c-c++-common/pr48418.c.jj     2013-01-08 15:25:36.501003969 
+0100
+++ gcc/testsuite/c-c++-common/pr48418.c        2013-01-08 15:21:54.000000000 
+0100
@@ -0,0 +1,20 @@
+/* PR c/48418 */
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2" } */
+
+int
+foo (int x)
+{
+  const int a = sizeof (int) * __CHAR_BIT__;
+  const int b = -7;
+  int c = 0;
+  c += x << a;                            /* { dg-warning "left shift count >= 
width of type" } */
+  c += x << b;                            /* { dg-warning "left shift count is 
negative" } */
+  c += x << (sizeof (int) * __CHAR_BIT__); /* { dg-warning "left shift count 
>= width of type" } */
+  c += x << -7;                                   /* { dg-warning "left shift 
count is negative" } */
+  c += x >> a;                            /* { dg-warning "right shift count 
>= width of type" } */
+  c += x >> b;                            /* { dg-warning "right shift count 
is negative" } */
+  c += x >> (sizeof (int) * __CHAR_BIT__); /* { dg-warning "right shift count 
>= width of type" } */
+  c += x >> -7;                                   /* { dg-warning "right shift 
count is negative" } */
+  return c;
+}

        Jakub

Reply via email to