Hi! On the following testcase we ICE, because eltsize is 0 and when we int_const_binop (TRUNC_DIV_EXPR, maxbound, size_int (0)), that of course returns NULL. The upper bound for zero sized elements is just not meaningful, if we use any index we still won't reach maximum object size that way.
While looking at that, I've discovered a couple of other issues though. One is that the off subtraction seems misplaced. get_addr_base_and_unit_offset computes an offset in bytes, so it corresponds to the __PTRDIFF_MAX__ limit on object size (also in bytes), not to the __PTRDIFF_MAX__ limit divided by element size. So I believe we first want to subtract off (and only if it is positive, we do not want to enlarge the limit) from __PTRDIFF_MAX__ and then divide rather than what the code was doing before. Another thing is that the code has been mixing up types randomly, something being in ptrdiff_type_node, something in sizetype. And yet another thing is that even if we can't compute any sensible upper bound (e.g. the eltsize 0 case; I believe the VLA case just won't happen here, because we replace the VLAs with dereferences of a pointer I believe the ARRAY_REFs should have been transformed into POINTER_PLUS anyway), we can still warn about indexes smaller than low bound (especially if the low bound is not zero like in Fortran). The Warray-bounds.c testcase needed adjustment, because it was written with the same bad computation of the maximum - __PTRDIFF_MAX__ / sizeof (elt) - offset rather than (__PTRDIFF_MAX__ - offset) / sizeof (elt). Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2017-11-22 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/83044 * tree-vrp.c (vrp_prop::check_array_ref): If eltsize is not INTEGER_CST or is 0, clear up_bound{,_p1} and later ignore tests that need the upper bound. Subtract offset from get_addr_base_and_unit_offset only if positive and subtract it before division by eltsize rather than after it. * gcc.dg/pr83044.c: New test. * c-c++-common/Warray-bounds.c (fb): Fix up MAX value. --- gcc/tree-vrp.c.jj 2017-11-17 08:40:28.000000000 +0100 +++ gcc/tree-vrp.c 2017-11-21 14:13:47.184974061 +0100 @@ -4795,24 +4795,30 @@ vrp_prop::check_array_ref (location_t lo the size of the largest object is PTRDIFF_MAX. */ tree eltsize = array_ref_element_size (ref); - /* FIXME: Handle VLAs. */ - if (TREE_CODE (eltsize) != INTEGER_CST) - return; - - tree maxbound = TYPE_MAX_VALUE (ptrdiff_type_node); - - up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize); - - tree arg = TREE_OPERAND (ref, 0); - - HOST_WIDE_INT off; - if (get_addr_base_and_unit_offset (arg, &off)) - up_bound_p1 = wide_int_to_tree (sizetype, - wi::sub (wi::to_wide (up_bound_p1), - off)); - - up_bound = int_const_binop (MINUS_EXPR, up_bound_p1, - build_int_cst (ptrdiff_type_node, 1)); + if (TREE_CODE (eltsize) != INTEGER_CST + || integer_zerop (eltsize)) + { + up_bound = NULL_TREE; + up_bound_p1 = NULL_TREE; + } + else + { + tree maxbound = TYPE_MAX_VALUE (ptrdiff_type_node); + tree arg = TREE_OPERAND (ref, 0); + HOST_WIDE_INT off; + + if (get_addr_base_and_unit_offset (arg, &off) && off > 0) + maxbound = wide_int_to_tree (sizetype, + wi::sub (wi::to_wide (maxbound), + off)); + else + maxbound = fold_convert (sizetype, maxbound); + + up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize); + + up_bound = int_const_binop (MINUS_EXPR, up_bound_p1, + build_int_cst (ptrdiff_type_node, 1)); + } } else up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound, @@ -4823,7 +4829,7 @@ vrp_prop::check_array_ref (location_t lo tree artype = TREE_TYPE (TREE_OPERAND (ref, 0)); /* Empty array. */ - if (tree_int_cst_equal (low_bound, up_bound_p1)) + if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1)) { warning_at (location, OPT_Warray_bounds, "array subscript %E is above array bounds of %qT", @@ -4843,7 +4849,8 @@ vrp_prop::check_array_ref (location_t lo if (vr && vr->type == VR_ANTI_RANGE) { - if (TREE_CODE (up_sub) == INTEGER_CST + if (up_bound + && TREE_CODE (up_sub) == INTEGER_CST && (ignore_off_by_one ? tree_int_cst_lt (up_bound, up_sub) : tree_int_cst_le (up_bound, up_sub)) @@ -4856,7 +4863,8 @@ vrp_prop::check_array_ref (location_t lo TREE_NO_WARNING (ref) = 1; } } - else if (TREE_CODE (up_sub) == INTEGER_CST + else if (up_bound + && TREE_CODE (up_sub) == INTEGER_CST && (ignore_off_by_one ? !tree_int_cst_le (up_sub, up_bound_p1) : !tree_int_cst_le (up_sub, up_bound))) --- gcc/testsuite/gcc.dg/pr83044.c.jj 2017-11-21 14:15:29.221696588 +0100 +++ gcc/testsuite/gcc.dg/pr83044.c 2017-11-21 13:27:58.000000000 +0100 @@ -0,0 +1,14 @@ +/* PR tree-optimization/83044 */ +/* { dg-do compile } */ +/* { dg-options "-Wall -std=gnu89 -O2" } */ + +struct A { int b[0]; }; +struct B { struct A c[0]; }; +void bar (int *); + +void +foo (void) +{ + struct B d; + bar (d.c->b); +} --- gcc/testsuite/c-c++-common/Warray-bounds.c.jj 2017-11-17 08:40:32.000000000 +0100 +++ gcc/testsuite/c-c++-common/Warray-bounds.c 2017-11-22 11:30:29.047189568 +0100 @@ -200,7 +200,7 @@ void fb (struct B *p) T (p->a1x[9].a1[0]); - enum { MAX = DIFF_MAX / sizeof *p->a1x - sizeof *p }; + enum { MAX = (DIFF_MAX - sizeof *p) / sizeof *p->a1x }; T (p->a1x[DIFF_MIN].a1); /* { dg-warning "array subscript -\[0-9\]+ is below array bounds" } */ T (p->a1x[-1].a1); /* { dg-warning "array subscript -1 is below array bounds" } */ Jakub