Jakub pointed out that parenthesized decomposition of an array wasn't
properly using direct-initialization.  Rather than pass the flags down
into build_vec_init at this point in GCC 7 development, let's turn the
initializer into something that build_vec_init recognizes as
direct-initialization.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit ea395e328d0f3e3d7800ddb319f0e25b6c363ce9
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Jan 18 16:04:31 2017 -0500

            PR c++/79130 - decomposition and direct-initialization
    
            * init.c (build_aggr_init): Communicate direct-initialization to
            build_vec_init.
            (build_vec_init): Check for array copy sooner.
            * parser.c (cp_parser_decomposition_declaration): Remove call to
            build_x_compound_expr_from_list.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 8f68c88b..15388b1 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1574,20 +1574,24 @@ build_aggr_init (tree exp, tree init, int flags, 
tsubst_flags_t complain)
   TREE_READONLY (exp) = 0;
   TREE_THIS_VOLATILE (exp) = 0;
 
-  if (init && init != void_type_node
-      && TREE_CODE (init) != TREE_LIST
-      && !(TREE_CODE (init) == TARGET_EXPR
-          && TARGET_EXPR_DIRECT_INIT_P (init))
-      && !DIRECT_LIST_INIT_P (init))
-    flags |= LOOKUP_ONLYCONVERTING;
-
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
       tree itype = init ? TREE_TYPE (init) : NULL_TREE;
       int from_array = 0;
 
       if (VAR_P (exp) && DECL_DECOMPOSITION_P (exp))
-       from_array = 1;
+       {
+         from_array = 1;
+         if (init && DECL_P (init)
+             && !(flags & LOOKUP_ONLYCONVERTING))
+           {
+             /* Wrap the initializer in a CONSTRUCTOR so that build_vec_init
+                recognizes it as direct-initialization.  */
+             init = build_constructor_single (init_list_type_node,
+                                              NULL_TREE, init);
+             CONSTRUCTOR_IS_DIRECT_INIT (init) = true;
+           }
+       }
       else
        {
          /* An array may not be initialized use the parenthesized
@@ -1621,6 +1625,13 @@ build_aggr_init (tree exp, tree init, int flags, 
tsubst_flags_t complain)
       return stmt_expr;
     }
 
+  if (init && init != void_type_node
+      && TREE_CODE (init) != TREE_LIST
+      && !(TREE_CODE (init) == TARGET_EXPR
+          && TARGET_EXPR_DIRECT_INIT_P (init))
+      && !DIRECT_LIST_INIT_P (init))
+    flags |= LOOKUP_ONLYCONVERTING;
+
   if ((VAR_P (exp) || TREE_CODE (exp) == PARM_DECL)
       && !lookup_attribute ("warn_unused", TYPE_ATTRIBUTES (type)))
     /* Just know that we've seen something for this node.  */
@@ -3825,6 +3836,18 @@ build_vec_init (tree base, tree maxindex, tree init,
       && from_array != 2)
     init = TARGET_EXPR_INITIAL (init);
 
+  bool direct_init = false;
+  if (from_array && init && BRACE_ENCLOSED_INITIALIZER_P (init)
+      && CONSTRUCTOR_NELTS (init) == 1)
+    {
+      tree elt = CONSTRUCTOR_ELT (init, 0)->value;
+      if (TREE_CODE (TREE_TYPE (elt)) == ARRAY_TYPE)
+       {
+         direct_init = DIRECT_LIST_INIT_P (init);
+         init = elt;
+       }
+    }
+
   /* If we have a braced-init-list, make sure that the array
      is big enough for all the initializers.  */
   bool length_check = (init && TREE_CODE (init) == CONSTRUCTOR
@@ -3905,18 +3928,6 @@ build_vec_init (tree base, tree maxindex, tree init,
   base = get_temp_regvar (ptype, rval);
   iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
 
-  bool direct_init = false;
-  if (from_array && init && BRACE_ENCLOSED_INITIALIZER_P (init)
-      && CONSTRUCTOR_NELTS (init) == 1)
-    {
-      tree elt = CONSTRUCTOR_ELT (init, 0)->value;
-      if (TREE_CODE (TREE_TYPE (elt)) == ARRAY_TYPE)
-       {
-         direct_init = DIRECT_LIST_INIT_P (init);
-         init = elt;
-       }
-    }
-
   /* If initializing one array from another, initialize element by
      element.  We rely upon the below calls to do the argument
      checking.  Evaluate the initializer before entering the try block.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6d3b877..29dcfea 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13026,9 +13026,6 @@ cp_parser_decomposition_declaration (cp_parser *parser,
       *init_loc = cp_lexer_peek_token (parser->lexer)->location;
       tree initializer = cp_parser_initializer (parser, &is_direct_init,
                                                &non_constant_p);
-      if (TREE_CODE (initializer) == TREE_LIST)
-       initializer = build_x_compound_expr_from_list (initializer, ELK_INIT,
-                                                      tf_warning_or_error);
 
       if (decl != error_mark_node)
        {
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp6.C 
b/gcc/testsuite/g++.dg/cpp1z/decomp6.C
index ed6fce4..7a8a239 100644
--- a/gcc/testsuite/g++.dg/cpp1z/decomp6.C
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp6.C
@@ -89,4 +89,40 @@ main ()
   }
   if (ccnt != 12 || dcnt != 24 || cccnt != 6 || tccnt != 6)
     __builtin_abort ();
+
+  {
+    A a[6];
+    if (ccnt != 18 || dcnt != 24 || cccnt != 6 || tccnt != 6)
+      __builtin_abort ();
+    {
+      auto [b,c,d,e,f,g] ( a );                // { dg-warning "decomposition 
declaration only available with" "" { target c++14_down } }
+      if (ccnt != 18 || dcnt != 24 || cccnt != 12 || tccnt != 6)
+       __builtin_abort ();
+      b.a++;
+      c.a += 2;
+      f.a += 3;
+      if (b.a != 7 || c.a != 8 || d.a != 6 || e.a != 6 || f.a != 9 || g.a != 6)
+       __builtin_abort ();
+      if (&b == &a[0] || &c == &a[1] || &d == &a[2] || &e == &a[3] || &f == 
&a[4] || &g == &a[5])
+       __builtin_abort ();
+      {
+       auto&[ h, i, j, k, l, m ] (a);  // { dg-warning "decomposition 
declaration only available with" "" { target c++14_down } }
+       if (ccnt != 18 || dcnt != 24 || cccnt != 12 || tccnt != 6)
+         __builtin_abort ();
+       j.a += 4;
+       k.a += 5;
+       m.a += 6;
+       if (a[0].a != 6 || a[1].a != 6 || a[2].a != 10 || a[3].a != 11 || 
a[4].a != 6 || a[5].a != 12)
+         __builtin_abort ();
+       if (&h != &a[0] || &i != &a[1] || &j != &a[2] || &k != &a[3] || &l != 
&a[4] || &m != &a[5])
+         __builtin_abort ();
+      }
+      if (ccnt != 18 || dcnt != 24 || cccnt != 12 || tccnt != 6)
+       __builtin_abort ();
+    }
+    if (ccnt != 18 || dcnt != 30 || cccnt != 12 || tccnt != 6)
+      __builtin_abort ();
+  }
+  if (ccnt != 18 || dcnt != 36 || cccnt != 12 || tccnt != 6)
+    __builtin_abort ();
 }

Reply via email to