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...