re PR c++/59659 (large zero-initialized std::array compile time excessive)
authorJason Merrill <jason@redhat.com>
Wed, 15 Jan 2014 19:10:09 +0000 (14:10 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 15 Jan 2014 19:10:09 +0000 (14:10 -0500)
PR c++/59659
* typeck2.c (massage_init_elt): New.
(process_init_constructor_record)
(process_init_constructor_union): Use it.
(process_init_constructor_array): Use it.  Use RANGE_EXPR.
(split_nonconstant_init_1): Handle it.
* semantics.c (cxx_eval_vec_init_1): Use force_rvalue.

From-SVN: r206639

gcc/cp/ChangeLog
gcc/cp/semantics.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/opt/value-init1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/opt/value-init2.C [new file with mode: 0644]

index 9213de72d1b4698ef597e09badd4e03de0808402..c15c8fd511c501b2b80807d011f6ccc6520641ae 100644 (file)
@@ -1,3 +1,13 @@
+2014-01-14  Jason Merrill  <jason@redhat.com>
+
+       PR c++/59659
+       * typeck2.c (massage_init_elt): New.
+       (process_init_constructor_record)
+       (process_init_constructor_union): Use it.
+       (process_init_constructor_array): Use it.  Use RANGE_EXPR.
+       (split_nonconstant_init_1): Handle it.
+       * semantics.c (cxx_eval_vec_init_1): Use force_rvalue.
+
 2014-01-09  Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
        PR c++/59631
index 9f878874e6d71e44434a34f2839f9585b8d82bd3..eb04266aee81f10a76910c4506051c0ac4cc3b3a 100644 (file)
@@ -8961,19 +8961,13 @@ cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init,
       else
        {
          /* Copying an element.  */
-         vec<tree, va_gc> *argvec;
          gcc_assert (same_type_ignoring_top_level_qualifiers_p
                      (atype, TREE_TYPE (init)));
          eltinit = cp_build_array_ref (input_location, init, idx,
                                        tf_warning_or_error);
          if (!real_lvalue_p (init))
            eltinit = move (eltinit);
-         argvec = make_tree_vector ();
-         argvec->quick_push (eltinit);
-         eltinit = (build_special_member_call
-                    (NULL_TREE, complete_ctor_identifier, &argvec,
-                     elttype, LOOKUP_NORMAL, tf_warning_or_error));
-         release_tree_vector (argvec);
+         eltinit = force_rvalue (eltinit, tf_warning_or_error);
          eltinit = cxx_eval_constant_expression
            (call, eltinit, allow_non_constant, addr, non_constant_p, overflow_p);
        }
index d9c36470029ec0da1a28daa8b69911ad989eb418..25edbacce96e85d51a4766803974ec05308eb0b7 100644 (file)
@@ -631,24 +631,40 @@ split_nonconstant_init_1 (tree dest, tree init)
              CONSTRUCTOR_ELTS (init)->ordered_remove (idx);
              --idx;
 
-             if (array_type_p)
-               sub = build4 (ARRAY_REF, inner_type, dest, field_index,
-                             NULL_TREE, NULL_TREE);
+             if (TREE_CODE (field_index) == RANGE_EXPR)
+               {
+                 /* Use build_vec_init to initialize a range.  */
+                 tree low = TREE_OPERAND (field_index, 0);
+                 tree hi = TREE_OPERAND (field_index, 1);
+                 sub = build4 (ARRAY_REF, inner_type, dest, low,
+                               NULL_TREE, NULL_TREE);
+                 sub = cp_build_addr_expr (sub, tf_warning_or_error);
+                 tree max = size_binop (MINUS_EXPR, hi, low);
+                 code = build_vec_init (sub, max, value, false, 0,
+                                        tf_warning_or_error);
+                 add_stmt (code);
+               }
              else
-               sub = build3 (COMPONENT_REF, inner_type, dest, field_index,
-                             NULL_TREE);
-
-             code = build2 (INIT_EXPR, inner_type, sub, value);
-             code = build_stmt (input_location, EXPR_STMT, code);
-             code = maybe_cleanup_point_expr_void (code);
-             add_stmt (code);
-             if (type_build_dtor_call (inner_type))
                {
-                 code = (build_special_member_call
-                         (sub, complete_dtor_identifier, NULL, inner_type,
-                          LOOKUP_NORMAL, tf_warning_or_error));
-                 if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (inner_type))
-                   finish_eh_cleanup (code);
+                 if (array_type_p)
+                   sub = build4 (ARRAY_REF, inner_type, dest, field_index,
+                                 NULL_TREE, NULL_TREE);
+                 else
+                   sub = build3 (COMPONENT_REF, inner_type, dest, field_index,
+                                 NULL_TREE);
+
+                 code = build2 (INIT_EXPR, inner_type, sub, value);
+                 code = build_stmt (input_location, EXPR_STMT, code);
+                 code = maybe_cleanup_point_expr_void (code);
+                 add_stmt (code);
+                 if (type_build_dtor_call (inner_type))
+                   {
+                     code = (build_special_member_call
+                             (sub, complete_dtor_identifier, NULL, inner_type,
+                              LOOKUP_NORMAL, tf_warning_or_error));
+                     if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (inner_type))
+                       finish_eh_cleanup (code);
+                   }
                }
 
              num_split_elts++;
