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

Reply via email to