On 5/26/26 6:40 AM, Jakub Jelinek wrote:
Hi!
Is my understanding correct that for stores changing the active union
member at constant evaluation time we want to start lifetime of all
subobjects except variant members, while std::start_lifetime only does
that without any subobjects?
I think so, yes.
Furthermore, there are the https://wg21.link/P2641R4 and
https://wg21.link/P3450R1 std::is_within_lifetime papers which we need to
implement and track lifetime even in more detail. Looking at clang, they
do implement the first paper using __builtin_is_within_lifetime builtin, but
not the second one; wonder if the second paper is implementable purely in
headers (somehow try to evaluate if static_cast<const volatile U*>(p)
is a constant expression) or whether we need a two argument builtin instead of
one
(where the other argument would be say a null pointer of the
const volatile U * type) and how to deal with compatibility when LLVM 22
already has __has_builtin(__builtin_is_within_lifetime) but not
support the 2 argument one.
Anyway, my limited understanding is that lifetime of an object starts at the
end of a constructor or during vacuous initialization and ends when
destructor starts, the object is destroyed or reused.
So, I think solely for __builtin_start_lifetime purposes we need to
differentiate between CONSTRUCTOR_NO_CLEARING CONSTRUCTORs which do have
all omitted elements within lifetime and such constructors which have all
omitted elements not within lifetime,
Yes.
but then also need a flag on each
CONSTRUCTOR whether that whole subobject is within lifetime.
I think it does make sense to have an additional flag to distinguish the
period of construction. cxx_eval_store_expression uses TREE_READONLY to
check period of construction for const objects, but we need something
else for the general case.
Does e.g. ptr[2].~T (); on an array previously all within lifetime make
that particular element not within a lifetime?
Yes. _store_expression currently handles EOL clobbers with
else if (TREE_CLOBBER_P (init))
{
if (AGGREGATE_TYPE_P (type))
{
if (*valp && TREE_CODE (*valp) == CONSTRUCTOR)
CONSTRUCTOR_ELTS (*valp) = nullptr;
else
*valp = build_constructor (type, nullptr);
TREE_CONSTANT (*valp) = true;
TREE_SIDE_EFFECTS (*valp) = false;
CONSTRUCTOR_NO_CLEARING (*valp) = true;
CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits;
}
else
*valp = void_node;
}
I'd expect this to just need tweaking.
Or only for class types?
The hole checking in the patch then would need to differentiate between the
within lifetime and not within lifetime holes.