From d68ddd2b35078ab61f164b268bac63767b2a8e6a Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 20 Nov 2017 19:58:01 +0100 Subject: 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 ++++++++++++++++++++++++++++++++---- 5 files changed, 216 insertions(+), 46 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6a690a1..31b20ff 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 f7da6a2..9d97da3 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 1fc1280..e209f18 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 b3bdd38..8280769 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 e135b0d..b3b3c58 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; } -- cgit v1.1