On 2/17/21 6:56 AM, Jakub Jelinek wrote:
On Tue, Feb 16, 2021 at 08:34:41PM -0700, Martin Sebor via Gcc-patches wrote:
+         if (integer_all_onesp (nelts))
+           /* Zero length array.  */
+           eltsize = 0;
+         else
            {
-             tree bnds[] = { TYPE_MIN_VALUE (dom), TYPE_MAX_VALUE (dom) };
-             if (TREE_CODE (arg) == COMPONENT_REF)
-               {
-                 offset_int size = maxobjsize;
-                 if (tree fldsize = component_ref_size (arg))
-                   size = wi::to_offset (fldsize);
-                 arrbounds[1] = wi::lrshift (size, eltsizelog2);
-               }
-             else if (array_at_struct_end_p (arg) || !bnds[0] || !bnds[1])
-               arrbounds[1] = wi::lrshift (maxobjsize, eltsizelog2);
-             else
-               arrbounds[1] = (wi::to_offset (bnds[1]) - wi::to_offset 
(bnds[0])
-                               + 1) * eltsize;
+             tree esz = TYPE_SIZE_UNIT (TREE_TYPE (reftype));
+             if (TREE_CODE (esz) == INTEGER_CST)
+               /* Array element is not a VLA.  */
+               eltsize = wi::to_offset (esz);
            }
+
+         if (!array_at_struct_end_p (arg)
+             && TREE_CODE (nelts) == INTEGER_CST)
+           arrbounds[1] = (wi::to_offset (nelts) + 1) * eltsize;
          else
-           arrbounds[1] = wi::lrshift (maxobjsize, eltsizelog2);
+           {
+             /* Use log2 of size to convert the array byte size in to its
+                upper bound in elements.  */
+             const offset_int eltsizelog2 = wi::floor_log2 (eltsize);
+             arrbounds[1] = wi::lrshift (maxobjsize, eltsizelog2);

So, what will this do for zero length arrays at the end of struct?
eltsize will be 0 and wi::floor_log2 (eltsize) is -1, and shifting by -1,
while maybe not UB in wide_int computations, is certainly just weird.
Why do you use eltsize = 0 for the [0] arrays?  They can still have their
element size and if array_at_struct_end_p and the element type is not a variable
length type, using the actual eltsize seems better.
Only when !array_at_struct_end_p we should ensure arrbounds[1] will be 0
and indeed that (wi::to_offset (nelts) + 1) * eltsize would likely not do
that because wi::to_offset is -1ULL or so, not -1.

The code is only entered for references to declared objects so
the array_at_struct_end_p() test is unnecessary.  I've removed
it in the attached revision.


Also, I'm not sure I understand the right shift by floor_log2 of eltsize,
why can't you simply divide maxobjsize by eltsize (if eltsize is not 0).

I'm pretty sure that's because wide_int doesn't have division and
I assumed offset_int didn't either when I originally wrote the code.
I've changed it to use division.

Attached is a revised patch.

Martin
PR tree-optimization/99121 - ICE in -Warray-bounds on a VLA of zero-length array

gcc/ChangeLog:

	PR tree-optimization/99121
	* gimple-array-bounds.cc (array_bounds_checker::check_mem_ref):
	Avoid assuming array element size is constant.  Handle zero-length
	arrays of VLAs.

gcc/testsuite/ChangeLog:

	PR tree-optimization/99121
	* c-c++-common/Warray-bounds-9.c: New test.
	* gcc.dg/Warray-bounds-71.c: New test.

diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index 2576556f76b..046b78d463e 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -594,34 +594,31 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
 	      || (DECL_EXTERNAL (arg) && array_at_struct_end_p (ref))))
 	return false;
 
-      /* FIXME: Should this be 1 for Fortran?  */
       arrbounds[0] = 0;
 
       if (TREE_CODE (reftype) == ARRAY_TYPE)
 	{
-	  /* Set to the size of the array element (and adjust below).  */
-	  eltsize = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (reftype)));
-	  /* Use log2 of size to convert the array byte size in to its
-	     upper bound in elements.  */
-	  const offset_int eltsizelog2 = wi::floor_log2 (eltsize);
-	  if (tree dom = TYPE_DOMAIN (reftype))
+	  tree nelts = array_type_nelts (reftype);
+	  if (integer_all_onesp (nelts))
+	    /* Zero length array.  */
+	    arrbounds[1] = 0;
+	  else
 	    {
-	      tree bnds[] = { TYPE_MIN_VALUE (dom), TYPE_MAX_VALUE (dom) };
-	      if (TREE_CODE (arg) == COMPONENT_REF)
-		{
-		  offset_int size = maxobjsize;
-		  if (tree fldsize = component_ref_size (arg))
-		    size = wi::to_offset (fldsize);
-		  arrbounds[1] = wi::lrshift (size, eltsizelog2);
-		}
-	      else if (array_at_struct_end_p (arg) || !bnds[0] || !bnds[1])
-		arrbounds[1] = wi::lrshift (maxobjsize, eltsizelog2);
+	      tree esz = TYPE_SIZE_UNIT (TREE_TYPE (reftype));
+	      if (TREE_CODE (esz) == INTEGER_CST)
+		/* Array element is either not a VLA or it's a VLA with
+		   zero size (such as int A[n][n][0];).  */
+		eltsize = wi::to_offset (esz);
 	      else
-		arrbounds[1] = (wi::to_offset (bnds[1]) - wi::to_offset (bnds[0])
-				+ 1) * eltsize;
+		return false;
+
+	      if (TREE_CODE (nelts) == INTEGER_CST)
+		arrbounds[1] = (wi::to_offset (nelts) + 1) * eltsize;
+	      else if (eltsize == 0)
+		arrbounds[1] = 0;
+	      else
+		arrbounds[1] = maxobjsize / eltsize;
 	    }
