The implementation cannot not copy the padding bits when the user
invokes memcpy.
That is wrong. There is no way to observe that padding bits have been copied anyway, so this can be optimized away under the as-if rule. In fact, memcpy can (and in practice is) optimized to a mov between registers when possible, and a mov of x87 floating-point types does not copy padding bits because none exist in the first place.
It's like arguing that creating an int variable requires the compiler to put four bytes on stack memory. Just no.
It could theoretically do something funny with them when
the user invokes bit_cast, but that is still acceptable if the result is
usable (specifically, those bits of the result that were not produced
from the input padding bits).
Yes, in fact it does something funny with constant evaluation; as mentioned, LLVM does not have an object representation and does not have any tracked padding bits at compile time. Object representations for bit-cating are generated on the fly.
Noone is proposing to rely on padding bits. On the contrary, I and David
propose to add an utility for clearing padding bits, which, if anything,
could improve security.
But your utility has no observable effect in the abstract machine. Padding bits do not really exist (see the two examples I just brought up). You're clearing bits that don't really exist, and the user has no way to observe their values anyway.
I'm not opposed to a function whose effect is completely implementation-defined (similar to std::breakpoint) if you want to standardize __builtin_clear_padding, but that's as far as we can go with the object model.
> There are still floating-point types where certain representations
> result in CPU traps when used in an operation, if you find that to be
> more convincing of a reason.
Yes. And the possibility of producing a trap value of such a type exists
whether or not it is produced via padding or value representation bits
in the source.
Producing representations not valid for the type is a separate issue, and should stay UB.
> memcpy has well defined behavior, regardless of how it's implemented. If
> the program says memcpy then the source is copied as is to the target,
> with padding bits and everything. I do not see a fundamental reason why
> then the target should not be allowed to be used.
>
> Because the source could also not be used. For all intents and purposes,
> padding bits are eternally indeterminate quantum bits, and querying
> their value results in your CPU exploding.
This premise is too disconnected from reality.
Look, even the standard acknowledges that objects are represented with
bytes stored in some kind of storage.
No, this is wrong. See the aforementioned examples.
memcpy must write something to the target bits where the source padding
bits map onto. You could argue that memcpy could magically produce
garbage there instead of actually reading it from source (although no
implementation does such silly things, to my knowledge), but that would
still be acceptable if the user doesn't use those garbage bits. And I
maintain, the user should be allowed to do that, I see no reason why he
shouldn't.
No, it's not required to do anything like that because you're not able to observe whether it actually copied memory. Memory is an implementation detail, and the implementation is free to not copy anything if it knows that all the input bytes are indeterminate anyway. There is no observable distinction between any two indeterminate bytes.
So what you're saying is that there is no legal way to bit_cast a
_BitInt(3) to something else (e.g. uint8_t), that this is a good thing?
I'm sorry, but I disagree.
I'm saying it's not a good thing, and it would be useful to have something like std::bit_cast_zero_padding, or for padding wipes to be the default behavior of std::bit_cast. I just don't see any need to overhaul the object model, possibly disallowing vast amounts of optimizations.
I'm also saying that the approach of wiping the padding bits in the object before it gets bit-cast doesn't make any sense, considering those bits don't really exist, or if they exist, are very magical, even if you think of them as being much more predictable and well-behaved than the object model actually says.
But padding bits exist and are exposable in various ways. Denying this
is living in a delusional world and results in people writing
non-portable and non-conforming code anyway.
That's not a nice way of putting it. It's also questionable why considering padding-bits to be unpredictable would result in non-portable and non-conforming code. It seems like a cautious and conservative model.
If anything, it's more dangerous to rely on memcpy to copy padding bits just because that's your intuition and mental model, without any wording to actually support this, and with various known implementations contradicting that mental model.