On 3/19/20 2:06 PM, Patrick Palka via Gcc-patches wrote:
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...

We should probably clear the flag when we assign to u.x because once we give a value to one union member, the union has a value.

Jason

Reply via email to