In this PR, we have a large std::array of pairs.  Since the C array is
wrapped in a class we don't go to build_vec_init, so we end up with
digest_init wanting to build up the element initializer for each
element of the array.

In the more general case, like 80272, we have a data structure
problem: we don't currently have a good way of expressing the same
dynamic initialization of many elements within a CONSTRUCTOR.
RANGE_EXPR probably ought to work, but will need more work at
genericize or gimplify time.

But in this case, the initialization for each element reduces to
constant 0, so we don't even need to add anything to the CONSTRUCTOR.
We just need to realize that if the initializer for one element is 0,
the others will be as well, and we don't need to iterate over the
whole array.

For the trunk, I also use a RANGE_EXPR to handle constant
initialization by a value other than 0.

#include <array>
#include <utility>

void foo ()
{
  std::array<std::pair<int, int>, 1024 * 1024> arr {};
}

Tested x86_64-pc-linux-gnu, applying to trunk and 8.
commit 45b75c343a5ab44a039923febbfd6d9c11ad1621
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Jun 26 14:58:58 2018 -0400

            PR c++/86320 - memory-hog with std::array of pair
    
            * typeck2.c (process_init_constructor_array): Only compute a
            constant initializer once.

diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 43e236de41c..91aa5a62856 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1365,8 +1365,22 @@ process_init_constructor_array (tree type, tree init, int nested,
 	if (next)
 	  {
 	    flags |= picflag_from_initializer (next);
-	    CONSTRUCTOR_APPEND_ELT (v, size_int (i), next);
+	    if (len > i+1
+		&& (initializer_constant_valid_p (next, TREE_TYPE (next))
+		    == null_pointer_node))
+	      {
+		tree range = build2 (RANGE_EXPR, size_type_node,
+				     build_int_cst (size_type_node, i),
+				     build_int_cst (size_type_node, len - 1));
+		CONSTRUCTOR_APPEND_ELT (v, range, next);
+		break;
+	      }
+	    else
+	      CONSTRUCTOR_APPEND_ELT (v, size_int (i), next);
 	  }
+	else
+	  /* Don't bother checking all the other elements.  */
+	  break;
       }
 
   CONSTRUCTOR_ELTS (init) = v;
commit 484d1a56ac83f53bf0a6064d9762acceb9d2f158
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Jun 26 14:58:58 2018 -0400

            PR c++/86320 - memory-hog with std::array of pair
    
            * typeck2.c (process_init_constructor_array): If zero-initialization
            is fine for one element, we're done.

diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 43e236de41c..5f738f038f0 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1367,6 +1367,9 @@ process_init_constructor_array (tree type, tree init, int nested,
 	    flags |= picflag_from_initializer (next);
 	    CONSTRUCTOR_APPEND_ELT (v, size_int (i), next);
 	  }
+	else
+	  /* Don't bother checking all the other elements.  */
+	  break;
       }
 
   CONSTRUCTOR_ELTS (init) = v;

Reply via email to