For classes with trivial copy constructors that might have other data
packed into their tail padding, we represent the copy with an
assignment between arrays of unsigned char.  This is valid in normal
code, but constant expressions don't allow that sort of type punning,
so we need to look through it.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 9a90dc96b1aec8133f94feb12d53347a0d640fa5
Author: Jason Merrill <ja...@redhat.com>
Date:   Sat Oct 15 15:32:05 2016 -0400

            PR c++/77945 - constexpr and trivial copy
    
            * constexpr.c (maybe_simplify_trivial_copy): New.
            (cxx_eval_store_expression): Call it.
            * call.c (build_over_call): Use unsigned char for trivial copy.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4bee487..4c19d2f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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))));
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index f5235fc..3c4fcfa 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -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
index 0000000..d241114
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-trivial2.C
@@ -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{});
+}

Reply via email to