Hi!

As described in the PR, in C++ we can have assignments
where both the lhs and rhs are COMPONENT_REFs with TREE_ADDRESSABLE types,
including padding, but the FIELD_DECLs are artificial fields that have
narrower bit sizes.
store_field in this case takes the path of bit-field handling (even when
it has bitpos and bitsize multiples of BITS_PER_UNIT (I think that is
necessarily true for the TREE_ADDRESSABLE types), which is incorrect,
because the rhs is expanded in that case through expand_normal, which
for a result type wider than the FIELD_DECL with forces it into a temporary.
In older GCCs that just generated inefficient code (copy the rhs into a
stack temporary, then copy that to lhs), but GCC trunk ICEs on that.
Fixed by not taking the bit-field path in that case after verifying
we'll be able to expand it properly using the normal store_expr.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-02-19  Jakub Jelinek  <ja...@redhat.com>

        PR c++/69851
        * expr.c (store_field): Don't use bit-field path if exp is
        COMPONENT_REF with TREE_ADDRESSABLE type, where TYPE_SIZE is
        different from bitsize, but DECL_SIZE of FIELD_DECL is bitsize
        and the assignment can be performed by bitwise copy.  Formatting
        fix.

        * g++.dg/torture/pr69851.C: New test.

--- gcc/expr.c.jj       2016-02-12 00:50:55.000000000 +0100
+++ gcc/expr.c  2016-02-19 10:43:59.639162531 +0100
@@ -6643,14 +6643,24 @@ store_field (rtx target, HOST_WIDE_INT b
          /* Except for initialization of full bytes from a CONSTRUCTOR, which
             we will handle specially below.  */
          && !(TREE_CODE (exp) == CONSTRUCTOR
-              && bitsize % BITS_PER_UNIT == 0))
+              && bitsize % BITS_PER_UNIT == 0)
+         /* And except for bitwise copying of TREE_ADDRESSABLE types,
+            where the FIELD_DECL has the right bitsize, but TREE_TYPE (exp)
+            includes some extra padding.  */
+         && (!TREE_ADDRESSABLE (TREE_TYPE (exp))
+             || TREE_CODE (exp) != COMPONENT_REF
+             || TREE_CODE (DECL_SIZE (TREE_OPERAND (exp, 1))) != INTEGER_CST
+             || (bitsize % BITS_PER_UNIT != 0)
+             || (bitpos % BITS_PER_UNIT != 0)
+             || (compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)), bitsize)
+                 != 0)))
       /* If we are expanding a MEM_REF of a non-BLKmode non-addressable
          decl we must use bitfield operations.  */
       || (bitsize >= 0
          && TREE_CODE (exp) == MEM_REF
          && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
          && DECL_P (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
-         && !TREE_ADDRESSABLE (TREE_OPERAND (TREE_OPERAND (exp, 0),0 ))
+         && !TREE_ADDRESSABLE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
          && DECL_MODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != BLKmode))
     {
       rtx temp;
--- gcc/testsuite/g++.dg/torture/pr69851.C.jj   2016-02-19 10:59:22.224438830 
+0100
+++ gcc/testsuite/g++.dg/torture/pr69851.C      2016-02-19 10:59:12.000000000 
+0100
@@ -0,0 +1,24 @@
+// PR c++/69851
+// { dg-do compile }
+// { dg-options "-std=c++11" }
+
+template <typename T>
+struct A { T a; };
+template <unsigned long, typename...>
+struct B;
+template <unsigned long N, typename T, typename... U>
+struct B<N, T, U...> : B<1, U...>, A<T>
+{
+  B (B &) = default;
+  B (B &&x) : B(x) {}
+};
+template <unsigned long N, typename T>
+struct B<N, T> {};
+struct C { C (C &); };
+struct D {};
+
+void
+foo (B<0, C, D, int, int> a)
+{
+  B<0, C, D, int, int> b (a);
+}

        Jakub

Reply via email to