aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2017-11-20 19:58:01 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2017-11-20 19:58:01 +0100
commitd68ddd2b35078ab61f164b268bac63767b2a8e6a (patch)
treec5234ca2dab614ccfd0a1f96421fdb36976af8bf /gcc/cp
parent6c7a259b817ea4d1eae117a426a08fc85f943788 (diff)
downloadgcc-d68ddd2b35078ab61f164b268bac63767b2a8e6a.zip
gcc-d68ddd2b35078ab61f164b268bac63767b2a8e6a.tar.gz
gcc-d68ddd2b35078ab61f164b268bac63767b2a8e6a.tar.bz2
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
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog19
-rw-r--r--gcc/cp/name-lookup.c39
-rw-r--r--gcc/cp/name-lookup.h1
-rw-r--r--gcc/cp/parser.c119
-rw-r--r--gcc/cp/typeck2.c84
5 files changed, 216 insertions, 46 deletions
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 <jakub@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.
+
2017-11-20 David Malcolm <dmalcolm@redhat.com>
* 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<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)
@@ -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<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
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<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);
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<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;
@@ -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;
}