Hi! This patch adds support for c++2a designated initializers. We've been supporting a small restricted subset of C99 initializers as a GNU extension before, the C++2A designated initializers are partly a subset of that, but on the other side extent it more and add some further restrictions.
I've tried to keep the new restrictions limited to -std=c++2a/-std=gnu++2a, so existing code in C++{98,11,14,17} can use the old extensions (this is the case of e.g. the requirement that either all or none of the initializer clauses use designator, previously we were allowing mixing them), while cases where the new code extends the previous behavior are allowed always (e.g. the possibility to skip over some non-static data members which are then initialized like other not explictly initialized members or anonymous aggregate handling). I've noticed we didn't issue any pedwarn for [0] = C99 designators, so that is fixed too. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2017-11-13 Jakub Jelinek <ja...@redhat.com> P0329R4: Designated Initialization * parser.c (cp_parser_initializer_clause): List in comment grammar designated-initializer-list. (cp_parser_initializer_list): Allow .identifier = without pedwarn for C++2A, parse .identifier { ... }. Improve location_t argument to pedwarn. Add pedwarn for [cst] = designators. Diagnose ... in designated initializer list. Diagnose mixing designated and non-designated initializer clauses for C++2A. Diagnose duplicated identifiers in designators. * name-lookup.h (search_anon_aggr): New declaration. * name-lookup.c (fields_linear_search): Use search_anon_aggr. (search_anon_aggr): New function. * typeck2.c (process_init_constructor_record): Allow designator to skip over some non-static data members. Handle anonymous aggregates. Add diagnostics for designator order not matching member declaration order. * g++.dg/ext/desig2.C: Adjust comment, no sorry about designator refering to second member. (b): New variable and associated expected diagnostic. * g++.dg/ext/desig4.C: For C++2A expect diagnostics. * g++.dg/ext/desig5.C: Add dg-do dg-compile and empty dg-options. * g++.dg/ext/desig8.C: Likewise. * g++.dg/ext/desig9.C: New test. * g++.dg/ext/pr27019.C: Don't expect any diagnostics. * g++.dg/init/error2.C: Adjust expected diagnostics. * g++.dg/cpp0x/desig1.C: Add dg-options with -pedantic, expect warning on C99 designators. * g++.dg/cpp2a/desig1.C: New test. * g++.dg/cpp2a/desig2.C: New test. * g++.dg/cpp2a/desig3.C: New test. * g++.dg/cpp2a/desig4.C: New test. * g++.dg/cpp2a/desig5.C: New test. * g++.dg/cpp2a/desig6.C: New test. --- gcc/cp/parser.c.jj 2017-11-10 15:42:02.000000000 +0100 +++ gcc/cp/parser.c 2017-11-13 19:23:04.384100628 +0100 @@ -21988,6 +21988,7 @@ cp_parser_initializer_clause (cp_parser* braced-init-list: { initializer-list , [opt] } + { designated-initializer-list , [opt] } { } Returns a CONSTRUCTOR. The CONSTRUCTOR_ELTS will be @@ -22104,6 +22105,18 @@ cp_parser_array_designator_p (cp_parser initializer-clause ... [opt] initializer-list , initializer-clause ... [opt] + C++2A Extension: + + designated-initializer-list: + designated-initializer-clause + designated-initializer-list , designated-initializer-clause + + designated-initializer-clause: + designator brace-or-equal-initializer + + designator: + . identifier + GNU Extension: initializer-list: @@ -22124,6 +22137,8 @@ static vec<constructor_elt, va_gc> * cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) { vec<constructor_elt, va_gc> *v = NULL; + bool first_p = true; + tree first_designator = NULL_TREE; /* Assume all of the expressions are constant. */ *non_constant_p = false; @@ -22135,36 +22150,43 @@ cp_parser_initializer_list (cp_parser* p tree designator; tree initializer; bool clause_non_constant_p; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; - /* If the next token is an identifier and the following one is a - colon, we are looking at the GNU designated-initializer - syntax. */ - if (cp_parser_allow_gnu_extensions_p (parser) - && cp_lexer_next_token_is (parser->lexer, CPP_NAME) - && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON) + /* Handle the C++2A syntax, '. id ='. */ + if ((cxx_dialect >= cxx2a + || cp_parser_allow_gnu_extensions_p (parser)) + && cp_lexer_next_token_is (parser->lexer, CPP_DOT) + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME + && (cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ + || (cp_lexer_peek_nth_token (parser->lexer, 3)->type + == CPP_OPEN_BRACE))) { - /* Warn the user that they are using an extension. */ - pedwarn (input_location, OPT_Wpedantic, - "ISO C++ does not allow designated initializers"); + if (cxx_dialect < cxx2a) + pedwarn (loc, OPT_Wpedantic, + "C++ designated initializers only available with " + "-std=c++2a or -std=gnu++2a"); + /* Consume the `.'. */ + cp_lexer_consume_token (parser->lexer); /* Consume the identifier. */ designator = cp_lexer_consume_token (parser->lexer)->u.value; - /* Consume the `:'. */ - cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + /* Consume the `='. */ + cp_lexer_consume_token (parser->lexer); } - /* Also handle the C99 syntax, '. id ='. */ + /* Also, if the next token is an identifier and the following one is a + colon, we are looking at the GNU designated-initializer + syntax. */ else if (cp_parser_allow_gnu_extensions_p (parser) - && cp_lexer_next_token_is (parser->lexer, CPP_DOT) - && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME - && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ) + && cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && (cp_lexer_peek_nth_token (parser->lexer, 2)->type + == CPP_COLON)) { /* Warn the user that they are using an extension. */ - pedwarn (input_location, OPT_Wpedantic, - "ISO C++ does not allow C99 designated initializers"); - /* Consume the `.'. */ - cp_lexer_consume_token (parser->lexer); + pedwarn (loc, OPT_Wpedantic, + "ISO C++ does not allow GNU designated initializers"); /* Consume the identifier. */ designator = cp_lexer_consume_token (parser->lexer)->u.value; - /* Consume the `='. */ + /* Consume the `:'. */ cp_lexer_consume_token (parser->lexer); } /* Also handle C99 array designators, '[ const ] ='. */ @@ -22194,10 +22216,30 @@ cp_parser_initializer_list (cp_parser* p designator = NULL_TREE; else if (non_const) require_potential_rvalue_constant_expression (designator); + if (designator) + /* Warn the user that they are using an extension. */ + pedwarn (loc, OPT_Wpedantic, + "ISO C++ does not allow C99 designated initializers"); } else designator = NULL_TREE; + if (first_p) + { + first_designator = designator; + first_p = false; + } + else if (cxx_dialect >= cxx2a + && first_designator != error_mark_node + && (!first_designator != !designator)) + { + error_at (loc, "either all initializer clauses should be designated " + "or none of them should be"); + first_designator = error_mark_node; + } + else if (cxx_dialect < cxx2a && !first_designator) + first_designator = designator; + /* Parse the initializer. */ initializer = cp_parser_initializer_clause (parser, &clause_non_constant_p); @@ -22209,11 +22251,17 @@ cp_parser_initializer_list (cp_parser* p expansion. */ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) { + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + /* Consume the `...'. */ cp_lexer_consume_token (parser->lexer); - /* Turn the initializer into an initializer expansion. */ - initializer = make_pack_expansion (initializer); + if (designator && cxx_dialect >= cxx2a) + error_at (loc, + "%<...%> not allowed in designated initializer list"); + + /* Turn the initializer into an initializer expansion. */ + initializer = make_pack_expansion (initializer); } /* Add it to the vector. */ @@ -22236,6 +22284,31 @@ cp_parser_initializer_list (cp_parser* p cp_lexer_consume_token (parser->lexer); } + /* The same identifier shall not appear in multiple designators + of a designated-initializer-list. */ + if (first_designator) + { + unsigned int i; + tree designator, val; + FOR_EACH_CONSTRUCTOR_ELT (v, i, designator, val) + if (designator && TREE_CODE (designator) == IDENTIFIER_NODE) + { + if (IDENTIFIER_MARKED (designator)) + { + error_at (EXPR_LOC_OR_LOC (val, input_location), + "%<.%s%> designator used multiple times in " + "the same initializer list", + IDENTIFIER_POINTER (designator)); + (*v)[i].index = NULL_TREE; + } + else + IDENTIFIER_MARKED (designator) = 1; + } + FOR_EACH_CONSTRUCTOR_ELT (v, i, designator, val) + if (designator && TREE_CODE (designator) == IDENTIFIER_NODE) + IDENTIFIER_MARKED (designator) = 0; + } + return v; } --- gcc/cp/name-lookup.h.jj 2017-10-26 14:36:03.000000000 +0200 +++ gcc/cp/name-lookup.h 2017-11-13 16:33:16.751790779 +0100 @@ -307,6 +307,7 @@ extern void pop_decl_namespace (void); extern void do_namespace_alias (tree, tree); extern tree do_class_using_decl (tree, tree); extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *); +extern tree search_anon_aggr (tree, tree); extern tree get_class_binding_direct (tree, tree, int type_or_fns = -1); extern tree get_class_binding (tree, tree, int type_or_fns = -1); extern tree *get_member_slot (tree klass, tree name); --- gcc/cp/name-lookup.c.jj 2017-11-01 22:49:15.000000000 +0100 +++ gcc/cp/name-lookup.c 2017-11-13 16:54:17.629471698 +0100 @@ -1161,21 +1161,8 @@ fields_linear_search (tree klass, tree n && TREE_CODE (decl) == FIELD_DECL && ANON_AGGR_TYPE_P (TREE_TYPE (decl))) { - tree anon = TREE_TYPE (decl); - gcc_assert (COMPLETE_TYPE_P (anon)); - tree temp; - - if (vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (anon)) - temp = member_vec_linear_search (member_vec, name); - else - temp = fields_linear_search (anon, name, want_type); - - if (temp) - { - /* Anon members can only contain fields. */ - gcc_assert (!STAT_HACK_P (temp) && !DECL_DECLARES_TYPE_P (temp)); - return temp; - } + if (tree temp = search_anon_aggr (TREE_TYPE (decl), name)) + return temp; } if (DECL_NAME (decl) != name) @@ -1199,6 +1186,28 @@ fields_linear_search (tree klass, tree n return NULL_TREE; } +/* Look for NAME field inside of anonymous aggregate ANON. */ + +tree +search_anon_aggr (tree anon, tree name) +{ + gcc_assert (COMPLETE_TYPE_P (anon)); + tree ret; + + if (vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (anon)) + ret = member_vec_linear_search (member_vec, name); + else + ret = fields_linear_search (anon, name, false); + + if (ret) + { + /* Anon members can only contain fields. */ + gcc_assert (!STAT_HACK_P (ret) && !DECL_DECLARES_TYPE_P (ret)); + return ret; + } + return NULL_TREE; +} + /* Look for NAME as an immediate member of KLASS (including anon-members or unscoped enum member). TYPE_OR_FNS is zero for regular search. >0 to get a type binding (if there is one) and <0 --- gcc/cp/typeck2.c.jj 2017-11-07 08:45:21.000000000 +0100 +++ gcc/cp/typeck2.c 2017-11-13 17:23:09.590432311 +0100 @@ -1371,6 +1371,7 @@ process_init_constructor_record (tree ty restart: int flags = 0; unsigned HOST_WIDE_INT idx = 0; + int designator_skip = -1; /* Generally, we will always have an index for each initializer (which is a FIELD_DECL, put by reshape_init), but compound literals don't go trough reshape_init. So we need to handle both cases. */ @@ -1394,6 +1395,7 @@ process_init_constructor_record (tree ty if (type == error_mark_node) return PICFLAG_ERRONEOUS; + next = NULL_TREE; if (idx < CONSTRUCTOR_NELTS (init)) { constructor_elt *ce = &(*CONSTRUCTOR_ELTS (init))[idx]; @@ -1404,18 +1406,42 @@ process_init_constructor_record (tree ty deferred. */ gcc_assert (TREE_CODE (ce->index) == FIELD_DECL || identifier_p (ce->index)); - if (ce->index != field - && ce->index != DECL_NAME (field)) + if (ce->index == field || ce->index == DECL_NAME (field)) + next = ce->value; + else if (ANON_AGGR_TYPE_P (type) + && search_anon_aggr (type, + TREE_CODE (ce->index) == FIELD_DECL + ? DECL_NAME (ce->index) + : ce->index)) + /* If the element is an anonymous union object and the + initializer list is a designated-initializer-list, the + anonymous union object is initialized by the + designated-initializer-list { D }, where D is the + designated-initializer-clause naming a member of the + anonymous union object. */ + next = build_constructor_single (type, ce->index, ce->value); + else { - ce->value = error_mark_node; - sorry ("non-trivial designated initializers not supported"); + ce = NULL; + if (designator_skip == -1) + designator_skip = 1; } } + else + { + designator_skip = 0; + next = ce->value; + } - gcc_assert (ce->value); - next = massage_init_elt (type, ce->value, complain); - ++idx; + if (ce) + { + gcc_assert (ce->value); + next = massage_init_elt (type, next, complain); + ++idx; + } } + if (next) + /* Already handled above. */; else if (DECL_INITIAL (field)) { if (skipped > 0) @@ -1494,7 +1520,49 @@ process_init_constructor_record (tree ty if (idx < CONSTRUCTOR_NELTS (init)) { if (complain & tf_error) - error ("too many initializers for %qT", type); + { + constructor_elt *ce = &(*CONSTRUCTOR_ELTS (init))[idx]; + /* For better diagnostics, try to find out if it is really + the case of too many initializers or if designators are + in incorrect order. */ + if (designator_skip == 1 && ce->index) + { + gcc_assert (TREE_CODE (ce->index) == FIELD_DECL + || identifier_p (ce->index)); + for (field = TYPE_FIELDS (type); + field; field = DECL_CHAIN (field)) + { + if (!DECL_NAME (field) && DECL_C_BIT_FIELD (field)) + continue; + if (TREE_CODE (field) != FIELD_DECL + || (DECL_ARTIFICIAL (field) + && !(cxx_dialect >= cxx17 + && DECL_FIELD_IS_BASE (field)))) + continue; + + if (ce->index == field || ce->index == DECL_NAME (field)) + break; + if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) + { + tree t + = search_anon_aggr (TREE_TYPE (field), + TREE_CODE (ce->index) == FIELD_DECL + ? DECL_NAME (ce->index) + : ce->index); + if (t) + { + field = t; + break; + } + } + } + } + if (field) + error ("designator order for field %qD does not match declaration " + "order in %qT", field, type); + else + error ("too many initializers for %qT", type); + } else return PICFLAG_ERRONEOUS; } --- gcc/testsuite/g++.dg/ext/desig2.C.jj 2011-07-21 09:54:35.000000000 +0200 +++ gcc/testsuite/g++.dg/ext/desig2.C 2017-11-13 18:39:50.324537143 +0100 @@ -12,8 +12,9 @@ __extension__ int i[4] = { [0] = 1, [1] // Currently, except for unions, the C++ front end only supports // designators that designate the element that would have been initialized -// anyway. While that's true, make sure that we get a sorry rather than -// bad code. +// anyway, except that C++2A designators can skip over some direct +// non-static data members. While that's true, make sure that we get +// a sorry rather than bad code. struct A { @@ -21,5 +22,6 @@ struct A int j; }; -__extension__ A a = { .j = 1 }; // { dg-message "non-trivial" } +__extension__ A a = { .j = 1 }; +__extension__ A b = { .j = 2, .i = 1 }; // { dg-error "designator order for field 'A::i' does not match declaration order in 'A'" } __extension__ int j[2] = { [1] = 1 }; // { dg-message "non-trivial" } --- gcc/testsuite/g++.dg/ext/desig4.C.jj 2011-12-16 08:37:36.000000000 +0100 +++ gcc/testsuite/g++.dg/ext/desig4.C 2017-11-13 18:41:37.697231905 +0100 @@ -5,6 +5,10 @@ char g[] = { [7] = "abcd" }; // { d int a = { .foo = 6 }; // { dg-error "designator" } int b = { [0] = 1 }; // { dg-error "designator" } _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 } _Complex float d = { [0] = 0, 1 }; // { dg-error "designator" } + // { dg-error "either all initializer clauses should be designated or none of them should be" "" { target c++2a } .-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 } _Complex float f = { 0, [0] = 1 }; // { dg-error "designator" } + // { dg-error "either all initializer clauses should be designated or none of them should be" "" { target c++2a } .-1 } --- gcc/testsuite/g++.dg/ext/desig5.C.jj 2013-03-27 12:52:19.000000000 +0100 +++ gcc/testsuite/g++.dg/ext/desig5.C 2017-11-13 19:29:57.005142269 +0100 @@ -1,4 +1,6 @@ // PR c++/55951 +// { dg-do compile } +// { dg-options "" } enum { A }; --- gcc/testsuite/g++.dg/ext/desig8.C.jj 2014-12-15 19:36:54.000000000 +0100 +++ gcc/testsuite/g++.dg/ext/desig8.C 2017-11-13 19:30:31.303730112 +0100 @@ -1,3 +1,5 @@ // PR c++/58882 +// { dg-do compile } +// { dg-options "" } int a[] = { [0.] = 0 }; // { dg-error "integral constant-expression" } --- gcc/testsuite/g++.dg/ext/desig9.C.jj 2017-11-13 19:31:17.992169069 +0100 +++ gcc/testsuite/g++.dg/ext/desig9.C 2017-11-13 19:31:11.361248751 +0100 @@ -0,0 +1,3 @@ +// { dg-do compile } + +int a[2] = { [0] = 1, [1] = 2 }; // { dg-error "does not allow C99 designated initializers" } --- gcc/testsuite/g++.dg/ext/pr27019.C.jj 2008-10-23 13:21:04.000000000 +0200 +++ gcc/testsuite/g++.dg/ext/pr27019.C 2017-11-13 21:36:56.335818475 +0100 @@ -8,4 +8,4 @@ struct A int z[1]; }; -A a = { z:{} }; // { dg-message "unimplemented" } +A a = { z:{} }; --- gcc/testsuite/g++.dg/init/error2.C.jj 2011-02-25 19:01:45.000000000 +0100 +++ gcc/testsuite/g++.dg/init/error2.C 2017-11-13 21:39:23.870022426 +0100 @@ -5,7 +5,7 @@ template<int> struct A { static int a[1]; }; -template<int N> int A<N>::a[1] = { X:0 }; /* { dg-error "does not allow designated|was not declared|designated initializer for an array" } */ +template<int N> int A<N>::a[1] = { X:0 }; /* { dg-error "does not allow GNU designated|was not declared|designated initializer for an array" } */ void foo() { --- gcc/testsuite/g++.dg/cpp0x/desig1.C.jj 2014-12-15 19:36:54.000000000 +0100 +++ gcc/testsuite/g++.dg/cpp0x/desig1.C 2017-11-13 19:28:49.609952140 +0100 @@ -1,12 +1,13 @@ // PR c++/58882 // { dg-do compile { target c++11 } } +// { dg-options "-pedantic" } struct A { constexpr operator int() const { return 0; } }; -int a[] = { [A()] = 0 }; +int a[] = { [A()] = 0 }; // { dg-warning "does not allow C99 designated initializers" } enum E { e0 }; @@ -15,7 +16,7 @@ struct B constexpr operator E() const { return E::e0; } }; -int b[] = { [B()] = 0 }; +int b[] = { [B()] = 0 }; // { dg-warning "does not allow C99 designated initializers" } enum class SE { se0 }; @@ -25,3 +26,4 @@ struct C }; int c[] = { [C()] = 0 }; // { dg-error "integral constant-expression" } + // { dg-warning "does not allow C99 designated initializers" "" { target *-*-* } .-1 } --- gcc/testsuite/g++.dg/cpp2a/desig1.C.jj 2017-11-13 17:32:58.847273824 +0100 +++ gcc/testsuite/g++.dg/cpp2a/desig1.C 2017-11-13 17:32:38.000000000 +0100 @@ -0,0 +1,21 @@ +// { dg-do compile } +// { dg-options "-pedantic" } + +struct A { int a; }; +struct B { int b; A c; int d; }; +A a = { 1 }; +A b = { .a = 2 }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } +B c = { 3, { 4 }, 5 }; +B d = { .b = 6, .c { 7 }, .d = 8 }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } +B e = { .c = { .a = 9 } }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } + +int +main () +{ + if (a.a != 1 || b.a != 2 + || c.b != 3 || c.c.a != 4 || c.d != 5 + || d.b != 6 || d.c.a != 7 || d.d != 8 + || e.b != 0 || e.c.a != 9 || e.d != 0) + __builtin_abort (); + return 0; +} --- gcc/testsuite/g++.dg/cpp2a/desig2.C.jj 2017-11-13 17:54:00.859941240 +0100 +++ gcc/testsuite/g++.dg/cpp2a/desig2.C 2017-11-13 18:23:08.131718362 +0100 @@ -0,0 +1,19 @@ +// { dg-do compile } +// { dg-options "" } + +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++2a } } +S d = { .a = 1, 2, 3 }; // { dg-error "either all initializer clauses should be designated or none of them should be" "" { target c++2a } } +S e = { .b = 1, .b = 2 }; // { dg-error "designator used multiple times in the same initializer list" } + +#if __cplusplus > 201103L +template <int... N> +void +foo () +{ + S f = { .a = N... }; // { dg-error "'...' not allowed in designated initializer list" "" { target c++2a } } +} +#endif --- gcc/testsuite/g++.dg/cpp2a/desig3.C.jj 2017-11-13 18:08:39.066273072 +0100 +++ gcc/testsuite/g++.dg/cpp2a/desig3.C 2017-11-13 18:34:19.582557691 +0100 @@ -0,0 +1,27 @@ +// { dg-do run { target c++17 } } +// { dg-options "-pedantic" } + +struct S { int a; union { int b; double c; union { short e; long f; }; }; int d; }; +S s = { 1, 2, 3 }; +S t = { .a = 4, .b = 5, .d = 6 }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } +S u = { .a = 7, .c = 8.0, .d = 9 }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } +S v = { .c = 10.0, .d = 11 }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } +S w = { .b = 12 }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } +S x = { .b = 13 }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } +S y = { .a = 14, .e = 15, .d = 16 }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } +S z = { .f = 17 }; // { dg-warning "designated initializers only available with" "" { target c++17_down } } + +int +main () +{ + if (s.a != 1 || s.b != 2 || s.d != 3 + || t.a != 4 || t.b != 5 || t.d != 6 + || u.a != 7 || u.c != 8.0 || u.d != 9 + || v.a != 0 || v.c != 10.0 || v.d != 11 + || w.a != 0 || w.b != 12 || w.d != 0 + || x.a != 0 || x.b != 13 || x.d != 0 + || y.a != 14 || y.e != 15 || y.d != 16 + || z.a != 0 || z.f != 17 || z.d != 0) + __builtin_abort (); + return 0; +} --- gcc/testsuite/g++.dg/cpp2a/desig4.C.jj 2017-11-13 18:09:48.315431954 +0100 +++ gcc/testsuite/g++.dg/cpp2a/desig4.C 2017-11-13 18:16:35.870481685 +0100 @@ -0,0 +1,19 @@ +// { dg-do compile } +// { dg-options "" } + +struct A { int x, y; }; +struct B { int y, x; }; +void f(A a, int); // #1 +void f(B b, ...); // #2 +void g(A a); // #3 { dg-message "candidate:" } +void g(B b); // #4 { dg-message "candidate:" } +void h() { + f({.x = 1, .y = 2}, 0); // OK; calls #1 + // { dg-warning "extended initializer lists only available with" "" { target c++98_only } .-1 } + f({.y = 2, .x = 1}, 0); // error: selects #1 + // { dg-error "designator order for field 'A::x' does not match declaration order in 'A'" "" { target *-*-* } .-1 } + // { dg-warning "extended initializer lists only available with" "" { target c++98_only } .-2 } + g({.x = 1, .y = 2}); // error: ambiguous between #3 and #4 + // { dg-error "is ambiguous" "" { target *-*-* } .-1 } + // { dg-warning "extended initializer lists only available with" "" { target c++98_only } .-2 } +} --- gcc/testsuite/g++.dg/cpp2a/desig5.C.jj 2017-11-13 18:16:59.264197539 +0100 +++ gcc/testsuite/g++.dg/cpp2a/desig5.C 2017-11-13 18:36:50.150727362 +0100 @@ -0,0 +1,11 @@ +// { dg-do compile } +// { dg-options "" } + +union u { int a; const char* b; }; +u a = { 1 }; +u b = a; +u c = 1; // { dg-error "conversion from 'int' to non-scalar type 'u' requested" } +u d = { 0, "asdf" }; // { dg-error "too many initializers for" } +u e = { "asdf" }; // { dg-error "invalid conversion from 'const char\\*' to 'int'" } +u f = { .b = "asdf" }; +u g = { .a = 1, .b = "asdf" }; // { dg-error "too many initializers for" } --- gcc/testsuite/g++.dg/cpp2a/desig6.C.jj 2017-11-13 18:45:56.280092195 +0100 +++ gcc/testsuite/g++.dg/cpp2a/desig6.C 2017-11-13 19:17:26.650159089 +0100 @@ -0,0 +1,23 @@ +// { dg-do compile } +// { dg-options "" } + +struct A { int x, z, y; }; +struct B { int y, a, x; }; +void f(A a, int); // #1 +void f(B b, ...); // #2 +void g(A a); // #3 { dg-message "candidate:" } +void g(B b); // #4 { dg-message "candidate:" } +void h() { + f({.x = 1, .y = 2}, 0); // OK; calls #1 + // { dg-warning "extended initializer lists only available with" "" { target c++98_only } .-1 } + f({.y = 2, .x = 1}, 0); // error: selects #1 + // { dg-error "designator order for field 'A::x' does not match declaration order in 'A'" "" { target *-*-* } .-1 } + // { dg-warning "extended initializer lists only available with" "" { target c++98_only } .-2 } + f({.x = 1, .z = 2, .y = 3}, 0); // OK; calls #1 + // { dg-warning "extended initializer lists only available with" "" { target c++98_only } .-1 } + f({.y = 3, .a = 2, .x = 1}, 0); // OK; calls #2 + // { dg-warning "extended initializer lists only available with" "" { target c++98_only } .-1 } + g({.x = 1, .y = 2}); // error: ambiguous between #3 and #4 + // { dg-error "is ambiguous" "" { target *-*-* } .-1 } + // { dg-warning "extended initializer lists only available with" "" { target c++98_only } .-2 } +} Jakub