public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-6326] c++: loop over array elts w/o explicit init [PR92385]
@ 2022-01-07  0:24 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2022-01-07  0:24 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:e948436eab818c527dd60b0ef939c4f42fbe8ba4

commit r12-6326-ge948436eab818c527dd60b0ef939c4f42fbe8ba4
Author: Jason Merrill <jason@redhat.com>
Date:   Sat Jan 1 16:00:09 2022 -0500

    c++: loop over array elts w/o explicit init [PR92385]
    
    The PR complains that initializing a large array with {} takes a long time
    to compile; this was because digest_init would turn {} into a long
    CONSTRUCTOR with an initializer for each element, instead of more sensibly
    generating a loop.  The standard doesn't specify this implementation, but it
    does allow for it by specifying that a temporary created "when a default
    constructor is called to initialize an element of an array with no
    corresponding initializer" is destroyed "before the construction of the next
    array element, if any." rather than living until the end of the complete
    object initialization as usual.
    
    This change is also needed before the PR94041 fix extends the lifetime of
    temporaries from elements with explicit initializers.
    
    To implement this, I change digest_init so that in cases where
    initialization of trailing array elements isn't constant, we return a
    VEC_INIT_EXPR instead of a bare CONSTRUCTOR; when it is encountered later,
    we call build_vec_init to generate the actual initialization code.
    
            PR c++/92385
    
    gcc/cp/ChangeLog:
    
            * typeck2.c (PICFLAG_VEC_INIT): New.
            (process_init_constructor_array): Set it.
            (process_init_constructor): Handle it.
            (split_nonconstant_init_1): Handle VEC_INIT_EXPR.
            * init.c (build_vec_init): Likewise.
            * cp-gimplify.c (cp_gimplify_expr): Factor out...
            * tree.c (expand_vec_init_expr): ...this function.
            (build_vec_init_elt): Handle BRACE_ENCLOSED_INITIALIZER_P.
            (build_vec_init_expr): Likewise.
            * constexpr.c (cxx_eval_vec_init): Likewise.
            (reduced_constant_expression_p): Check arrays before C++20.
            * cp-tree.h (expand_vec_init_expr): Declare.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/init/array61.C: New test.

Diff:
---
 gcc/cp/cp-tree.h                    |  1 +
 gcc/cp/constexpr.c                  | 35 +++++++++++++++++++++++++----
 gcc/cp/cp-gimplify.c                | 13 +++--------
 gcc/cp/init.c                       | 11 +++++++++-
 gcc/cp/tree.c                       | 44 ++++++++++++++++++++++++++-----------
 gcc/cp/typeck2.c                    | 23 ++++++++++++++++---
 gcc/testsuite/g++.dg/init/array61.C | 16 ++++++++++++++
 7 files changed, 112 insertions(+), 31 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 10ca8098a85..0a3697f2f98 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7779,6 +7779,7 @@ extern bool array_of_runtime_bound_p		(tree);
 extern bool vla_type_p				(tree);
 extern tree build_array_copy			(tree);
 extern tree build_vec_init_expr			(tree, tree, tsubst_flags_t);
+extern tree expand_vec_init_expr		(tree, tree, tsubst_flags_t);
 extern void diagnose_non_constexpr_vec_init	(tree);
 extern tree hash_tree_cons			(tree, tree, tree);
 extern tree hash_tree_chain			(tree, tree);
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 72be45c9e87..4a4b347c31d 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -3020,8 +3020,7 @@ reduced_constant_expression_p (tree t)
 	  if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
 	    /* An initialized vector would have a VECTOR_CST.  */
 	    return false;
