diff options
author | Jason Merrill <jason@redhat.com> | 2022-01-01 16:00:09 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2022-01-06 19:23:16 -0500 |
commit | e948436eab818c527dd60b0ef939c4f42fbe8ba4 (patch) | |
tree | 71b7313390be11341e0c975d27076d8387b9c39c /gcc/cp/constexpr.c | |
parent | ad64a821970ef5547d77ece22d302b0e599ae0d2 (diff) | |
download | gcc-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.c | 35 |
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; |