@@ -1101,6 +1117,22 @@ picflag_from_initializer (tree init)
   return 0;
 }
 
+/* Adjust INIT for going into a CONSTRUCTOR.  */
+
+static tree
+massage_init_elt (tree type, tree init, tsubst_flags_t complain)
+{
+  init = digest_init_r (type, init, true, LOOKUP_IMPLICIT, complain);
+  /* Strip a simple TARGET_EXPR when we know this is an initializer.  */
+  if (TREE_CODE (init) == TARGET_EXPR
+      && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (init))))
+    init = TARGET_EXPR_INITIAL (init);
+  /* When we defer constant folding within a statement, we may want to
+     defer this folding as well.  */
+  init = maybe_constant_init (init);
+  return init;
+}
+
 /* Subroutine of process_init_constructor, which will process an initializer
    INIT for an array or vector of type TYPE. Returns the flags (PICFLAG_*)
    which describe the initializers.  */
@@ -1158,8 +1190,7 @@ process_init_constructor_array (tree type, tree init,
       else
        ce->index = size_int (i);
       gcc_assert (ce->value);
-      ce->value = digest_init_r (TREE_TYPE (type), ce->value, true,
-                                LOOKUP_IMPLICIT, complain);
+      ce->value = massage_init_elt (TREE_TYPE (type), ce->value, complain);
 
       if (ce->value != error_mark_node)
        gcc_assert (same_type_ignoring_top_level_qualifiers_p
@@ -1168,33 +1199,42 @@ process_init_constructor_array (tree type, tree init,
       flags |= picflag_from_initializer (ce->value);
     }
 
-  /* No more initializers. If the array is unbounded, we are done. Otherwise,
-     we must add initializers ourselves.  */
-  if (!unbounded)
-    for (; i < len; ++i)
-      {
-       tree next;
-
-       if (type_build_ctor_call (TREE_TYPE (type)))
-         {
-           /* If this type needs constructors run for default-initialization,
-             we can't rely on the back end to do it for us, so make the
-             initialization explicit by list-initializing from {}.  */
-           next = build_constructor (init_list_type_node, NULL);
-           next = digest_init (TREE_TYPE (type), next, complain);
-         }
-       else if (!zero_init_p (TREE_TYPE (type)))
-         next = build_zero_init (TREE_TYPE (type),
-                                 /*nelts=*/NULL_TREE,
-                                 /*static_storage_p=*/false);
-       else
-         /* The default zero-initialization is fine for us; don't
-            add anything to the CONSTRUCTOR.  */
-         break;
+  /* No more initializers. If the array is unbounded, or we've initialized
+     all the elements, we are done. Otherwise, we must add initializers
+     ourselves.  */
+  if (!unbounded && i < len)
+    {
+      tree next;
 
-       flags |= picflag_from_initializer (next);
-       CONSTRUCTOR_APPEND_ELT (v, size_int (i), next);
-      }
+      if (type_build_ctor_call (TREE_TYPE (type)))
+       {
+         /* If this type needs constructors run for default-initialization,
+            we can't rely on the back end to do it for us, so make the
+            initialization explicit by list-initializing from {}.  */
+         next = build_constructor (init_list_type_node, NULL);
+         next = massage_init_elt (TREE_TYPE (type), next, complain);
+         if (initializer_zerop (next))
+           /* The default zero-initialization is fine for us; don't
+              add anything to the CONSTRUCTOR.  */
+           next = NULL_TREE;
+       }
+      else if (!zero_init_p (TREE_TYPE (type)))
+       next = build_zero_init (TREE_TYPE (type),
+                               /*nelts=*/NULL_TREE,
+                               /*static_storage_p=*/false);
+      else
+       /* The default zero-initialization is fine for us; don't
+          add anything to the CONSTRUCTOR.  */
+       next = NULL_TREE;
+
+      if (next)
+       {
+         flags |= picflag_from_initializer (next);
+         tree index = build2 (RANGE_EXPR, sizetype, size_int (i),
+                              size_int (len - 1));
+         CONSTRUCTOR_APPEND_ELT (v, index, next);
+       }
+    }
 
   CONSTRUCTOR_ELTS (init) = v;
   return flags;
@@ -1263,8 +1303,7 @@ process_init_constructor_record (tree type, tree init,
            }
 
          gcc_assert (ce->value);
-         next = digest_init_r (type, ce->value, true,
-                               LOOKUP_IMPLICIT, complain);
+         next = massage_init_elt (type, ce->value, complain);
          ++idx;
        }
       else if (type_build_ctor_call (TREE_TYPE (field)))
@@ -1274,18 +1313,7 @@ process_init_constructor_record (tree type, tree init,
             for us, so build up TARGET_EXPRs.  If the type in question is
             a class, just build one up; if it's an array, recurse.  */
          next = build_constructor (init_list_type_node, NULL);
-         if (MAYBE_CLASS_TYPE_P (TREE_TYPE (field)))
-           {
-             next = finish_compound_literal (TREE_TYPE (field), next,
-                                             complain);
-             /* direct-initialize the target. No temporary is going
-                 to be involved.  */
-             if (TREE_CODE (next) == TARGET_EXPR)
-               TARGET_EXPR_DIRECT_INIT_P (next) = true;
-           }
-
-         next = digest_init_r (TREE_TYPE (field), next, true,
-                               LOOKUP_IMPLICIT, complain);
+         next = massage_init_elt (TREE_TYPE (field), next, complain);
 
          /* Warn when some struct elements are implicitly initialized.  */
          warning (OPT_Wmissing_field_initializers,
@@ -1422,8 +1450,7 @@ process_init_constructor_union (tree type, tree init,
     }
 
   if (ce->value && ce->value != error_mark_node)
-    ce->value = digest_init_r (TREE_TYPE (ce->index), ce->value,
-                              true, LOOKUP_IMPLICIT, complain);
+    ce->value = massage_init_elt (TREE_TYPE (ce->index), ce->value, complain);
 
   return picflag_from_initializer (ce->value);
 }
diff --git a/gcc/testsuite/g++.dg/opt/value-init1.C b/gcc/testsuite/g++.dg/opt/value-init1.C
new file mode 100644 (file)
index 0000000..fd38b2e
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/59659
+// { dg-options "-fdump-tree-gimple -std=c++11" }
+// { dg-final { scan-tree-dump-times "i = 0" 0 "gimple" } }
+// { dg-final { cleanup-tree-dump "gimple" } }
+
+struct S { S () = default; S (int i); int i; };
+struct A { S s[100]; };
+
+void
+foo ()
+{
+  A a = {{}};
+}
diff --git a/gcc/testsuite/g++.dg/opt/value-init2.C b/gcc/testsuite/g++.dg/opt/value-init2.C
new file mode 100644 (file)
index 0000000..515cca0
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/59659
+// { dg-options "-fdump-tree-gimple" }
+// { dg-final { scan-tree-dump-times "S::S" 1 "gimple" } }
+// { dg-final { cleanup-tree-dump "gimple" } }
+
+struct S { S (); S (int i); int i; };
+struct A { S s[100]; };
+
+void
+foo ()
+{
+  A a = {{}};
+}