This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] P0329R4: Designated Initialization


Hi!

This patch adds support for c++2a designated initializers.
We've been supporting a small restricted subset of C99 initializers as a GNU
extension before, the C++2A designated initializers are partly a subset of
that, but on the other side extent it more and add some further
restrictions.

I've tried to keep the new restrictions limited to -std=c++2a/-std=gnu++2a,
so existing code in C++{98,11,14,17} can use the old extensions (this is the
case of e.g. the requirement that either all or none of the initializer clauses
use designator, previously we were allowing mixing them), while cases where
the new code extends the previous behavior are allowed always (e.g. the
possibility to skip over some non-static data members which are then
initialized like other not explictly initialized members or anonymous
aggregate handling).
I've noticed we didn't issue any pedwarn for [0] = C99 designators, so that
is fixed too.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2017-11-13  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.

	* 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.

--- gcc/cp/parser.c.jj	2017-11-10 15:42:02.000000000 +0100
+++ gcc/cp/parser.c	2017-11-13 19:23:04.384100628 +0100
@@ -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;
 }
 
--- gcc/cp/name-lookup.h.jj	2017-10-26 14:36:03.000000000 +0200
+++ gcc/cp/name-lookup.h	2017-11-13 16:33:16.751790779 +0100
@@ -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);
--- gcc/cp/name-lookup.c.jj	2017-11-01 22:49:15.000000000 +0100
+++ gcc/cp/name-lookup.c	2017-11-13 16:54:17.629471698 +0100
@@ -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
--- gcc/cp/typeck2.c.jj	2017-11-07 08:45:21.000000000 +0100
+++ gcc/cp/typeck2.c	2017-11-13 17:23:09.590432311 +0100
@@ -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;
     }
--- gcc/testsuite/g++.dg/ext/desig2.C.jj	2011-07-21 09:54:35.000000000 +0200
+++ gcc/testsuite/g++.dg/ext/desig2.C	2017-11-13 18:39:50.324537143 +0100
@@ -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" }
--- gcc/testsuite/g++.dg/ext/desig4.C.jj	2011-12-16 08:37:36.000000000 +0100
+++ gcc/testsuite/g++.dg/ext/desig4.C	2017-11-13 18:41:37.697231905 +0100
@@ -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 }
--- gcc/testsuite/g++.dg/ext/desig5.C.jj	2013-03-27 12:52:19.000000000 +0100
+++ gcc/testsuite/g++.dg/ext/desig5.C	2017-11-13 19:29:57.005142269 +0100
@@ -1,4 +1,6 @@
 // PR c++/55951
+// { dg-do compile }
+// { dg-options "" }
 
 enum { A };
 
--- gcc/testsuite/g++.dg/ext/desig8.C.jj	2014-12-15 19:36:54.000000000 +0100
+++ gcc/testsuite/g++.dg/ext/desig8.C	2017-11-13 19:30:31.303730112 +0100
@@ -1,3 +1,5 @@
 // PR c++/58882
+// { dg-do compile }
+// { dg-options "" }
 
 int a[] = { [0.] = 0 }; // { dg-error "integral constant-expression" }
--- gcc/testsuite/g++.dg/ext/desig9.C.jj	2017-11-13 19:31:17.992169069 +0100
+++ gcc/testsuite/g++.dg/ext/desig9.C	2017-11-13 19:31:11.361248751 +0100
@@ -0,0 +1,3 @@
+// { dg-do compile }
+
+int a[2] = { [0] = 1, [1] = 2 };	// { dg-error "does not allow C99 designated initializers" }
--- gcc/testsuite/g++.dg/ext/pr27019.C.jj	2008-10-23 13:21:04.000000000 +0200
+++ gcc/testsuite/g++.dg/ext/pr27019.C	2017-11-13 21:36:56.335818475 +0100
@@ -8,4 +8,4 @@ struct A
                 int z[1];
 };
 
-A a = { z:{} }; // { dg-message "unimplemented" }
+A a = { z:{} };
--- gcc/testsuite/g++.dg/init/error2.C.jj	2011-02-25 19:01:45.000000000 +0100
+++ gcc/testsuite/g++.dg/init/error2.C	2017-11-13 21:39:23.870022426 +0100
@@ -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()
 {
--- gcc/testsuite/g++.dg/cpp0x/desig1.C.jj	2014-12-15 19:36:54.000000000 +0100
+++ gcc/testsuite/g++.dg/cpp0x/desig1.C	2017-11-13 19:28:49.609952140 +0100
@@ -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 }
--- gcc/testsuite/g++.dg/cpp2a/desig1.C.jj	2017-11-13 17:32:58.847273824 +0100
+++ gcc/testsuite/g++.dg/cpp2a/desig1.C	2017-11-13 17:32:38.000000000 +0100
@@ -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;
+}
--- gcc/testsuite/g++.dg/cpp2a/desig2.C.jj	2017-11-13 17:54:00.859941240 +0100
+++ gcc/testsuite/g++.dg/cpp2a/desig2.C	2017-11-13 18:23:08.131718362 +0100
@@ -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
--- gcc/testsuite/g++.dg/cpp2a/desig3.C.jj	2017-11-13 18:08:39.066273072 +0100
+++ gcc/testsuite/g++.dg/cpp2a/desig3.C	2017-11-13 18:34:19.582557691 +0100
@@ -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;
+}
--- gcc/testsuite/g++.dg/cpp2a/desig4.C.jj	2017-11-13 18:09:48.315431954 +0100
+++ gcc/testsuite/g++.dg/cpp2a/desig4.C	2017-11-13 18:16:35.870481685 +0100
@@ -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 }
+}
--- gcc/testsuite/g++.dg/cpp2a/desig5.C.jj	2017-11-13 18:16:59.264197539 +0100
+++ gcc/testsuite/g++.dg/cpp2a/desig5.C	2017-11-13 18:36:50.150727362 +0100
@@ -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" }
--- gcc/testsuite/g++.dg/cpp2a/desig6.C.jj	2017-11-13 18:45:56.280092195 +0100
+++ gcc/testsuite/g++.dg/cpp2a/desig6.C	2017-11-13 19:17:26.650159089 +0100
@@ -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 }
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]