Attached is a revised patch with three changes:

1) use wi::to_offset (max_object_size ()) instead of tree_to_shwi()
   as requested,
2) avoid warning for accesses to elements of arrays of empty types
   (PR 99475 that I noticed while testing the original patch),
3) include the size of the destination even for declared objects to
   make warnings for nonempty accesses to elements of arrays of empty
   structs slightly clearer.

Accesses to zero-length arrays continue to be diagnosed (except for
trailing arrays of unknown objects), as are nonempty accesses to empty
types.

The warning message for (3) remains unchanged, i.e., for the following:

  struct S { } a[3];

  void g (int n)
  {
    ((int*)a)[0] = 0;
  }

it's:

warning: array subscript 0 is outside array bounds of ‘struct S[3]’ [-Warray-bounds]

This could be improved by mentioning the type of the access when
it's not the same as that of the accessed object as is already done
for partially out of bounds accesses:

warning: subscript int[0] is outside array bounds of ‘struct S[3]’ [-Warray-bounds]

but making this change at the same time feels like feature creep and
out of scope for stage 4.

Retested on x86_64-linux.

On 2/18/21 1:55 PM, Martin Sebor wrote:
On 2/18/21 11:03 AM, Jakub Jelinek wrote:
On Thu, Feb 18, 2021 at 07:00:52PM +0100, Jakub Jelinek wrote:
The size of the VLA is zero regardless of its bound and accessing
it is invalid so the warning is expected.

Yes, some warning, but not the one you are giving, that is nonsensical.
Array subscript 0 is not outside of array bounds of struct S[n], a[anything]
will still be zero sized and will not be problematic.

The warning is designed for ordinary arrays of nonzero size.  There's
no point in putting an effort into coming up with a special warning
just for those because they serve no purpose in these contexts (as
complete objects).


Scalar objects with zero size will always have that zero size,
similarly arrays thereof (constant or variable sized).
So the warning should be simply if eltsize == 0,
check if the access is before or after the object and complain
that a memory access is done before or after a zero sized object %qD.

    Jakub

No, I don't think making this exception would be helpful.  Zero length
arrays are a non-standard extension meant to be used as struct members,
before flexible array members were added to C.  In other contexts, they
are almost certainly unintended and so likely bugs.  There's no valid
use case for such arrays, and diagnosing accesses to them helps find
such bugs.

That said, I also don't think a fix for the ICE should be held up
because we disagree on this vanishingly unimportant corner case.
The ICE effectively prevents using such arrays (VLAs) and since no
bug reports have been raised for it since it was introduced in GCC
9 it's unlikely that any code relies on it.  (I suspect the bug
itself was the result of fuzzing.)

Martin

PR tree-optimization/99121 - ICE in -Warray-bounds on a VLA of zero-length array
PR tree-optimization/99475 - bogus -Warray-bounds accessing an array element of empty structs

gcc/ChangeLog:

	PR tree-optimization/99121
	PR tree-optimization/99475
	* 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
	PR tree-optimization/99475
	* c-c++-common/Warray-bounds-10.c: New test.
	* c-c++-common/Warray-bounds-9.c: New test.
	* gcc.dg/Warray-bounds-71.c: New test.
	* gcc.dg/Warray-bounds-72.c: New test.
	* gcc.dg/Warray-bounds-73.c: New test.

diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index 54f32051199..bd6caee7d5a 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -419,7 +419,7 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
   tree cstoff = TREE_OPERAND (ref, 1);
   tree varoff = NULL_TREE;
 
-  const offset_int maxobjsize = tree_to_shwi (max_object_size ());
+  const offset_int maxobjsize = wi::to_offset (max_object_size ());
 
   /* The zero-based array or string constant bounds in bytes.  Initially
      set to [-MAXOBJSIZE - 1, MAXOBJSIZE]  until a tighter bound is
@@ -553,7 +553,12 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
 	offrange[1] = arrbounds[1];
     }
 
+  /* Type of the access.  */
+  tree axstype = TREE_TYPE (ref);
+  /* TYpe of the referenced object if it can be determined or array
+     of unsigned char for allocated objects.  */
   tree reftype = NULL_TREE;
