PR c++/77945 - constexpr and trivial copy
authorJason Merrill <jason@redhat.com>
Sat, 15 Oct 2016 21:25:55 +0000 (17:25 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 15 Oct 2016 21:25:55 +0000 (17:25 -0400)
* constexpr.c (maybe_simplify_trivial_copy): New.
(cxx_eval_store_expression): Call it.
* call.c (build_over_call): Use unsigned char for trivial copy.

From-SVN: r241204

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/constexpr.c
gcc/testsuite/g++.dg/cpp0x/constexpr-trivial2.C [new file with mode: 0644]

index 43c573b1e11c9d1e00cfcb8f78c6aed13c7fdc5b..54ffee800429e49735027ba3b57c7c9f150675cb 100644 (file)
@@ -1,3 +1,10 @@
+2016-10-15  Jason Merrill  <jason@redhat.com>
+
+       PR c++/77945
+       * constexpr.c (maybe_simplify_trivial_copy): New.
+       (cxx_eval_store_expression): Call it.
+       * call.c (build_over_call): Use unsigned char for trivial copy.
+
 2016-10-14  Jason Merrill  <jason@redhat.com>
 
        Implement P0017R1, C++17 aggregates with bases.
index 4bee487857d7a63a19ef498fe87686b293195d1c..4c19d2ffcd381beab145cb04cd8d007a2f332b09 100644 (file)
@@ -7909,7 +7909,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
          arg2 = TYPE_SIZE_UNIT (as_base);
          arg0 = cp_build_addr_expr (to, complain);
 
-         array_type = build_array_type (char_type_node,
+         array_type = build_array_type (unsigned_char_type_node,
                                         build_index_type
                                           (size_binop (MINUS_EXPR,
                                                        arg2, size_int (1))));
index f5235fc21e6e49d38781a56898f812c362a25be9..3c4fcfaeef931b0568ab0691d7b885ca22e6550e 100644 (file)
@@ -3206,6 +3206,26 @@ var_in_maybe_constexpr_fn (tree t)
   return var_in_constexpr_fn (t);
 }
 
+/* We're assigning INIT to TARGET.  In do_build_copy_constructor and
+   build_over_call we implement trivial copy of a class with tail padding using
+   assignment of character arrays, which is valid in normal code, but not in
+   constexpr evaluation.  We don't need to worry about clobbering tail padding
+   in constexpr evaluation, so strip the type punning.  */
+
+static void
+maybe_simplify_trivial_copy (tree &target, tree &init)
+{
+  if (TREE_CODE (target) == MEM_REF
+      && TREE_CODE (init) == MEM_REF
+      && TREE_TYPE (target) == TREE_TYPE (init)
+      && TREE_CODE (TREE_TYPE (target)) == ARRAY_TYPE
+      && TREE_TYPE (TREE_TYPE (target)) == unsigned_char_type_node)
+    {
+      target = build_fold_indirect_ref (TREE_OPERAND (target, 0));
+      init = build_fold_indirect_ref (TREE_OPERAND (init, 0));
+    }
+}
+
 /* Evaluate an INIT_EXPR or MODIFY_EXPR.  */
 
 static tree
@@ -3222,6 +3242,9 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
 
   /* First we figure out where we're storing to.  */
   tree target = TREE_OPERAND (t, 0);
+
+  maybe_simplify_trivial_copy (target, init);
+
   tree type = TREE_TYPE (target);
   target = cxx_eval_constant_expression (ctx, target,
                                         true,
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial2.C
new file mode 100644 (file)
index 0000000..d241114
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/77945
+// { dg-do compile { target c++11 } }
+
+struct T 
+{ 
+    int x = 0; 
+    bool y = 0; 
+    constexpr T() {}
+};
+
+int main()
+{
+    constexpr T t = (T{} = T{});
+}