From d68ddd2b35078ab61f164b268bac63767b2a8e6a Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 20 Nov 2017 19:58:01 +0100 Subject: [PATCH] P0329R4: Designated Initialization 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. From-SVN: r254964 --- gcc/cp/ChangeLog | 19 +++++ gcc/cp/name-lookup.c | 39 +++++---- gcc/cp/name-lookup.h | 1 + gcc/cp/parser.c | 119 ++++++++++++++++++++++------ gcc/cp/typeck2.c | 84 ++++++++++++++++++-- gcc/testsuite/ChangeLog | 21 +++++ gcc/testsuite/g++.dg/cpp0x/desig1.C | 6 +- gcc/testsuite/g++.dg/cpp2a/desig1.C | 21 +++++ gcc/testsuite/g++.dg/cpp2a/desig2.C | 19 +++++ gcc/testsuite/g++.dg/cpp2a/desig3.C | 27 +++++++ gcc/testsuite/g++.dg/cpp2a/desig4.C | 19 +++++ gcc/testsuite/g++.dg/cpp2a/desig5.C | 11 +++ gcc/testsuite/g++.dg/cpp2a/desig6.C | 23 ++++++ gcc/testsuite/g++.dg/ext/desig2.C | 8 +- gcc/testsuite/g++.dg/ext/desig4.C | 4 + gcc/testsuite/g++.dg/ext/desig5.C | 2 + gcc/testsuite/g++.dg/ext/desig8.C | 2 + gcc/testsuite/g++.dg/ext/desig9.C | 3 + gcc/testsuite/g++.dg/ext/pr27019.C | 2 +- gcc/testsuite/g++.dg/init/error2.C | 2 +- 20 files changed, 379 insertions(+), 53 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig3.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig4.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig5.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig6.C create mode 100644 gcc/testsuite/g++.dg/ext/desig9.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6a690a1f06e..31b20ffa3e0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2017-11-20 Jakub Jelinek + + 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. + 2017-11-20 David Malcolm * name-lookup.c: Define INCLUDE_UNIQUE_PTR before including system.h. diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index f7da6a29078..9d97da383e7 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1163,21 +1163,8 @@ fields_linear_search (tree klass, tree name, bool want_type) && 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 *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) @@ -1201,6 +1188,28 @@ fields_linear_search (tree klass, tree name, bool want_type) 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 *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 diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 1fc128070d3..e209f183796 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -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 *); +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); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b3bdd38cc21..82807690c88 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -21991,6 +21991,7 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) braced-init-list: { initializer-list , [opt] } + { designated-initializer-list , [opt] } { } Returns a CONSTRUCTOR. The CONSTRUCTOR_ELTS will be @@ -22107,6 +22108,18 @@ cp_parser_array_designator_p (cp_parser *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: @@ -22127,6 +22140,8 @@ static vec * cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) { vec *v = NULL; + bool first_p = true; + tree first_designator = NULL_TREE; /* Assume all of the expressions are constant. */ *non_constant_p = false; @@ -22138,36 +22153,43 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_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) - { - /* Warn the user that they are using an extension. */ - pedwarn (input_location, OPT_Wpedantic, - "ISO C++ does not allow designated initializers"); + /* 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))) + { + 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 ] ='. */ @@ -22197,10 +22219,30 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_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); @@ -22212,11 +22254,17 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_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. */ @@ -22239,6 +22287,31 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_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; } diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index e135b0de363..b3b3c581afb 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1371,6 +1371,7 @@ process_init_constructor_record (tree type, tree init, 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 type, tree init, 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 type, tree init, 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 type, tree init, 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; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ba7426a38a4..c8f4f498852 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,24 @@ +2017-11-20 Jakub Jelinek + + P0329R4: Designated Initialization + * 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. + 2017-11-20 Nathan Sidwell PR c++/82878 diff --git a/gcc/testsuite/g++.dg/cpp0x/desig1.C b/gcc/testsuite/g++.dg/cpp0x/desig1.C index cc527308f0d..393f5309f7f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/desig1.C +++ b/gcc/testsuite/g++.dg/cpp0x/desig1.C @@ -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 } diff --git a/gcc/testsuite/g++.dg/cpp2a/desig1.C b/gcc/testsuite/g++.dg/cpp2a/desig1.C new file mode 100644 index 00000000000..d6bc0681cc0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/desig1.C @@ -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; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/desig2.C b/gcc/testsuite/g++.dg/cpp2a/desig2.C new file mode 100644 index 00000000000..7a036182062 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/desig2.C @@ -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 +void +foo () +{ + S f = { .a = N... }; // { dg-error "'...' not allowed in designated initializer list" "" { target c++2a } } +} +#endif diff --git a/gcc/testsuite/g++.dg/cpp2a/desig3.C b/gcc/testsuite/g++.dg/cpp2a/desig3.C new file mode 100644 index 00000000000..50d2fade96a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/desig3.C @@ -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; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/desig4.C b/gcc/testsuite/g++.dg/cpp2a/desig4.C new file mode 100644 index 00000000000..6f53ad42466 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/desig4.C @@ -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 } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/desig5.C b/gcc/testsuite/g++.dg/cpp2a/desig5.C new file mode 100644 index 00000000000..574d0b3133d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/desig5.C @@ -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" } diff --git a/gcc/testsuite/g++.dg/cpp2a/desig6.C b/gcc/testsuite/g++.dg/cpp2a/desig6.C new file mode 100644 index 00000000000..a2d0a1036a4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/desig6.C @@ -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 } +} diff --git a/gcc/testsuite/g++.dg/ext/desig2.C b/gcc/testsuite/g++.dg/ext/desig2.C index 229ae527d77..b117878f5a7 100644 --- a/gcc/testsuite/g++.dg/ext/desig2.C +++ b/gcc/testsuite/g++.dg/ext/desig2.C @@ -12,8 +12,9 @@ __extension__ int i[4] = { [0] = 1, [1] = 2 }; // 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" } diff --git a/gcc/testsuite/g++.dg/ext/desig4.C b/gcc/testsuite/g++.dg/ext/desig4.C index 48d629a943f..33be2582be2 100644 --- a/gcc/testsuite/g++.dg/ext/desig4.C +++ b/gcc/testsuite/g++.dg/ext/desig4.C @@ -5,6 +5,10 @@ char g[] = { [7] = "abcd" }; // { dg-error "designator" } 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 } diff --git a/gcc/testsuite/g++.dg/ext/desig5.C b/gcc/testsuite/g++.dg/ext/desig5.C index 48cce3183b5..b310ef5cdf3 100644 --- a/gcc/testsuite/g++.dg/ext/desig5.C +++ b/gcc/testsuite/g++.dg/ext/desig5.C @@ -1,4 +1,6 @@ // PR c++/55951 +// { dg-do compile } +// { dg-options "" } enum { A }; diff --git a/gcc/testsuite/g++.dg/ext/desig8.C b/gcc/testsuite/g++.dg/ext/desig8.C index 98e7bfdca46..db988ed1393 100644 --- a/gcc/testsuite/g++.dg/ext/desig8.C +++ b/gcc/testsuite/g++.dg/ext/desig8.C @@ -1,3 +1,5 @@ // PR c++/58882 +// { dg-do compile } +// { dg-options "" } int a[] = { [0.] = 0 }; // { dg-error "integral constant-expression" } diff --git a/gcc/testsuite/g++.dg/ext/desig9.C b/gcc/testsuite/g++.dg/ext/desig9.C new file mode 100644 index 00000000000..c696a3f45fe --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/desig9.C @@ -0,0 +1,3 @@ +// { dg-do compile } + +int a[2] = { [0] = 1, [1] = 2 }; // { dg-error "does not allow C99 designated initializers" } diff --git a/gcc/testsuite/g++.dg/ext/pr27019.C b/gcc/testsuite/g++.dg/ext/pr27019.C index c96d51c14ec..d83ea867f61 100644 --- a/gcc/testsuite/g++.dg/ext/pr27019.C +++ b/gcc/testsuite/g++.dg/ext/pr27019.C @@ -8,4 +8,4 @@ struct A int z[1]; }; -A a = { z:{} }; // { dg-message "unimplemented" } +A a = { z:{} }; diff --git a/gcc/testsuite/g++.dg/init/error2.C b/gcc/testsuite/g++.dg/init/error2.C index 43d24f13b73..067e7def0eb 100644 --- a/gcc/testsuite/g++.dg/init/error2.C +++ b/gcc/testsuite/g++.dg/init/error2.C @@ -5,7 +5,7 @@ template struct A { static int a[1]; }; -template int A::a[1] = { X:0 }; /* { dg-error "does not allow designated|was not declared|designated initializer for an array" } */ +template int A::a[1] = { X:0 }; /* { dg-error "does not allow GNU designated|was not declared|designated initializer for an array" } */ void foo() { -- 2.30.2