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