diff options
author | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-10-04 03:02:19 +0000 |
---|---|---|
committer | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-10-04 03:02:19 +0000 |
commit | 8dd0dafee8cd2f161826d270bcae8d841ed4394d (patch) | |
tree | bad0acaaba7970ed145f998726734ce13187ad34 /gcc | |
parent | a64813cd3303033f6b33e25be09555057417440b (diff) | |
download | gcc-8dd0dafee8cd2f161826d270bcae8d841ed4394d.tar.gz |
PR 23445
* tree-vrp.c (extract_range_from_assert): If the new numeric
range created out of the assertion contradicts the existing
numeric range of the ASSERT_EXPR variable, make the new range
varying.
testsuite/
PR 23445
* gcc.c-torture/compile/pr23445.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@104936 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/pr23445.c | 10 | ||||
-rw-r--r-- | gcc/tree-vrp.c | 102 |
4 files changed, 106 insertions, 19 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9bdcb056f40..229ef27c46e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2005-10-03 Diego Novillo <dnovillo@redhat.com> + + PR 23445 + * tree-vrp.c (extract_range_from_assert): If the new numeric + range created out of the assertion contradicts the existing + numeric range of the ASSERT_EXPR variable, make the new range + varying. + 2005-10-03 Kaz Kojima <kkojima@gcc.gnu.org> * config/sh/sh.c (sh_register_move_cost): Add case for moving diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cf96bb514a0..6aa6e81b5e9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-10-03 Diego Novillo <dnovillo@redhat.com> + + PR 23445 + * gcc.c-torture/compile/pr23445.c: New test. + 2005-10-03 Alexandre Oliva <aoliva@redhat.com> * g++.dg/overload/unknown1.C: New. diff --git a/gcc/testsuite/gcc.c-torture/compile/pr23445.c b/gcc/testsuite/gcc.c-torture/compile/pr23445.c new file mode 100644 index 00000000000..3ddf9b702c7 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr23445.c @@ -0,0 +1,10 @@ + struct buffer_head { + char *b_data; + }; + void asfs_deletebnode( struct buffer_head *bhsec) { + if (bhsec == 0) { + void *bnc2 = (void *) bhsec->b_data; + if (bnc2) return; + if (bhsec) __brelse(bhsec); + } + } diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 7d7e0c9e9c3..e9d6c81c7d4 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -880,29 +880,93 @@ extract_range_from_assert (value_range_t *vr_p, tree expr) else gcc_unreachable (); - /* If VAR already had a known range and the two ranges have a - non-empty intersection, we can refine the resulting range. - Since the assert expression creates an equivalency and at the - same time it asserts a predicate, we can take the intersection of - the two ranges to get better precision. */ + /* If VAR already had a known range, it may happen that the new + range we have computed and VAR's range are not compatible. For + instance, + + if (p_5 == NULL) + p_6 = ASSERT_EXPR <p_5, p_5 == NULL>; + x_7 = p_6->fld; + p_8 = ASSERT_EXPR <p_6, p_6 != NULL>; + + While the above comes from a faulty program, it will cause an ICE + later because p_8 and p_6 will have incompatible ranges and at + the same time will be considered equivalent. A similar situation + would arise from + + if (i_5 > 10) + i_6 = ASSERT_EXPR <i_5, i_5 > 10>; + if (i_5 < 5) + i_7 = ASSERT_EXPR <i_6, i_6 < 5>; + + Again i_6 and i_7 will have incompatible ranges. It would be + pointless to try and do anything with i_7's range because + anything dominated by 'if (i_5 < 5)' will be optimized away. + Note, due to the wa in which simulation proceeds, the statement + i_7 = ASSERT_EXPR <...> we would never be visited because the + conditiona 'if (i_5 < 5)' always evaluates to false. However, + this extra check does not hurt and may protect against future + changes to VRP that may get into a situation similar to the + NULL pointer dereference example. + + Note that these compatibility tests are only needed when dealing + with ranges or a mix of range and anti-range. If VAR_VR and VR_P + are both anti-ranges, they will always be compatible, because two + anti-ranges will always have a non-empty intersection. */ + var_vr = get_value_range (var); - if (var_vr->type == VR_RANGE - && vr_p->type == VR_RANGE - && value_ranges_intersect_p (var_vr, vr_p)) + + /* We may need to make adjustments when VR_P and VAR_VR are numeric + ranges or anti-ranges. */ + if (vr_p->type == VR_VARYING + || vr_p->type == VR_UNDEFINED + || var_vr->type == VR_VARYING + || var_vr->type == VR_UNDEFINED + || symbolic_range_p (vr_p) + || symbolic_range_p (var_vr)) + return; + + if (var_vr->type == VR_RANGE && vr_p->type == VR_RANGE) { - /* Use the larger of the two minimums. */ - if (compare_values (vr_p->min, var_vr->min) == -1) - min = var_vr->min; - else - min = vr_p->min; + /* If the two ranges have a non-empty intersection, we can + refine the resulting range. Since the assert expression + creates an equivalency and at the same time it asserts a + predicate, we can take the intersection of the two ranges to + get better precision. */ + if (value_ranges_intersect_p (var_vr, vr_p)) + { + /* Use the larger of the two minimums. */ + if (compare_values (vr_p->min, var_vr->min) == -1) + min = var_vr->min; + else + min = vr_p->min; - /* Use the smaller of the two maximums. */ - if (compare_values (vr_p->max, var_vr->max) == 1) - max = var_vr->max; - else - max = vr_p->max; + /* Use the smaller of the two maximums. */ + if (compare_values (vr_p->max, var_vr->max) == 1) + max = var_vr->max; + else + max = vr_p->max; - set_value_range (vr_p, vr_p->type, min, max, vr_p->equiv); + set_value_range (vr_p, vr_p->type, min, max, vr_p->equiv); + } + else + { + /* The two ranges do not intersect, set the new range to + VARYING, because we will not be able to do anything + meaningful with it. */ + set_value_range_to_varying (vr_p); + } + } + else if ((var_vr->type == VR_RANGE && vr_p->type == VR_ANTI_RANGE) + || (var_vr->type == VR_ANTI_RANGE && vr_p->type == VR_RANGE)) + { + /* A range and an anti-range will cancel each other only if + their ends are the same. For instance, in the example above, + p_8's range ~[0, 0] and p_6's range [0, 0] are incompatible, + so VR_P should be set to VR_VARYING. */ + if (compare_values (var_vr->min, vr_p->min) == 0 + && compare_values (var_vr->max, vr_p->max) == 0) + set_value_range_to_varying (vr_p); } } |