@@ -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;
}
@@ -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);
@@ -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
@@ -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;
}
@@ -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" }
@@ -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 }
@@ -1,4 +1,6 @@
// PR c++/55951
+// { dg-do compile }
+// { dg-options "" }
enum { A };
@@ -1,3 +1,5 @@
// PR c++/58882
+// { dg-do compile }
+// { dg-options "" }
int a[] = { [0.] = 0 }; // { dg-error "integral constant-expression" }
@@ -0,0 +1,3 @@
+// { dg-do compile }
+
+int a[2] = { [0] = 1, [1] = 2 }; // { dg-error "does not allow C99 designated initializers" }
@@ -8,4 +8,4 @@ struct A
int z[1];
};
-A a = { z:{} }; // { dg-message "unimplemented" }
+A a = { z:{} };
@@ -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()
{
@@ -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 }
@@ -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;
+}
@@ -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
@@ -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;
+}
@@ -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 }
+}
@@ -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" }
@@ -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 }
+}