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" } }