Commit d68ddd2b by Jakub Jelinek Committed by Jakub Jelinek

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
parent 6c7a259b
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> 2017-11-20 David Malcolm <dmalcolm@redhat.com>
* name-lookup.c: Define INCLUDE_UNIQUE_PTR before including system.h. * name-lookup.c: Define INCLUDE_UNIQUE_PTR before including system.h.
......
...@@ -1163,21 +1163,8 @@ fields_linear_search (tree klass, tree name, bool want_type) ...@@ -1163,21 +1163,8 @@ fields_linear_search (tree klass, tree name, bool want_type)
&& TREE_CODE (decl) == FIELD_DECL && TREE_CODE (decl) == FIELD_DECL
&& ANON_AGGR_TYPE_P (TREE_TYPE (decl))) && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
{ {
tree anon = TREE_TYPE (decl); if (tree temp = search_anon_aggr (TREE_TYPE (decl), name))
gcc_assert (COMPLETE_TYPE_P (anon)); return temp;
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 (DECL_NAME (decl) != name) if (DECL_NAME (decl) != name)
...@@ -1201,6 +1188,28 @@ fields_linear_search (tree klass, tree name, bool want_type) ...@@ -1201,6 +1188,28 @@ fields_linear_search (tree klass, tree name, bool want_type)
return NULL_TREE; 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 /* Look for NAME as an immediate member of KLASS (including
anon-members or unscoped enum member). TYPE_OR_FNS is zero for 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 regular search. >0 to get a type binding (if there is one) and <0
......
...@@ -307,6 +307,7 @@ extern void pop_decl_namespace (void); ...@@ -307,6 +307,7 @@ extern void pop_decl_namespace (void);
extern void do_namespace_alias (tree, tree); extern void do_namespace_alias (tree, tree);
extern tree do_class_using_decl (tree, tree); extern tree do_class_using_decl (tree, tree);
extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *); 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_direct (tree, tree, int type_or_fns = -1);
extern tree get_class_binding (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); extern tree *get_member_slot (tree klass, tree name);
......
...@@ -21991,6 +21991,7 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) ...@@ -21991,6 +21991,7 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
braced-init-list: braced-init-list:
{ initializer-list , [opt] } { initializer-list , [opt] }
{ designated-initializer-list , [opt] }
{ } { }
Returns a CONSTRUCTOR. The CONSTRUCTOR_ELTS will be Returns a CONSTRUCTOR. The CONSTRUCTOR_ELTS will be
...@@ -22107,6 +22108,18 @@ cp_parser_array_designator_p (cp_parser *parser) ...@@ -22107,6 +22108,18 @@ cp_parser_array_designator_p (cp_parser *parser)
initializer-clause ... [opt] initializer-clause ... [opt]
initializer-list , 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: GNU Extension:
initializer-list: initializer-list:
...@@ -22127,6 +22140,8 @@ static vec<constructor_elt, va_gc> * ...@@ -22127,6 +22140,8 @@ static vec<constructor_elt, va_gc> *
cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
{ {
vec<constructor_elt, va_gc> *v = NULL; vec<constructor_elt, va_gc> *v = NULL;
bool first_p = true;
tree first_designator = NULL_TREE;
/* Assume all of the expressions are constant. */ /* Assume all of the expressions are constant. */
*non_constant_p = false; *non_constant_p = false;
...@@ -22138,36 +22153,43 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) ...@@ -22138,36 +22153,43 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
tree designator; tree designator;
tree initializer; tree initializer;
bool clause_non_constant_p; 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 /* Handle the C++2A syntax, '. id ='. */
colon, we are looking at the GNU designated-initializer if ((cxx_dialect >= cxx2a
syntax. */ || cp_parser_allow_gnu_extensions_p (parser))
if (cp_parser_allow_gnu_extensions_p (parser) && cp_lexer_next_token_is (parser->lexer, CPP_DOT)
&& cp_lexer_next_token_is (parser->lexer, CPP_NAME) && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME
&& cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON) && (cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ
{ || (cp_lexer_peek_nth_token (parser->lexer, 3)->type
/* Warn the user that they are using an extension. */ == CPP_OPEN_BRACE)))
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. */ /* Consume the identifier. */
designator = cp_lexer_consume_token (parser->lexer)->u.value; designator = cp_lexer_consume_token (parser->lexer)->u.value;
/* Consume the `:'. */ if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
cp_lexer_consume_token (parser->lexer); /* 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) else if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_DOT) && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
&& cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
&& cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ) == CPP_COLON))
{ {
/* Warn the user that they are using an extension. */ /* Warn the user that they are using an extension. */
pedwarn (input_location, OPT_Wpedantic, pedwarn (loc, OPT_Wpedantic,
"ISO C++ does not allow C99 designated initializers"); "ISO C++ does not allow GNU designated initializers");
/* Consume the `.'. */
cp_lexer_consume_token (parser->lexer);
/* Consume the identifier. */ /* Consume the identifier. */
designator = cp_lexer_consume_token (parser->lexer)->u.value; designator = cp_lexer_consume_token (parser->lexer)->u.value;
/* Consume the `='. */ /* Consume the `:'. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
} }
/* Also handle C99 array designators, '[ const ] ='. */ /* Also handle C99 array designators, '[ const ] ='. */
...@@ -22197,10 +22219,30 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) ...@@ -22197,10 +22219,30 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
designator = NULL_TREE; designator = NULL_TREE;
else if (non_const) else if (non_const)
require_potential_rvalue_constant_expression (designator); 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 else
designator = NULL_TREE; 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. */ /* Parse the initializer. */
initializer = cp_parser_initializer_clause (parser, initializer = cp_parser_initializer_clause (parser,
&clause_non_constant_p); &clause_non_constant_p);
...@@ -22212,11 +22254,17 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) ...@@ -22212,11 +22254,17 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
expansion. */ expansion. */
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
{ {
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
/* Consume the `...'. */ /* Consume the `...'. */
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
/* Turn the initializer into an initializer expansion. */ if (designator && cxx_dialect >= cxx2a)
initializer = make_pack_expansion (initializer); 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. */ /* Add it to the vector. */
...@@ -22239,6 +22287,31 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p) ...@@ -22239,6 +22287,31 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
cp_lexer_consume_token (parser->lexer); 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; return v;
} }
...@@ -1371,6 +1371,7 @@ process_init_constructor_record (tree type, tree init, ...@@ -1371,6 +1371,7 @@ process_init_constructor_record (tree type, tree init,
restart: restart:
int flags = 0; int flags = 0;
unsigned HOST_WIDE_INT idx = 0; unsigned HOST_WIDE_INT idx = 0;
int designator_skip = -1;
/* Generally, we will always have an index for each initializer (which is /* 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 a FIELD_DECL, put by reshape_init), but compound literals don't go trough
reshape_init. So we need to handle both cases. */ reshape_init. So we need to handle both cases. */
...@@ -1394,6 +1395,7 @@ process_init_constructor_record (tree type, tree init, ...@@ -1394,6 +1395,7 @@ process_init_constructor_record (tree type, tree init,
if (type == error_mark_node) if (type == error_mark_node)
return PICFLAG_ERRONEOUS; return PICFLAG_ERRONEOUS;
next = NULL_TREE;
if (idx < CONSTRUCTOR_NELTS (init)) if (idx < CONSTRUCTOR_NELTS (init))
{ {
constructor_elt *ce = &(*CONSTRUCTOR_ELTS (init))[idx]; constructor_elt *ce = &(*CONSTRUCTOR_ELTS (init))[idx];
...@@ -1404,18 +1406,42 @@ process_init_constructor_record (tree type, tree init, ...@@ -1404,18 +1406,42 @@ process_init_constructor_record (tree type, tree init,
deferred. */ deferred. */
gcc_assert (TREE_CODE (ce->index) == FIELD_DECL gcc_assert (TREE_CODE (ce->index) == FIELD_DECL
|| identifier_p (ce->index)); || identifier_p (ce->index));
if (ce->index != field if (ce->index == field || ce->index == DECL_NAME (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; ce = NULL;
sorry ("non-trivial designated initializers not supported"); if (designator_skip == -1)
designator_skip = 1;
} }
} }
else
{
designator_skip = 0;
next = ce->value;
}
gcc_assert (ce->value); if (ce)
next = massage_init_elt (type, ce->value, complain); {
++idx; gcc_assert (ce->value);
next = massage_init_elt (type, next, complain);
++idx;
}
} }
if (next)
/* Already handled above. */;
else if (DECL_INITIAL (field)) else if (DECL_INITIAL (field))
{ {
if (skipped > 0) if (skipped > 0)
...@@ -1494,7 +1520,49 @@ process_init_constructor_record (tree type, tree init, ...@@ -1494,7 +1520,49 @@ process_init_constructor_record (tree type, tree init,
if (idx < CONSTRUCTOR_NELTS (init)) if (idx < CONSTRUCTOR_NELTS (init))
{ {
if (complain & tf_error) 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 else
return PICFLAG_ERRONEOUS; return PICFLAG_ERRONEOUS;
} }
......
2017-11-20 Jakub Jelinek <jakub@redhat.com>
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 <nathan@acm.org> 2017-11-20 Nathan Sidwell <nathan@acm.org>
PR c++/82878 PR c++/82878
......
// PR c++/58882 // PR c++/58882
// { dg-do compile { target c++11 } } // { dg-do compile { target c++11 } }
// { dg-options "-pedantic" }
struct A struct A
{ {
constexpr operator int() const { return 0; } 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 }; enum E { e0 };
...@@ -15,7 +16,7 @@ struct B ...@@ -15,7 +16,7 @@ struct B
constexpr operator E() const { return E::e0; } 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 }; enum class SE { se0 };
...@@ -25,3 +26,4 @@ struct C ...@@ -25,3 +26,4 @@ struct C
}; };
int c[] = { [C()] = 0 }; // { dg-error "integral constant-expression" } int c[] = { [C()] = 0 }; // { dg-error "integral constant-expression" }
// { dg-warning "does not allow C99 designated initializers" "" { target *-*-* } .-1 }
// { 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;
}
// { 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
// { 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;
}
// { 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 }
}
// { 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" }
// { 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 }
}
...@@ -12,8 +12,9 @@ __extension__ int i[4] = { [0] = 1, [1] = 2 }; ...@@ -12,8 +12,9 @@ __extension__ int i[4] = { [0] = 1, [1] = 2 };
// Currently, except for unions, the C++ front end only supports // Currently, except for unions, the C++ front end only supports
// designators that designate the element that would have been initialized // designators that designate the element that would have been initialized
// anyway. While that's true, make sure that we get a sorry rather than // anyway, except that C++2A designators can skip over some direct
// bad code. // non-static data members. While that's true, make sure that we get
// a sorry rather than bad code.
struct A struct A
{ {
...@@ -21,5 +22,6 @@ struct A ...@@ -21,5 +22,6 @@ struct A
int j; 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" } __extension__ int j[2] = { [1] = 1 }; // { dg-message "non-trivial" }
...@@ -5,6 +5,10 @@ char g[] = { [7] = "abcd" }; // { dg-error "designator" } ...@@ -5,6 +5,10 @@ char g[] = { [7] = "abcd" }; // { dg-error "designator" }
int a = { .foo = 6 }; // { dg-error "designator" } int a = { .foo = 6 }; // { dg-error "designator" }
int b = { [0] = 1 }; // { dg-error "designator" } int b = { [0] = 1 }; // { dg-error "designator" }
_Complex float c = { .foo = 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" } _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" } _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" } _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 }
// PR c++/55951 // PR c++/55951
// { dg-do compile }
// { dg-options "" }
enum { A }; enum { A };
......
// PR c++/58882 // PR c++/58882
// { dg-do compile }
// { dg-options "" }
int a[] = { [0.] = 0 }; // { dg-error "integral constant-expression" } int a[] = { [0.] = 0 }; // { dg-error "integral constant-expression" }
// { dg-do compile }
int a[2] = { [0] = 1, [1] = 2 }; // { dg-error "does not allow C99 designated initializers" }
...@@ -8,4 +8,4 @@ struct A ...@@ -8,4 +8,4 @@ struct A
int z[1]; int z[1];
}; };
A a = { z:{} }; // { dg-message "unimplemented" } A a = { z:{} };
...@@ -5,7 +5,7 @@ template<int> struct A ...@@ -5,7 +5,7 @@ template<int> struct A
{ {
static int a[1]; 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() void foo()
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment