array-bounds: Fix up ICE on overaligned variables [PR99109]
authorJakub Jelinek <jakub@redhat.com>
Thu, 18 Feb 2021 08:45:19 +0000 (09:45 +0100)
committerJakub Jelinek <jakub@redhat.com>
Thu, 18 Feb 2021 08:45:19 +0000 (09:45 +0100)
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  <jakub@redhat.com>

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
gcc/testsuite/g++.dg/warn/Warray-bounds-17.C [new file with mode: 0644]

index 2576556f76ba2b13ab530e893752d4349f6c7568..d7fd2c741110945829c76cb90e8ccdf24e96ac94 100644 (file)
@@ -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 (file)
index 0000000..64fbd08
--- /dev/null
@@ -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);
+}