[cfe-dev] Smart Pointer Lifetime Optimizations
John McCall via cfe-dev
cfe-dev at lists.llvm.org
Wed Jun 10 12:18:37 PDT 2020
On 10 Jun 2020, at 14:32, Richard Smith wrote:
> On Mon, 8 Jun 2020 at 19:52, John McCall via cfe-dev
> <cfe-dev at lists.llvm.org>
> wrote:
>> It definitely changes observable semantics, but it’s not
>> *obviously*
>> non-conforming; [expr.call]p7 gives us a lot of flexibility here:
>>
>> It is implementation-defined whether the lifetime of a parameter
>> ends when the function in which it is defined returns or at the
>> end of the enclosing full-expression.
>>
> This is the non-conformance I'm referring to:
> https://godbolt.org/z/cgf5_2
>
> Even given [expr.call]p7, we are still required to destroy
> automatic-storage-duration objects in reverse construction order by
> [stmt.jump]p2:
>
> "On exit from a scope (however accomplished), objects with automatic
> storage duration (6.7.5.3) that have been constructed in that scope
> are
> destroyed in the reverse order of their construction."
Don’t temporaries not have automatic storage duration formally?
That’s why [class.temporary]p7 has to spell out the interordering
of destruction of lifetime-extended temporaries.
[expr.call]p7 is the most specific statement about the destruction
of parameters. Under normal principles of interpretation, it should
take priority.
Doing the parameters in reverse order seems like a more serious problem,
but one that we can address very specifically. On targets where we
normally emit left-to-right (everywhere except MS, right?), we can
just destroy arguments right-to-left in the caller. I think we
probably do this already, because we probably push cleanups
left-to-right. The one exception about argument order is with
assignment operators, where the standard forces us to emit the RHS
first. Simple assignment operators can only be declared as non-static
member functions with one parameter, so there can only be one by-value
parameter in the first place. Compound assignment operators could in
theory be overloaded with two by-value parameters, but of course
they’ll usually have a reference on the LHS instead. If we really
feel strongly about this case, we could destroy left-to-right and
thus make this only a problem when someone takes the address of an
oddly-defined overloaded compound assignment operator. Or we could
call it a standard bug, yeah.
>> Now, it’s possible that the copy-elision rules have an unfortunate
>> impact here. IIRC an object initialized with an elided copy is
>> supposed
>> to take on the longer of the two natural lifetimes. Does that mean
>> that
>> if you have a parameter initialized by an elided copy from a
>> temporary,
>> the parameter needs to live until the end of the calling
>> full-expression
>> like the temporary would have? If so, you either wouldn’t be able
>> to
>> use a callee-destroy ABI or you wouldn’t be allowed to elide copies
>> into parameters, and the latter seems unacceptable.
>>
> That case can no longer arise when initializing a function parameter
> under
> the new guaranteed copy-elision rules, so this problem is gone at
> least in
> C++17 onwards. But yes, historically I believe it was that case that
> an
> implementation that did callee cleanup was effectively not permitted
> to
> perform copy elision for function parameters (though of course
> implementations did perform copy elision anyway).
And rightly so. :)
John.
More information about the cfe-dev
mailing list