diff mbox

C++ PATCH for c++/70139 (-fno-elide-constructors breaks regex)

Message ID 56EC61DB.3010006@redhat.com
State New
Headers show

Commit Message

Jason Merrill March 18, 2016, 8:15 p.m. UTC
The constexpr code for shortcutting trivial copy ctor/op= didn't get 
updated for the C++14 constexpr implementation, where we need to 
consider side effects.

For GCC 5.4 I'm just going to disable the shortcut.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit a805189949e8ed36713d5eb78c283a5000566bf0
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Mar 18 14:57:58 2016 -0400

    	PR c++/70139
    	* constexpr.c (cxx_eval_call_expression): Fix trivial copy.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 5f97c9d..1f496b5 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1239,19 +1239,39 @@  cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       return t;
     }
 
+  constexpr_ctx new_ctx = *ctx;
+  if (DECL_CONSTRUCTOR_P (fun) && !ctx->object
+      && TREE_CODE (t) == AGGR_INIT_EXPR)
+    {
+      /* We want to have an initialization target for an AGGR_INIT_EXPR.
+	 If we don't already have one in CTX, use the AGGR_INIT_EXPR_SLOT.  */
+      new_ctx.object = AGGR_INIT_EXPR_SLOT (t);
+      tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL);
+      CONSTRUCTOR_NO_IMPLICIT_ZERO (ctor) = true;
+      ctx->values->put (new_ctx.object, ctor);
+      ctx = &new_ctx;
+    }
+
   /* Shortcut trivial constructor/op=.  */
   if (trivial_fn_p (fun))
     {
+      tree init = NULL_TREE;
       if (call_expr_nargs (t) == 2)
-	{
-	  tree arg = convert_from_reference (get_nth_callarg (t, 1));
-	  return cxx_eval_constant_expression (ctx, arg,
-					       lval, non_constant_p,
-					       overflow_p);
-	}
+	init = convert_from_reference (get_nth_callarg (t, 1));
       else if (TREE_CODE (t) == AGGR_INIT_EXPR
 	       && AGGR_INIT_ZERO_FIRST (t))
-	return build_zero_init (DECL_CONTEXT (fun), NULL_TREE, false);
+	init = build_zero_init (DECL_CONTEXT (fun), NULL_TREE, false);
+      if (init)
+	{
+	  tree op = get_nth_callarg (t, 0);
+	  if (is_dummy_object (op))
+	    op = ctx->object;
+	  else
+	    op = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (op)), op);
+	  tree set = build2 (MODIFY_EXPR, TREE_TYPE (op), op, init);
+	  return cxx_eval_constant_expression (ctx, set, lval,
+					       non_constant_p, overflow_p);
+	}
     }
 
   /* We can't defer instantiating the function any longer.  */
@@ -1287,19 +1307,6 @@  cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
         }
     }
 
-  constexpr_ctx new_ctx = *ctx;
-  if (DECL_CONSTRUCTOR_P (fun) && !ctx->object
-      && TREE_CODE (t) == AGGR_INIT_EXPR)
-    {
-      /* We want to have an initialization target for an AGGR_INIT_EXPR.
-	 If we don't already have one in CTX, use the AGGR_INIT_EXPR_SLOT.  */
-      new_ctx.object = AGGR_INIT_EXPR_SLOT (t);
-      tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL);
-      CONSTRUCTOR_NO_IMPLICIT_ZERO (ctor) = true;
-      ctx->values->put (new_ctx.object, ctor);
-      ctx = &new_ctx;
-    }
-
   bool non_constant_args = false;
   cxx_bind_parameters_in_call (ctx, t, &new_call,
 			       non_constant_p, overflow_p, &non_constant_args);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial1.C
new file mode 100644
index 0000000..f4b74a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial1.C
@@ -0,0 +1,20 @@ 
+// PR c++/70139
+// { dg-options "-fno-elide-constructors" }
+// { dg-do compile { target c++11 } }
+
+template<class T, class U>
+struct A
+{
+  T a;
+  U b;
+  constexpr A () : a (), b () { }
+  constexpr A (const T &x, const U &y) : a (x), b (y) { }
+};
+struct B
+{
+  constexpr B (const bool x) : c (x) {}
+  constexpr bool operator!= (const B x) const { return c != x.c; }
+  bool c;
+};
+constexpr static A<B, B*> d[] = { { B (true), nullptr }, { B (false), nullptr } };
+static_assert (d[0].a != d[1].a, "");