-	  else if (cxx_dialect >= cxx20
-		   && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+	  else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
 	    {
 	      /* There must be a valid constant initializer at every array
 		 index.  */
@@ -4955,8 +4954,36 @@ cxx_eval_vec_init (const constexpr_ctx *ctx, tree t,
 {
   tree atype = TREE_TYPE (t);
   tree init = VEC_INIT_EXPR_INIT (t);
-  tree r = cxx_eval_vec_init_1 (ctx, atype, init,
-				VEC_INIT_EXPR_VALUE_INIT (t),
+  bool value_init = VEC_INIT_EXPR_VALUE_INIT (t);
+  if (!init || !BRACE_ENCLOSED_INITIALIZER_P (init))
+    ;
+  else if (CONSTRUCTOR_NELTS (init) == 0)
+    {
+      /* Handle {} as value-init.  */
+      init = NULL_TREE;
+      value_init = true;
+    }
+  else
+    {
+      /* This is a more complicated case, like needing to loop over trailing
+	 elements; call build_vec_init and evaluate the result.  */
+      tsubst_flags_t complain = ctx->quiet ? tf_none : tf_warning_or_error;
+      constexpr_ctx new_ctx = *ctx;
+      if (!ctx->object)
+	{
+	  /* We want to have an initialization target for an VEC_INIT_EXPR.
+	     If we don't already have one in CTX, use the VEC_INIT_EXPR_SLOT.  */
+	  new_ctx.object = VEC_INIT_EXPR_SLOT (t);
+	  tree ctor = new_ctx.ctor = build_constructor (atype, NULL);
+	  CONSTRUCTOR_NO_CLEARING (ctor) = true;
+	  ctx->global->values.put (new_ctx.object, ctor);
+	  ctx = &new_ctx;
+	}
+      init = expand_vec_init_expr (ctx->object, t, complain);
+      return cxx_eval_constant_expression (ctx, init, lval, non_constant_p,
+					   overflow_p);
+    }
+  tree r = cxx_eval_vec_init_1 (ctx, atype, init, value_init,
 				lval, non_constant_p, overflow_p);
   if (*non_constant_p)
     return t;
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 27e78ee3d24..e4f24428629 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -462,21 +462,14 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 
     case VEC_INIT_EXPR:
       {
-	location_t loc = input_location;
-	tree init = VEC_INIT_EXPR_INIT (*expr_p);
-	int from_array = (init && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE);
-	gcc_assert (EXPR_HAS_LOCATION (*expr_p));
-	input_location = EXPR_LOCATION (*expr_p);
-	*expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p), NULL_TREE,
-				  init, VEC_INIT_EXPR_VALUE_INIT (*expr_p),
-				  from_array,
-				  tf_warning_or_error);
+	*expr_p = expand_vec_init_expr (NULL_TREE, *expr_p,
+					tf_warning_or_error);
+
 	hash_set<tree> pset;
 	cp_walk_tree (expr_p, cp_fold_r, &pset, NULL);
 	cp_genericize_tree (expr_p, false);
 	copy_if_shared (expr_p);
 	ret = GS_OK;
-	input_location = loc;
       }
       break;
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 2cab4b4cdce..2a7dfe2b505 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -4337,12 +4337,19 @@ build_vec_init (tree base, tree maxindex, tree init,
       && from_array != 2)
     init = TARGET_EXPR_INITIAL (init);
 
+  if (init && TREE_CODE (init) == VEC_INIT_EXPR)
+    {
+      gcc_checking_assert (false);
+      init = VEC_INIT_EXPR_INIT (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)
+      if (TREE_CODE (TREE_TYPE (elt)) == ARRAY_TYPE
+	  && TREE_CODE (elt) != VEC_INIT_EXPR)
 	{
 	  direct_init = DIRECT_LIST_INIT_P (init);
 	  init = elt;
@@ -4516,6 +4523,8 @@ build_vec_init (tree base, tree maxindex, tree init,
 	  current_stmt_tree ()->stmts_are_full_exprs_p = 1;
 	  if (digested)
 	    one_init = build2 (INIT_EXPR, type, baseref, elt);
+	  else if (TREE_CODE (elt) == VEC_INIT_EXPR)
+	    one_init = expand_vec_init_expr (baseref, elt, complain);
 	  else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
 	    one_init = build_aggr_init (baseref, elt, 0, complain);
 	  else
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 61998019312..8bd1964e867 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -756,13 +756,11 @@ build_vec_init_elt (tree type, tree init, tsubst_flags_t complain)
   else if (init == void_type_node)
     return build_value_init (inner_type, complain);
 
-  gcc_assert (init == NULL_TREE
-	      || (same_type_ignoring_top_level_qualifiers_p
-		  (type, TREE_TYPE (init))));
-
   releasing_vec argvec;
-  if (init)
+  if (init && !BRACE_ENCLOSED_INITIALIZER_P (init))
     {
+      gcc_assert (same_type_ignoring_top_level_qualifiers_p
+		  (type, TREE_TYPE (init)));
       tree init_type = strip_array_types (TREE_TYPE (init));
       tree dummy = build_dummy_object (init_type);
       if (!lvalue_p (init))
@@ -788,25 +786,28 @@ build_vec_init_elt (tree type, tree init, tsubst_flags_t complain)
 tree
 build_vec_init_expr (tree type, tree init, tsubst_flags_t complain)
 {
-  tree slot;
-  bool value_init = false;
-  tree elt_init;
-  if (init && TREE_CODE (init) == CONSTRUCTOR)
+  if (init && TREE_CODE (init) == VEC_INIT_EXPR)
     {
-      gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (init));
-      /* We built any needed constructor calls in digest_init.  */
-      elt_init = init;
+      gcc_checking_assert (false);
+      return init;
     }
+
+  tree elt_init;
+  if (init && TREE_CODE (init) == CONSTRUCTOR
+      && !BRACE_ENCLOSED_INITIALIZER_P (init))
+    /* We built any needed constructor calls in digest_init.  */
+    elt_init = init;
   else
     elt_init = build_vec_init_elt (type, init, complain);
 
+  bool value_init = false;
   if (init == void_type_node)
     {
       value_init = true;
       init = NULL_TREE;
     }
 
-  slot = build_local_temp (type);
+  tree slot = build_local_temp (type);
   init = build2 (VEC_INIT_EXPR, type, slot, init);
   TREE_SIDE_EFFECTS (init) = true;
   SET_EXPR_LOCATION (init, input_location);
@@ -819,6 +820,23 @@ build_vec_init_expr (tree type, tree init, tsubst_flags_t complain)
   return init;
 }
 
+/* Call build_vec_init to expand VEC_INIT into TARGET (for which NULL_TREE
+   means VEC_INIT_EXPR_SLOT).  */
+
+tree
+expand_vec_init_expr (tree target, tree vec_init, tsubst_flags_t complain)
+{
+  iloc_sentinel ils = EXPR_LOCATION (vec_init);
+
+  if (!target)
+    target = VEC_INIT_EXPR_SLOT (vec_init);
+  tree init = VEC_INIT_EXPR_INIT (vec_init);
+  int from_array = (init && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE);
+  return build_vec_init (target, NULL_TREE, init,
+			 VEC_INIT_EXPR_VALUE_INIT (vec_init),
+			 from_array, complain);
+}
+
 /* Give a helpful diagnostic for a non-constexpr VEC_INIT_EXPR in a context
    that requires a constant expression.  */
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 84cef54e112..3d4d35e13c6 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1317,6 +1317,7 @@ digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain)
 #define PICFLAG_NOT_ALL_CONSTANT 2
 #define PICFLAG_NOT_ALL_SIMPLE 4
 #define PICFLAG_SIDE_EFFECTS 8
+#define PICFLAG_VEC_INIT 16
 
 /* Given an initializer INIT, return the flag (PICFLAG_*) which better
    describe it.  */
@@ -1460,10 +1461,19 @@ process_init_constructor_array (tree type, tree init, int nested, int flags,
 
 	if (next)
 	  {
-	    picflags |= picflag_from_initializer (next);
-	    if (len > i+1
+	    if (next != error_mark_node
+		&& ! seen_error () // Improves error-recovery on anew5.C.
 		&& (initializer_constant_valid_p (next, TREE_TYPE (next))
-		    == null_pointer_node))
+		    != null_pointer_node))
+	      {
+		/* Use VEC_INIT_EXPR for non-constant initialization of
+		   trailing elements with no explicit initializers.  */
+		picflags |= PICFLAG_VEC_INIT;
+		break;
+	      }
+
+	    picflags |= picflag_from_initializer (next);
+	    if (len > i+1)
 	      {
 		tree range = build2 (RANGE_EXPR, size_type_node,
 				     build_int_cst (size_type_node, i),
@@ -1858,6 +1868,13 @@ process_init_constructor (tree type, tree init, int nested, int flags,
       if (!(picflags & PICFLAG_NOT_ALL_SIMPLE))
 	TREE_STATIC (init) = 1;
     }
+  if (picflags & PICFLAG_VEC_INIT)
+    {
+      /* Defer default-initialization of array elements with no corresponding
+	 initializer-clause until later so we can use a loop.  */
+      TREE_TYPE (init) = init_list_type_node;
+      init = build_vec_init_expr (type, init, complain);
+    }
   return init;
 }
 \f
diff --git a/gcc/testsuite/g++.dg/init/array61.C b/gcc/testsuite/g++.dg/init/array61.C
new file mode 100644
index 00000000000..eaf535c2546
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array61.C
@@ -0,0 +1,16 @@
+// PR c++/92385
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -fdump-tree-gimple }
+// { dg-final { scan-tree-dump-times "item::item" 1 "gimple" } }
+
+struct item {
+  int i;
+  item();
+};
+
+struct item_array {
+  item a[10];
+  item_array();
+};
+
+item_array::item_array() : a{} {}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-01-07  0:24 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-07  0:24 [gcc r12-6326] c++: loop over array elts w/o explicit init [PR92385] Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).