Hi! check_mem_ref builds artificial arrays for variables that don't have array type. The C standard says: "For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type." so it isn't completely wrong and does simplify the function. But, layout_type can fail if the size of the element type is not a multiple of its alignment (i.e. overaligned types) and we then ICE because of that.
The following patch uses TYPE_MAIN_VARIANT in those cases instead, but only for the types that need it, as for the diagnostics it is better to use the typedef names etc. that were really used in the source if possible. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2021-02-17 Jakub Jelinek <ja...@redhat.com> PR middle-end/99109 * gimple-array-bounds.cc (overaligned_type_p): New function. (array_bounds_checker::check_mem_ref): For overaligned types use TYPE_MAIN_VARIANT of reftype as element type of a new array. * g++.dg/warn/Warray-bounds-17.C: New test. --- gcc/gimple-array-bounds.cc.jj 2021-01-04 10:25:37.471249246 +0100 +++ gcc/gimple-array-bounds.cc 2021-02-16 17:00:41.961750114 +0100 @@ -386,6 +386,21 @@ build_zero_elt_array_type (tree eltype) return arrtype; } +/* Return true if it is not possible to build an array with element type + ELTYPE, because either ELTYPE has alignment larger than its size + or its size is not a multiple of its alignment. */ + +static bool +overaligned_type_p (tree eltype) +{ + return (TYPE_SIZE_UNIT (eltype) + && TREE_CODE (TYPE_SIZE_UNIT (eltype)) == INTEGER_CST + && !integer_zerop (TYPE_SIZE_UNIT (eltype)) + && TYPE_ALIGN_UNIT (eltype) > 1 + && wi::zext (wi::to_wide (TYPE_SIZE_UNIT (eltype)), + ffs_hwi (TYPE_ALIGN_UNIT (eltype)) - 1) != 0); +} + /* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds references to string constants. If VRP can determine that the array subscript is a constant, check if it is outside valid range. @@ -553,6 +568,8 @@ array_bounds_checker::check_mem_ref (loc reftype = TREE_TYPE (TREE_TYPE (arg)); if (TREE_CODE (reftype) == ARRAY_TYPE) reftype = TREE_TYPE (reftype); + else if (overaligned_type_p (reftype)) + reftype = TYPE_MAIN_VARIANT (reftype); if (tree refsize = TYPE_SIZE_UNIT (reftype)) if (TREE_CODE (refsize) == INTEGER_CST) eltsize = wi::to_offset (refsize); @@ -675,7 +692,11 @@ array_bounds_checker::check_mem_ref (loc /* Treat a reference to a non-array object as one to an array of a single element. */ if (TREE_CODE (reftype) != ARRAY_TYPE) - reftype = build_array_type_nelts (reftype, 1); + { + if (overaligned_type_p (reftype)) + reftype = TYPE_MAIN_VARIANT (reftype); + reftype = build_array_type_nelts (reftype, 1); + } /* Extract the element type out of MEM_REF and use its size to compute the index to print in the diagnostic; arrays --- gcc/testsuite/g++.dg/warn/Warray-bounds-17.C.jj 2021-02-16 17:24:14.178813304 +0100 +++ gcc/testsuite/g++.dg/warn/Warray-bounds-17.C 2021-02-16 17:23:35.305251062 +0100 @@ -0,0 +1,15 @@ +// PR middle-end/99109 +// { dg-do compile } +// { dg-options "-O2 -Warray-bounds" } + +typedef int A __attribute__((aligned (64))); +void foo (int *); + +void +bar (void) +{ + A b; // { dg-message "while referencing" } + int *p = &b; + int *x = (p - 1); // { dg-warning "outside array bounds" } + foo (x); +} Jakub