Is it allowed to apply std::bit_cast to an object of empty class, converting it to some not-empty class of the same size? And especially is it allowed to do in a constant expression?
I was surprised to find that the following simple program
#include <bit>
struct A {};
struct B { unsigned char b; };
// ok in MSVC and GCC, fail in Clang
static_assert( 0 == std::bit_cast<B>(A{}).b );
is accepted by both GCC and MSVC, and only Clang complains:
error: static assertion expression is not an integral constant expression
Online demo: https://gcc.godbolt.org/z/cGW3Mq3je
What is the correct behavior here according to the standard?
From [bit.cast]/2:
So, in your case, the behavior of the expression is undefined, but not because of the
std::bit_castitself.Because the bits of
bdo not correspond to any bit of the value representation ofA{}, they are indeterminate and the value ofbitself is consequently indeterminate. Only becausebhas typeunsigned char, this is not immediately undefined behavior.However, for the comparison with
0 ==, you then read the value ofb, which causes undefined behavior because its value is indeterminate.Of course, because you are using the comparison as the condition in a
static_assert, the program will not have undefined behavior, but will be ill-formed instead, because the expression is not a constant expression. In a constant expression any lvalue-to-rvalue conversion on an indeterminate value is disallowed. The compiler needs to diagnose this and therefore only Clang is conforming.