From f72e3d8c9ffb81d25d4fdba10056cd2197e22d64 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 18 Feb 2021 09:45:19 +0100 Subject: [PATCH] array-bounds: Fix up ICE on overaligned variables [PR99109] 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. 2021-02-18 Jakub Jelinek PR middle-end/99109 * gimple-array-bounds.cc (build_zero_elt_array_type): Rename to ... (build_printable_array_type): ... this. Add nelts argument. For overaligned eltype, use TYPE_MAIN_VARIANT (eltype) instead. If nelts, call build_array_type_nelts. (array_bounds_checker::check_mem_ref): Use build_printable_array_type instead of build_zero_elt_array_type and build_array_type_nelts. * g++.dg/warn/Warray-bounds-17.C: New test. --- gcc/gimple-array-bounds.cc | 24 +++++++++++++------- gcc/testsuite/g++.dg/warn/Warray-bounds-17.C | 15 ++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Warray-bounds-17.C diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc index 2576556f76b..d7fd2c74111 100644 --- a/gcc/gimple-array-bounds.cc +++ b/gcc/gimple-array-bounds.cc @@ -372,12 +372,23 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, return warned; } -/* Hack around the internal representation constraints and build a zero - element array type that actually renders as T[0] in diagnostcs. */ +/* Wrapper around build_array_type_nelts that makes sure the array + can be created at all and handles zero sized arrays specially. */ static tree -build_zero_elt_array_type (tree eltype) +build_printable_array_type (tree eltype, unsigned HOST_WIDE_INT nelts) { + if (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) + eltype = TYPE_MAIN_VARIANT (eltype); + + if (nelts) + return build_array_type_nelts (eltype, nelts); + tree idxtype = build_range_type (sizetype, size_zero_node, NULL_TREE); tree arrtype = build_array_type (eltype, idxtype); arrtype = build_distinct_type_copy (TYPE_MAIN_VARIANT (arrtype)); @@ -561,10 +572,7 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref, return false; offset_int nelts = arrbounds[1] / eltsize; - if (nelts == 0) - reftype = build_zero_elt_array_type (reftype); - else - reftype = build_array_type_nelts (reftype, nelts.to_uhwi ()); + reftype = build_printable_array_type (reftype, nelts.to_uhwi ()); } else if (TREE_CODE (arg) == ADDR_EXPR) { @@ -675,7 +683,7 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref, /* 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); + reftype = build_printable_array_type (reftype, 1); /* Extract the element type out of MEM_REF and use its size to compute the index to print in the diagnostic; arrays diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-17.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-17.C new file mode 100644 index 00000000000..64fbd080123 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-17.C @@ -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); +} -- 2.30.2