The change committed yesterday to handle the C++ 2a string literals
as non-type template arguments treats empty string initializers for
trailing pointer array elements as zero.  That's of course wrong
because addresses of literals are non-zero.

The attached tweak constrains the trimming of trailing zero
initializers to either non-pointer initializers or non-pointer
types.

The patch passes x86_64 bootstrap (but so did the change yesterday).
The tests are still running.  Is it okay to commit if the tests pass?

I'm also separately bootstrapping using the configure options from
the report where apparently it caused the x86_64 bootstrap to fail.

Martin
PR bootstrap/89980 - pointer initialization with empty string folded to zero

gcc/cp/ChangeLog:

	PR bootstrap/89980
	* decl.c (reshape_init_array_1): Avoid treating empty strings
	as zeros in array initializers.

gcc/testsuite/ChangeLog:

	PR bootstrap/89980
	* g++.dg/init/array52.C: New test.

Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 270165)
+++ gcc/cp/decl.c	(working copy)
@@ -5800,7 +5800,7 @@ reshape_init_array_1 (tree elt_type, tree max_inde
     }
 
   /* Set to the index of the last element with a non-zero initializer.
-     Initializers for elements past this one can be dropped.  */
+     Zero initializers for elements past this one can be dropped.  */
   unsigned HOST_WIDE_INT last_nonzero = -1;
   /* Loop until there are no more initializers.  */
   for (index = 0;
@@ -5820,7 +5820,11 @@ reshape_init_array_1 (tree elt_type, tree max_inde
       if (!TREE_CONSTANT (elt_init))
 	TREE_CONSTANT (new_init) = false;
 
-      if (!initializer_zerop (elt_init))
+      /* Pointers initialized to strings must be treated as non-zero
+	 even if the string is empty.  */
+      tree init_type = TREE_TYPE (elt_init);
+      if (POINTER_TYPE_P (elt_type) != POINTER_TYPE_P (init_type)
+	  || !initializer_zerop (elt_init))
 	last_nonzero = index;
 
       /* This can happen with an invalid initializer (c++/54501).  */
Index: gcc/testsuite/g++.dg/init/array52.C
===================================================================
--- gcc/testsuite/g++.dg/init/array52.C	(nonexistent)
+++ gcc/testsuite/g++.dg/init/array52.C	(working copy)
@@ -0,0 +1,102 @@
+// PR c++/89980 - pointer initialization with empty string folded to zero
+// { dg-do compile }
+// { dg-options "-O2 -Wall -fdump-tree-optimized" }
+
+#if __cplusplus >= 201103L
+
+#define SA(e) static_assert (e, #e)
+
+static constexpr const char* const ca1[2] = { "" };
+
+void fca1 (void)
+{
+  SA (ca1[0] && ca1[0][0] == 0 && ca1[1] == 0);
+}
+
+static constexpr const char* const ca2[][2] =
+{
+  { }, { 0 }, { 0, 0 }, { "" }, { "", "" }, { "", 0 }, { 0, "" }
+};
+
+void fca2 (void)
+{
+  SA (ca2[0][0] == 0 && ca2[0][1] == 0);
+  SA (ca2[1][0] == 0 && ca2[1][1] == 0);
+  SA (ca2[2][0] == 0 && ca2[2][1] == 0);
+
+  SA (ca2[3][0] && ca2[3][0][0] == 0 && ca2[3][1] == 0);
+  SA (ca2[4][0] && ca2[4][0][0] == 0 && ca2[4][1] && ca2[4][1][0] == 0);
+  SA (ca2[5][0] && ca2[5][0][0] == 0 && ca2[5][1] == 0);
+  SA (ca2[6][0] == 0 && ca2[6][1] && ca2[6][1][0] == 0);
+}
+
+struct A
+{
+  const char *p;
+  char a[2];
+};
+
+static constexpr A ca3[] =
+{
+  {  }, { 0 }, { 0, "" }, { "" }, { "", "" }
+};
+
+void fca3 (void)
+{
+  SA (ca3[0].p == 0 && ca3[0].a[0] == 0 && ca3[0].a[1] == 0);
+  SA (ca3[1].p == 0 && ca3[1].a[0] == 0 && ca3[1].a[1] == 0);
+  SA (ca3[2].p == 0 && ca3[2].a[0] == 0 && ca3[2].a[1] == 0);
+  SA (ca3[3].p && ca3[3].p[0] == 0 && ca3[3].a[0] == 0 && ca3[3].a[1] == 0);
+  SA (ca3[4].p && ca3[4].p[0] == 0 && ca3[4].a[0] == 0 && ca3[4].a[1] == 0);
+}
+
+#endif   // C++ 11 and above
+
+
+#define A(e) ((e) ? (void)0 : __builtin_abort ())
+
+static const char* const a1[2] = { "" };
+
+void fa1 (void)
+{
+  A (a1[0] && a1[0][0] == 0 && a1[1] == 0);
+}
+
+static const char* const a2[][2] =
+{
+  { }, { 0 }, { 0, 0 }, { "" }, { "", "" }, { "", 0 }, { 0, "" }
+};
+
+void fa2 (void)
+{
+  A (a2[0][0] == 0 && a2[0][1] == 0);
+  A (a2[1][0] == 0 && a2[1][1] == 0);
+  A (a2[2][0] == 0 && a2[2][1] == 0);
+
+  A (a2[3][0] && a2[3][0][0] == 0 && a2[3][1] == 0);
+  A (a2[4][0] && a2[4][0][0] == 0 && a2[4][1] && a2[4][1][0] == 0);
+  A (a2[5][0] && a2[5][0][0] == 0 && a2[5][1] == 0);
+  A (a2[6][0] == 0 && a2[6][1] && a2[6][1][0] == 0);
+}
+
+struct B
+{
+  const char *p;
+  char a[2];
+};
+
+static const B a3[] =
+{
+  {  }, { 0 }, { 0, "" }, { "" }, { "", "" }
+};
+
+void fa3 (void)
+{
+  A (a3[0].p == 0 && a3[0].a[0] == 0 && a3[0].a[1] == 0);
+  A (a3[1].p == 0 && a3[1].a[0] == 0 && a3[1].a[1] == 0);
+  A (a3[2].p == 0 && a3[2].a[0] == 0 && a3[2].a[1] == 0);
+  A (a3[3].p && a3[3].p[0] == 0 && a3[3].a[0] == 0 && a3[3].a[1] == 0);
+  A (a3[4].p && a3[4].p[0] == 0 && a3[4].a[0] == 0 && a3[4].a[1] == 0);
+}
+
+// { dg-final { scan-tree-dump-not "abort" "optimized" } }

Reply via email to