2024-07-18 Jakub Jelinek <ja...@redhat.com>
PR c++/114460
* g++.dg/cpp26/aggr-init1.C: New test.
* g++.dg/cpp26/aggr-init2.C: New test.
--- gcc/testsuite/g++.dg/cpp26/aggr-init1.C.jj 2024-07-18 12:25:03.767375097
+0200
+++ gcc/testsuite/g++.dg/cpp26/aggr-init1.C 2024-07-18 14:27:48.324677997
+0200
@@ -0,0 +1,341 @@
+// P3106R1 - Clarifying rules for brace elision in aggregate initialization
+// Examples from C++26 [dcl.init.aggr]
+// { dg-do run }
+
+extern "C" void abort ();
+
+namespace N1 {
+#if __cpp_designated_initializers >= 201707L
+ struct C {
+ union {
+ int a;
+ const char* p;
+ };
+ int x;
+ } c = { .a = 1, .x = 3 };
+ constexpr C c2 = { .a = 1, .x = 3 };
+ static_assert (c2.a == 1 && c2.x == 3, "");
+#endif
+
+ bool
+ test ()
+ {
+#if __cpp_designated_initializers >= 201707L
+ return c.a == 1 && c.x == 3;
+#else
+ return true;
+#endif
+ }
+}
+
+namespace N2 {
+ struct A {
+ int x;
+ struct B {
+ int i;
+ int j;
+ } b;
+ } a = { 1, { 2, 3 } };
+
+#if __cplusplus >= 201703L
+ struct base1 { int b1, b2 = 42; };
+ struct base2 {
+ base2 () { b3 = 42; }
+ int b3;
+ };
+ struct derived : base1, base2 {
+ int d;
+ };
+
+ derived d1 { { 1, 2 }, {}, 4 };
+ derived d2 { {}, {}, 4 };
+#endif
+
+ bool
+ test ()
+ {
+ return a.x == 1 && a.b.i == 2 && a.b.j == 3
+#if __cplusplus >= 201703L
+ && d1.b1 == 1 && d1.b2 == 2 && d1.b3 == 42 && d1.d == 4
+ && d2.b1 == 0 && d2.b2 == 42 && d2.b3 == 42 && d2.d == 4
+#endif
+ ;
+ }
+
+#if __cplusplus >= 201703L
+ constexpr A a2 = { 1, { 2, 3 } };
+ static_assert (a2.x == 1 && a2.b.i == 2 && a2.b.j == 3, "");
+
+ struct base3 {
+#if __cplusplus >= 202002L
+ constexpr base3 () { b3 = 42; }
+#else
+ constexpr base3 () : b3 (42) {}
+#endif
+ int b3;
+ };
+ struct derived2 : base1, base3 {
+ int d;
+ };
+ constexpr derived2 d3 { { 1, 2}, {}, 4};
+ constexpr derived2 d4 { {}, {}, 4 };
+ static_assert (d3.b1 == 1 && d3.b2 == 2 && d3.b3 == 42 && d3.d == 4, "");
+ static_assert (d4.b1 == 0 && d4.b2 == 42 && d4.b3 == 42 && d4.d == 4, "");
+#endif
+}
+
+namespace N3 {
+#if __cplusplus >= 201402L
+ struct S { int a; const char *b; int c; int d = b[a]; };
+ S ss = { 1, "asdf" };
+ constexpr S ss2 = { 1, "asdf" };
+ static_assert (ss2.a == 1 && ss2.b[0] == 'a' && ss2.b[3] == 'f' && ss2.c == 0 && ss2.d
== 's', "");
+
+#if __cpp_designated_initializers >= 201707L
+ struct string { int s = -42; };
+ struct A {
+ string a;
+ int b = 42;
+ int c = -1;
+ };
+ static_assert (A { .c = 21 }.a.s == -42 && A { .c = 21 }.b == 42 && A { .c = 21 }.c ==
21, "");
+#endif
+#endif
+
+ bool
+ test ()
+ {
+#if __cplusplus >= 201402L
+ return ss.a == 1 && __builtin_strcmp (ss.b, "asdf") == 0 && ss.c == 0 &&
ss.d == 's';
+#else
+ return true;
+#endif
+ }
+}
+
+namespace N4 {
+ int x[] = { 1, 3, 5 };
+
+ bool
+ test ()
+ {
+ return sizeof (x) == 3 * sizeof (int) && x[0] == 1 && x[1] == 3 && x[2] ==
5;
+ }
+
+#if __cplusplus >= 201103L
+ constexpr int x2[] = { 1, 3, 5 };
+ static_assert (sizeof (x2) == 3 * sizeof (int)
+ && x2[0] == 1 && x2[1] == 3 && x2[2] == 5, "");
+#endif
+}
+
+namespace N5 {
+ struct X { int i, j, k; };
+ X a[] = { 1, 2, 3, 4, 5, 6 };
+ X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } };
+
+ bool
+ test ()
+ {
+ return sizeof (a) == sizeof (b) && __builtin_memcmp (a, b, sizeof (a)) ==
0;
+ }
+
+#if __cplusplus >= 201103L
+ constexpr X a2[] = { 1, 2, 3, 4, 5, 6 };
+ constexpr X b2[2] = { { 1, 2, 3 }, { 4, 5, 6 } };
+ static_assert (sizeof (a2) == 2 * sizeof (X)
+ && a2[0].i == 1 && a2[0].j == 2 && a2[0].k == 3
+ && a2[1].i == 4 && a2[1].j == 5 && a2[1].k == 6, "");
+ static_assert (sizeof (b2) == 2 * sizeof (X)
+ && b2[0].i == 1 && b2[0].j == 2 && b2[0].k == 3
+ && b2[1].i == 4 && b2[1].j == 5 && b2[1].k == 6, "");
+#endif
+}
+
+namespace N7 {
+ struct A {
+ int i;
+ static int s;
+ int j;
+ int : 17;
+ int k;
+ } a = { 1, 2, 3 };
+
+ bool
+ test ()
+ {
+ return a.i == 1 && a.j == 2 && a.k == 3;
+ }
+
+#if __cplusplus >= 201103L
+ constexpr A a2 = { 1, 2, 3 };
+ static_assert (a2.i == 1 && a2.j == 2 && a2.k == 3, "");
+#endif
+}
+
+namespace N9 {
+ int x[2][2] = { 3, 1, 4, 2 };
+ float y[4][3] = {
+ { 1 }, { 2 }, { 3 }, { 4 }
+ };
+
+ bool
+ test ()
+ {
+ return x[0][0] == 3 && x[0][1] == 1 && x[1][0] == 4 && x[1][1] == 2
+ && y[0][0] == 1.f && y[0][1] == 0.f && y[0][2] == 0.f
+ && y[1][0] == 2.f && y[1][1] == 0.f && y[1][2] == 0.f
+ && y[2][0] == 3.f && y[2][1] == 0.f && y[2][2] == 0.f
+ && y[3][0] == 4.f && y[3][1] == 0.f && y[3][2] == 0.f;
+ }
+
+#if __cplusplus >= 201103L
+ constexpr int x2[2][2] = { 3, 1, 4, 2 };
+ constexpr float y2[4][3] = {
+ { 1 }, { 2 }, { 3 }, { 4 }
+ };
+ static_assert (x2[0][0] == 3 && x2[0][1] == 1 && x2[1][0] == 4 && x2[1][1] == 2,
"");
+ static_assert (y2[0][0] == 1.f && y2[0][1] == 0.f && y2[0][2] == 0.f, "");
+ static_assert (y2[1][0] == 2.f && y2[1][1] == 0.f && y2[1][2] == 0.f, "");
+ static_assert (y2[2][0] == 3.f && y2[2][1] == 0.f && y2[2][2] == 0.f, "");
+ static_assert (y2[3][0] == 4.f && y2[3][1] == 0.f && y2[3][2] == 0.f, "");
+#endif
+}
+
+namespace N10 {
+ struct S1 { int a, b; };
+ struct S2 { S1 s, t; };
+
+ S2 x[2] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ S2 y[2] = {
+ {
+ { 1, 2 },
+ { 3, 4 }
+ },
+ {
+ { 5, 6 },
+ { 7, 8 }
+ }
+ };
+
+ bool
+ test ()
+ {
+ return sizeof (x) == sizeof (y) && __builtin_memcmp (x, y, sizeof (x)) ==
0;
+ }
+
+#if __cplusplus >= 201103L
+ constexpr S2 x2[2] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ constexpr S2 y2[2] = { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } };
+ static_assert (x2[0].s.a == 1 && x2[0].s.b == 2 && x2[0].t.a == 3 && x2[0].t.b == 4,
"");
+ static_assert (x2[1].s.a == 5 && x2[1].s.b == 6 && x2[1].t.a == 7 && x2[1].t.b == 8,
"");
+ static_assert (y2[0].s.a == 1 && y2[0].s.b == 2 && y2[0].t.a == 3 && y2[0].t.b == 4,
"");
+ static_assert (y2[1].s.a == 5 && y2[1].s.b == 6 && y2[1].t.a == 7 && y2[1].t.b == 8,
"");
+#endif
+}
+
+namespace N12 {
+ float y[4][3] = {
+ { 1, 3, 5 },
+ { 2, 4, 6 },
+ { 3, 5, 7 },
+ };
+ float y2[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
+
+ bool
+ test ()
+ {
+ for (int i = 0; i < 4; ++i)
+ for (int j = 0; j < 3; ++j)
+ if (y[i][j] != (i == 3 ? 0.f : (float) (i + 1 + j * 2))
+ || y[i][j] != y2[i][j])
+ return false;
+ return true;
+ }
+
+#if __cplusplus >= 201103L
+ constexpr float y3[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, };
+ constexpr float y4[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };
+ static_assert (y3[0][0] == 1.f && y3[0][1] == 3.f && y3[0][2] == 5.f, "");
+ static_assert (y3[1][0] == 2.f && y3[1][1] == 4.f && y3[1][2] == 6.f, "");
+ static_assert (y3[2][0] == 3.f && y3[2][1] == 5.f && y3[2][2] == 7.f, "");
+ static_assert (y3[3][0] == 0.f && y3[3][1] == 0.f && y3[3][2] == 0.f, "");
+ static_assert (y4[0][0] == 1.f && y4[0][1] == 3.f && y4[0][2] == 5.f, "");
+ static_assert (y4[1][0] == 2.f && y4[1][1] == 4.f && y4[1][2] == 6.f, "");
+ static_assert (y4[2][0] == 3.f && y4[2][1] == 5.f && y4[2][2] == 7.f, "");
+ static_assert (y4[3][0] == 0.f && y4[3][1] == 0.f && y4[3][2] == 0.f, "");
+#endif
+}
+
+namespace N13 {
+ bool
+ test ()
+ {
+ struct S { } s;
+ struct A {
+ S s1;
+ int i1;
+ S s2;
+ int i2;
+ S s3;
+ int i3;
+ } a = {
+ { },
+ 0,
+ s,
+ 0
+ };
+ return a.i1 == 0 && a.i2 == 0;
+ }
+}
+
+namespace N14 {
+ struct A {
+ int i;
+ operator int ();
+ };
+ struct B {
+ A a1, a2;
+ int z;
+ };
+ A a;
+ B b = { 4, a, a };
+ A::operator int () { return 42; }
+
+ bool
+ test ()
+ {
+ return b.a1.i == 4 && b.a2.i == 0 && b.z == 42;
+ }
+
+#if __cplusplus >= 201103L
+ struct A2 {
+ int i;
+ constexpr operator int () const { return 42; }
+ };
+ struct B2 {
+ A2 a1, a2;
+ int z;
+ };
+ constexpr A2 a2 = { 26 };
+ constexpr B2 b2 = { 4, a2, a2 };
+ static_assert (b2.a1.i == 4 && b2.a2.i == 26 && b2.z == 42, "");
+#endif
+}
+
+int
+main ()
+{
+ if (!N1::test ()
+ || !N2::test ()
+ || !N3::test ()
+ || !N4::test ()
+ || !N5::test ()
+ || !N7::test ()
+ || !N9::test ()
+ || !N10::test ()
+ || !N12::test ()
+ || !N13::test ()
+ || !N14::test ())
+ abort ();
+}
--- gcc/testsuite/g++.dg/cpp26/aggr-init2.C.jj 2024-07-18 13:03:47.980808005
+0200
+++ gcc/testsuite/g++.dg/cpp26/aggr-init2.C 2024-07-18 14:31:20.930947591
+0200
@@ -0,0 +1,67 @@
+// P3106R1 - Clarifying rules for brace elision in aggregate initialization
+// Examples from C++26 [dcl.init.aggr]
+// { dg-do compile }
+
+namespace N1 {
+#if __cpp_designated_initializers >= 201707L
+ struct C {
+ union {
+ int a;
+ const char* p;
+ };
+ int x;
+ };
+ constexpr C c2 = { .a = 42.0, .x = 3 }; // { dg-error "narrowing conversion of
'4.2e\\\+1' from 'double' to 'int'" "" { target c++20 } }
+#endif
+}
+
+namespace N6 {
+#if __cplusplus >= 201103L
+ struct S {
+ int y[] = { 0 }; // { dg-error "ISO C\\\+\\\+ forbids flexible array member 'y'"
"" { target c++11 } }
+ // { dg-error "flexible array member 'N6::S::y' in an otherwise empty
'struct N6::S' is a GCC extension" "" { target c++11 } .-1 }
+ // { dg-error "initializer for flexible array member 'int N6::S::y
\\\[\\\]'" "" { target c++11 } .-2 }
+ };
+#endif
+}
+
+namespace N8 {
+#if __cplusplus >= 201402L
+ struct A;
+ extern A a;
+ struct A {
+ const A &a1 { A { a, a } };
+ const A &a2 { A { } }; // { dg-error "default member initializer for 'N8::A::a2' required
before the end of its enclosing class" "" { target c++14 } }
+ }; // { dg-error "invalid initialization of reference of type 'const
N8::A\\\&' from expression of type '<brace-enclosed initializer list>'" "" { target
c++14 } .-1 }
+ A a { a, a };
+
+ struct B {
+ int n = B {}.n; // { dg-error "default member initializer for 'N8::B::n'
required before the end of its enclosing class" "" { target c++14 } }
+ };
+
+ struct C;
+ extern C c;
+ struct C {
+ const C &c1 { C { c, c } };
+ const C &c2 { C { c, c } };
+ };
+ C c { c, c };
+#endif
+}
+
+namespace N11 {
+ char cv[4] = { 'a', 's', 'd', 'f', 0 }; // { dg-error "too many initializers
for 'char \\\[4\\\]'" }
+}
+
+namespace N15 {
+ union u { int a; const char* b; };
+ u a = { 1 };
+ u b = a;
+ u c = 1; // { dg-error "conversion from 'int' to
non-scalar type 'N15::u' requested" }
+ u d = { 0, "asdf" }; // { dg-error "too many initializers for
'N15::u'" }
+ u e = { "asdf" }; // { dg-error "invalid conversion from 'const
char\\\*' to 'int'" }
+#if __cpp_designated_initializers >= 201707L
+ u f = { .b = "asdf" };
+ u g = { .a = 1, .b = "asdf" }; // { dg-error "too many initializers for 'N15::u'"
"" { target c++20 } }
+#endif
+}
Jakub