On 7/23/26 4:49 AM, Jakub Jelinek wrote:
On Thu, Jul 23, 2026 at 12:04:40AM -0400, Jason Merrill wrote:
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.
It seems unfortunate to need to do all this extra adjustment instead of
handling it by the usual reshaping. If the designator names a base member,
would it work to clear direct_desig (and set field to the base field) so the
existing code recurses like for an anonymous aggr member?
That is actually what I've implemented first, but it doesn't work, several
tests in the added tests then fail.
The reason why it works for the ANON_AGGR_TYPE_P cases is that the
recursive reshape_init_r -> reshape_init_class has:
if (!field && ANON_AGGR_TYPE_P (type))
/* Apparently the designator isn't for a member of this anonymous
struct, so head back to the enclosing class. */
break;
so, it will stop after all (in case of anon union after the first)
initializer clause.
Now, for the end of the set of initializer clauses which belong to a
particular base class (and so should be handled together by the recursive
call), the condition is much more complicated. If we passed that outer type
to the recursion as a new argument, we'd need to repeat the lookups using
that type, i.e. all of that get_class_binding + lookup_member +
same_type_ignoring_top_level_qualifiers_p + lookup_base etc. And we
would need to do it not just in the if (!field && parent_type) case.
Consider
struct A { int a, x; };
struct B { int b, x; };
struct C : A, B { int c; };
struct D : C { int x; };
auto d = D { .c = 1, .x = 2 };
I believe according to the rules added in the paper, this should be valid
and same as D { { { }, { }, .c = 1 }, .x = 2 }; because x is a member of
the D class, a is not, it belongs to the C base class.
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)?
- 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");
Can we make it a -Wc++29-extensions pedwarn in earlier modes?
So do you want this to be a partially supported extension in C++ 20 to 26
with pedwarns? What would that do?
The paper has basically two parts, for
struct A { int a; };
struct B : A { int b; };
one is to allow
B { { .a = 1 }, .b = 2 }
and the other is to allow
B { .a = 1, .b = 2 }
Allowing the latter in C++20 to C++26 is a bad idea IMHO, because that
changes the behavior of some valid code, as e.g.
https://eel.is/c++draft/diff.cpp26.dcl#1
shows.
Agreed.
Supporting the former as an extension with pedwarns is possible, but it
isn't about changing one error_at to pedwarn IMHO.
In the patch currently, the parser.cc change arranges for the
error_at (loc, "either all initializer clauses should be designated "
"or none of them should be");
error not to be emitted for C++29 unless it is the [0] = designator case,
and emit the other error
error_at (loc, "designated initializer clause should not "
"be followed by non-designated");
for C++29 if it is non-designated after designated (and nothing for
designated after non-designated).
What should we do for C++20 to C++26? Just emit the
error_at (loc, "either all initializer clauses should be designated "
"or none of them should be");
error in the non-designated after designated and emit the same thing
as pedwarn for designated after non-designated? I'm afraid anything else
would just confuse users.
That's what I was thinking, yes.
And the
+ if (complain & tf_error)
+ error ("last non-designated initializer clause "
+ "does not appertain to a base class "
+ "subobject");
error in decl.cc would need to be done for cxx_dialect >= cxx20
rather than cxx_dialect >= cxx29.
Jakub