Date: Fri, 23 Jan 2026 06:55:50 +0100
> Good point. IIUC, the x87 `fstpt` instruction (used by GCC's codegen)
> writes only 10 bytes, not 16 bytes.
> And Clang's codegen *explicitly* writes only 10 bytes, not 16 bytes,
> using integer `movw`.
>
> Now, *at constexpr time,* GCC does act as if it's zeroing the padding
> bits: https://godbolt.org/z/o6Gcen1P5
> And EDG 6.8's __builtin_bit_cast seems to be doing the same thing, zeroing
> the padding bits: https://gcc.godbolt.org/z/GEMYbhdx8
>
It's worth noting that both GCC and Clang are correct because this is a
case of undefined behavior during constant evaluation.
https://eel.is/c++draft/bit.cast#4.2 states that the behavior is undefined
when you get a padding bit from the source into a non-padding bit within
the destination. The one-liner repro for the divergence is:
constexpr auto x = __builtin_bit_cast(__int128, 0.0L); // GCC OK, Clang
error
Whereas Clang rejects the bit_cast entirely. IIUC, Clang is using logic
similar to Jan's to insist that this std::bit_cast has UB so it shouldn't
compile at constexpr time.
Clang rejects that code, but simply on the basis that constant evaluation
hits something that's UB. Clang is already allowed to do that. What I'm
suggesting is that the call to std::bit_cast should be ill-formed because
it's unconditionally UB, and thus indicative of a programmer error, even if
never evaluated.
GCC accepts that code, which it's allowed to do. It's simply undefined
behavior at compile time.
> writes only 10 bytes, not 16 bytes.
> And Clang's codegen *explicitly* writes only 10 bytes, not 16 bytes,
> using integer `movw`.
>
> Now, *at constexpr time,* GCC does act as if it's zeroing the padding
> bits: https://godbolt.org/z/o6Gcen1P5
> And EDG 6.8's __builtin_bit_cast seems to be doing the same thing, zeroing
> the padding bits: https://gcc.godbolt.org/z/GEMYbhdx8
>
It's worth noting that both GCC and Clang are correct because this is a
case of undefined behavior during constant evaluation.
https://eel.is/c++draft/bit.cast#4.2 states that the behavior is undefined
when you get a padding bit from the source into a non-padding bit within
the destination. The one-liner repro for the divergence is:
constexpr auto x = __builtin_bit_cast(__int128, 0.0L); // GCC OK, Clang
error
Whereas Clang rejects the bit_cast entirely. IIUC, Clang is using logic
similar to Jan's to insist that this std::bit_cast has UB so it shouldn't
compile at constexpr time.
Clang rejects that code, but simply on the basis that constant evaluation
hits something that's UB. Clang is already allowed to do that. What I'm
suggesting is that the call to std::bit_cast should be ill-formed because
it's unconditionally UB, and thus indicative of a programmer error, even if
never evaluated.
GCC accepts that code, which it's allowed to do. It's simply undefined
behavior at compile time.
Received on 2026-01-23 05:56:06
