From: Martin Sebor Date: Thu, 5 Mar 2020 01:19:31 +0000 (-0700) Subject: PR c++/90938 - Initializing array with {1} works but not {0} X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=cb2409c60aeff498064346f85165531a3bbead14;p=gcc.git PR c++/90938 - Initializing array with {1} works but not {0} gcc/cp/ChangeLog: PR c++/90938 * tree.c (type_initializer_zero_p): Fail for structs initialized with non-structs. gcc/testsuite/ChangeLog: PR c++/90938 * g++.dg/init/array55.C: New test. * g++.dg/init/array56.C: New test. * g++.dg/cpp2a/nontype-class33.C: New test. --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 254e5a31096..f01563e96fc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2020-03-04 Martin Sebor + + PR c++/90938 + * tree.c (type_initializer_zero_p): Fail for structs initialized + with non-structs. + 2020-03-04 Jason Merrill PR c++/90432 diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 3fc6287d566..a412345e3bf 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5727,7 +5727,15 @@ type_initializer_zero_p (tree type, tree init) return TREE_CODE (init) != STRING_CST && initializer_zerop (init); if (TREE_CODE (init) != CONSTRUCTOR) - return initializer_zerop (init); + { + /* A class can only be initialized by a non-class type if it has + a ctor that converts from that type. Such classes are excluded + since their semantics are unknown. */ + if (RECORD_OR_UNION_TYPE_P (type) + && !RECORD_OR_UNION_TYPE_P (TREE_TYPE (init))) + return false; + return initializer_zerop (init); + } if (TREE_CODE (type) == ARRAY_TYPE) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 468f7673e29..95c8710800b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2020-03-04 Martin Sebor + + PR c++/90938 + * g++.dg/init/array55.C: New test. + * g++.dg/init/array56.C: New test. + * g++.dg/cpp2a/nontype-class33.C: New test. + 2020-03-04 Martin Sebor PR tree-optimization/93986 diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class33.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class33.C new file mode 100644 index 00000000000..1b9dfb88918 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class33.C @@ -0,0 +1,36 @@ +// PR c++/90938 - Initializing array with {1} works, but not {0} +// { dg-do compile { target c++2a } } +// { dg-options "-Wall" } + +struct A { int i; }; +struct B { A a[2]; }; + +static const constexpr A a0 = { 0 }; +static const constexpr A a_ = { }; + +template struct X { }; + +typedef X XB; +typedef X XB; +typedef X XB; +typedef X XB; +typedef X XB; +typedef X XB; +typedef X XB; +typedef X XB; +typedef X XB; + + +struct C { constexpr C () = default; }; +struct D { C c[2]; }; + +static const constexpr C c_ = { }; + +template struct Y { }; + +typedef Y YD; +typedef Y YD; +typedef Y YD; +typedef Y YD; +typedef Y YD; +typedef Y YD; diff --git a/gcc/testsuite/g++.dg/init/array55.C b/gcc/testsuite/g++.dg/init/array55.C new file mode 100644 index 00000000000..70fb183b897 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/array55.C @@ -0,0 +1,27 @@ +/* PR c++/90938 - Initializing array with {1} works, but not {0} + { dg-do compile { target c++11 } } */ + +struct A +{ + A () = delete; + A (int) = delete; +}; + +A a_[] = { 0 }; // { dg-error "use of deleted function 'A::A\\\(int\\\)'" } + +A a1[1] = { 0 }; // { dg-error "use of deleted function 'A::A\\\(int\\\)'" } + + +struct B +{ + B () = delete; + B (int) = delete; + B (long); +}; + +B b_[] = { 0 }; // { dg-error "use of deleted function 'B::B\\\(int\\\)'" } + +B b1[1] = { 0 }; // { dg-error "use of deleted function 'B::B\\\(int\\\)'" } + +B b2[] = { 0L }; +B b3[1] = { 0L }; diff --git a/gcc/testsuite/g++.dg/init/array56.C b/gcc/testsuite/g++.dg/init/array56.C new file mode 100644 index 00000000000..63e16663ec1 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/array56.C @@ -0,0 +1,107 @@ +/* PR c++/90938 - Initializing array with {1} works, but not {0} + { dg-do compile { target c++11 } } + { dg-options "-O -Wall -fdump-tree-optimized" } */ + +#define assert(e) \ + ((e) ? (void)0 \ + : (__builtin_printf ("assertion failed on line %i: %s\n", \ + __LINE__, #e), \ + __builtin_abort ())) + +namespace A { + +struct X +{ + X () = default; + X (int n) : n (n + 1) { } + int n; +}; + +static_assert (__is_trivial (X), "X is trivial"); + +static void test () +{ + { + X x[] { 0 }; + assert (1 == x->n); + } + + { + X x[1] { 0 }; + assert (1 == x->n); // fails + } + + { + X x[2] { 0 }; + assert (1 == x[0].n && 0 == x[1].n); // fails + } + + { + X x[] { 1, 0 }; + assert (2 == x[0].n && 1 == x[1].n); // passes + } + + { + X x[2] { 1, 0 }; + assert (2 == x[0].n && 1 == x[1].n); // fails + } +} + +} + +namespace B { + +struct X +{ + X () = default; + X (int *p) : p (p ? p : new int (1)) { } + int *p; +}; + +static_assert (__is_trivial (X), "X is trivial"); + +static void test () +{ + X x[1] { nullptr }; + assert (*x->p == 1); // fails + + X y[1] { 0 }; + assert (*y->p == 1); // fails +} + +} + +namespace C { + +static const char *vector_swizzle (int vecsize, int index) +{ + static const char *swizzle[4][4] = + { + { ".x", ".y", ".z", ".w" }, + { ".xy", ".yz", ".zw", nullptr }, + { ".xyz", ".yzw", nullptr, nullptr }, + { "", nullptr, nullptr, nullptr }, + }; + + assert (vecsize >= 1 && vecsize <= 4); + assert (index >= 0 && index < 4); + assert (swizzle[vecsize - 1][index]); + + return swizzle[vecsize - 1][index]; +} + +static void test () +{ + assert (!*vector_swizzle(4, 0)); +} + +} + +int main () +{ + A::test (); + B::test (); + C::test (); +} + +// { dg-final { scan-tree-dump-not "abort" "optimized" } }