On Fri, Mar 11, 2016 at 09:27:54AM -0500, Jason Merrill wrote: > On 03/10/2016 01:39 PM, Jakub Jelinek wrote: > >+ /* Don't reuse the result of cxx_eval_constant_expression > >+ call if it isn't a constant initializer or if it requires > >+ relocations. */ > > Let's phrase this positively ("Reuse the result if..."). > > >+ if (new_ctx.ctor != ctx->ctor) > >+ eltinit = new_ctx.ctor; > >+ for (i = 1; i < max; ++i) > >+ { > >+ idx = build_int_cst (size_type_node, i); > >+ CONSTRUCTOR_APPEND_ELT (*p, idx, eltinit); > >+ } > > This is going to use the same CONSTRUCTOR for all the elements, which will > lead to problems if we then store into a subobject of one of the elements > and see that reflected in all the others as well. We need to unshare_expr > when reusing the initializer.
Well, but then even what has been already committed is unsafe, initializer_constant_valid_p can return null_pointer_node even on CONSTRUCTOR, or CONSTRUCTOR holding CONSTRUCTORs etc. So, either we need to unshare_expr it in every case, so CONSTRUCTOR_APPEND_ELT (*p, idx, unshare_expr (eltinit)); or alternatively we could use some flag on CONSTRUCTOR to mark (possibly) shared ctors and unshare them upon constexpr store to them, or unshare whenever we store. What would be a testcase for the unsharing? Following still works: // PR c++/70001 // { dg-do compile { target c++14 } } struct B { int a; constexpr B () : a (0) { } constexpr B (int x) : a (x) { } }; struct C { B c; constexpr C () : c (0) { } }; struct A { B b[1 << 4]; }; struct D { C d[1 << 4]; }; constexpr int foo (int a, int b) { A c; c.b[a].a += b; c.b[b].a += a; return c.b[0].a + c.b[a].a + c.b[b].a; } constexpr int d = foo (1, 2); constexpr int e = foo (0, 3); constexpr int f = foo (2, 4); static_assert (d == 3 && e == 6 && f == 6, ""); constexpr int bar (int a, int b) { D c; c.d[a].c.a += b; c.d[b].c.a += a; return c.d[0].c.a + c.d[a].c.a + c.d[b].c.a; } constexpr int g = bar (1, 2); constexpr int h = bar (0, 3); constexpr int i = bar (2, 4); static_assert (g == 3 && h == 6 && i == 6, ""); Jakub