This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[3.4 only] PR c/22589: ICE on casting to long long
- From: Richard Sandiford <richard at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: gdr at integrable-solutions dot net
- Date: Wed, 27 Jul 2005 21:01:18 +0100
- Subject: [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;
+ }