From [bit.cast]/2:
[...] A bit in the value representation of the result is indeterminate if it does not correspond to a bit in the value representation of from [...].
For each bit in the value representation of the result that is indeterminate, the smallest object containing that bit has an indeterminate value; the behavior is undefined unless that object is of unsigned ordinary character type or std::byte type. [...]
So, in your case, the behavior of the expression is undefined, but not because of the std::bit_cast
itself.
Because the bits of b
do not correspond to any bit of the value representation of A{}
, they are indeterminate and the value of b
itself is consequently indeterminate. Only because b
has type unsigned char
, this is not immediately undefined behavior.
However, for the comparison with 0 ==
, you then read the value of b
, 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.