When mentioning the type of the accessed object -Warray-bounds
treats singleton objects as arrays of one element for simplicity.
But because the code doesn't distinguish between function and
object pointers, a warning for an out-of-bounds index into
a singleton function pointer object attempts to create an array
of one function.  Since arrays of functions are invalid,
the helper function the code calls fails with an error issued
to the user.

To avoid this the attached patch avoids this singleton-to-array
shortcut for function pointers.  Tested on x86_64-linux.

Martin

PR middle-end/101601 - [12 Regression] -Warray-bounds triggers error: arrays of functions are not meaningful

	PR middle-end/101601

gcc/ChangeLog:

	* gimple-array-bounds.cc (array_bounds_checker::check_mem_ref): Remove
	a pointless test.
	Handle pointers to functions.

gcc/testsuite/ChangeLog:

	* g++.dg/warn/Warray-bounds-25.C: New test.
	* gcc.dg/Warray-bounds-85.c: New test.

diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index 598c76bf52e..9ead2182519 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -421,10 +421,9 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
   /* The type and size of the access.  */
   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);
+  if (tree access_size = TYPE_SIZE_UNIT (axstype))
+    if (TREE_CODE (access_size) == INTEGER_CST)
+      axssize = wi::to_offset (access_size);
 
   access_ref aref;
   if (!compute_objsize (ref, 0, &aref, ranges))
@@ -451,20 +450,28 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
   tree reftype = TREE_TYPE (aref.ref);
   /* The size of the referenced array element.  */
   offset_int eltsize = 1;
-  /* The byte size of the array has already been determined above
-     based on a pointer ARG.  Set ELTSIZE to the size of the type
-     it points to and REFTYPE to the array with the size, rounded
-     down as necessary.  */
   if (POINTER_TYPE_P (reftype))
     reftype = TREE_TYPE (reftype);
-  if (TREE_CODE (reftype) == ARRAY_TYPE)
-    reftype = TREE_TYPE (reftype);
-  if (tree refsize = TYPE_SIZE_UNIT (reftype))
-    if (TREE_CODE (refsize) == INTEGER_CST)
-      eltsize = wi::to_offset (refsize);
 
-  const offset_int nelts = aref.sizrng[1] / eltsize;
-  reftype = build_printable_array_type (reftype, nelts.to_uhwi ());
+  if (TREE_CODE (reftype) == FUNCTION_TYPE)
+    /* Restore the original (pointer) type and avoid trying to create
+       an array of functions (done below).  */
+    reftype = TREE_TYPE (aref.ref);
+  else
+    {
+      /* The byte size of the array has already been determined above
+	 based on a pointer ARG.  Set ELTSIZE to the size of the type
+	 it points to and REFTYPE to the array with the size, rounded
+	 down as necessary.  */
+      if (TREE_CODE (reftype) == ARRAY_TYPE)
+	reftype = TREE_TYPE (reftype);
+      if (tree refsize = TYPE_SIZE_UNIT (reftype))
+	if (TREE_CODE (refsize) == INTEGER_CST)
+	  eltsize = wi::to_offset (refsize);
+
+      const offset_int nelts = aref.sizrng[1] / eltsize;
+      reftype = build_printable_array_type (reftype, nelts.to_uhwi ());
+    }
 
   /* Compute the more permissive upper bound when IGNORE_OFF_BY_ONE
      is set (when taking the address of the one-past-last element
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-25.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-25.C
new file mode 100644
index 00000000000..a93da037560
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-25.C
@@ -0,0 +1,59 @@
+/* PR middle-end/101601 - [12 Regression] -Warray-bounds triggers error:
+   arrays of functions are not meaningful
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+typedef void Fvv (void);
+
+extern Fvv* pf;       // { dg-message "'pf'" }
+
+void f (...);
+
+void test_funptr (void)
+{
+  f (&pf);
+  f (&pf + 1);
+  f (&pf + 2);        // { dg-warning "subscript 2 is outside array bounds of 'void \\\(\\\* ?\\\[1]\\\)\\\(\\\)'" }
+}
+
+typedef int Fii_ (int, ...);
+
+extern Fii_* pfa[3];  // { dg-message "'pfa'" }
+
+void test_funptr_array (void)
+{
+  f (pfa);
+  f (pfa + 1);
+  f (pfa + 2);
+  f (pfa + 3);
+  f (pfa + 4);        // { dg-warning "subscript 4 is outside array bounds of 'int \\\(\\\* ?\\\[3]\\\)\\\(int, ...\\\)'" }
+}
+
+
+struct A;
+typedef void (A::*MFvv)(void);
+
+MFvv pmf;
+
+void test_memfunptr (void)
+{
+  f (&pmf);
+  f (&pmf + 1);
+  f (&pmf + 2);       // { dg-warning "subscript 2 is outside array bounds of 'void \\\(A::\\\* ?\\\[1]\\\)\\\(\\\)'" }
+}
+
+
+typedef int (A::*MFii)(int);
+
+MFii pmfa[4];
+
+void test_memfunptr_array (void)
+{
+  f (pmfa);
+  f (pmfa + 1);
+  f (pmfa + 2);
+  f (pmfa + 3);
+  f (pmfa + 4);
+  f (pmfa + 5);       // { dg-warning "subscript 5 is outside array bounds of 'int \\\(A::\\\* ?\\\[4]\\\)\\\(int\\\)'" }
+
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-85.c b/gcc/testsuite/gcc.dg/Warray-bounds-85.c
new file mode 100644
index 00000000000..0ee71200cbb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-85.c
@@ -0,0 +1,30 @@
+/* PR middle-end/101601 - [12 Regression] -Warray-bounds triggers error:
+   arrays of functions are not meaningful
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+typedef void Fvv (void);
+
+extern Fvv* pf;       // { dg-message "'pf'" }
+
+void f (void*);
+
+void test_funptr (void)
+{
+  f (&pf);
+  f (&pf + 1);
+  f (&pf + 2);        // { dg-warning "subscript 2 is outside array bounds of 'void \\\(\\\*\\\[1]\\\)\\\(void\\\)'" }
+}
+
+typedef int Fii_ (int, ...);
+
+extern Fii_* pfa[3];  // { dg-message "'pfa'" }
+
+void test_funptr_array (void)
+{
+  f (pfa);
+  f (pfa + 1);
+  f (pfa + 2);
+  f (pfa + 3);
+  f (pfa + 4);        // { dg-warning "subscript 4 is outside array bounds of 'int \\\(\\\*\\\[3]\\\)\\\(int, ...\\\)'" }
+}

Reply via email to