From 7f0e23e931064d8e8758e01d95bfb89b8fa32e6e Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Tue, 1 Mar 2016 21:32:38 -0500
Subject: [PATCH] re PR c++/69995 ([C++14] Invalid result when evaluating
 constexpr function)

	PR c++/69995

	* constexpr.c (cxx_eval_call_expression): Unshare arg.
	(cxx_eval_constant_expression) [DECL_EXPR]: Unshare init.
	[TARGET_EXPR]: Unshare init.

From-SVN: r233877
---
 gcc/cp/ChangeLog                             |  7 ++++++
 gcc/cp/constexpr.c                           |  5 ++++
 gcc/testsuite/g++.dg/cpp1y/constexpr-copy2.C | 24 ++++++++++++++++++
 gcc/testsuite/g++.dg/cpp1y/constexpr-copy3.C | 26 ++++++++++++++++++++
 4 files changed, 62 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-copy2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-copy3.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 04e142684598..3a24cc9392b8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,10 @@
+2016-03-01  Jason Merrill  <jason@redhat.com>
+
+	PR c++/69995
+	* constexpr.c (cxx_eval_call_expression): Unshare arg.
+	(cxx_eval_constant_expression) [DECL_EXPR]: Unshare init.
+	[TARGET_EXPR]: Unshare init.
+
 2016-03-01  Patrick Palka  <ppalka@gcc.gnu.org>
 
 	PR c++/68948
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 5e359404c8d6..a21997ab97a3 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 000000000000..6707975f0ab5
--- /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 000000000000..cce4b54df7f6
--- /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());