+  /* The byte size of the referenced array element.  */
   offset_int eltsize = -1;
   if (arrbounds[0] >= 0)
     {
@@ -602,34 +607,44 @@ 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)
+	      tree esz = TYPE_SIZE_UNIT (TREE_TYPE (reftype));
+	      if (TREE_CODE (esz) != INTEGER_CST)
+		return false;
+
+	      eltsize = wi::to_offset (esz);
+	      if (eltsize == 0)
 		{
-		  offset_int size = maxobjsize;
-		  if (tree fldsize = component_ref_size (arg))
-		    size = wi::to_offset (fldsize);
-		  arrbounds[1] = wi::lrshift (size, eltsizelog2);
+		  /* Array element is either not a VLA or it's a VLA with
+		     zero size (such as int[n][n][0]).  Check to see if
+		     the most derived element type is an empty type such
+		     as a struct with zero size and if so, treat it as if
+		     it had size of 1 to avoid warning on empty accesses
+		     to elements of such arrays that GCC eliminates.  */
+		  tree elt = strip_array_types (reftype);
+		  if (TYPE_EMPTY_P (elt) && TYPE_EMPTY_P (axstype))
+		    {
+		      nelts = integer_zero_node;
+		      eltsize = 1;
+		    }
 		}
-	      else if (array_at_struct_end_p (arg) || !bnds[0] || !bnds[1])
-		arrbounds[1] = wi::lrshift (maxobjsize, eltsizelog2);
+
+	      if (TREE_CODE (nelts) == INTEGER_CST)
+		arrbounds[1] = (wi::to_offset (nelts) + 1) * eltsize;
+	      else if (eltsize == 0)
+		arrbounds[1] = 0;
 	      else
-		arrbounds[1] = (wi::to_offset (bnds[1]) - wi::to_offset (bnds[0])
-				+ 1) * eltsize;
+		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);
@@ -667,16 +682,15 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
   const bool lboob = (arrbounds[0] == arrbounds[1]
 		      || offrange[0] >= ubound
 		      || offrange[1] < arrbounds[0]);
-  /* Set if only the upper bound of the subscript is out of bounds.
-     This can happen when using a bigger type to index into an array
-     of a smaller type, as is common with unsigned char.  */
-  tree axstype = TREE_TYPE (ref);
   offset_int axssize = 0;
   if (TREE_CODE (axstype) != UNION_TYPE)
     if (tree access_size = TYPE_SIZE_UNIT (axstype))
       if (TREE_CODE (access_size) == INTEGER_CST)
 	axssize = wi::to_offset (access_size);
 
