Hi!
The following patch implements the C++29 P2287R6
Designated-initializers for Base Classes
paper.
One change is during parsing, to match the new designated-initializer-list
grammar, the patch allows non-designated clauses followed by designated
clauses for C++29 (but rejects designated followed by non-designated and
also when using GNU style [0] = designators non-designated by designated
with that GNU array style, while the grammar allows now in theory
{ 1, 2, [3] = 3, [4] = 4 } in theory I think it is undesirable to allow
that mixing, the designated after non-designated has been added solely
for base classes and arrays don't have those).
Another change is in the if (first_desig && cxx_dialect >= cxx29) hunk,
to reject non-designated clause which doesn't appertain to base class
followed by designated clause.
Yet another change is the lookup_member as fallback to get_class_binding,
but according to the paper it shouldn't replace it, even if there is
ambiguity, if the designator names a NSDM of current class, that should
be what is used, only if it is an ambiguity inside of base classes there
should be an error.
And finally, if field for C++29 is from some base class, find out the
corresponding base FIELD_DECL and find out how many consecutive designators
belong to the same FIELD_DECL and recurse. For anonymous aggregates
the recursion is handled slightly differently, we call reshape_init_r
instead of reshape_init_class and reshape_init_class called from it will
stop looking on first field which is not found. reshape_init_r in the
case of designators from a base reports some undesirable errors and where
to stop would mean we'd need to pass for the recursion extra arguments
and treat designators for testing in one spot as belonging to the desired
class and in another again as belonging to the current (i.e. base) class.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2026-07-20 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.
* decl.cc (reshape_init_class): Diagnose non-designated clause not
appertaining to base class followed by designated clause for C++29.
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/cpp2a/desig13.C: Expect different diagnostics for C++29.
* g++.dg/cpp2a/desig2.C: Likewise.
* g++.dg/cpp2a/desig20.C: Likewise.
* g++.dg/ext/desig4.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/cpp/embed-14.C: Expect different diagnostics for C++29.
* g++.dg/parse/pr43765.C: Likewise.
--- gcc/c-family/c-cppbuiltin.cc.jj 2026-06-30 09:21:01.997647474 +0200
+++ gcc/c-family/c-cppbuiltin.cc 2026-07-17 19:07:50.061835633 +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-17 10:01:19.088527517 +0200
+++ gcc/cp/parser.cc 2026-07-17 22:04:23.353933490 +0200
@@ -29406,13 +29406,24 @@ 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");
+ 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
+ && (cxx_dialect < cxx20 || cxx_dialect >= cxx29))
first_designator = designator;
/* Parse the initializer. */
--- gcc/cp/decl.cc.jj 2026-07-17 10:01:19.084527568 +0200
+++ gcc/cp/decl.cc 2026-07-17 21:52:56.975434210 +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 >= cxx29)
+ {
+ 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/cpp2a/desig2.C.jj 2026-03-27 10:17:15.701305169
+0100
+++ gcc/testsuite/g++.dg/cpp2a/desig2.C 2026-07-17 19:37:23.547883305 +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-error "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++29 } .-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-03-27 10:17:15.701305169
+0100
+++ gcc/testsuite/g++.dg/cpp2a/desig13.C 2026-07-17 19:35:54.318988173
+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-03-27 10:17:15.701305169
+0100
+++ gcc/testsuite/g++.dg/cpp2a/desig20.C 2026-07-17 19:39:08.052589287
+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-03-27 10:17:15.789303733
+0100
+++ gcc/testsuite/g++.dg/ext/desig4.C 2026-07-17 22:09:09.177391357 +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-error "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/cpp29/feat-cxx29.C.jj 2026-06-30 09:21:01.998061992
+0200
+++ gcc/testsuite/g++.dg/cpp29/feat-cxx29.C 2026-07-17 19:08:20.834454841
+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-17 18:44:44.079995878
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig1.C 2026-07-17 19:12:02.379713154 +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-17 19:00:37.515188123
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig2.C 2026-07-17 19:04:10.595551385 +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"
"" { target c++29 } }
+ // { 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-17 19:10:49.593613938
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig3.C 2026-07-17 19:51:19.927526878 +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-17 19:53:06.548206649
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig4.C 2026-07-17 20:02:40.411102044 +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-17 20:04:31.718725654
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig5.C 2026-07-17 20:12:25.277869784 +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-17 20:14:30.520321081
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig6.C 2026-07-17 20:19:41.633477176 +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-17 20:20:57.315545897
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig7.C 2026-07-17 20:28:53.578685422 +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-17 20:22:50.205156773
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig8.C 2026-07-17 20:31:52.372485337 +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-17 20:33:04.456598330
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig9.C 2026-07-17 20:35:36.767724118 +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-19 22:01:06.228479042
+0200
+++ gcc/testsuite/g++.dg/cpp29/desig10.C 2026-07-19 22:22:24.512797996
+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/cpp/embed-14.C.jj 2026-03-27 10:17:15.396310146
+0100
+++ gcc/testsuite/g++.dg/cpp/embed-14.C 2026-07-18 08:59:11.779483852 +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/parse/pr43765.C.jj 2026-03-27 10:17:16.086298886
+0100
+++ gcc/testsuite/g++.dg/parse/pr43765.C 2026-07-18 09:01:23.671746590
+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-error "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++26_down } .-2 }
+// { dg-error "last non-designated initializer clause does not appertain to a
base class subobject" "" { target c++29 } .-3 }
Jakub