]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
P0329R4: Designated Initialization
authorJakub Jelinek <jakub@redhat.com>
Mon, 20 Nov 2017 18:58:01 +0000 (19:58 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 20 Nov 2017 18:58:01 +0000 (19:58 +0100)
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

20 files changed:
gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/desig1.C
gcc/testsuite/g++.dg/cpp2a/desig1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/desig2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/desig3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/desig4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/desig5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/desig6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/desig2.C
gcc/testsuite/g++.dg/ext/desig4.C
gcc/testsuite/g++.dg/ext/desig5.C
gcc/testsuite/g++.dg/ext/desig8.C
gcc/testsuite/g++.dg/ext/desig9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/pr27019.C
gcc/testsuite/g++.dg/init/error2.C

index 6a690a1f06eb189bc5c63ebe7ecf4668ca1170b6..31b20ffa3e0f52c2237b3d2103a023262193674a 100644 (file)
@@ -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.
index f7da6a290784cc896f1c9374755fd30c678ca6ff..9d97da383e73c149346773794888946ff1197487 100644 (file)
@@ -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
index 1fc128070d30b7619dc1f99a1973f6f7abfaa7b0..e209f18379671e82848beb79b300d59372d375a3 100644 (file)
@@ -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);
index b3bdd38cc21dc603d94d5b8ba2cf49bfd0819739..82807690c88c30cb89c98ac6ce945b9e1e1a524a 100644 (file)
@@ -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;
 }
 
index e135b0de363503bfa1e89dcd97d977e466020c91..b3b3c581afbdee00555bd1252972b52ff863416a 100644 (file)
@@ -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;
     }
index ba7426a38a44e9fbe8e293eb686951ece071926a..c8f4f498852ab68319cf8ea3fcb6be90bce2a92c 100644 (file)
@@ -1,3 +1,24 @@
+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>
 
        PR c++/82878
index cc527308f0d7f55574ab330e769dc6ac392fe438..393f5309f7f8dcae5c31fdc50378b5f58c423245 100644 (file)
@@ -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 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig1.C b/gcc/testsuite/g++.dg/cpp2a/desig1.C
new file mode 100644 (file)
index 0000000..d6bc068
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig2.C b/gcc/testsuite/g++.dg/cpp2a/desig2.C
new file mode 100644 (file)
index 0000000..7a03618
--- /dev/null
@@ -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
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig3.C b/gcc/testsuite/g++.dg/cpp2a/desig3.C
new file mode 100644 (file)
index 0000000..50d2fad
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig4.C b/gcc/testsuite/g++.dg/cpp2a/desig4.C
new file mode 100644 (file)
index 0000000..6f53ad4
--- /dev/null
@@ -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 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig5.C b/gcc/testsuite/g++.dg/cpp2a/desig5.C
new file mode 100644 (file)
index 0000000..574d0b3
--- /dev/null
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig6.C b/gcc/testsuite/g++.dg/cpp2a/desig6.C
new file mode 100644 (file)
index 0000000..a2d0a10
--- /dev/null
@@ -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 }
+}
index 229ae527d77fcf5c300f11290a3767fabf56dbb6..b117878f5a788382054128ec6558f40daa84e307 100644 (file)
@@ -12,8 +12,9 @@ __extension__ int i[4] = { [0] = 1, [1] = 2 };
 
 // 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" }
index 48d629a943f29b32e766c683592cedad7b519274..33be2582be2ad9fd97da84985e110d3417d511a6 100644 (file)
@@ -5,6 +5,10 @@ char g[] = { [7] = "abcd" };        // { dg-error "designator" }
 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 }
index 48cce3183b53be7ac458968c6dffdf69e3c5c235..b310ef5cdf3490cf9eaae2c833f8ae79367b90a1 100644 (file)
@@ -1,4 +1,6 @@
 // PR c++/55951
+// { dg-do compile }
+// { dg-options "" }
 
 enum { A };
 
index 98e7bfdca46bb550ab10c786b602b895a4515b2b..db988ed13933ce26a2b6653d9248e8772fc2b1ad 100644 (file)
@@ -1,3 +1,5 @@
 // PR c++/58882
+// { dg-do compile }
+// { dg-options "" }
 
 int a[] = { [0.] = 0 }; // { dg-error "integral constant-expression" }
diff --git a/gcc/testsuite/g++.dg/ext/desig9.C b/gcc/testsuite/g++.dg/ext/desig9.C
new file mode 100644 (file)
index 0000000..c696a3f
--- /dev/null
@@ -0,0 +1,3 @@
+// { dg-do compile }
+
+int a[2] = { [0] = 1, [1] = 2 };       // { dg-error "does not allow C99 designated initializers" }
index c96d51c14ec29c38c29bd13863206165b7b4d5b5..d83ea867f611c4a5bd021a7bab7932cff3b4b040 100644 (file)
@@ -8,4 +8,4 @@ struct A
                 int z[1];
 };
 
-A a = { z:{} }; // { dg-message "unimplemented" }
+A a = { z:{} };
index 43d24f13b732a5817fef8e92985b46968c832cec..067e7def0eb907b8b4c2a4a5c3e6d4de6ab77027 100644 (file)
@@ -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()
 {