-	  else
-	    arrbounds[1] = wi::lrshift (maxobjsize, eltsizelog2);
 
 	  /* Determine a tighter bound of the non-array element type.  */
 	  tree eltype = TREE_TYPE (reftype);
diff --git a/gcc/testsuite/c-c++-common/Warray-bounds-9.c b/gcc/testsuite/c-c++-common/Warray-bounds-9.c
new file mode 100644
index 00000000000..8ff592b363c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Warray-bounds-9.c
@@ -0,0 +1,144 @@
+/* PR tree-optimization/99121 - ICE in -Warray-bounds on a multidimensional
+   VLA
+   { dg-do compile }
+   { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+#define NOIPA __attribute__ ((noipa))
+
+void sink (void*, ...);
+#define T(a, x) sink (a, x)
+
+
+NOIPA void a_0_n (int n)
+{
+  int a[0][n];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_n_0 (int n)
+{
+  int a[n][0];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+
+NOIPA void a_1_n_0 (int n)
+{
+  int a[1][n][0];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_1_0_n (int n)
+{
+  int a[1][0][n];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_0_1_n (int n)
+{
+  int a[0][1][n];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_0_n_1 (int n)
+{
+  int a[0][n][1];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_n_0_n (int n)
+{
+  int a[n][0][n];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_n_n_0 (int n)
+{
+  int a[n][n][0];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_0_n_n (int n)
+{
+  int a[0][n][n];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_0_0_n (int n)
+{
+  int a[0][0][n];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_n_0_0 (int n)
+{
+  int a[n][0][0];
+
+  sink (a);
+
+  T (a, ((int *) a)[0]);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((char *) a)[1]);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a, ((float *) a)[n]);    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void a_n_n_n (int n)
+{
+  int a[n][n][n];
+
+  sink (a);
+
+  T (a, ((int *) a)[-1]);     // { dg-warning "\\\[-Warray-bounds" "pr99140" { xfail *-*-* } }
+  T (a, ((int *) a)[0]);
+  T (a, ((char *) a)[1]);
+  T (a, ((float *) a)[n]);
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-71.c b/gcc/testsuite/gcc.dg/Warray-bounds-71.c
new file mode 100644
index 00000000000..c2af9bef78c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-71.c
@@ -0,0 +1,53 @@
+/* PR tree-optimization/99121 - ICE in -Warray-bounds on a multidimensional
+   VLA
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wno-strict-aliasing -ftrack-macro-expansion=0" } */
+
+#define NOIPA __attribute__ ((noipa))
+
+void sink (void*, ...);
+#define T(a, x) sink (a, x)
+
+
+NOIPA void ma_0_n (int n)
+{
+  struct {
+    int a[0][n];
+  } s;
+
+  sink (&s);
+
+  T (&s, ((int *) s.a)[0]);   // { dg-warning "\\\[-Warray-bounds" }
+  T (&s, ((char *) s.a)[0]);  // { dg-warning "\\\[-Warray-bounds" }
+  T (&s, ((float *) s.a)[0]); // { dg-warning "\\\[-Warray-bounds" }
+
+  T (&s, ((int *) s.a)[1]);   // { dg-warning "\\\[-Warray-bounds" }
+  T (&s, ((char *) s.a)[1]);  // { dg-warning "\\\[-Warray-bounds" }
+  T (&s, ((float *) s.a)[1]); // { dg-warning "\\\[-Warray-bounds" }
+
+  T (&s, ((int *) s.a)[n]);   // { dg-warning "\\\[-Warray-bounds" "pr99129" { xfail *-*-* } }
+  T (&s, ((char *) s.a)[n]);  // { dg-warning "\\\[-Warray-bounds" "pr99129" { xfail *-*-* } }
+  T (&s, ((float *) s.a)[n]); // { dg-warning "\\\[-Warray-bounds" "pr99129" { xfail *-*-* } }
+}
+
+
+NOIPA void ma_n_0 (int n)
+{
+  struct {
+    int a[n][0];
+  } s;
+
+  sink (&s);
+
+  T (&s, ((int *) s.a)[0]);   // { dg-warning "\\\[-Warray-bounds" }
+  T (&s, ((char *) s.a)[0]);  // { dg-warning "\\\[-Warray-bounds" }
+  T (&s, ((float *) s.a)[0]); // { dg-warning "\\\[-Warray-bounds" }
+
+  T (&s, ((int *) s.a)[1]);   // { dg-warning "\\\[-Warray-bounds" }
+  T (&s, ((char *) s.a)[1]);  // { dg-warning "\\\[-Warray-bounds" }
+  T (&s, ((float *) s.a)[1]); // { dg-warning "\\\[-Warray-bounds" }
+
+  T (&s, ((int *) s.a)[n]);   // { dg-warning "\\\[-Warray-bounds" "pr99129" { xfail *-*-* } }
+  T (&s, ((char *) s.a)[n]);  // { dg-warning "\\\[-Warray-bounds" "pr99129" { xfail *-*-* } }
+  T (&s, ((float *) s.a)[n]); // { dg-warning "\\\[-Warray-bounds" "pr99129" { xfail *-*-* } }
+}

Reply via email to