[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