> My intuition is that you could get those guarantees if you ran
> std::clear_padding, std::memcpy to a byte array, and then std::bit_cast out
> of a byte array into std::uint128_t. However, that forces compilers to
> permanently spill objects from registers (such as function parameters
> passed via register) into memory when std::clear_padding is used on them
> because it's possible that someone will later read the padding bits. Maybe
> merely the possibility that std::clear_padding is run in some opaque
> function causes pessimizations. This would definitely need to be
> investigated when proposing a std::clear_padding function.

No, it does not. Again, the only thing that matters is the behaviour.

The compiler does not have to make the variable concrete in memory.

But behavior needs to be implemented in some fashion, and specifying certain behavior constrains what implementations are possible, sometimes in surprising ways.

If you receive a long double function parameter and your calling conventions are so that this is passed via floating-point stack, there are no padding bits in that object which could be cleared. Ergo, if you ran std::clear_padding, this would require spilling the object from the floating-point stack into memory so that the padding bits can be accessed later, with the guaranteed cleared value.

To be fair, I don't think std::clear_padding creates this problem; you can already memcpy into an object to manipulate its padding bits, so the problem starts with padding bits being observable. However, use of clear_padding and memcpy idioms may pessimize code in practice, so perhaps that's not an idiom we want to promote.

By comparison, std::bit_cast_clear_padding ignores the values of input padding bits, so the compiler would never be required to track their values.