On Sat, 17 Jan 2026 at 16:46, Thiago Macieira via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Saturday, 17 January 2026 03:22:24 Pacific Standard Time Jan Schultke via
Std-Proposals wrote:
> I've decided to tackle the issue in a proposal:
> https://isocpp.org/files/papers/D3969R0.html
>
> Thanks for the feedback, it's been quite helpful in making this draft and
> addressing possible design alternatives.

Feedback:

In the introduction:
Please introduce that you're talking about x86 and 80-bit extended-precision
long double before you talk about the bug. There are several architectures
where it isn't.

Is it UB to *cast* from long double to __int128? Or is it UB to observe the
padding bits on the destination?

Suppose for example one did:
  auto a = std::bit_cast<unsigned __int128>(0.0L);
  auto b = std::bit_cast<std::array<uint16_t, 8>>(a);

The value of the 128-bit integer was never observed, it was only used as a
source to casting to an array of 16 bytes. And observing the non-padding
bytes/words in that array shouldn't be UB, should it?

It's UB according to [bit.cast]. Copying padding bits from the original into the value representation of the destination makes the value indeterminate, and this makes the call to bit_cast UB. Observing padding bits has nothing to do with it.
 
I wouldn't write "is an alternative spelling for std::unreachable". Please
elaborate on how you're reaching that conlusion: this operation is always UB
and therefore the compiler is allowed to assume didn't happen, therefore we
conclude that it is unreachable.

Well, I think it may be worth adding an explanation of the relevant [bit.cast] wording in the introduction. I don't see any other way of phrasing it though; std::bit_cast<__int128, long double> and std::unreachable have the same behavior.
 
In the design:

I'm not satisfied with the arguments for leaving std::bit_cast unchanged for
byte arrays. What's the point of accessing the indeterminate padding bytes in
byte form? Since they are indeterminate, the program also has indeterminate
behaviour if one uses them in a control expression (I believe it turns UB
too). The only two things one *can* do to the indeterminate bytes are to copy
them to other bytes or to overwrite them with determinate bytes.

Well yeah, the current design allows you to copy them around, and not much else. I don't see much motivation for changing that status quo though, and the problem described in the paper doesn't have to do with the case of casting to byte arrays.

But then under as-if rule, the compiler can see whether one did any of that
and avoid emitting the pad-clearing.

As for using an older version of std::bit_cast, I don't see a problem. The
__cpp_lib_bit_cast macro would get updated to a new value, so application
developers would know the behaviour has been updated. If they would know to
use std::bit_cast_clear_padding(), they would also know to check the value of
the macro.

People diligently checking feature-test macros is a very optimistic assumption. The issue is that if we only change bit_cast, then the function compiles either way, whether it has UB or the compiler is recent and it's well-defined. If you're forced to spell it std::bit_cast_zero_padding, it either compiles and does the right thing, or it doesn't compile.

 
I would agree with the surprise that it does clear when one didn't expect it.
However, the end result is that std::bit_cast is relegated to the niche use-
cases and std::bit_cast_clear_padding is the general one, superior in almost
every aspect, and requires adding #if everywhere.

It would only require adding #if for a few versions, just like any other feature. One should always prioritize the overall design, which lives for decades rather than the temporary transition state.

I don't think that std::bit_cast_zero_padding makes for a better "default" option anyway. std::bit_cast would be used in the vast majority of cases where you don't have padding issues, like casting float to int, or casting a type to a byte array.

std::bit_cast_zero_padding solves a very specific edge case where you have padding bits in the source type and need to give them some arbitrary value in the destination type. I don't think this is common.