On Thu, Jul 30, 2020 at 05:59:18PM -0400, Jason Merrill via Gcc-patches wrote:
> > Even if we are guaranteed that (what guarantees it?) when __builtin_bit_cast
> > is constexpr evaluated no initializer will be omitted if may be value 
> > initialized
> > to something other than all zeros,
> 
> This is established by digest_init/process_init_constructor_record, which
> replace implicit value-initialization with explicit values when it's not
> simple zero-initialization.

Ok, I see.

> > we still need to track what bits are well
> > defined and what are not (e.g. any padding in there).
> 
> > Thinking about it now, maybe the mask handling for !CONSTRUCTOR_NO_CLEARING
> > is incorrect though if there are missing initializers, because those omitted
> > initializers still could have paddings with unspecified content, right?
> 
> Zero-initialization (and thus trivial value-initialization) of a class also
> zeroes out padding bits, so when !CONSTRUCTOR_NO_CLEARING all bits should be
> well defined.

Does the standard require that somewhere?  Because that is not what the
compiler implements right now.
If I try:
extern "C" void *memcpy (void *, const void *, decltype (sizeof 0)) noexcept;
struct S { int a, b : 31, c; short d; signed char e; };
S a = S ();
constexpr S d = S ();

S
foo ()
{
  return S ();
}

void
bar (int *p)
{
  S b = foo ();
  S c = S ();
  memcpy (p, &a, sizeof (S));
  memcpy (p + 4, &b, sizeof (S));
  memcpy (p + 8, &c, sizeof (S));
  memcpy (p + 12, &d, sizeof (S));
}
then a will have the padding bit initialized iff it has a constant
initializer (as .data/.rodata initializers have all bits well defined),
but both foo, the copying of foo result to b and the initialization of c
all make the padding bit unspecified.

The gimplifier indeed has code that for !CONSTRUCTOR_NO_CLEARING
CONSTRUCTORs it will clear them fully first, but that only triggers if
the CONSTRUCTOR is characterized as incomplete, which is checked by whether
all the initializable fields have a corresponding initializer element,
so it doesn't count padding bits, in the middle or at the end of structures.

So, shall std::bit_cast be well defined if reading the padding bits
from these cases even when at runtime they would be undefined?  Or do we
need to change the gimplifier (and expansion etc.) for C++?

Talking about the cases where the types in the destination aren't unsigned
char/std::byte, that has some special rules and Marek has filed a PR for
those.

        Jakub

Reply via email to