PR middle-end/88956 - ICE: Floating point exception on a memcpy from an zero-length constant array

gcc/ChangeLog:

	PR c/88956
	* gimple-fold.c (fold_array_ctor_reference): Avoid zero-length arrays.

gcc/testsuite/ChangeLog:

	PR c/88956
	* gcc.dg/Warray-bounds-39.c: New test.

Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(revision 268086)
+++ gcc/gimple-fold.c	(working copy)
@@ -6715,12 +6715,14 @@ fold_array_ctor_reference (tree type, tree ctor,
   elt_size = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor))));
 
   /* When TYPE is non-null, verify that it specifies a constant-sized
-     accessed not larger than size of array element.  */
-  if (type
-      && (!TYPE_SIZE_UNIT (type)
-	  || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
-	  || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type))
-	  || elt_size == 0))
+     accessed not larger than size of array element.  Avoid using zero
+     ELT_SIZE, the result of an empty initializer for a zero-length
+     array.  */
+  if (elt_size == 0
+      || (type
+	  && (!TYPE_SIZE_UNIT (type)
+	      || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
+	      || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type)))))
     return NULL_TREE;
 
   /* Compute the array index we look for.  */
Index: gcc/testsuite/gcc.dg/Warray-bounds-39.c
===================================================================
--- gcc/testsuite/gcc.dg/Warray-bounds-39.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/Warray-bounds-39.c	(working copy)
@@ -0,0 +1,115 @@
+/* PR middle-end/88956 - ICE: Floating point exception on a memcpy from
+   an zero-length constant array
+   Verify both that memory and string calls with a zero-length array
+   don't cause an ICE, and also that they emit warnings.
+   { dg-do compile }
+   { dg-options "-O2 -Wall" }  */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* memcpy (void*, const void*, size_t);
+extern void* memmove (void*, const void*, size_t);
+extern char* strcpy (char*, const char*);
+extern char* strncpy (char*, const char*, size_t);
+
+const char s0[0] = { };
+const char s0_0[0][0] = { };
+const char s0_1[0][1] = { };
+const char s1_0[1][0] = { };
+
+char d[4];
+
+void* test_memcpy_s0_1 (void *d)
+{
+  return memcpy (d, s0, 1);       /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s0_2 (void *d)
+{
+  return memcpy (d, s0, 2);       /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s0_0_1 (void *d)
+{
+  return memcpy (d, s0_0, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s0_0_2 (void *d)
+{
+  return memcpy (d, s0_0, 2);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+
+void* test_memcpy_s0_1_1 (void *d)
+{
+  return memcpy (d, s0_1, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s0_1_2 (void *d)
+{
+  return memcpy (d, s0_1, 2);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+
+void* test_memcpy_s1_0_1 (void *d)
+{
+  return memcpy (d, s1_0, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s1_0_2 (void *d)
+{
+  return memcpy (d, s1_0, 2);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+
+void* test_memmove_s0_1 (void *d)
+{
+  return memmove (d, s0, 1);      /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memmove_s0_2 (void *d)
+{
+  return memmove (d, s0, 2);      /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memmove_s0_0_1 (void *d)
+{
+  return memmove (d, s0_0, 1);    /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memmove_s0_0_2 (void *d)
+{
+  return memmove (d, s0_0, 2);    /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+
+char* test_strcpy_s0 (char *d)
+{
+  return strcpy (d, s0);          /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+char* test_strcpy_s0_0 (char *d)
+{
+  return strcpy (d, s0_0[0]);     /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+
+char* test_strncpy_s0_1 (char *d)
+{
+  return strncpy (d, s0, 1);    /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+char* test_strncpy_s0_2 (char *d)
+{
+  return strncpy (d, s0, 2);    /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+char* test_strncpy_s0_0_1 (char *d)
+{
+  return strncpy (d, s0_0[0], 1); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+char* test_strncpy_s0_0_2 (char *d)
+{
+  return strncpy (d, s0_0[0], 2); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
