Patchwork [C/C++] shift with negative or too big count warning (PR c/48418)

login
register
mail settings
Submitter Jakub Jelinek
Date Jan. 8, 2013, 8:04 p.m.
Message ID <20130108200403.GN7269@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/210489/
State New
Headers show

Comments

Jakub Jelinek - Jan. 8, 2013, 8:04 p.m.
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  <jakub@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.


	Jakub
Joseph S. Myers - Jan. 8, 2013, 10:32 p.m.
On Tue, 8 Jan 2013, Jakub Jelinek wrote:

> 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?

The C front-end changes are OK.  Properly diagnostic messages inside ? : 
conditionals should be marked up with G_() to ensure that both cases are 
extracted for translation, though in this case it doesn't matter much 
given that the message wording should stay identical to other copies of 
the same messages.
Jason Merrill - Jan. 9, 2013, 2:45 p.m.
The C++ change is OK.

Jason

Patch

--- 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;
+}