<div dir="ltr"><div dir="ltr">On Wed, 10 Jun 2020 at 12:18, John McCall via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 10 Jun 2020, at 14:32, Richard Smith wrote:<br>
> On Mon, 8 Jun 2020 at 19:52, John McCall via cfe-dev <br>
> <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>><br>
> wrote:<br>
>> It definitely changes observable semantics, but it’s not <br>
>> *obviously*<br>
>> non-conforming; [expr.call]p7 gives us a lot of flexibility here:<br>
>><br>
>> It is implementation-defined whether the lifetime of a parameter<br>
>> ends when the function in which it is defined returns or at the<br>
>> end of the enclosing full-expression.<br>
>><br>
> This is the non-conformance I'm referring to: <br>
> <a href="https://godbolt.org/z/cgf5_2" rel="noreferrer" target="_blank">https://godbolt.org/z/cgf5_2</a><br>
><br>
> Even given [expr.call]p7, we are still required to destroy<br>
> automatic-storage-duration objects in reverse construction order by<br>
> [stmt.jump]p2:<br>
><br>
> "On exit from a scope (however accomplished), objects with automatic<br>
> storage duration (6.7.5.3) that have been constructed in that scope <br>
> are<br>
> destroyed in the reverse order of their construction."<br>
<br>
Don’t temporaries not have automatic storage duration formally?<br></blockquote><div><br></div><div>The intent is that they don't; we have a longstanding open issue to introduce a notion of "full-expression storage duration" to describe temporary objects. But in the absence of such a language change, it's unclear which utterances about "automatic storage duration" apply to temporaries.</div><div><br></div><div>But in any case, I think that's immaterial here, because function parameters are local variables, not temporary objects, and do have automatic storage duration even in the hypothetical world where there's a different storage duration for temporaries.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
That’s why [class.temporary]p7 has to spell out the interordering<br>
of destruction of lifetime-extended temporaries.<br>
<br>
[expr.call]p7 is the most specific statement about the destruction<br>
of parameters.   Under normal principles of interpretation, it should<br>
take priority.<br></blockquote><div><br></div><div>Well, p7 says nothing about the relative ordering of parameter destructions, only the points where such destruction may occur. The only place we constrain the relative ordering, as far as I know, is [stmt.jump]p2, and that intends to cover the destruction of local variables (including parameters) as part of a return statement. The [expr.call]p7 change intended to permit implementations to choose between caller and callee cleanup, not to override the "destruction order is reverse construction order" rule for automatic storage duration variables.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Doing the parameters in reverse order seems like a more serious problem,<br>
but one that we can address very specifically.  On targets where we<br>
normally emit left-to-right (everywhere except MS, right?), we can<br>
just destroy arguments right-to-left in the caller. I think we</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
probably do this already, because we probably push cleanups<br>
left-to-right.</blockquote><div><br></div><div>We can't destroy [[trivial_abi]] parameters in the caller. That's the heart of the problem: [[trivial_abi]] forces destruction into the callee, because the caller doesn't have access to the parameter after the call.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The one exception about argument order is with<br>
assignment operators, where the standard forces us to emit the RHS<br>
first.  Simple assignment operators can only be declared as non-static<br>
member functions with one parameter, so there can only be one by-value<br>
parameter in the first place.  Compound assignment operators could in<br>
theory be overloaded with two by-value parameters, but of course<br>
they’ll usually have a reference on the LHS instead.  If we really<br>
feel strongly about this case, we could destroy left-to-right and<br>
thus make this only a problem when someone takes the address of an<br>
oddly-defined overloaded compound assignment operator.  Or we could<br>
call it a standard bug, yeah.<br></blockquote><div><br></div><div>I'm arguing on the core reflector right now that this case is a standard bug :) I think it would be great if we only got this wrong for an address-taken non-member operator$= function (that's the only case where right-to-left argument evaluation order is mandated and observable).</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
>> Now, it’s possible that the copy-elision rules have an unfortunate<br>
>> impact here. IIRC an object initialized with an elided copy is <br>
>> supposed<br>
>> to take on the longer of the two natural lifetimes. Does that mean <br>
>> that<br>
>> if you have a parameter initialized by an elided copy from a <br>
>> temporary,<br>
>> the parameter needs to live until the end of the calling <br>
>> full-expression<br>
>> like the temporary would have? If so, you either wouldn’t be able <br>
>> to<br>
>> use a callee-destroy ABI or you wouldn’t be allowed to elide copies<br>
>> into parameters, and the latter seems unacceptable.<br>
>><br>
> That case can no longer arise when initializing a function parameter <br>
> under<br>
> the new guaranteed copy-elision rules, so this problem is gone at <br>
> least in<br>
> C++17 onwards. But yes, historically I believe it was that case that <br>
> an<br>
> implementation that did callee cleanup was effectively not permitted <br>
> to<br>
> perform copy elision for function parameters (though of course<br>
> implementations did perform copy elision anyway).<br>
<br>
And rightly so. :)<br>
<br>
John.<br>
_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
</blockquote></div></div>