On 02/29/2016 09:25 AM, Jason Merrill wrote:
The bug here was that we were sharing the CONSTRUCTOR between the value of 'a' and the elements of 'result', so changing 'a' also changed the value of result[0]. Oops.
And there were a few other places with the same problem. Tested x86_64-pc-linux-gnu, applying to trunk and 5.
commit 0b712dc1cf26859a8ae01eac4ea60005c82e95eb Author: Jason Merrill <ja...@redhat.com> Date: Tue Mar 1 01:28:41 2016 -0500 PR c++/69995 * constexpr.c (cxx_eval_call_expression): Unshare arg. (cxx_eval_constant_expression) [DECL_EXPR]: Unshare init. [TARGET_EXPR]: Unshare init. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 5e35940..a21997a 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1365,6 +1365,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, tree oparm = TREE_PURPOSE (bound); tree arg = TREE_VALUE (bound); gcc_assert (DECL_NAME (remapped) == DECL_NAME (oparm)); + /* Don't share a CONSTRUCTOR that might be changed. */ + arg = unshare_expr (arg); ctx->values->put (remapped, arg); bound = TREE_CHAIN (bound); remapped = DECL_CHAIN (remapped); @@ -3366,6 +3368,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, init = cxx_eval_constant_expression (ctx, init, false, non_constant_p, overflow_p); + /* Don't share a CONSTRUCTOR that might be changed. */ + init = unshare_expr (init); ctx->values->put (r, init); } else if (ctx == &new_ctx) @@ -3410,6 +3414,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (lval) { tree slot = TARGET_EXPR_SLOT (t); + r = unshare_expr (r); ctx->values->put (slot, r); return slot; } diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-copy2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-copy2.C new file mode 100644 index 0000000..6707975 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-copy2.C @@ -0,0 +1,24 @@ +// PR c++/69995 +// { dg-do compile { target c++14 } } + +struct A +{ + int i; +}; + +constexpr int f(A a) +{ + ++a.i; + return a.i; +} + +constexpr bool g() +{ + A a = { 42 }; + if (f(a) != 43) return false; + if (a.i != 42) return false; + return true; +} + +#define SA(X) static_assert((X),#X) +SA(g()); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-copy3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-copy3.C new file mode 100644 index 0000000..cce4b54 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-copy3.C @@ -0,0 +1,26 @@ +// PR c++/69995 +// { dg-do compile { target c++14 } } + +struct A +{ + int i; +}; + +constexpr int f(A a) +{ + ++a.i; + return a.i; +} + +constexpr bool g() +{ + A a = { 42 }; + A b = a; + ++b.i; + if (b.i != 43) return false; + if (a.i != 42) return false; + return true; +} + +#define SA(X) static_assert((X),#X) +SA(g());