Hi! The following testcase is rejected, because when trying to encode a zeroing CONSTRUCTOR, the code was using build_constructor to build initializers for the elements but when recursing the function handles CONSTRUCTOR only for aggregate types.
The following patch fixes that by using build_zero_cst instead for non-aggregates. Another option would be add handling CONSTRUCTOR for non-aggregates in native_encode_initializer. Or we can do both, I guess the middle-end generally doesn't like CONSTRUCTORs for scalar variables, but am not 100% sure if the FE doesn't produce those sometimes. Ok for trunk if it passes bootstrap/regtest? So far it passed make check-c++-all RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} dg.exp=bit-cast*' 2020-12-04 Jakub Jelinek <ja...@redhat.com> PR libstd++/93121 * fold-const.c (native_encode_initializer): Use build_constructor only for aggregate types, otherwise use build_zero_cst. * g++.dg/cpp2a/bit-cast6.C: New test. --- gcc/fold-const.c.jj 2020-12-03 15:37:25.795342398 +0100 +++ gcc/fold-const.c 2020-12-04 11:25:54.949421799 +0100 @@ -8104,11 +8104,16 @@ native_encode_initializer (tree init, un { if (valueinit == -1) { - tree zero = build_constructor (TREE_TYPE (type), NULL); + tree zero; + if (AGGREGATE_TYPE_P (TREE_TYPE (type))) + zero = build_constructor (TREE_TYPE (type), NULL); + else + zero = build_zero_cst (TREE_TYPE (type)); r = native_encode_initializer (zero, ptr + curpos, fieldsize, 0, mask + curpos); - ggc_free (zero); + if (TREE_CODE (zero) == CONSTRUCTOR) + ggc_free (zero); if (!r) return 0; valueinit = curpos; @@ -8255,8 +8260,13 @@ native_encode_initializer (tree init, un { cnt--; field = fld; - val = build_constructor (TREE_TYPE (fld), NULL); - to_free = val; + if (AGGREGATE_TYPE_P (TREE_TYPE (fld))) + { + val = build_constructor (TREE_TYPE (fld), NULL); + to_free = val; + } + else + val = build_zero_cst (TREE_TYPE (fld)); } } --- gcc/testsuite/g++.dg/cpp2a/bit-cast6.C.jj 2020-12-04 11:36:12.963456560 +0100 +++ gcc/testsuite/g++.dg/cpp2a/bit-cast6.C 2020-12-04 11:35:59.227611364 +0100 @@ -0,0 +1,31 @@ +// PR libstd++/93121 +// { dg-do compile { target c++20 } } + +namespace std +{ +enum class byte : unsigned char {}; +template <typename To, typename From> +constexpr To +bit_cast (const From &from) +{ + return __builtin_bit_cast (To, from); +} +} + +struct S { unsigned short s[2]; }; +constexpr std::byte from1[sizeof (S)]{}; +constexpr auto to1 = std::bit_cast<S>(from1); +constexpr unsigned char from2[sizeof (S)]{}; +constexpr auto to2 = std::bit_cast<S>(from2); + +constexpr bool +cmp (const S &s1, const S &s2) +{ + for (int i = 0; i < sizeof (s1.s) / sizeof (s1.s[0]); i++) + if (s1.s[i] != s2.s[i]) + return false; + return true; +} + +static_assert (cmp (to1, S{})); +static_assert (cmp (to2, S{})); Jakub