Message ID | ZpkPaiT0/JrwtKs0@tucnak |
---|---|
State | New |
Headers | show |
Series | c++: Add [dcl.init.aggr] examples to testsuite | expand |
On 7/18/24 8:49 AM, Jakub Jelinek wrote: > Hi! > > When working on the #embed optimization support, I went recently through > all of reshape_init_r* and today I read in detail all the P3106R1 changes > and I believe we implement it that way for years. > To double check that, I've added tests with the current [dcl.init.aggr] > examples but tested in all the languages from C++98 to C++26, of course > guarded as needed for constructs which require newer versions of C++. > The examples come in two tests, one is a runtime test for the non-erroneous > examples, the other is a compile time test for the diagnostics. > The former one includes mostly intact examples with runtime checking (both > to test what is written in the section exactly and to test at least > something with C++98) and then when useful also adds constexpr tests with > static_asserts for C++11 and later. > > Tested on x86_64-linux and i686-linux with > GXX_TESTSUITE_STDS=98,11,14,17,20,23,26 make check-g++ RUNTESTFLAGS='dg.exp=aggr-init*.C' > Ok for trunk? > > Also tested on GCC 11 branch with > GXX_TESTSUITE_STDS=98,11,14,17,20,2b make check-g++ RUNTESTFLAGS='dg.exp=aggr-init*.C' > where just the " is a GCC extension" part of one error is left out, > otherwise it passes the same, ditto with clang 14 (of course with different > diagnostics, but verified it emits diagnostics on the right lines), so I > believe we can claim implementation of this DR paper, either in all versions > or at least in GCC 11+. OK, thanks. And yes, the intention of P3106 was to better describe the behavior of existing implementations. > 2024-07-18 Jakub Jelinek <jakub@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 >
--- 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 +}