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