On Sat, Jul 25, 2026 at 01:04:35PM +0200, Jakub Jelinek wrote:
> On Fri, Jul 24, 2026 at 09:41:34PM +0200, Jakub Jelinek wrote:
> > On Fri, Jul 24, 2026 at 03:15:25PM -0400, Jason Merrill wrote:
> > > Ah, good point. It might make sense to do all the lookups in a first pass
> > > and change the indices to the FIELD_DECLs (and remove the assert/update
> > > the
> > > comment that we don't do this)?
> >
> > I can try. That would just save the lookup during recursion, but not e.g.
> > the
> > discovery of which base class (if any) it belongs to, that will need to be
> > done again and again during recursion.
>
> Actually, I think changing d->cur->index or new_end->index is wrong.
> If we have say
> struct A { int a, b; };
> struct B : A { int c; };
> struct C { int a, b, d; };
> struct D : C { int e, c; };
> void foo (B, A);
> void foo (D, C);
> void bar () { foo ({ .a = 1, .b = 2, .c = 3 }, { .d = 1 }); }
> then it first checks if calling the first foo overload is viable. Now,
> d->cur points to the CONSTRUCTOR_ELTS of the original shared CONSTRUCTOR
> with IDENTIFIER_NODE a, b, c. If reshape_init_class modifies it in place
> to avoid the extra lookups (see incremental patch below), it will work
> just fine during that call, we later found out the second argument is
> not suitable for A, so continue with the next overload, but at this point
> we have a CONSTRUCTOR which has been modified, doesn't have IDENTIFIER_NODE
> indices but FIELD_DECLs from A. While the second overload is usable in
> this case, we think it is not appropriate.
> Will add this to the testsuite.
Added to testsuite (also the other testcases from the thread).
I think if we really wanted this lookup caching, either we'd need to create
a vector, store the cached lookup results in there and pass it around
to recursive calls, or we could create a vector, store there the original
values, change the *->index to the lookup results and ensure (through RAII,
we have way too many returns) to revert this back afterwards.
> > > That's what I was thinking, yes.
> >
> > Ok.
>
> Done with the changes, now to cover it in the testsuite.
Here is an updated patch which supports { { 1 }, .x = 2 } as an
extension for C++ 20 to 26 with pedwarn -Wc++-29-extensions, but
not the above caching.
Bootstrapped/regtested on x86_64-linux and i686-linux.
2026-07-27 Jakub Jelinek <[email protected]>
PR c++/125989
gcc/c-family/
* c-cppbuiltin.cc (c_cpp_builtins): Predefine
__cpp_designated_initializers to 202606 instead of 201707 for
C++29.
gcc/cp/
* parser.cc: Implement C++29 P2287R6 - Designated-initializers for
Base Classes.
(cp_parser_initializer_list): For C++29, allow non-designated clauses
followed by designated ones, provided designators are identifiers.
For C++20-26, allow that as a pedwarned about extension but use the
C++20 wording in that case.
* decl.cc (reshape_init_class): Diagnose non-designated clause not
appertaining to base class followed by designated clause for C++ >= 20.
For C++29, if get_class_binding for designator is unsuccessful, use
lookup_member afterwards and handle the case where the lookup succeeds
for some member of a base class through recursive reshape_init_class.
gcc/testsuite/
* g++.dg/cpp/embed-14.C: Expect different diagnostics for C++29 and
sometimes for C++20-C++26 too.
* g++.dg/cpp2a/desig2.C: Likewise.
* g++.dg/cpp2a/desig13.C: Likewise.
* g++.dg/cpp2a/desig20.C: Likewise.
* g++.dg/ext/desig4.C: Likewise.
* g++.dg/parse/pr43765.C: Likewise.
* g++.dg/cpp29/feat-cxx29.C: Expect different value of
__cpp_designated_initializers for C++29.
* g++.dg/cpp29/desig1.C: New test.
* g++.dg/cpp29/desig2.C: New test.
* g++.dg/cpp29/desig3.C: New test.
* g++.dg/cpp29/desig4.C: New test.
* g++.dg/cpp29/desig5.C: New test.
* g++.dg/cpp29/desig6.C: New test.
* g++.dg/cpp29/desig7.C: New test.
* g++.dg/cpp29/desig8.C: New test.
* g++.dg/cpp29/desig9.C: New test.
* g++.dg/cpp29/desig10.C: New test.
* g++.dg/cpp29/desig11.C: New test.
* g++.dg/cpp29/desig12.C: New test.
* g++.dg/cpp29/desig13.C: New test.
* g++.dg/cpp29/desig14.C: New test.
* g++.dg/cpp29/desig15.C: New test.
* g++.dg/cpp29/desig16.C: New test.
--- gcc/c-family/c-cppbuiltin.cc.jj 2026-07-23 10:54:23.196712733 +0200
+++ gcc/c-family/c-cppbuiltin.cc 2026-07-25 12:29:16.269749175 +0200
@@ -1072,7 +1072,8 @@ c_cpp_builtins (cpp_reader *pfile)
/* Set feature test macros for C++20. */
cpp_define (pfile, "__cpp_init_captures=201803L");
cpp_define (pfile, "__cpp_generic_lambdas=201707L");
- cpp_define (pfile, "__cpp_designated_initializers=201707L");
+ if (cxx_dialect <= cxx26)
+ cpp_define (pfile, "__cpp_designated_initializers=201707L");
if (cxx_dialect <= cxx20)
cpp_define (pfile, "__cpp_constexpr=202002L");
cpp_define (pfile, "__cpp_constexpr_in_decltype=201711L");
@@ -1129,6 +1130,7 @@ c_cpp_builtins (cpp_reader *pfile)
{
/* Set feature test macros for C++29. */
cpp_define (pfile, "__cpp_pp_embed=202606L");
+ cpp_define (pfile, "__cpp_designated_initializers=202606L");
}
if (flag_concepts && cxx_dialect > cxx14)
cpp_define (pfile, "__cpp_concepts=202002L");
--- gcc/cp/parser.cc.jj 2026-07-23 10:54:23.202712656 +0200
+++ gcc/cp/parser.cc 2026-07-25 12:40:00.187078337 +0200
@@ -29406,13 +29406,35 @@ cp_parser_initializer_list (cp_parser* p
}
else if (cxx_dialect >= cxx20
&& first_designator != error_mark_node
- && (!first_designator != !designator))
+ && (!first_designator != !designator)
+ && (cxx_dialect < cxx29
+ || first_designator
+ || TREE_CODE (designator) != IDENTIFIER_NODE))
{
- error_at (loc, "either all initializer clauses should be designated "
- "or none of them should be");
- first_designator = error_mark_node;
+ if (cxx_dialect < cxx29
+ && !first_designator
+ && TREE_CODE (designator) == IDENTIFIER_NODE)
+ {
+ pedwarn (loc, OPT_Wc__29_extensions,
+ "either all initializer clauses should be "
+ "designated or none of them should be");
+ first_designator = designator;
+ }
+ else
+ {
+ if (cxx_dialect < cxx29
+ || TREE_CODE (first_designator
+ ? first_designator
+ : designator) != IDENTIFIER_NODE)
+ error_at (loc, "either all initializer clauses should be "
+ "designated or none of them should be");
+ else
+ error_at (loc, "designated initializer clause should not "
+ "be followed by non-designated");
+ first_designator = error_mark_node;
+ }
}
- else if (cxx_dialect < cxx20 && !first_designator)
+ else if (!first_designator)
first_designator = designator;
/* Parse the initializer. */
--- gcc/cp/decl.cc.jj 2026-07-24 18:38:54.335025287 +0200
+++ gcc/cp/decl.cc 2026-07-25 12:56:25.349098545 +0200
@@ -7831,12 +7831,14 @@ reshape_init_class (tree type, reshape_i
/* For C++20 CTAD, handle pack expansions in the base list. */
tree last_was_pack_expansion = NULL_TREE;
+ bool first_desig = true;
/* Loop through the initializable fields, gathering initializers. */
while (d->cur != d->end)
{
tree field_init;
constructor_elt *old_cur = d->cur;
+ constructor_elt *old_end = d->end, *new_end = NULL;
unsigned old_raw_idx = d->raw_idx;
bool direct_desig = false;
@@ -7861,9 +7863,31 @@ reshape_init_class (tree type, reshape_i
}
else if (TREE_CODE (d->cur->index) == IDENTIFIER_NODE)
{
+ if (first_desig && cxx_dialect >= cxx20)
+ {
+ if (CONSTRUCTOR_NELTS (new_init))
+ {
+ constructor_elt *last
+ = &CONSTRUCTOR_ELTS (new_init)->last ();
+ if (last->index == NULL_TREE
+ || TREE_CODE (last->index) != FIELD_DECL
+ || !DECL_FIELD_IS_BASE (last->index))
+ {
+ if (complain & tf_error)
+ error ("last non-designated initializer clause "
+ "does not appertain to a base class "
+ "subobject");
+ return error_mark_node;
+ }
+ }
+ first_desig = false;
+ }
CONSTRUCTOR_IS_DESIGNATED_INIT (new_init) = true;
field = get_class_binding (type, d->cur->index);
direct_desig = true;
+ if (!field && cxx_dialect >= cxx29)
+ field = lookup_member (type, d->cur->index, /*protect=*/2,
+ /*want_type=*/false, complain);
}
else
{
@@ -7913,6 +7937,55 @@ reshape_init_class (tree type, reshape_i
ictx = cctx;
}
+ if (cxx_dialect >= cxx29)
+ {
+ tree ibinfo = lookup_base (type, ictx, ba_unique, NULL,
+ complain);
+ if (ibinfo && ibinfo != error_mark_node)
+ {
+ while (BINFO_INHERITANCE_CHAIN (ibinfo) != binfo)
+ ibinfo = BINFO_INHERITANCE_CHAIN (ibinfo);
+ ictx = TREE_TYPE (ibinfo);
+
+ /* Find out which following elements also correspond
+ to the same ibinfo, and temporarily change d->end
+ to the first element after that. */
+ new_end = d->cur + 1;
+ while (new_end != d->end)
+ {
+ if (new_end->index == NULL_TREE
+ || TREE_CODE (new_end->index) != IDENTIFIER_NODE)
+ break;
+ field = get_class_binding (type, new_end->index);
+ if (field != NULL_TREE)
+ break;
+ field = lookup_member (type, new_end->index,
+ /*protect=*/2,
+ /*want_type=*/false, tf_none);
+ if (!field || TREE_CODE (field) != FIELD_DECL)
+ break;
+
+ tree nictx = DECL_CONTEXT (field);
+ if (same_type_ignoring_top_level_qualifiers_p (nictx,
+ type))
+ break;
+ while (ANON_AGGR_TYPE_P (nictx))
+ nictx = TYPE_CONTEXT (nictx);
+
+ ibinfo = lookup_base (type, nictx, ba_unique, NULL,
+ tf_none);
+ if (!ibinfo || ibinfo == error_mark_node)
+ break;
+ while (BINFO_INHERITANCE_CHAIN (ibinfo) != binfo)
+ ibinfo = BINFO_INHERITANCE_CHAIN (ibinfo);
+ if (TREE_TYPE (ibinfo) != ictx)
+ break;
+ new_end++;
+ }
+ goto found;
+ }
+ }
+
/* Not found, e.g. FIELD is a member of a base class. */
if (complain & tf_error)
error ("%qD is not a direct member of %qT", field, type);
@@ -7958,6 +8031,14 @@ reshape_init_class (tree type, reshape_i
d->cur->value, complain);
d->cur++;
}
+ else if (new_end)
+ {
+ d->end = new_end;
+ field_init = reshape_init_class (TREE_TYPE (field), d,
+ /*first_initializer_p=*/NULL_TREE,
+ complain);
+ d->end = old_end;
+ }
else
field_init = reshape_init_r (TREE_TYPE (field), d,
/*first_initializer_p=*/NULL_TREE,
--- gcc/testsuite/g++.dg/cpp/embed-14.C.jj 2026-07-23 10:54:23.204712630
+0200
+++ gcc/testsuite/g++.dg/cpp/embed-14.C 2026-07-25 12:29:16.312042618 +0200
@@ -3,8 +3,8 @@
struct S { int a; long b; unsigned char c[63]; int d; };
S s = {
-#embed __FILE__ limit (64) prefix (.a = 1, .b = ) suffix (, .d = 2) // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++20 } }
-};
+#embed __FILE__ limit (64) prefix (.a = 1, .b = ) suffix (, .d = 2) // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target { c++20 && c++26_down } } }
+}; // {
dg-error "designated initializer clause should not be followed by
non-designated" "" { target c++29 } .-1 }
const unsigned char t[66] = {
#embed __FILE__ limit (64) prefix ([0] = 1, [1] =) suffix (, [65] = 2) // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++20 } }
};
--- gcc/testsuite/g++.dg/cpp2a/desig2.C.jj 2026-07-23 10:54:23.205712617
+0200
+++ gcc/testsuite/g++.dg/cpp2a/desig2.C 2026-07-25 13:25:15.480272179 +0200
@@ -5,8 +5,10 @@ struct S { int a, b, c; };
S a = { 1, 2, 3 };
S b = { .a = 1, .b = 2, .c = 3 };
-S c = { 1, .b = 2, .c = 3 }; // { dg-error "either all initializer clauses
should be designated or none of them should be" "" { target c++20 } }
-S d = { .a = 1, 2, 3 }; // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target c++20 } }
+S c = { 1, .b = 2, .c = 3 }; // { dg-warning "either all initializer clauses
should be designated or none of them should be" "" { target { c++20 &&
c++26_down } } }
+ // { dg-error "last non-designated initializer
clause does not appertain to a base class subobject" "" { target c++20 } .-1 }
+S d = { .a = 1, 2, 3 }; // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target { c++20 &&
c++26_down } } }
+ // { dg-error "designated initializer clause
should not be followed by non-designated" "" { target c++29 } .-1 }
S e = { .b = 1, .b = 2 }; // { dg-error "designator used multiple times
in the same initializer list" }
#if __cplusplus > 201103L
--- gcc/testsuite/g++.dg/cpp2a/desig13.C.jj 2026-07-23 10:54:23.205712617
+0200
+++ gcc/testsuite/g++.dg/cpp2a/desig13.C 2026-07-25 12:29:16.310182812
+0200
@@ -11,6 +11,7 @@ void
baz ()
{
foo ({.d = 5, 6, .b = 2, 3}); // { dg-error "designator order for
field 'S::b' does not match declaration order in 'S'" }
- // { dg-error "either all initializer clauses
should be designated or none of them should be" "" { target c++20 } .-1 }
+ // { dg-error "either all initializer clauses
should be designated or none of them should be" "" { target { c++20 &&
c++26_down } } .-1 }
+ // { dg-error "designated initializer clause
should not be followed by non-designated" "" { target c++29 } .-2 }
bar ({.b = 1, .a = 2}); // { dg-error "designator order for field
'T::a' does not match declaration order in 'T'" }
}
--- gcc/testsuite/g++.dg/cpp2a/desig20.C.jj 2026-07-23 10:54:23.205712617
+0200
+++ gcc/testsuite/g++.dg/cpp2a/desig20.C 2026-07-25 12:29:16.310324024
+0200
@@ -16,5 +16,5 @@ struct B : A {
int main()
{
[[maybe_unused]] B b =
- { .a = 10, .d = 42 }; // { dg-error "not a direct member" }
+ { .a = 10, .d = 42 }; // { dg-error "not a direct member" ""
{ target c++26_down } }
}
--- gcc/testsuite/g++.dg/ext/desig4.C.jj 2026-07-23 10:54:23.205712617
+0200
+++ gcc/testsuite/g++.dg/ext/desig4.C 2026-07-25 13:26:09.228562235 +0200
@@ -5,10 +5,11 @@ char g[] = { [7] = "abcd" }; // { d
int a = { .foo = 6 }; // { dg-error "designator" }
int b = { [0] = 1 }; // { dg-error "12:designator .0." }
_Complex float c = { .foo = 0, 1 }; // { dg-error "designator" }
- // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target c++2a } .-1
}
+ // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target { c++20 &&
c++26_down } } .-1 }
+ // { dg-error "designated initializer
clause should not be followed by non-designated" "" { target c++29 } .-2 }
_Complex float d = { [0] = 0, 1 }; // { dg-error "23:designator .0." }
- // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target c++2a } .-1
}
+ // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target c++20 } .-1
}
_Complex float e = { 0, .foo = 1 }; // { dg-error "designator" }
- // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target c++2a } .-1
}
+ // { dg-warning "either all initializer
clauses should be designated or none of them should be" "" { target { c++20 &&
c++26_down } } .-1 }
_Complex float f = { 0, [0] = 1 }; // { dg-error "26:designator .0." }
- // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target c++2a } .-1
}
+ // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target c++20 } .-1
}
--- gcc/testsuite/g++.dg/parse/pr43765.C.jj 2026-07-23 10:54:23.205712617
+0200
+++ gcc/testsuite/g++.dg/parse/pr43765.C 2026-07-25 13:38:33.877768307
+0200
@@ -10,8 +10,9 @@ const char *temp[] = {"607", "612", 0};
SomeType vals[] =
{
- { 0, values : temp, }, // { dg-error "either all initializer clauses
should be designated or none of them should be" "" { target c++2a } }
+ { 0, values : temp, }, // { dg-warning "either all initializer
clauses should be designated or none of them should be" "" { target { c++20 &&
c++26_down } } }
0
};
// (note the error below is on the wrong line)
-// { dg-error "initialization of flexible array member in a nested context" ""
{ target *-*-* } .-2 }
+// { dg-error "initialization of flexible array member in a nested context" ""
{ target c++17_down } .-2 }
+// { dg-error "last non-designated initializer clause does not appertain to a
base class subobject" "" { target c++20 } .-3 }
--- gcc/testsuite/g++.dg/cpp29/feat-cxx29.C.jj 2026-07-23 10:54:23.205712617
+0200
+++ gcc/testsuite/g++.dg/cpp29/feat-cxx29.C 2026-07-25 12:29:16.310924209
+0200
@@ -469,8 +469,8 @@
#ifndef __cpp_designated_initializers
# error "__cpp_designated_initializers"
-#elif __cpp_designated_initializers != 201707
-# error "__cpp_designated_initializers != 201707"
+#elif __cpp_designated_initializers != 202606
+# error "__cpp_designated_initializers != 202606"
#endif
#ifndef __cpp_constexpr_in_decltype
--- gcc/testsuite/g++.dg/cpp29/desig1.C.jj 2026-07-25 12:29:16.311095548
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig1.C 2026-07-25 12:29:16.311095548 +0200
@@ -0,0 +1,12 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+
+struct A { int a; };
+struct B : A { int b; };
+auto b1 = B { { 1 }, 2 };
+auto b2 = B { 1, 2 };
+auto b3 = B { .a = 1, .b = 2 }; // { dg-error "'B' has no
non-static data member named 'a'" "" { target c++26_down } }
+auto b4 = B { { .a = 1 }, .b = 2 }; // { dg-error "either all initializer
clauses should be designated or none of them should be" "" { target c++26_down
} }
+auto b5 = B { .a { 1 }, .b { 2 } }; // { dg-error "'B' has no non-static
data member named 'a'" "" { target c++26_down } }
+auto b6 = B { .b = 2, .a = 1 }; // { dg-error "designator order
for field 'B::A' does not match declaration order in 'B'" "" { target c++29 } }
+ // { dg-error "'B' has no non-static
data member named 'a'" "" { target c++26_down } .-1 }
--- gcc/testsuite/g++.dg/cpp29/desig2.C.jj 2026-07-25 12:29:16.311199144
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig2.C 2026-07-25 13:22:55.304123720 +0200
@@ -0,0 +1,9 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+
+struct A { A (const char *); int a; };
+struct B : A { int b, c; };
+auto b1 = B { "hello", .b = 3, .c = 4 }; // { dg-error "either all
initializer clauses should be designated or none of them should be" "" { target
c++26_down } }
+auto b2 = B { { "hello" }, .b = 3, .c = 4 }; // { dg-error "either all
initializer clauses should be designated or none of them should be" "" { target
c++26_down } }
+auto b3 = B { "nope", 3, .c = 4 }; // { dg-error "last
non-designated initializer clause does not appertain to a base class subobject"
}
+ // { dg-error "either all
initializer clauses should be designated or none of them should be" "" { target
c++26_down } .-1 }
--- gcc/testsuite/g++.dg/cpp29/desig3.C.jj 2026-07-25 12:29:16.311285313
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig3.C 2026-07-25 12:29:16.311285313 +0200
@@ -0,0 +1,41 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++29 } }
+
+struct A { int a; };
+struct B : A { int b; };
+constexpr auto b1 = B { { 1 }, 2 };
+constexpr auto b2 = B { 3, 4 };
+constexpr auto b3 = B { .a = 5, .b = 6 };
+constexpr auto b4 = B { { .a = 7 }, .b = 8 };
+constexpr auto b5 = B { .a { 9 }, .b { 10 } };
+static_assert (b1.a == 1 && b1.b == 2);
+static_assert (b2.a == 3 && b2.b == 4);
+static_assert (b3.a == 5 && b3.b == 6);
+static_assert (b4.a == 7 && b4.b == 8);
+static_assert (b5.a == 9 && b5.b == 10);
+
+struct C { constexpr C (const char *x) : a (0) { while (*x) a += *x++; } int
a; };
+struct D : C { int b, c; };
+constexpr auto d1 = D { "abc", .b = 3, .c = 4 };
+constexpr auto d2 = D { { "de" }, .b = 5, .c = 6 };
+static_assert (d1.a == 'a' + 'b' + 'c' && d1.b == 3 && d1.c == 4);
+static_assert (d2.a == 'd' + 'e' && d2.b == 5 && d2.c == 6);
+
+struct E { int x; };
+struct F : E { int x; };
+constexpr auto f1 = F { .x = 1 };
+constexpr auto f2 = F { { .x = 2 }, .x = 3 };
+constexpr auto f3 = F { E { 4 }, .x = 5 };
+static_assert (f1.E::x == 0 && f1.F::x == 1);
+static_assert (f2.E::x == 2 && f2.F::x == 3);
+static_assert (f3.E::x == 4 && f3.F::x == 5);
+
+struct G { int g; };
+struct H { int h; };
+struct I : G, H { int i; };
+constexpr auto i1 = I { { .g = 1 }, { .h = 2 }, .i = 3 };
+constexpr auto i2 = I { { .g = 4 }, .h = 5, .i = 6 };
+constexpr auto i3 = I { { .g = 7 }, H { 8 }, .i = 9 };
+static_assert (i1.g == 1 && i1.h == 2 && i1.i == 3);
+static_assert (i2.g == 4 && i2.h == 5 && i2.i == 6);
+static_assert (i3.g == 7 && i3.h == 8 && i3.i == 9);
--- gcc/testsuite/g++.dg/cpp29/desig4.C.jj 2026-07-25 12:29:16.311389226
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig4.C 2026-07-25 12:29:16.311389226 +0200
@@ -0,0 +1,13 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+
+struct F { int f; };
+struct G { int g; };
+struct H : F, G { int h; };
+auto h1 = H { { .f = 1 }, { .g = 2 }, .h = 3 }; // { dg-error
"either all initializer clauses should be designated or none of them should be"
"" { target c++26_down } }
+auto h2 = H { { .f = 1 }, .g = 2, .h = 3 }; // { dg-error "either
all initializer clauses should be designated or none of them should be" "" {
target c++26_down } }
+ // { dg-error "'H' has
no non-static data member named 'g'" "" { target c++26_down } .-1 }
+auto h3 = H { { .f = 1 }, G { 2 }, .h = 3 }; // { dg-error "either
all initializer clauses should be designated or none of them should be" "" {
target c++26_down } }
+auto h4 = H { { .f = 1 }, { .g = 2 }, .g = 3, .h = 4 }; // { dg-error
"designator order for field 'H::G' does not match declaration order in 'H'" ""
{ target c++29 } }
+ // { dg-error "either
all initializer clauses should be designated or none of them should be" "" {
target c++26_down } .-1 }
+ // { dg-error "'H' has
no non-static data member named 'g'" "" { target c++26_down } .-2 }
--- gcc/testsuite/g++.dg/cpp29/desig5.C.jj 2026-07-25 12:29:16.311484136
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig5.C 2026-07-25 12:29:16.311484136 +0200
@@ -0,0 +1,25 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+
+struct A { int a; };
+struct B : A { int b; };
+struct C : A { C (); int c; };
+struct D : C { int d; };
+
+auto a = A { .a = 1 };
+auto b = B { .a = 1, .b = 2 }; // { dg-error "'B' has no non-static data
member named 'a'" "" { target c++26_down } }
+auto c = C { .c = 1 }; // { dg-error "designated initializers cannot
be used with a non-aggregate type 'C'" }
+ // { dg-error "no matching function for call
to" "" { target *-*-* } .-1 }
+auto d = D { .a = 1 }; // { dg-error "designated initializers cannot
be used with a non-aggregate type 'C'" "" { target c++29 } }
+ // { dg-error "'D' has no non-static data
member named 'a'" "" { target c++26_down } .-1 }
+
+struct E { int x; };
+struct F : E { int x; };
+constexpr auto f = F { .x = 1 };
+static_assert (f.E::x == 0 && f.F::x == 1);
+
+struct G { int x; };
+struct H { int x; };
+struct I : G, H { };
+auto i = I { .x = 1 }; // { dg-error "request for member 'x' is
ambiguous" "" { target c++29 } }
+ // { dg-error "'I' has no non-static data
member named 'x'" "" { target c++26_down } .-1 }
--- gcc/testsuite/g++.dg/cpp29/desig6.C.jj 2026-07-25 12:29:16.311569408
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig6.C 2026-07-25 12:29:16.311569408 +0200
@@ -0,0 +1,16 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++29 } }
+
+struct A { int a1, a2; };
+struct B : A { int b; };
+struct C : A { int a1; };
+A v0 = A { 1, .a2 = 2 }; // { dg-error "last
non-designated initializer clause does not appertain to a base class subobject"
}
+constexpr B v1 = B { .a1 = 1, .b = 2 }; // the explicitly
initialized elements are [A, B::b]
+static_assert (v1.a1 == 1 && v1.a2 == 0 && v1.b == 2);
+constexpr B v2 = B { .a1 = 1, .a2 = 2, .b = 3 };// the explicitly initialized
elements are [A, B::b]
+static_assert (v2.a1 == 1 && v2.a2 == 2 && v2.b == 3);
+constexpr B v3 = B { A { 1, 2 }, .b = 3 }; // the explicitly initialized
elements are [A, B::b]
+static_assert (v3.a1 == 1 && v3.a2 == 2 && v3.b == 3);
+B v4 = B { A { }, .a2 = 1, .b = 3 }; // { dg-error "designator order
for field 'B::A' does not match declaration order in 'B'" }
+constexpr C v5 = C { .a1 = 4 }; // the explicitly
initialized elements are [C::a1]
+static_assert (v5.A::a1 == 0 && v5.a2 == 0 && v5.C::a1 == 4);
--- gcc/testsuite/g++.dg/cpp29/desig7.C.jj 2026-07-25 12:29:16.311653627
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig7.C 2026-07-25 12:29:16.311653627 +0200
@@ -0,0 +1,10 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++29 } }
+
+struct A { int a; };
+struct B : A { int b; };
+struct C : B { int c; };
+constexpr B x = B { .a = 1 };
+static_assert (x.a == 1 && x.b == 0);
+constexpr C y = C { .a = 2, .b = 3, .c = 4 };
+static_assert (y.a == 2 && y.b == 3 && y.c == 4);
--- gcc/testsuite/g++.dg/cpp29/desig8.C.jj 2026-07-25 12:29:16.311739042
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig8.C 2026-07-25 12:29:16.311739042 +0200
@@ -0,0 +1,19 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++29 } }
+
+struct A { int x; int y; int z; };
+A a { .y = 2, .x = 1 }; // { dg-error "designator order
for field 'A::x' does not match declaration order in 'A'" }
+constexpr A b { .x = 1, .z = 2 };
+static_assert (b.x == 1 && b.y == 0 && b.z == 2);
+struct B : A { int q; };
+constexpr B e { .x = 1, .q = 3 };
+static_assert (e.x == 1 && e.y == 0 && e.z == 0 && e.q == 3);
+B f { .q = 3, .x = 1 }; // { dg-error "designator order
for field 'B::A' does not match declaration order in 'B'" }
+struct C { int p; int x; };
+struct D : A, C { };
+constexpr D g { .y = 1, .p = 2 };
+static_assert (g.A::x == 0 && g.y == 1 && g.z == 0 && g.p == 2 && g.C::x == 0);
+D h { .x = 2 }; // { dg-error "request for
member 'x' is ambiguous" }
+struct NonAggr { int na; NonAggr (int); };
+struct E : NonAggr { int e; };
+E i { .na = 1, .e = 2 }; // { dg-error "designated initializers
cannot be used with a non-aggregate type 'NonAggr'" }
--- gcc/testsuite/g++.dg/cpp29/desig9.C.jj 2026-07-25 12:29:16.311823219
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig9.C 2026-07-25 12:29:16.311823219 +0200
@@ -0,0 +1,12 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+
+struct A { int a; };
+struct B : A { int b; };
+void foo (A); // { dg-message "candidate 1: 'void
foo\\\(A\\\)'" "" { target c++29 } }
+void foo (B); // { dg-message "candidate 2: 'void
foo\\\(B\\\)'" "" { target c++29 } }
+void
+bar ()
+{
+ foo ({ .a = 1 }); // { dg-error "call of overloaded
'foo\\\(<brace-enclosed initializer list>\\\)' is ambiguous" "" { target c++29
} }
+} // { dg-message "there are 2 candidates" "" {
target c++29 } .-1 }
--- gcc/testsuite/g++.dg/cpp29/desig10.C.jj 2026-07-25 12:29:16.311906780
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig10.C 2026-07-25 12:29:16.311906780
+0200
@@ -0,0 +1,43 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++29 } }
+
+struct A { int a, b, c; };
+struct B { int d, e; };
+struct C : A { int f, g; };
+struct D : B { int h, i; };
+struct E : C, D { int j; };
+constexpr auto e1 = E { .a = 1, .c = 2, .f = 3, .d = 4, .i = 5, .j = 6 };
+static_assert (e1.a == 1 && e1.b == 0 && e1.c == 2 && e1.f == 3 && e1.g == 0
+ && e1.d == 4 && e1.e == 0 && e1.h == 0 && e1.i == 5 && e1.j ==
6);
+auto e2 = E { 1, 2, 3, 4, 5, .j = 6 }; // { dg-error "last non-designated
initializer clause does not appertain to a base class subobject" }
+constexpr auto e3 = E { { .a = 1, .b = 2 }, .j = 3 };
+static_assert (e3.a == 1 && e3.b == 2 && e3.c == 0 && e3.f == 0 && e3.g == 0
+ && e3.d == 0 && e3.e == 0 && e3.h == 0 && e3.i == 0 && e3.j ==
3);
+constexpr auto e4 = E { {}, { { .e = 1 }, .i = 2 }, .j = 3 };
+static_assert (e4.a == 0 && e4.b == 0 && e4.c == 0 && e4.f == 0 && e4.g == 0
+ && e4.d == 0 && e4.e == 1 && e4.h == 0 && e4.i == 2 && e4.j ==
3);
+constexpr auto e5 = E { { { .b = 1 }, .f = 2 }, { { .d = 3 }, .h = 4 }, .j = 5
};
+static_assert (e5.a == 0 && e5.b == 1 && e5.c == 0 && e5.f == 2 && e5.g == 0
+ && e5.d == 3 && e5.e == 0 && e5.h == 4 && e5.i == 0 && e5.j ==
5);
+constexpr auto e6 = E { .a = 1, .b = 2, .c = 3, .f = 4, .g = 5, .d = 6,
+ .e = 7, .h = 8, .i = 9, .j = 10 };
+static_assert (e6.a == 1 && e6.b == 2 && e6.c == 3 && e6.f == 4 && e6.g == 5
+ && e6.d == 6 && e6.e == 7 && e6.h == 8 && e6.i == 9 && e6.j ==
10);
+auto e7 = E { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, .g = 7,
+ .h = 8, .i = 9, .j = 10 };// { dg-error "designator order for
field 'E::C' does not match declaration order in 'E'" }
+auto e8 = E { {}, {}, .a = 1, .j = 2 }; // { dg-error "designator order
for field 'E::C' does not match declaration order in 'E'" }
+auto e9 = E { {}, .f = 1 }; // { dg-error "designator order for
field 'E::C' does not match declaration order in 'E'" }
+auto e10 = E { {}, {}, .e = 1 }; // { dg-error "designator order for
field 'E::D' does not match declaration order in 'E'" }
+auto e11 = E { {}, {}, .h = 1 }; // { dg-error "designator order for
field 'E::D' does not match declaration order in 'E'" }
+auto e12 = E { .a = 0, .b = 0, .c = 0, .d = 0, .e = 0, .f = 0, .g = 0, .h = 0,
.i = 0, .j = 0,
+ .a = 0, .b = 0, .c = 0, .d = 0, .e = 0, .f = 0, .g = 0, .h = 0,
.i = 0, .j = 0 };
+// { dg-error "'.a' designator used multiple times in the same initializer
list" "" { target *-*-* } .-1 }
+// { dg-error "'.b' designator used multiple times in the same initializer
list" "" { target *-*-* } .-2 }
+// { dg-error "'.c' designator used multiple times in the same initializer
list" "" { target *-*-* } .-3 }
+// { dg-error "'.d' designator used multiple times in the same initializer
list" "" { target *-*-* } .-4 }
+// { dg-error "'.e' designator used multiple times in the same initializer
list" "" { target *-*-* } .-5 }
+// { dg-error "'.f' designator used multiple times in the same initializer
list" "" { target *-*-* } .-6 }
+// { dg-error "'.g' designator used multiple times in the same initializer
list" "" { target *-*-* } .-7 }
+// { dg-error "'.h' designator used multiple times in the same initializer
list" "" { target *-*-* } .-8 }
+// { dg-error "'.i' designator used multiple times in the same initializer
list" "" { target *-*-* } .-9 }
+// { dg-error "'.j' designator used multiple times in the same initializer
list" "" { target *-*-* } .-10 }
--- gcc/testsuite/g++.dg/cpp29/desig11.C.jj 2026-07-25 13:53:02.118533848
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig11.C 2026-07-25 13:58:08.511556352
+0200
@@ -0,0 +1,21 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++29 } }
+
+struct A { int a, x; };
+struct B { int b, x; };
+struct C : A, B { int c; };
+struct D : C { int x; };
+constexpr auto d = D { .c = 1, .x = 2 };
+static_assert (d.a == 0 && d.A::x == 0 && d.b == 0 && d.B::x == 0
+ && d.c == 1 && d.D::x == 2);
+struct E { int a, x; };
+struct F : E { int x; };
+constexpr auto f = F { .a = 1, .x = 2 };
+static_assert (f.a == 1 && f.E::x == 0 && f.F::x == 2);
+struct G { int a, b; };
+struct H : G { int c; };
+struct I { int a, b, d; };
+struct J : I { int e, c; };
+constexpr int foo (H, G) { return 1; }
+constexpr int foo (J, I) { return 42; }
+static_assert (foo ({ .a = 1, .b = 2, .c = 3 }, { .d = 1 }) == 42);
--- gcc/testsuite/g++.dg/cpp29/desig12.C.jj 2026-07-25 14:02:14.616361362
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig12.C 2026-07-25 14:11:55.362818085
+0200
@@ -0,0 +1,13 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+// { dg-options "-Wno-c++29-extensions" }
+
+struct A { int a, b; };
+struct B { int c, d; };
+struct C : A, B { int e, f; };
+auto c1 = C { { .a = 1, .b = 2 }, { .c = 3, .d = 4 }, .e = 5, .f = 6 };
+auto c2 = C { { .a = 1, .b = 2 }, .e = 5, .f = 6 };
+auto c3 = C { {}, { .c = 3, .d = 4 }, .f = 6 };
+auto c4 = C { .e = 1, 2 }; // { dg-error "either all initializer clauses
should be designated or none of them should be" "" { target c++26_down } }
+ // { dg-error "designated initializer clause
should not be followed by non-designated" "" { target c++29 } .-1 }
+auto a1 = A { 1, .b = 2 }; // { dg-error "last non-designated initializer
clause does not appertain to a base class subobject" }
--- gcc/testsuite/g++.dg/cpp29/desig13.C.jj 2026-07-25 14:06:02.727399967
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig13.C 2026-07-25 14:13:31.319568434
+0200
@@ -0,0 +1,14 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+// { dg-options "-Wc++29-extensions" }
+
+struct A { int a, b; };
+struct B { int c, d; };
+struct C : A, B { int e, f; };
+auto c1 = C { { .a = 1, .b = 2 }, { .c = 3, .d = 4 }, .e = 5, .f = 6 };
// { dg-warning "either all initializer clauses should be designated or none of
them should be" "" { target c++26_down } }
+auto c2 = C { { .a = 1, .b = 2 }, .e = 5, .f = 6 }; // {
dg-warning "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } }
+auto c3 = C { {}, { .c = 3, .d = 4 }, .f = 6 };
// { dg-warning "either all initializer clauses should be designated or none of
them should be" "" { target c++26_down } }
+auto c4 = C { .e = 1, 2 }; // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } }
+ // {
dg-error "designated initializer clause should not be followed by
non-designated" "" { target c++29 } .-1 }
+auto a1 = A { 1, .b = 2 }; // {
dg-error "last non-designated initializer clause does not appertain to a base
class subobject" }
+ // {
dg-warning "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } .-1 }
--- gcc/testsuite/g++.dg/cpp29/desig14.C.jj 2026-07-25 14:15:33.439978044
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig14.C 2026-07-25 14:14:50.913531871
+0200
@@ -0,0 +1,14 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+// { dg-options "" }
+
+struct A { int a, b; };
+struct B { int c, d; };
+struct C : A, B { int e, f; };
+auto c1 = C { { .a = 1, .b = 2 }, { .c = 3, .d = 4 }, .e = 5, .f = 6 };
// { dg-warning "either all initializer clauses should be designated or none of
them should be" "" { target c++26_down } }
+auto c2 = C { { .a = 1, .b = 2 }, .e = 5, .f = 6 }; // {
dg-warning "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } }
+auto c3 = C { {}, { .c = 3, .d = 4 }, .f = 6 };
// { dg-warning "either all initializer clauses should be designated or none of
them should be" "" { target c++26_down } }
+auto c4 = C { .e = 1, 2 }; // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } }
+ // {
dg-error "designated initializer clause should not be followed by
non-designated" "" { target c++29 } .-1 }
+auto a1 = A { 1, .b = 2 }; // {
dg-error "last non-designated initializer clause does not appertain to a base
class subobject" }
+ // {
dg-warning "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } .-1 }
--- gcc/testsuite/g++.dg/cpp29/desig15.C.jj 2026-07-25 14:15:30.733013298
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig15.C 2026-07-25 14:17:11.822696794
+0200
@@ -0,0 +1,15 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+// { dg-options "-Werror=c++29-extensions" }
+
+struct A { int a, b; };
+struct B { int c, d; };
+struct C : A, B { int e, f; };
+auto c1 = C { { .a = 1, .b = 2 }, { .c = 3, .d = 4 }, .e = 5, .f = 6 };
// { dg-error "either all initializer clauses should be designated or none of
them should be" "" { target c++26_down } }
+auto c2 = C { { .a = 1, .b = 2 }, .e = 5, .f = 6 }; // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } }
+auto c3 = C { {}, { .c = 3, .d = 4 }, .f = 6 };
// { dg-error "either all initializer clauses should be designated or none of
them should be" "" { target c++26_down } }
+auto c4 = C { .e = 1, 2 }; // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } }
+ // {
dg-error "designated initializer clause should not be followed by
non-designated" "" { target c++29 } .-1 }
+auto a1 = A { 1, .b = 2 }; // {
dg-error "last non-designated initializer clause does not appertain to a base
class subobject" }
+ // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } .-1 }
+ // {
dg-message "some warnings being treated as errors" "" { target c++26_down } 0 }
--- gcc/testsuite/g++.dg/cpp29/desig16.C.jj 2026-07-25 14:15:27.679053071
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig16.C 2026-07-25 14:15:23.593106283
+0200
@@ -0,0 +1,13 @@
+// C++29 P2287R6 - Designated-initializers for Base Classes
+// { dg-do compile { target c++20 } }
+
+struct A { int a, b; };
+struct B { int c, d; };
+struct C : A, B { int e, f; };
+auto c1 = C { { .a = 1, .b = 2 }, { .c = 3, .d = 4 }, .e = 5, .f = 6 };
// { dg-error "either all initializer clauses should be designated or none of
them should be" "" { target c++26_down } }
+auto c2 = C { { .a = 1, .b = 2 }, .e = 5, .f = 6 }; // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } }
+auto c3 = C { {}, { .c = 3, .d = 4 }, .f = 6 };
// { dg-error "either all initializer clauses should be designated or none of
them should be" "" { target c++26_down } }
+auto c4 = C { .e = 1, 2 }; // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } }
+ // {
dg-error "designated initializer clause should not be followed by
non-designated" "" { target c++29 } .-1 }
+auto a1 = A { 1, .b = 2 }; // {
dg-error "last non-designated initializer clause does not appertain to a base
class subobject" }
+ // {
dg-error "either all initializer clauses should be designated or none of them
should be" "" { target c++26_down } .-1 }
Jakub