aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/constexpr.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-01-01 16:00:09 -0500
committerJason Merrill <jason@redhat.com>2022-01-06 19:23:16 -0500
commite948436eab818c527dd60b0ef939c4f42fbe8ba4 (patch)
tree71b7313390be11341e0c975d27076d8387b9c39c /gcc/cp/constexpr.c
parentad64a821970ef5547d77ece22d302b0e599ae0d2 (diff)
downloadgcc-e948436eab818c527dd60b0ef939c4f42fbe8ba4.zip
gcc-e948436eab818c527dd60b0ef939c4f42fbe8ba4.tar.gz
gcc-e948436eab818c527dd60b0ef939c4f42fbe8ba4.tar.bz2
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.
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r--gcc/cp/constexpr.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 72be45c..4a4b347 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;