On 8/27/20 6:19 AM, Richard Biener wrote:
On Thu, 27 Aug 2020, Jakub Jelinek wrote:
On Fri, Jul 31, 2020 at 04:28:05PM -0400, Jason Merrill via Gcc-patches wrote:
On 7/31/20 6:06 AM, Jakub Jelinek wrote:
On Fri, Jul 31, 2020 at 10:54:46AM +0100, Jonathan Wakely wrote:
Does the standard require that somewhere? Because that is not what the
compiler implements right now.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78620
But does that imply that all CONSTRUCTORs without CONSTRUCTOR_NO_CLEARING
need to be treated that way? I mean, aren't such CONSTRUCTORs used also for
other initializations?
Yes, they are also used to represent constant values of classes that are
initialized by constexpr constructor.
And, are the default copy constructors or assignment operators supposed to
also copy the padding bits, or do they become unspecified again through
that?
For a non-union class, a defaulted copy is defined as memberwise copy, not a
copy of the entire object representation. So I guess strictly speaking the
padding bits do become unspecified. But I think if the copy is trivial, in
practice all implementations do copy the object representation; perhaps the
specification should adjust accordingly.
Sorry for not responding earlier. I think at least in GCC there is no
guarantee the copying is copying the object representation rather than
memberwise copy, both are possible, depending e.g. whether SRA happens or
not.
Note we've basically settled on that SRA needs to copy padding and that
GIMPLE copies all bytes for aggregate copies and thus
x = {}
is equivalent to a memset.
So, shouldn't we have a new CONSTRUCTOR flag that will represent whether
padding bits are cleared or not and then use it e.g. in the gimplifier?
Right now the gimplifier only adds first zero initialization if
CONSTRUCTOR_NO_CLEARING is not set and some initializers are not present,
so if there is a new flag, we'd need to in that case find out if there are
any padding bits and do the zero initialization in that case.
A question is if GIMPLE var = {}; statement (empty CONSTRUCTOR) is handled
as zero initialization of also the padding bits, or if we should treat it
that way only if the CONSTRUCTOR on the rhs has the new bit set and e.g.
when lowering memset 0 into var = {}; set the bit too.
From what I understood on IRC, D has similar need for zero initialization of
padding.
Now indeed the gimplifier will turn a aggregate CTOR initialization
to memberwise init without caring for padding. Which means GENERIC
has the less strict semantics and we indeed would need some CTOR flag
to tell whether padding is implicitely zero or undefined?
CONSTRUCTOR_NO_CLEARING would seem to already mean that, but the C++
front end uses it just to indicate whether some fields are
uninitialized. I suppose C++ could use a LANG_FLAG for that instead of
the generic flag.
In the testcase below, what is and what is not UB?
#include <bit>
struct S { int a : 31; int b; };
struct T { int a, b; };
constexpr int
foo ()
{
S a = S ();
S b = { 0, 0 };
S c = a;
S d;
S e;
d = a;
e = S ();
int u = std::bit_cast (T, a).a; // Is this well defined due to value
initialization of a?
int v = std::bit_cast (T, b).a; // But this is invalid, right? There is no
difference in the IL though.
int w = std::bit_cast (T, c).a; // And this is also invalid, or are default
copy ctors required to copy padding bits?
int x = std::bit_cast (T, d).a; // Similarly for default copy assignment
operators...
int y = std::bit_cast (T, e).a; // And this too?
int z = std::bit_cast (T, S ()).a; // This one is well defined?
return u + v + w + x + y + z;
}
constexpr int x = foo ();
Jakub