+  /* Set if only the upper bound of the subscript is out of bounds.
+     This can happen when using a bigger type to index into an array
+     of a smaller type, as is common with unsigned char.  */
   const bool uboob = !lboob && offrange[0] + axssize > ubound;
   if (lboob || uboob)
     {
@@ -731,7 +745,8 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
   if (warned)
     {
       if (DECL_P (arg))
-	inform (DECL_SOURCE_LOCATION (arg), "while referencing %qD", arg);
+	inform (DECL_SOURCE_LOCATION (arg), "while referencing %qD "
+		"of size %wu", arg, minbound.to_uhwi ());
       else if (alloc_stmt)
 	{
 	  location_t loc = gimple_location (alloc_stmt);
diff --git a/gcc/testsuite/c-c++-common/Warray-bounds-10.c b/gcc/testsuite/c-c++-common/Warray-bounds-10.c
new file mode 100644
index 00000000000..cfe9a383410
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Warray-bounds-10.c
@@ -0,0 +1,114 @@
+/* PR tree-optimization/99475 - bogus -Warray-bounds accessing an array
+   element of empty structs
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+struct S
+{
+#if SOME_CONFIG_MACRO
+  /* Suppose the contents are empty in the development configuration
+     but non-empty in others.  Out of bounds accesses to elements of
+     the arrays below should be diagnosed in all configurations,
+     including when S is empty, even if they are folded away.  */
+  int member;
+#endif
+};
+
+extern struct S sa3[3];
+extern struct S sa2_3[2][3];
+extern struct S sa3_4_5[3][4][5];
+
+void sink (void*);
+
+
+void access_sa3 (struct S s)
+{
+  sa3[0] = s;
+  sa3[1] = s;
+  sa3[2] = s;
+  sa3[3] = s;       // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+}
+
+void access_sa3_ptr (struct S s)
+{
+  struct S *p = &sa3[0];
+
+  p[0] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[3] = s;         // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+}
+
+void access_sa2_3_ptr (struct S s)
+{
+  struct S *p = &sa2_3[0][0];
+
+  p[0] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[6] = s;         // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+}
+
+void access_sa3_4_5_ptr (struct S s, int i)
+{
+  struct S *p = &sa3_4_5[0][0][0];
+
+  p[0] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[60] = s;        // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+}
+
+
+void access_vla3 (struct S s, unsigned n)
+{
+  struct S vla3[3 < n ? 3 : n];
+
+  vla3[0] = s;
+  vla3[1] = s;
+  vla3[2] = s;
+  vla3[3] = s;       // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+
+  sink (vla3);
+}
+
+void access_vla3_ptr (struct S s, unsigned n)
+{
+  struct S vla3[3 < n ? 3 : n];
+  struct S *p = &vla3[0];
+
+  p[0] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[3] = s;         // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+
+  sink (vla3);
+}
+
+void access_vla2_3_ptr (struct S s, unsigned n)
+{
+  struct S vla2_3[2 < n ? 2 : n][3 < n ? 3 : n];
+  struct S *p = &vla2_3[0][0];
+
+  p[0] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[6] = s;         // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+
+  sink (vla2_3);
+}
+
+void access_vla3_4_5_ptr (struct S s, unsigned n)
+{
+  struct S vla3_4_5[3 < n ? 3 : n][4 < n ? 4 : n][5 < n ? 5 : n];
+  struct S *p = &vla3_4_5[0][0][0];
+
+  p[0] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = s;         // { dg-bogus "\\\[-Warray-bounds" }
+  p[60] = s;        // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+
+  sink (vla3_4_5);
+}
+
+// { dg-prune-output "empty struct has size 0 in C" }
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 *-*-* } }
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-72.c b/gcc/testsuite/gcc.dg/Warray-bounds-72.c
new file mode 100644
index 00000000000..b44ac9d3aa2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-72.c
@@ -0,0 +1,112 @@
+/* PR tree-optimization/99475 - bogus -Warray-bounds accessing an array
+   element of empty structs
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+struct S
+{
+#if SOME_CONFIG_MACRO
+  /* Suppose the contents are empty in the development configuration
+     but non-empty in others.  Out of bounds accesses to elements of
+     the arrays below should be diagnosed in all configurations,
+     including when S is empty, even if they are folded away.  */
+  int member;
+#endif
+};
+
+extern struct S sa3[3];
+extern struct S sa2_3[2][3];
+extern struct S sa3_4_5[3][4][5];
+
+void sink (void*);
+
+
+void access_sa3 (void)
+{
+  sa3[0] = (struct S){ };
+  sa3[1] = (struct S){ };
+  sa3[2] = (struct S){ };
+  sa3[3] = (struct S){ };       // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+}
+
+void access_sa3_ptr (void)
+{
+  struct S *p = &sa3[0];
+
+  p[0] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[3] = (struct S){ };         // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+}
+
+void access_sa2_3_ptr (void)
+{
+  struct S *p = &sa2_3[0][0];
+
+  p[0] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[6] = (struct S){ };         // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+}
+
+void access_sa3_4_5_ptr (struct S s, int i)
+{
+  struct S *p = &sa3_4_5[0][0][0];
+
+  p[0] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[60] = (struct S){ };        // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+}
+
+
+void access_vla3 (struct S s, unsigned n)
+{
+  struct S vla3[3 < n ? 3 : n];
+
+  vla3[0] = (struct S){ };
+  vla3[1] = (struct S){ };
+  vla3[2] = (struct S){ };
+  vla3[3] = (struct S){ };       // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+
+  sink (vla3);
+}
+
+void access_vla3_ptr (struct S s, unsigned n)
+{
+  struct S vla3[3 < n ? 3 : n];
+  struct S *p = &vla3[0];
+
+  p[0] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[3] = (struct S){ };         // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+
+  sink (vla3);
+}
+
+void access_vla2_3_ptr (struct S s, unsigned n)
+{
+  struct S vla2_3[2 < n ? 2 : n][3 < n ? 3 : n];
+  struct S *p = &vla2_3[0][0];
+
+  p[0] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[6] = (struct S){ };         // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+
+  sink (vla2_3);
+}
+
+void access_vla3_4_5_ptr (struct S s, unsigned n)
+{
+  struct S vla3_4_5[3 < n ? 3 : n][4 < n ? 4 : n][5 < n ? 5 : n];
+  struct S *p = &vla3_4_5[0][0][0];
+
+  p[0] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[1] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[2] = (struct S){ };         // { dg-bogus "\\\[-Warray-bounds" }
+  p[60] = (struct S){ };        // { dg-warning "\\\[-Warray-bounds" "pr?????" { xfail *-*-* } }
+
+  sink (vla3_4_5);
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-73.c b/gcc/testsuite/gcc.dg/Warray-bounds-73.c
new file mode 100644
index 00000000000..73c335fd8a6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-73.c
@@ -0,0 +1,109 @@
+/* PR tree-optimization/99475 - bogus -Warray-bounds accessing an array
+   element of empty structs
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wno-strict-aliasing" } */
+
+typedef _Bool bool;
+
+#define NOIPA __attribute__ ((noipa))
+
+struct S { };
+
+extern struct S sa3[3];
+extern struct S sa2_3[2][3];
+extern struct S sa3_4_5[3][4][5];
+
+void sink (void*);
+
+
+NOIPA void access_sa3 (void)
+{
+  ((bool*)sa3)[0] = __LINE__;     // { dg-warning "\\\[-Warray-bounds" }
+  ((bool*)sa3)[1] = __LINE__;     // { dg-warning "\\\[-Warray-bounds" }
+  ((bool*)sa3)[2] = __LINE__;     // { dg-warning "\\\[-Warray-bounds" }
+  ((bool*)sa3)[3] = __LINE__;     // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void access_sa3_ptr (void)
+{
+  bool *p = (bool*)&sa3[0];
+
+  p[0] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[1] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[2] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[3] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void access_sa2_3_ptr (void)
+{
+  bool *p = (bool*)&sa2_3[0][0];
+
+  p[0] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[1] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[2] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[6] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+}
+
+NOIPA void access_sa3_4_5_ptr (struct S s, int i)
+{
+  bool *p = (bool*)&sa3_4_5[0][0][0];
+
+  p[0] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[1] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[2] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[60] = __LINE__;       // { dg-warning "\\\[-Warray-bounds" }
+}
+
+
+NOIPA void access_vla3 (struct S s, unsigned n)
+{
+  struct S vla3[3 < n ? 3 : n];
+
+  ((bool*)vla3)[0] = __LINE__;    // { dg-warning "\\\[-Warray-bounds" }
+  ((bool*)vla3)[1] = __LINE__;    // { dg-warning "\\\[-Warray-bounds" }
+  ((bool*)vla3)[2] = __LINE__;    // { dg-warning "\\\[-Warray-bounds" }
+  ((bool*)vla3)[3] = __LINE__;    // { dg-warning "\\\[-Warray-bounds" }
+
+  sink (vla3);
+}
+
+NOIPA void access_vla3_ptr (struct S s, unsigned n)
+{
+  struct S vla3[3 < n ? 3 : n];
+  bool *p = (bool*)&vla3[0];
+
+  p[0] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[1] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[2] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[3] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+
+  sink (vla3);
+}
+
+NOIPA void access_vla2_3_ptr (struct S s, unsigned n)
+{
+  struct S vla2_3[2 < n ? 2 : n][3 < n ? 3 : n];
+  bool *p = (bool*)&vla2_3[0][0];
+
+  p[0] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[1] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[2] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[6] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+
+  sink (vla2_3);
+}
+
+NOIPA void access_vla3_4_5_ptr (struct S s, unsigned n)
+{
+  struct S vla3_4_5[3 < n ? 3 : n][4 < n ? 4 : n][5 < n ? 5 : n];
+  bool *p = (bool*)&vla3_4_5[0][0][0];
+
+  p[0] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[1] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[2] = __LINE__;        // { dg-warning "\\\[-Warray-bounds" }
+  p[60] = __LINE__;       // { dg-warning "\\\[-Warray-bounds" }
+
+  sink (vla3_4_5);
+}
+
+// { dg-prune-output "empty struct has size 0 in C" }

Reply via email to