On Thu, 19 Mar 2020, Marek Polacek wrote:
> On Thu, Mar 19, 2020 at 01:06:35PM -0400, Patrick Palka via Gcc-patches wrote:
> > On Thu, 19 Mar 2020, Patrick Palka wrote:
> >
> > > This patch adds a check to detect changing the active union member during
> > > initialization of the union. It uses the CONSTRUCTOR_NO_CLEARING flag as
> > > a
> > > proxy for whether the non-empty CONSTRUCTOR of UNION_TYPE we're assigning
> > > to in
> > > cxx_eval_store_expression is in the process of being initialized, which
> > > seems to
> > > work well.
> >
> > If we can't rely on CONSTRUCTOR_NO_CLEARING to be set iff a CONSTRUCTOR
> > is in the process of being initialized, then here's an alternative patch
> > for consideration, that detects this UB in an indirect way and after the
> > fact.
>
> Yeah, I'm not sure if that would work well, especially in C++20 where we
> sometimes don't clear it:
>
> /* The result of a constexpr function must be completely initialized.
>
> However, in C++20, a constexpr constructor doesn't necessarily have
> to initialize all the fields, so we don't clear CONSTRUCTOR_NO_CLEARING
> in order to detect reading an unitialized object in constexpr instead
> of value-initializing it. (reduced_constant_expression_p is expected to
> take care of clearing the flag.) */
> if (TREE_CODE (result) == CONSTRUCTOR
> && (cxx_dialect < cxx2a
> || !DECL_CONSTRUCTOR_P (fun)))
> clear_no_implicit_zero (result);
>
> and rely on reduced_constant_expression_p to clear it.
I see, thanks. Here's a reproducer for the issue you pointed out, which
is a valid testcase but gets rejected with the proposed patch:
union U
{
int x;
char y;
};
constexpr bool
baz ()
{
U u;
u.x = 3;
u.y = 7;
return (u.y == 7);
}
static_assert (baz ());
CONSTRUCTOR_NO_CLEARING is set for 'u' and is not cleared after its
constructor returns, and so the check yields a false positive for the
assignment to u.y. That's unfortunate...