This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[3.4 only] PR c/22589: ICE on casting to long long


This patch fixes a 3.4-only segfault on:

    int bar (char *foo)
    {
      return (long long) ((int) foo + 0) < 0;
    }

The segfault occurs in shorten_compare:

    primop0 = get_narrower (op0, &unsignedp0);
    ...
    type = c_common_signed_or_unsigned_type (unsignedp0,
                                             TREE_TYPE (primop0));
    ...
    maxval = TYPE_MAX_VALUE (type);
    minval = TYPE_MIN_VALUE (type);
    ...
    if (type != *restype_ptr)
      {
--->    minval = convert (*restype_ptr, minval);
        maxval = convert (*restype_ptr, maxval);
      }

op0 is:

    <NOP_EXPR "long long" <NOP_EXPR "int" foo>>

primop0 is foo, and type is "char *",  which has no min and max values.

The initial representation of "(int) foo" is:

    <CONVERT_EXPR "int" foo>

(as opposed to NOP_EXPR), but fold later converts:

    <PLUS_EXPR <CONVERT_EXPR "int" foo> 0>

into:

    <NOP_EXPR "int" foo>

This is relatively new behaviour and was introduced by:

2004-02-15  Roger Sayle  <roger@eyesopen.com>

	Backport from mainline:

	2004-02-07  Roger Sayle  <roger@eyesopen.com>
	PR middle-end/13696
	* fold-const.c (fold_convert): New function to provide type
	conversion to the middle-end without using convert.
	(negate_expr, associate_trees, size_diffop, omit_one_operand,
	operand_equal_for_comparison_p, pedantic_omit_one_operand,
	invert_truthvalue, optimize_bit_field_compare, range_binop,
	decode_field_reference, make_range, build_range_check, unextend,
	fold_truthop, extract_muldiv_1, fold_mathfn_compare,
	fold_binary_op_with_conditional_arg, fold_inf_compare,
	fold_single_bit_test, fold, multiple_of_p): Replace all calls to
	convert with calls to fold_convert.

Before this patch, fold() would return a CONVERT_EXPR instead.
The testcase therefore passes on 3.3 and earlier.

The segfault has been fixed in mainline by:

2004-07-08  Alexandre Oliva  <aoliva@redhat.com>

	Introduce H8SX support.
	....
	2004-06-16  Alexandre Oliva  <aoliva@redhat.com>
	* tree.c (get_narrower): Don't narrow integral types into
	non-integral types.

which was posted here:

    http://gcc.gnu.org/ml/gcc-patches/2004-06/msg01644.html

(I can't find any discussion about that part of the patch, but that
I think that's probably bad searching on my part, or perhaps a hole
in the archives.)

I don't know enough about trees to know (a) whether fold() is correct
in doing what it's doing and (b) whether Alex's patch is right.
(What exactly are the pre- and post- conditions for get_narrower?
Should shorten_compare() be more robust about handling non-integer
types?)

However, given that this bug is specific to a release branch, and
that the branch is deep into "maintenance only" mode, I think that
backporting the long-standing mainline patch is the best fix here.

Bootstrapped & regression tested on i686-pc-linux-gnu.  OK for 3.4?

Richard


	PR c/22589
	Backport from mainline:

	2004-06-16  Alexandre Oliva  <aoliva@redhat.com>
	* tree.c (get_narrower): Don't narrow integral types into
	non-integral types.

testsuite/
	PR c/22589
	* gcc.dg/pr22589.c: New test.

Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.342.2.5
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.342.2.5 tree.c
*** tree.c	23 Aug 2004 18:02:41 -0000	1.342.2.5
--- tree.c	27 Jul 2005 19:27:39 -0000
*************** get_narrower (tree op, int *unsignedp_pt
*** 4156,4161 ****
--- 4156,4162 ----
    int uns = 0;
    int first = 1;
    tree win = op;
+   bool integral_p = INTEGRAL_TYPE_P (TREE_TYPE (op));
  
    while (TREE_CODE (op) == NOP_EXPR)
      {
*************** get_narrower (tree op, int *unsignedp_pt
*** 4192,4197 ****
--- 4193,4202 ----
  	    uns = TREE_UNSIGNED (TREE_TYPE (op));
  	  first = 0;
  	  op = TREE_OPERAND (op, 0);
+ 	  /* Keep trying to narrow, but don't assign op to win if it
+ 	     would turn an integral type into something else.  */
+ 	  if (INTEGRAL_TYPE_P (TREE_TYPE (op)) != integral_p)
+ 	    continue;
  	}
  
        win = op;
diff -c /dev/null testsuite/gcc.dg/pr22589-1.c
*** /dev/null	2005-06-16 22:49:09.000000000 +0100
--- testsuite/gcc.dg/pr22589-1.c	2005-07-27 20:26:36.000000000 +0100
***************
*** 0 ****
--- 1,5 ----
+ /* { dg-options "" } */
+ int bar (char *foo)
+ {
+   return (long long) ((int) foo + 0) < 0;
+ }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]