A side benefit of the approach taken by this patch is that constexpr
evaluation of a simple VEC_INIT_EXPR for a high-dimensional array no
longer scales exponentially with the number of dimensions. This is
because after the RANGE_EXPR optimization, the CONSTRUCTOR for each
array dimension now consists of a single constructor_elt (with index
0...max-1) instead of two constructor_elts (with indexes 0 and 1...max-1
respectively). This is verified by the second testcase below.
Bootstrapped and regtested on x86_64-pc-linux-gnu. Does this look OK
for trunk and perhaps for backports?
gcc/cp/ChangeLog:
PR c++/96282
* constexpr.c (cxx_eval_vec_init_1): Move the i == 0 test to the
if statement that guards the RANGE_EXPR optimization. Consider the
RANGE_EXPR optimization before we append the first element.
Truncate ctx->ctor when performing the RANGE_EXPR optimization.
Make the built RANGE_EXPR start at index 0 instead of 1. Don't
call unshare_constructor.
gcc/testsuite/ChangeLog:
PR c++/96282
* g++.dg/cpp0x/constexpr-array26.C: New test.
* g++.dg/cpp0x/constexpr-array27.C: New test.
---
gcc/cp/constexpr.c | 36 ++++++++++---------
.../g++.dg/cpp0x/constexpr-array26.C | 13 +++++++
.../g++.dg/cpp0x/constexpr-array27.C | 18 ++++++++++
3 files changed, 51 insertions(+), 16 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-array26.C
create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-array27.C
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index b1c1d249c6e..3808a0713ba 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -4189,7 +4189,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree
atype, tree init,
if (value_init || init == NULL_TREE)
{
eltinit = NULL_TREE;
- reuse = i == 0;
+ reuse = true;
}
else
eltinit = cp_build_array_ref (input_location, init, idx, complain);
@@ -4206,7 +4206,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree
atype, tree init,
return ctx->ctor;
eltinit = cxx_eval_constant_expression (&new_ctx, init, lval,
non_constant_p, overflow_p);
- reuse = i == 0;
+ reuse = true;
}
else
{
@@ -4222,33 +4222,37 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree
atype, tree init,
}
if (*non_constant_p && !ctx->quiet)
break;
- if (new_ctx.ctor != ctx->ctor)
- {
- /* We appended this element above; update the value. */
- gcc_assert ((*p)->last().index == idx);
- (*p)->last().value = eltinit;
- }
- else
- CONSTRUCTOR_APPEND_ELT (*p, idx, eltinit);
+
/* Reuse the result of cxx_eval_constant_expression call
from the first iteration to all others if it is a constant
initializer that doesn't require relocations. */
- if (reuse
- && max > 1
+ if (i == 0
+ && reuse
&& (eltinit == NULL_TREE
|| (initializer_constant_valid_p (eltinit, TREE_TYPE (eltinit))
== null_pointer_node)))
{
if (new_ctx.ctor != ctx->ctor)
eltinit = new_ctx.ctor;
- tree range = build2 (RANGE_EXPR, size_type_node,
- build_int_cst (size_type_node, 1),
- build_int_cst (size_type_node, max - 1));
- CONSTRUCTOR_APPEND_ELT (*p, range, unshare_constructor (eltinit));
+ vec_safe_truncate (*p, 0);
+ if (max > 1)
+ idx = build2 (RANGE_EXPR, size_type_node,
+ build_int_cst (size_type_node, 0),
+ build_int_cst (size_type_node, max - 1));
+ CONSTRUCTOR_APPEND_ELT (*p, idx, eltinit);
break;
}
else if (i == 0)
vec_safe_reserve (*p, max);
+
+ if (new_ctx.ctor != ctx->ctor)
+ {
+ /* We appended this element above; update the value. */
+ gcc_assert ((*p)->last().index == idx);
+ (*p)->last().value = eltinit;
+ }
+ else
+ CONSTRUCTOR_APPEND_ELT (*p, idx, eltinit);
}
if (!*non_constant_p)
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array26.C
b/gcc/testsuite/g++.dg/cpp0x/constexpr-array26.C
new file mode 100644
index 00000000000..274f55a88bf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array26.C
@@ -0,0 +1,13 @@
+// PR c++/96282
+// { dg-do compile { target c++11 } }
+
+struct e { bool v = true; };
+
+template<int N>
+struct b { e m[N]; };
+
+template<int N>
+struct t : b<N> { constexpr t() : b<N>() {} };
+
+constexpr t<1> h1;
+constexpr t<42> h2;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array27.C
b/gcc/testsuite/g++.dg/cpp0x/constexpr-array27.C
new file mode 100644
index 00000000000..a5ce3f7be08
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array27.C
@@ -0,0 +1,18 @@
+// Verify that default initialization an array of aggregates within an
aggregate
+// does not scale exponentially with the number of dimensions.
+
+// { dg-do compile { target c++11 } }
+// Pass -fsyntax-only to stress only the performance of the frontend.
+// { dg-additional-options "-fsyntax-only" }
+
+struct A
+{
+ int a = 42;
+};
+
+struct B
+{
+ A b[2][2][2][2][2][2][2][2][2][2][2][2][2][2][2][2][2][2][2][2][2][2][2][2];
+};
+
+constexpr B c;
--
2.28.0.89.g85b4e0a6dc