2019-02-18 Jason Merrill <jason@redhat.com>
+ PR c++/89336 - multiple stores in constexpr stmt.
+ * constexpr.c (cxx_eval_store_expression): Preevaluate scalar or
+ assigned value.
+
* pt.c (check_explicit_specialization): If the declarator is a
template-id, only check whether the arguments are dependent.
maybe_simplify_trivial_copy (target, init);
tree type = TREE_TYPE (target);
+ bool preeval = SCALAR_TYPE_P (type) || TREE_CODE (t) == MODIFY_EXPR;
+ if (preeval)
+ {
+ /* Evaluate the value to be stored without knowing what object it will be
+ stored in, so that any side-effects happen first. */
+ if (!SCALAR_TYPE_P (type))
+ new_ctx.ctor = new_ctx.object = NULL_TREE;
+ init = cxx_eval_constant_expression (&new_ctx, init, false,
+ non_constant_p, overflow_p);
+ if (*non_constant_p)
+ return t;
+ }
target = cxx_eval_constant_expression (ctx, target,
true,
non_constant_p, overflow_p);
}
release_tree_vector (refs);
- if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
+ if (!preeval)
{
/* Create a new CONSTRUCTOR in case evaluation of the initializer
wants to modify it. */
*valp = build_constructor (type, NULL);
CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init;
}
- else if (TREE_CODE (*valp) == PTRMEM_CST)
- *valp = cplus_expand_constant (*valp);
new_ctx.ctor = *valp;
new_ctx.object = target;
+ init = cxx_eval_constant_expression (&new_ctx, init, false,
+ non_constant_p, overflow_p);
+ if (target == object)
+ /* The hash table might have moved since the get earlier. */
+ valp = ctx->values->get (object);
}
- init = cxx_eval_constant_expression (&new_ctx, init, false,
- non_constant_p, overflow_p);
/* Don't share a CONSTRUCTOR that might be changed later. */
init = unshare_constructor (init);
- if (target == object)
- /* The hash table might have moved since the get earlier. */
- valp = ctx->values->get (object);
- if (TREE_CODE (init) == CONSTRUCTOR)
+ if (*valp && TREE_CODE (*valp) == CONSTRUCTOR
+ && TREE_CODE (init) == CONSTRUCTOR)
{
/* An outer ctx->ctor might be pointing to *valp, so replace
its contents. */
--- /dev/null
+// PR c++/89336
+// { dg-do compile { target c++14 } }
+
+template <typename T, int N> struct A {
+ T a[N];
+ constexpr T &operator[] (int x) { return a[x]; }
+ constexpr const T &operator[] (int x) const { return a[x]; }
+};
+
+constexpr A<int, 16>
+foo ()
+{
+ A<int, 16> r{};
+ for (int i = 0; i < 6; ++i)
+ r[i + 8] = r[i] = i + 1;
+ return r;
+}
+
+constexpr auto x = foo ();
+static_assert (x[0] == 1, "");
+static_assert (x[1] == 2, "");
+static_assert (x[2] == 3, "");
+static_assert (x[3] == 4, "");
+static_assert (x[4] == 5, "");
+static_assert (x[5] == 6, "");
+static_assert (x[6] == 0, "");
+static_assert (x[7] == 0, "");
+static_assert (x[8] == 1, "");
+static_assert (x[9] == 2, "");
+static_assert (x[10] == 3, "");
+static_assert (x[11] == 4, "");
+static_assert (x[12] == 5, "");
+static_assert (x[13] == 6, "");
+static_assert (x[14] == 0, "");
+static_assert (x[15] == 0, "");
--- /dev/null
+// PR c++/89336
+// { dg-do compile { target c++14 } }
+
+constexpr int
+foo ()
+{
+ int a[16] = {};
+ int r = 0;
+ a[15] = a[14] = a[13] = a[12] = a[11] = a[10] = a[9] = a[8]
+ = a[7] = a[6] = a[5] = a[4] = a[3] = a[2] = a[1] = a[0] = 5;
+ for (int i = 0; i < 16; ++i)
+ r += a[i];
+ return r;
+}
+
+static_assert (foo () == 16 * 5, "");
+
+struct A { int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p; };
+
+constexpr int
+bar ()
+{
+ A a {};
+ a.p = a.o = a.n = a.m = a.l = a.k = a.j = a.i
+ = a.h = a.g = a.f = a.e = a.d = a.c = a.b = a.a = 8;
+ return a.a + a.b + a.c + a.d + a.e + a.f + a.g + a.h
+ + a.i + a.j + a.k + a.l + a.m + a.n + a.o + a.p;
+}
+
+static_assert (bar () == 16 * 8, "");
+
+constexpr int
+baz ()
+{
+ int a[16] = {};
+ int r = 0;
+ a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7]
+ = a[8] = a[9] = a[10] = a[11] = a[12] = a[13] = a[14] = a[15] = 7;
+ for (int i = 0; i < 16; ++i)
+ r += a[i];
+ return r;
+}
+
+static_assert (baz () == 16 * 7, "");
+
+constexpr int
+qux ()
+{
+ A a {};
+ a.a = a.b = a.c = a.d = a.e = a.f = a.g = a.h
+ = a.i = a.j = a.k = a.l = a.m = a.n = a.o = a.p = 6;
+ return a.a + a.b + a.c + a.d + a.e + a.f + a.g + a.h
+ + a.i + a.j + a.k + a.l + a.m + a.n + a.o + a.p;
+}
+
+static_assert (qux () == 16 * 6, "");