[PATCH] c++, libstdc++, v2: Implement C++26 P3726R2 - Adjustments to Union Lifetime Rules [PR125845]

Jason Merrill jason@redhat.com
Tue Sep 8 20:50:09 GMT 2026


On 9/8/26 4:14 PM, Jakub Jelinek wrote:
> On Tue, Sep 08, 2026 at 03:39:09PM -0400, Jason Merrill wrote:
>>> The init in that case is not a clobber, but an empty CONSTRUCTOR with
>>> the right flags.  Making start_lifetime implied from the
>>> CONSTRUCTOR_OMITTED_NOT_WITHIN_LIFETIME_P bit wouldn't be reliable.
>>> What we could do (but not done in the patch) is use some tree other than
>>> MODIFY_EXPR/INIT_EXPR with 2+ operands instead of the current MODIFY_EXPR,
>>> say MODOP_EXPR and let that mean start_lifetime.
>>
>> I like the sound of that, but won't insist on it.
> 
> Ok, will do that tomorrow.
> 
>>> I've filed PR127235 for this.  It is a preexisting bug (since C++20
>>> P1331R2 implementation I guess).  Dunno if here it is an error already
>>> to return the only partially initialized aggregate or only to initialize
>>> a constexpr var to that.  There is
>>>     /* 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 uninitialized 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 < cxx20
>>>             || !DECL_CONSTRUCTOR_P (fun)))
>>>       clear_no_implicit_zero (result);
>>> and fun here is not a constructor, so we happily clear the
>>> CONSTRUCTOR_NO_CLEARING bits.  Either it is invalid to return something like
>>> that, in that case we should be actually doing VERIFY_CONSTANT somewhere
>>> where we currently don't do it, or it is not and then we shouldn't ever call
>>> clear_no_implicit_zero for C++ >= 20.
>>
>> It's non-constant under https://eel.is/c++draft/expr.const#core-2.12 which
>> was also added by P1331; it's fine for the 'a' variable to be partially
>> initialized, but not to copy that uninitialized value.  The problem is that
>> by copying the struct as a whole we bypass the uninit check in
>> cxx_eval_component_reference.
>>
>> I guess _store_expression should reject init with CONSTRUCTOR_NO_CLEARING?
> 
> Is it ok to resolve that incrementally?

Yes.

> It is accepts-invalid, so we don't want to backport it though I guess.

Agreed.

>>> Now, the standard wording isn't clear on what happens when the
>>> function template is called on an array where its containing subobject
>>> isn't in lifetime either; the patch acts for the surrounding subobjects
>>> as a store, so makes all subobjects except for union members and the
>>> object it is called on within lifetime.  If something else should happen
>>> (e.g. make it non-constant), the patch will need changing.
>>
>> That sounds fine to me.
> 
> Yet another possibility would be to mark all the newly created CONSTRUCTORs
> for start_lifetime also with
> CONSTRUCTOR_NO_CLEARING/CONSTRUCTOR_OMITTED_NOT_WITHIN_LIFETIME_P

That sounds better: effectively calling start_lifetime on any enclosing 
objects first.  In particular if there's an out-of-lifetime enclosing 
object which is not a trivial-lifetime aggregate, it's non-constant.

Jason



More information about the Libstdc++ mailing list