diff mbox

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

Message ID 20130108200403.GN7269@tucnak.redhat.com
State New
Headers show

Commit Message

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

Comments

Joseph Myers Jan. 8, 2013, 10:32 p.m. UTC | #1
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. UTC | #2
The C++ change is OK.

Jason
diff mbox

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