Date: Fri, 23 Jan 2026 13:07:09 -0800
On Friday, 23 January 2026 10:02:24 Pacific Standard Time Sebastian Wittmeier
via Std-Proposals wrote:
> I am trying to summarize:
>
>
> So you define that
>
> std::clear_padding(T& t)
>
>
> would act on the lvalue t. t (as a lvalue) has a defined address in memory.
>
> All the padding bits/bytes are zeroed. Any access to the underlying storage
> (e.g. as std::byte or unsigned char) would read the zeroes.
> Any direct read or write of type T would still have or create indeterminate
> padding bits and bytes.
Any write.
A non-mutating operation cannot mutate the object, therefore any bits that had
been determined must remain determined.
> Using t as a reference parameter would keep the cleared padding bits, using
> it as a value parameter not in the general case.
Correct, but I wouldn't write this way.
Taking the address of a variable or binding a reference to it is non-mutating,
therefore the cleared padding bits must remain clear. Reading the variable to
assign it to a copy is also non-mutating, so the *original* variable retains
cleared padding bits. But the new one where the value was copied to was
mutated, therefore its padding bits are indeterminate.
> Returning t as a value would neither keep the padding bits, one exception
> could have been in theory RVO, but there is no RVO facility in the
> language, where the value to be returned can be accessed as a lvalue.
Same rule as above: returning by value writes to the return, therefore the
returned value's padding bits are indeterminate. RVO is an optimisation so it
is irrelevant.
That means depending on RVO and return-by-implicit-reference to retain cleared
padding bits is not portable.
> The language in general may not insert (anymore) any code changing the
> padding bits and bytes, if there was no write of t. This could have been
> possible up till now under the as-if rule, as the padding bits may have
> changed at any time.
I'm not sure. Others have argued that padding bits cannot change out of the
blue, without a write operation. I think we do want to firm up the language
here, though. One of two options:
* padding bits must remain the same, whether they were indeterminate or not
* padding bits must remain the same only if they were cleared
The test is something like this:
memcpy(buf, &type_with_padding, sizeof(type_with_padding));
// lots of code, but type_with_padding isn't modified
memcmp(buf, &type_with_padding, sizeof(type_with_padding)) == 0
And from reading the code generated by GCC[1] for the above for long double, I
think it would have the surprise "padding bits changed without write"
behaviour: it performs FSTP once at %rsp+64 (&v), and once at %rsp+16 then
copies to %rsp+32 (buf) (the third FSTP operation is the call to f()). Since
the two variables came from distinct FSTP operations, the padding bits would
be different. Clang and the old ICC only have two FSTP, so the origins of &v
and buf are the same, copied via all-bits-copying instructions.
[1] https://gcc.godbolt.org/z/Wxdxbjao5
via Std-Proposals wrote:
> I am trying to summarize:
>
>
> So you define that
>
> std::clear_padding(T& t)
>
>
> would act on the lvalue t. t (as a lvalue) has a defined address in memory.
>
> All the padding bits/bytes are zeroed. Any access to the underlying storage
> (e.g. as std::byte or unsigned char) would read the zeroes.
> Any direct read or write of type T would still have or create indeterminate
> padding bits and bytes.
Any write.
A non-mutating operation cannot mutate the object, therefore any bits that had
been determined must remain determined.
> Using t as a reference parameter would keep the cleared padding bits, using
> it as a value parameter not in the general case.
Correct, but I wouldn't write this way.
Taking the address of a variable or binding a reference to it is non-mutating,
therefore the cleared padding bits must remain clear. Reading the variable to
assign it to a copy is also non-mutating, so the *original* variable retains
cleared padding bits. But the new one where the value was copied to was
mutated, therefore its padding bits are indeterminate.
> Returning t as a value would neither keep the padding bits, one exception
> could have been in theory RVO, but there is no RVO facility in the
> language, where the value to be returned can be accessed as a lvalue.
Same rule as above: returning by value writes to the return, therefore the
returned value's padding bits are indeterminate. RVO is an optimisation so it
is irrelevant.
That means depending on RVO and return-by-implicit-reference to retain cleared
padding bits is not portable.
> The language in general may not insert (anymore) any code changing the
> padding bits and bytes, if there was no write of t. This could have been
> possible up till now under the as-if rule, as the padding bits may have
> changed at any time.
I'm not sure. Others have argued that padding bits cannot change out of the
blue, without a write operation. I think we do want to firm up the language
here, though. One of two options:
* padding bits must remain the same, whether they were indeterminate or not
* padding bits must remain the same only if they were cleared
The test is something like this:
memcpy(buf, &type_with_padding, sizeof(type_with_padding));
// lots of code, but type_with_padding isn't modified
memcmp(buf, &type_with_padding, sizeof(type_with_padding)) == 0
And from reading the code generated by GCC[1] for the above for long double, I
think it would have the surprise "padding bits changed without write"
behaviour: it performs FSTP once at %rsp+64 (&v), and once at %rsp+16 then
copies to %rsp+32 (buf) (the third FSTP operation is the call to f()). Since
the two variables came from distinct FSTP operations, the padding bits would
be different. Clang and the old ICC only have two FSTP, so the origins of &v
and buf are the same, copied via all-bits-copying instructions.
[1] https://gcc.godbolt.org/z/Wxdxbjao5
-- Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org Principal Engineer - Intel Data Center - Platform & Sys. Eng.
Received on 2026-01-23 21:07:18
