Take: ``` #include <bit> struct A { signed char b:1 = 0; signed char b1:7 = 0; }; struct B { unsigned char b; }; static_assert( std::bit_cast<B>(A{}).b == 0 ); ``` This should work as the bitfields span all of the char space but currently we get a sorry: ``` <source>:9:40: error: non-constant condition for static assertion 9 | static_assert( std::bit_cast<B>(A{}).b == 0 ); | ~~~~~~~~~~~~~~~~~~~~~~~~^~~~ In file included from <source>:2: <source>:9:32: in 'constexpr' expansion of 'std::bit_cast<B, A>(A{0, 0})' /opt/compiler-explorer/gcc-trunk-20240331/include/c++/14.0.1/bit:94:33: sorry, unimplemented: '__builtin_bit_cast' cannot be constant evaluated because the argument cannot be encoded 94 | return __builtin_bit_cast(_To, __from); | ^~~ ``` I had been looking for a quick workaround for PR 114536 (for little-endian only) but it looked like NSDMI for bitfields is not implemented fully.
Probably related: ``` #include <bit> struct A { int a: 7; }; static_assert( 1 == std::bit_cast<A>(std::bit_cast<int>(A{1})).a ); ``` It looks valid and accepted by MSVC, but GCC prints: error: '__builtin_bit_cast' accessing uninitialized byte at offset 0 Online demo: https://gcc.godbolt.org/z/3W5onY955
(In reply to Fedor Chelnokov from comment #1) > Probably related: > ``` > #include <bit> > > struct A { int a: 7; }; > > static_assert( 1 == std::bit_cast<A>(std::bit_cast<int>(A{1})).a ); > ``` > It looks valid and accepted by MSVC, but GCC prints: > error: '__builtin_bit_cast' accessing uninitialized byte at offset 0 > > Online demo: https://gcc.godbolt.org/z/3W5onY955 That is unrelated and gcc is actually correct there see pr 99637.
Created attachment 57863 [details] gcc14-pr114537.patch Untested fix.
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:1baec8deb014b8a7da58879a407a4c00cdeb5a09 commit r14-9784-g1baec8deb014b8a7da58879a407a4c00cdeb5a09 Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Apr 4 10:47:52 2024 +0200 fold-const: Handle NON_LVALUE_EXPR in native_encode_initializer [PR114537] The following testcase is incorrectly rejected. The problem is that for bit-fields native_encode_initializer expects the corresponding CONSTRUCTOR elt value must be INTEGER_CST, but that isn't the case here, it is wrapped into NON_LVALUE_EXPR by maybe_wrap_with_location. We could STRIP_ANY_LOCATION_WRAPPER as well, but as all we are looking for is INTEGER_CST inside, just looking through NON_LVALUE_EXPR seems easier. 2024-04-04 Jakub Jelinek <jakub@redhat.com> PR c++/114537 * fold-const.cc (native_encode_initializer): Look through NON_LVALUE_EXPR if val is INTEGER_CST. * g++.dg/cpp2a/bit-cast16.C: New test.
Sorry, in above example I had to use `unsigned char` type: ``` #include <bit> struct A { unsigned char a : 7; }; static_assert( std::bit_cast<A>(std::bit_cast<unsigned char>(A{1})).a == 1 ); ``` This program even after the fix in trunk, prints the same error as in the original post: <source>:5:32: in 'constexpr' expansion of 'std::bit_cast<A, unsigned char>(std::bit_cast<unsigned char, A>(A{1}))' /opt/compiler-explorer/gcc-trunk-20240405/include/c++/14.0.1/bit:94:33: sorry, unimplemented: '__builtin_bit_cast' cannot be constant evaluated because the argument cannot be encoded 94 | return __builtin_bit_cast(_To, __from); Online demo: https://gcc.godbolt.org/z/eqrsfGEnT
The releases/gcc-13 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:a297f9bbb9611414fe48f6d61a8829bf5808bd2c commit r13-8626-ga297f9bbb9611414fe48f6d61a8829bf5808bd2c Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Apr 4 10:47:52 2024 +0200 fold-const: Handle NON_LVALUE_EXPR in native_encode_initializer [PR114537] The following testcase is incorrectly rejected. The problem is that for bit-fields native_encode_initializer expects the corresponding CONSTRUCTOR elt value must be INTEGER_CST, but that isn't the case here, it is wrapped into NON_LVALUE_EXPR by maybe_wrap_with_location. We could STRIP_ANY_LOCATION_WRAPPER as well, but as all we are looking for is INTEGER_CST inside, just looking through NON_LVALUE_EXPR seems easier. 2024-04-04 Jakub Jelinek <jakub@redhat.com> PR c++/114537 * fold-const.cc (native_encode_initializer): Look through NON_LVALUE_EXPR if val is INTEGER_CST. * g++.dg/cpp2a/bit-cast16.C: New test. (cherry picked from commit 1baec8deb014b8a7da58879a407a4c00cdeb5a09)
The releases/gcc-12 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:42afabb838d511f5feb150bfa4e68b5880aae1fa commit r12-10518-g42afabb838d511f5feb150bfa4e68b5880aae1fa Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Apr 4 10:47:52 2024 +0200 fold-const: Handle NON_LVALUE_EXPR in native_encode_initializer [PR114537] The following testcase is incorrectly rejected. The problem is that for bit-fields native_encode_initializer expects the corresponding CONSTRUCTOR elt value must be INTEGER_CST, but that isn't the case here, it is wrapped into NON_LVALUE_EXPR by maybe_wrap_with_location. We could STRIP_ANY_LOCATION_WRAPPER as well, but as all we are looking for is INTEGER_CST inside, just looking through NON_LVALUE_EXPR seems easier. 2024-04-04 Jakub Jelinek <jakub@redhat.com> PR c++/114537 * fold-const.cc (native_encode_initializer): Look through NON_LVALUE_EXPR if val is INTEGER_CST. * g++.dg/cpp2a/bit-cast16.C: New test. (cherry picked from commit 1baec8deb014b8a7da58879a407a4c00cdeb5a09)
Should be fixed for 12.4+ and 13.4+ too.
The releases/gcc-11 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:5d6b1d8ffc4828874ecdb1cde1b794bc3b8d35af commit r11-11501-g5d6b1d8ffc4828874ecdb1cde1b794bc3b8d35af Author: Jakub Jelinek <jakub@redhat.com> Date: Thu Apr 4 10:47:52 2024 +0200 fold-const: Handle NON_LVALUE_EXPR in native_encode_initializer [PR114537] The following testcase is incorrectly rejected. The problem is that for bit-fields native_encode_initializer expects the corresponding CONSTRUCTOR elt value must be INTEGER_CST, but that isn't the case here, it is wrapped into NON_LVALUE_EXPR by maybe_wrap_with_location. We could STRIP_ANY_LOCATION_WRAPPER as well, but as all we are looking for is INTEGER_CST inside, just looking through NON_LVALUE_EXPR seems easier. 2024-04-04 Jakub Jelinek <jakub@redhat.com> PR c++/114537 * fold-const.c (native_encode_initializer): Look through NON_LVALUE_EXPR if val is INTEGER_CST. * g++.dg/cpp2a/bit-cast16.C: New test. (cherry picked from commit 1baec8deb014b8a7da58879a407a4c00cdeb5a09)
Fixed for 11.5 as well.