diff options
author | Martin Sebor <msebor@redhat.com> | 2019-08-01 23:45:36 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2019-08-01 17:45:36 -0600 |
commit | b74f15a88ee1a2b96784803f0e38c386796ee704 (patch) | |
tree | 7c4a96774ea3cef422ba9596824ceb090bf0ff21 /gcc | |
parent | f3b4eae6c3ac560f28f2d1d209ae5e0e030f95fe (diff) | |
download | gcc-b74f15a88ee1a2b96784803f0e38c386796ee704.zip gcc-b74f15a88ee1a2b96784803f0e38c386796ee704.tar.gz gcc-b74f15a88ee1a2b96784803f0e38c386796ee704.tar.bz2 |
PR c++/90947 - Simple lookup table of array of strings is miscompiled
gcc/cp/ChangeLog:
PR c++/90947
* decl.c (reshape_init_array_1): Avoid truncating initializer
lists containing string literals.
gcc/testsuite/ChangeLog:
PR c++/90947
* c-c++-common/array-1.c: New test.
* g++.dg/abi/mangle73.C: New test.
* g++.dg/cpp2a/nontype-class23.C: New test.
* g++.dg/init/array53.C: New test.
gcc/ChangeLog:
PR c++/90947
* tree.c (type_initializer_zero_p): Define.
* tree.h (type_initializer_zero_p): New function.
From-SVN: r273989
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/decl.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/array-1.c | 247 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/mangle73.C | 96 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/nontype-class23.C | 102 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/init/array53.C | 33 | ||||
-rw-r--r-- | gcc/tree.c | 67 | ||||
-rw-r--r-- | gcc/tree.h | 6 |
10 files changed, 574 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1186e07..e5c3a59 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2019-08-01 Martin Sebor <msebor@redhat.com> + + PR c++/90947 + * tree.c (type_initializer_zero_p): Define. + * tree.h (type_initializer_zero_p): New function. + 2019-08-01 Eric Botcazou <ebotcazou@adacore.com> * cfgrtl.c (relink_block_chain): Add line returns in dump file. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9a6c2e3..02992ae 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2019-08-01 Martin Sebor <msebor@redhat.com> + + PR c++/90947 + * decl.c (reshape_init_array_1): Avoid truncating initializer + lists containing string literals. + 2019-08-01 Marek Polacek <polacek@redhat.com> PR c++/90805 - detect narrowing in case values. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c8b9e3b..a1ab5ca 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5899,8 +5899,9 @@ reshape_init_array_1 (tree elt_type, tree max_index, reshape_iter *d, /* 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)) + if ((POINTER_TYPE_P (elt_type) != POINTER_TYPE_P (init_type))) + last_nonzero = index; + else if (!type_initializer_zero_p (elt_type, elt_init)) last_nonzero = index; /* This can happen with an invalid initializer (c++/54501). */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0b4334a..028f978 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2019-08-01 Martin Sebor <msebor@redhat.com> + + PR c++/90947 + * c-c++-common/array-1.c: New test. + * g++.dg/abi/mangle73.C: New test. + * g++.dg/cpp2a/nontype-class23.C: New test. + * g++.dg/init/array53.C: New test. + 2019-08-01 Uroš Bizjak <ubizjak@gmail.com> PR target/85693 diff --git a/gcc/testsuite/c-c++-common/array-1.c b/gcc/testsuite/c-c++-common/array-1.c new file mode 100644 index 0000000..5de9ade --- /dev/null +++ b/gcc/testsuite/c-c++-common/array-1.c @@ -0,0 +1,247 @@ +// PR c++/90947 - Simple lookup table of array of strings is miscompiled +// { dg-do compile } +// { dg-options "-O1 -fdump-tree-optimized" } + +#define assert(expr) ((expr) ? (void)0 : __builtin_abort ()) + +void pr90947 (void) +{ + int vecsize = 4; + int index = 0; + static const char *a[4][4] = + { + { ".x", ".y", ".z", ".w" }, + { ".xy", ".yz", ".zw", 0 }, + { ".xyz", ".yzw", 0, 0 }, + { "", 0, 0, 0 }, + }; + + assert (vecsize >= 1 && vecsize <= 4); + assert (index >= 0 && index < 4); + assert (a[vecsize - 1][index]); +} + +void f_a1_1 (void) +{ + { + const char* a[1][1] = { { 0 } }; + assert (0 == a[0][0]); + } + { + const char* a[1][1] = { { "" } }; + assert ('\0' == *a[0][0]); + } +} + +void f_a2_1 (void) +{ + { + const char* a[2][1] = { { "" }, { "" } }; + assert ('\0' == *a[0][0] && '\0' == *a[1][0]); + } + { + const char* a[2][1] = { { 0 }, { "" } }; + assert (0 == a[0][0] && '\0' == *a[1][0]); + } + { + const char* a[2][1] = { { }, { "" } }; + assert (0 == a[0][0] && '\0' == *a[1][0]); + } +} + +void f_a2_2 (void) +{ + { + const char* a[2][2] = { { "", "" }, { "", "" } }; + assert ('\0' == *a[0][0] && '\0' == *a[0][1]); + assert ('\0' == *a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { "", "" }, { "", 0 } }; + assert ('\0' == *a[0][0] && '\0' == *a[0][1]); + assert ('\0' == *a[1][0] && 0 == a[1][1]); + } + { + const char* a[2][2] = { { "", "" }, { "" } }; + assert ('\0' == *a[0][0] && '\0' == *a[0][1]); + assert ('\0' == *a[1][0] && 0 == a[1][1]); + } + { + const char* a[2][2] = { { "", "" }, { 0, "" } }; + assert ('\0' == *a[0][0] && '\0' == *a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { "", 0 }, { 0, "" } }; + assert ('\0' == *a[0][0] && 0 == a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { 0, 0 }, { 0, "" } }; + assert (0 == a[0][0] && 0 == a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { 0 }, { 0, "" } }; + assert (0 == a[0][0] && 0 == a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } + { + const char* a[2][2] = { { }, { 0, "" } }; + assert (0 == a[0][0] && 0 == a[0][1]); + assert (0 == a[1][0] && '\0' == *a[1][1]); + } +} + +void f_a2_2_2 (void) +{ + { + const char* a[2][2][2] = + { { { "", "" }, { "", "" } }, { { "", "" }, { "", "" } } }; + + assert ('\0' == *a[0][0][0] && '\0' == *a[0][0][1]); + assert ('\0' == *a[0][1][0] && '\0' == *a[0][1][1]); + assert ('\0' == *a[1][0][0] && '\0' == *a[1][0][1]); + assert ('\0' == *a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { "", "" }, { "", "" } }, { { "", "" }, { 0, "" } } }; + + assert ('\0' == *a[0][0][0] && '\0' == *a[0][0][1]); + assert ('\0' == *a[0][1][0] && '\0' == *a[0][1][1]); + assert ('\0' == *a[1][0][0] && '\0' == *a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { "", "" }, { "", "" } }, { { 0, 0 }, { 0, "" } } }; + + assert ('\0' == *a[0][0][0] && '\0' == *a[0][0][1]); + assert ('\0' == *a[0][1][0] && '\0' == *a[0][1][1]); + assert (0 == a[1][0][0] && 0 == a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { "", "" }, { 0, 0 } }, { { 0, 0 }, { 0, "" } } }; + + assert ('\0' == *a[0][0][0] && '\0' == *a[0][0][1]); + assert (0 == a[0][1][0] && 0 == a[0][1][1]); + assert (0 == a[1][0][0] && 0 == a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { 0, 0 }, { 0, 0 } }, { { 0, 0 }, { 0, "" } } }; + + assert (0 == a[0][0][0] && 0 == a[0][0][1]); + assert (0 == a[0][1][0] && 0 == a[0][1][1]); + assert (0 == a[1][0][0] && 0 == a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } + + { + const char* a[2][2][2] = + { { { }, { } }, { { }, { 0, "" } } }; + + assert (0 == a[0][0][0] && 0 == a[0][0][1]); + assert (0 == a[0][1][0] && 0 == a[0][1][1]); + assert (0 == a[1][0][0] && 0 == a[1][0][1]); + assert (0 == a[1][1][0] && '\0' == *a[1][1][1]); + } +} + +void f_sa2_2_2 (void) +{ + struct S { const char a[2], *s, c; }; + + { + const struct S a[2][2][2] = { + { }, + { + { { }, { "", "" } }, + { } + } + }; + + assert ('\0' == *a[0][0][0].a && 0 == a[0][0][0].s && 0 == a[0][0][0].c); + assert ('\0' == *a[0][0][1].a && 0 == a[0][0][1].s && 0 == a[0][0][1].c); + assert ('\0' == *a[0][1][0].a && 0 == a[0][1][0].s && 0 == a[0][1][0].c); + assert ('\0' == *a[0][1][1].a && 0 == a[0][1][1].s && 0 == a[0][1][1].c); + + assert ('\0' == *a[1][0][0].a && 0 == a[1][0][0].s && 0 == a[1][0][0].c); + assert ('\0' == *a[1][0][1].a && '\0' == *a[1][0][1].s && 0 == a[1][0][1].c); + assert ('\0' == *a[1][1][0].a && 0 == a[1][1][0].s && 0 == a[1][1][0].c); + assert ('\0' == *a[1][1][1].a && 0 == a[1][1][1].s && 0 == a[1][1][1].c); + } + + { + const struct S a[2][2][2] = { + { }, + { + { { } }, + { { "", "" } } + } + }; + + assert ('\0' == *a[0][0][0].a && 0 == a[0][0][0].s); + assert ('\0' == *a[0][0][1].a && 0 == a[0][0][1].s); + assert ('\0' == *a[0][1][0].a && 0 == a[0][1][0].s); + assert ('\0' == *a[0][1][1].a && 0 == a[0][1][1].s); + + assert ('\0' == *a[1][0][0].a && 0 == a[1][0][0].s); + assert ('\0' == *a[1][0][1].a && 0 == a[1][0][1].s); + assert ('\0' == *a[1][1][0].a && '\0' == *a[1][1][0].s); + assert ('\0' == *a[1][1][1].a && 0 == a[1][1][1].s); + } + + { + const struct S a[2][2][2] = { + { }, + { + { { }, { } }, + { { }, { "", "", 0 } } + } + }; + + assert ('\0' == *a[0][0][0].a && 0 == a[0][0][0].s); + assert ('\0' == *a[0][0][1].a && 0 == a[0][0][1].s); + assert ('\0' == *a[0][1][0].a && 0 == a[0][1][0].s); + assert ('\0' == *a[0][1][1].a && 0 == a[0][1][1].s); + + assert ('\0' == *a[1][0][0].a && 0 == a[1][0][0].s); + assert ('\0' == *a[1][0][1].a && 0 == a[1][0][1].s); + assert ('\0' == *a[1][1][0].a && 0 == a[1][1][0].s); + assert ('\0' == *a[1][1][1].a && '\0' == *a[1][1][1].s); + } + + { + const struct S a[2][2][2] = { + { + { { { 0 }, 0, 0 }, { { 0 } , 0, 0 } }, + { { { 0 }, 0, 0 }, { { 0 } , 0, 0 } }, + }, + { + { { { 0 }, 0, 0 }, { { 0 } , 0, 0 } }, + { { }, { "", "", 0 } } + } + }; + + assert ('\0' == *a[0][0][0].a && 0 == a[0][0][0].s); + assert ('\0' == *a[0][0][1].a && 0 == a[0][0][1].s); + assert ('\0' == *a[0][1][0].a && 0 == a[0][1][0].s); + assert ('\0' == *a[0][1][1].a && 0 == a[0][1][1].s); + + assert ('\0' == *a[1][0][0].a && 0 == a[1][0][0].s); + assert ('\0' == *a[1][0][1].a && 0 == a[1][0][1].s); + assert ('\0' == *a[1][1][0].a && 0 == a[1][1][0].s); + assert ('\0' == *a[1][1][1].a && '\0' == *a[1][1][1].s); + } +} + +// { dg-final { scan-tree-dump-not "abort" "optimized" } } diff --git a/gcc/testsuite/g++.dg/abi/mangle73.C b/gcc/testsuite/g++.dg/abi/mangle73.C new file mode 100644 index 0000000..2a5322a --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle73.C @@ -0,0 +1,96 @@ +// { dg-do compile { target c++2a } } + +struct A +{ + char a[2][2]; +}; + +template <A> struct B { }; + +typedef B<A{ { { 0, 0 }, { 0, 0 } } }> AZZZZ; +typedef B<A{ { { 0, 0 }, { 0 } } }> AZZZ_; +typedef B<A{ { { 0, 0 } } }> AZZ__; +typedef B<A{ { { 0 } } }> AZ___; +typedef B<A{ { { } } }> A____; + +typedef B<A{ { { "" }, { "" } } }> AS_S_; +typedef B<A{ { { "" }, { 0, 0 } } }> AS_ZZ; +typedef B<A{ { { "" }, { 0 } } }> AS_Z_; +typedef B<A{ { { "" } } }> AS___; + + +// Verify that the types mangle the same. +void a_zzzz (AZZZZ) { } +// { dg-final { scan-assembler "_Z6a_zzzz1BIXtl1AEEE" } } + +void a_zzz_ (AZZZ_) { } +// { dg-final { scan-assembler "_Z6a_zzz_1BIXtl1AEEE" } } + +void a_zz__ (AZZ__) { } +// { dg-final { scan-assembler "_Z6a_zz__1BIXtl1AEEE" } } + +void a_z___ (AZ___) { } +// { dg-final { scan-assembler "_Z6a_z___1BIXtl1AEEE" } } + +void a_____ (A____) { } +// { dg-final { scan-assembler "_Z6a_____1BIXtl1AEEE" } } + +void a_s_s_ (AS_S_) { } +// { dg-final { scan-assembler "_Z6a_s_s_1BIXtl1AEEE" } } + +void a_s_zz (AS_ZZ) { } +// { dg-final { scan-assembler "_Z6a_s_zz1BIXtl1AEEE" } } + +void a_s_z_ (AS_Z_) { } +// { dg-final { scan-assembler "_Z6a_s_z_1BIXtl1AEEE" } } + +void a_s___ (AS___) { } +// { dg-final { scan-assembler "_Z6a_s___1BIXtl1AEEE" } } + + +struct C +{ + struct { const char a[2][2], *p; } a[2]; +}; + +template <C> struct D { }; + +typedef D<C{{{{{ 0, 0 }, { 0, 0 }}, 0 }, {{{ 0, 0 }, { 0, 0 }}, 0 }}}> DZZZZZZZZZZ; +typedef D<C{{{{{ 0, 0 }, { 0, 0 }}, 0 }, {{{ 0, 0 }, { 0, 0 }}}}}> DZZZZZZZZZ_; +typedef D<C{{{{{ 0, 0 }, { 0, 0 }}, 0 }, {{{ 0, 0 }, { 0 }}}}}> DZZZZZZZZ__; +typedef D<C{{{{{ 0, 0 }, { 0, 0 }}, 0 }, {{{ 0, 0 } }}}}> DZZZZZZZ___; +typedef D<C{{{{{ 0, 0 }, { 0, 0 }}, 0 }, {{{ 0 } }}}}> DZZZZZZ____; +typedef D<C{{{{{ 0, 0 }, { 0, 0 }}, 0 }}}> DZZZZZ_____; +typedef D<C{{{{{ 0, 0 }, { 0, 0 }}}}}> DZZZZ______; +typedef D<C{{{{{ 0, 0 }, { 0 }}}}}> DZZZ_______; +typedef D<C{{{{{ 0, 0 }}}}}> DZZ________; +typedef D<C{{{{{ 0 }}}}}> DZ_________; +typedef D<C{ }> D__________; + +typedef D<C{{{{{ "" }, { "" }}, 0 }, {{{ "" }, { "" }}, 0 }}}> DS_S_ZS_S_Z; + +void d_zzzzzzzzzz (DZZZZZZZZZZ) { } +// { dg-final { scan-assembler "_Z12d_zzzzzzzzzz1DIXtl1CEEE" } } +void d_zzzzzzzzz_ (DZZZZZZZZZ_) { } +// { dg-final { scan-assembler "_Z12d_zzzzzzzzz_1DIXtl1CEEE" } } +void d_zzzzzzzz__ (DZZZZZZZZ__) { } +// { dg-final { scan-assembler "_Z12d_zzzzzzzz__1DIXtl1CEEE" } } +void d_zzzzzzz___ (DZZZZZZZ___) { } +// { dg-final { scan-assembler "_Z12d_zzzzzzz___1DIXtl1CEEE" } } +void d_zzzzzz____ (DZZZZZZ____) { } +// { dg-final { scan-assembler "_Z12d_zzzzzz____1DIXtl1CEEE" } } +void d_zzzzz_____ (DZZZZZ_____) { } +// { dg-final { scan-assembler "_Z12d_zzzzz_____1DIXtl1CEEE" } } +void d_zzzz______ (DZZZZ______) { } +// { dg-final { scan-assembler "_Z12d_zzzz______1DIXtl1CEEE" } } +void d_zzz_______ (DZZZ_______) { } +// { dg-final { scan-assembler "_Z12d_zzz_______1DIXtl1CEEE" } } +void d_zz________ (DZZ________) { } +// { dg-final { scan-assembler "_Z12d_zz________1DIXtl1CEEE" } } +void d_z_________ (DZ_________) { } +// { dg-final { scan-assembler "_Z12d_z_________1DIXtl1CEEE" } } +void d___________ (D__________) { } +// { dg-final { scan-assembler "_Z12d___________1DIXtl1CEEE" } } + +void d_s_s_zs_s_z (DS_S_ZS_S_Z) { } +// { dg-final { scan-assembler "_Z12d_s_s_zs_s_z1DIXtl1CEEE" } } diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class23.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class23.C new file mode 100644 index 0000000..ab9e80f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class23.C @@ -0,0 +1,102 @@ +// PR c++/90947 - Simple lookup table of array of strings is miscompiled +// Test to verify that the same specializations on non-type template +// parameters of class types are in fact treated as the same. Unlike +// nontype-class15.C which involves only one-dimensional arrays this +// test involves arrays of arrays and arrays of structs. +// { dg-do compile { target c++2a } } + +struct AA3 +{ + const char a[2][2][2]; +}; + +template <AA3> struct BAA3 { }; + +// Redeclare the same variable using different initialization forms +// of the same constant to verify that they are in fact all recognized +// as the same. +extern BAA3<AA3{{{ "", "" }, { "", "" }}}> baa3; +extern BAA3<AA3{{{ "", "" }, { "", { 0, 0 } }}}> baa3; +extern BAA3<AA3{{{ "", "" }, { "", { 0 } }}}> baa3; +extern BAA3<AA3{{{ "", "" }, { "", {} }}}> baa3; +extern BAA3<AA3{{{ "", "" }, { "" }}}> baa3; +extern BAA3<AA3{{{ "", "" }, { { 0, 0 } }}}> baa3; +extern BAA3<AA3{{{ "", "" }, { { 0 } }}}> baa3; +extern BAA3<AA3{{{ "", "" }, { {} }}}> baa3; +extern BAA3<AA3{{{ "", "" }, { }}}> baa3; +extern BAA3<AA3{{{ "", "" }}}> baa3; +extern BAA3<AA3{{{ "", { 0, 0 } }}}> baa3; +extern BAA3<AA3{{{ "", { 0 } }}}> baa3; +extern BAA3<AA3{{{ "", {} }}}> baa3; +extern BAA3<AA3{{{ "" }}}> baa3; +extern BAA3<AA3{{{ { 0, 0 } }}}> baa3; +extern BAA3<AA3{{{ { 0 } }}}> baa3; +extern BAA3<AA3{{{ {} }}}> baa3; +extern BAA3<AA3{{{ }}}> baa3; +extern BAA3<AA3{{ }}> baa3; +extern BAA3<AA3{ }> baa3; + +extern BAA3<AA3{{{ "", "" }, { "", "1" }}}> baa3_1; +extern BAA3<AA3{{{ "", "" }, { "", { '1', 0 } }}}> baa3_1; +extern BAA3<AA3{{{ "", "" }, { "", { '1' } }}}> baa3_1; + +extern BAA3<AA3{{{ "", "" }, { "1", {} }}}> baa3_2; +extern BAA3<AA3{{{ "", "" }, { "1" }}}> baa3_2; +extern BAA3<AA3{{{ "", "" }, { { '1', 0 } }}}> baa3_2; +extern BAA3<AA3{{{ "", "" }, { { '1' } }}}> baa3_2; + +extern BAA3<AA3{{{ "", "1" }}}> baa3_3; +extern BAA3<AA3{{{ "", { '1', 0 } }}}> baa3_3; +extern BAA3<AA3{{{ "", { '1' } }}}> baa3_3; + +extern BAA3<AA3{{{ "1" }}}> baa3_4; +extern BAA3<AA3{{{ { '1', 0 } }}}> baa3_4; +extern BAA3<AA3{{{ { '1' } }}}> baa3_4; + +struct AS2 +{ + struct S { const char a[2], *p; } a[2]; +}; + +template <AS2> struct BAS2 { }; + +extern BAS2<AS2{{{ "", 0 }, { "", 0 }}}> bas2; +extern BAS2<AS2{{{ "", 0 }, { {}, 0 }}}> bas2; +extern BAS2<AS2{{{ "", 0 }, { "" }}}> bas2; +extern BAS2<AS2{{{ "", 0 }, { {} }}}> bas2; +extern BAS2<AS2{{{ "", 0 }, { }}}> bas2; +extern BAS2<AS2{{{ "", 0 }}}> bas2; +extern BAS2<AS2{{{ {}, 0 }}}> bas2; +extern BAS2<AS2{{{ "" }}}> bas2; +extern BAS2<AS2{{{ {} }}}> bas2; +extern BAS2<AS2{{{ }}}> bas2; +extern BAS2<AS2{{ }}> bas2; +extern BAS2<AS2{ }> bas2; + +struct AS2_2 +{ + struct S { const char a[2], *p; } a[2][2]; +}; + +template <AS2_2> struct BAS2_2 { }; + +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 } }, { { "", 0 }, { "", 0 }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 } }, { { "", 0 }, { "" }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 } }, { { "", 0 }, { {} }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 } }, { { "", 0 }, { }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 } }, { { "", 0 } }}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 } }, { { "" } }}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 } }, { { {} } }}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 } }, { { }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 } }, { }}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "", 0 }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { "" }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { {} }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }, { }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "", 0 }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ "" }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ {} }}}}> b2_2; +extern BAS2_2<AS2_2{{{{ }}}}> b2_2; +extern BAS2_2<AS2_2{{{ }}}> b2_2; +extern BAS2_2<AS2_2{{ }}> b2_2; +extern BAS2_2<AS2_2{ }> b2_2; diff --git a/gcc/testsuite/g++.dg/init/array53.C b/gcc/testsuite/g++.dg/init/array53.C new file mode 100644 index 0000000..2bf4805 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/array53.C @@ -0,0 +1,33 @@ +// PR c++/90947 - Simple lookup table of array of strings is miscompiled +// Verify that initializers for arrays of elements of a class type with +// "unusual" data members are correctly recognized as non-zero. +// { dg-do compile } +// { dg-options "-O1 -fdump-tree-optimized" } + +struct S +{ + const char *p; + static int i; + enum { e }; + typedef int X; + int: 1, b:1; + union { + int c; + }; + const char *q; +}; + +void f (void) +{ + const struct S a[2] = + { + { /* .p = */ "", /* .b = */ 0, /* .c = */ 0, /* .q = */ "" }, + { /* .p = */ "", /* .b = */ 0, /* .c = */ 0, /* .q = */ "" } + }; + + if (!a[0].p || *a[0].p || !a[0].q || *a[0].q + || !a[1].p || *a[1].p || !a[1].q || *a[1].q) + __builtin_abort (); +} + +// { dg-final { scan-tree-dump-not "abort" "optimized" } } @@ -11376,6 +11376,73 @@ initializer_each_zero_or_onep (const_tree expr) } } +/* Given an initializer INIT for a TYPE, return true if INIT is zero + so that it can be replaced by value initialization. This function + distinguishes betwen empty strings as initializers for arrays and + for pointers (which make it return false). */ + +bool +type_initializer_zero_p (tree type, tree init) +{ + if (type == error_mark_node || init == error_mark_node) + return false; + + STRIP_NOPS (init); + + if (POINTER_TYPE_P (type)) + return TREE_CODE (init) != STRING_CST && initializer_zerop (init); + + if (TREE_CODE (init) != CONSTRUCTOR) + return initializer_zerop (init); + + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree elt_type = TREE_TYPE (type); + elt_type = TYPE_MAIN_VARIANT (elt_type); + if (elt_type == char_type_node) + return initializer_zerop (init); + + tree elt_init; + unsigned HOST_WIDE_INT i; + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, elt_init) + if (!type_initializer_zero_p (elt_type, elt_init)) + return false; + return true; + } + + if (TREE_CODE (type) != RECORD_TYPE) + return initializer_zerop (init); + + tree fld = TYPE_FIELDS (type); + + tree fld_init; + unsigned HOST_WIDE_INT i; + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, fld_init) + { + /* Advance to the next member, skipping over everything that + canot be initialized (including unnamed bit-fields). */ + while (TREE_CODE (fld) != FIELD_DECL + || DECL_ARTIFICIAL (fld) + || (DECL_BIT_FIELD (fld) && !DECL_NAME (fld))) + { + fld = DECL_CHAIN (fld); + if (!fld) + return true; + continue; + } + + tree fldtype = TREE_TYPE (fld); + if (!type_initializer_zero_p (fldtype, fld_init)) + return false; + + fld = DECL_CHAIN (fld); + if (!fld) + break; + } + + return true; +} + /* Check if vector VEC consists of all the equal elements and that the number of elements corresponds to the type of VEC. The function returns first element of the vector @@ -4623,6 +4623,12 @@ extern tree first_field (const_tree); extern bool initializer_zerop (const_tree, bool * = NULL); extern bool initializer_each_zero_or_onep (const_tree); +/* Analogous to initializer_zerop but also examines the type for + which the initializer is being used. Unlike initializer_zerop, + considers empty strings to be zero initializers for arrays and + non-zero for pointers. */ +extern bool type_initializer_zero_p (tree, tree); + extern wide_int vector_cst_int_elt (const_tree, unsigned int); extern tree vector_cst_elt (const_tree, unsigned int); |