(I've accidentally replied personally the first time, sorry for that.)
 
This is actually interesting and innovative as far as I know. No current compiler performs copy-elision on local variables of lifetime-extended reference type. As far as I can tell, the paper standard does not permit copy-elision in such situations. (But those two statements are not particularly correlated in real life. David Stone and I have been mostly-independently working on harmonizing practice with specification in these areas. See P0527, P1155, P1825 — P1825 subsumes the other two, and has been adopted for C++2a. P1825 doesn't talk about the lifetime-extension case.)

I've read the Slack thread, and it looks like I'll have to pull this part off. I wrote it as a [Note] to underline that this follows on its own from the current [class.copy.elision], in my vision. If this proposal is adopted, another proposal for guaranteed copy elision for lifetime-extended references can follow, along with a defect report on the existing wording. If anyone cares, that is.
For now, I've edited that note not to be innovative.

    Widget baz() {
        Widget one;
        if (rand()) return one;
        Widget two;
        return two;
    }
IIUC, your proposal mandates that `return two;` must use copy-elision (so `two` must be constructed straight into the return slot), but `return one;` may-or-may-not use copy-elision (which actually means that it cannot possibly use copy-elision, because it must leave the return slot available for `two`). Is that an accurate reading of your proposal's intent?

It is. And if you remove if(rand()), then one is still not a named return value.
By the way, NRVO has "return value", but it's actually "return object" in the standard, so it should probably be "named return object".
I've now replaced "named return value" with "named return object", and in the name of the proposal, too. What do you think about that?

P1144 "relocation" is 100% unrelated to copy-elision. Copy-elision is a core-language optimization that is done on a single object; trivial relocation is a library-level optimization that is [normally] done on a contiguous range of objects. If you don't have a contiguous range of objects (like a vector reallocation), then performing trivial relocation as an optimization probably doesn't buy you anything that you couldn't get from a good optimizer and the "as-if rule."  Returning a std::unique_ptr<int> "by move" is totally fine; the optimizer will get it.
(The other benefit of P1144 is that sometimes programmers need to use trivial relocation for actual API reasons, such as because some C API requires it. Having the `std::is_trivially_relocatable` trait allows those programmers to static_assert that what they're doing is actually safe.)

I understand the distinction. I included a reference to P1144, because it also lies in the group of proposals that "reduce moving". In that general group, there is a subgroup of relocation-related proposals and a subgroup of proposals that eliminate the need for a move altogether.

пт, 3 янв. 2020 г. в 23:35, Arthur O'Dwyer <arthur.j.odwyer@gmail.com>:
On Fri, Jan 3, 2020 at 2:17 PM Anton Zhilin via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hi! I've prepared a proposal (draft), which aims to provide guaranteed copy elision for common cases of local variables being returned from a function.

This proposal seems more realistic than your similarly motivated "alias-expressions" proposal.

 [ Note: Either the variable is of a non-reference type or it is a reference participating in lifetime extension. — end note ]

This is actually interesting and innovative as far as I know. No current compiler performs copy-elision on local variables of lifetime-extended reference type. As far as I can tell, the paper standard does not permit copy-elision in such situations. (But those two statements are not particularly correlated in real life. David Stone and I have been mostly-independently working on harmonizing practice with specification in these areas. See P0527, P1155, P1825 — P1825 subsumes the other two, and has been adopted for C++2a. P1825 doesn't talk about the lifetime-extension case.)

Widget foo() noexcept;
Widget bar() {
    auto&& w = foo();  // lifetime-extended temporary
    return w;  // no compiler implements copy-elision here
}

If you want to permit copy-elision on lifetime-extended variables, I think you'll have to do some surgery on the existing wording. Weak consensus in the #future-standard channel is that when http://eel.is/c++draft/class.copy.elision#1.1 talks about "the name of a non-volatile automatic object," you'd have to do some real mental gymnastics to interpret that to include non-volatile automatic variables of reference type which happen to refer to a lifetime-extended object. (Especially if you mean to exclude variables of reference type which happen to refer to automatic objects that aren't lifetime-extended.)

// https://godbolt.org/z/JrW848
Widget foo() noexcept;
Widget bar() {
    auto temp = foo();
    auto&& w = temp;  // reference to automatic object of the correct type, but not as a result of lifetime extension
    return w;  // copy-elision here would be insane
}

I'm vaguely skeptical of your use of "potential scope." No particular problem I can see, but I would bet money that there are problems I don't see yet.

    Widget baz() {
        Widget one;
        if (rand()) return one;
        Widget two;
        return two;
    }

IIUC, your proposal mandates that `return two;` must use copy-elision (so `two` must be constructed straight into the return slot), but `return one;` may-or-may-not use copy-elision (which actually means that it cannot possibly use copy-elision, because it must leave the return slot available for `two`). Is that an accurate reading of your proposal's intent?

P1144 "relocation" is 100% unrelated to copy-elision. Copy-elision is a core-language optimization that is done on a single object; trivial relocation is a library-level optimization that is [normally] done on a contiguous range of objects. If you don't have a contiguous range of objects (like a vector reallocation), then performing trivial relocation as an optimization probably doesn't buy you anything that you couldn't get from a good optimizer and the "as-if rule."  Returning a std::unique_ptr<int> "by move" is totally fine; the optimizer will get it.
(The other benefit of P1144 is that sometimes programmers need to use trivial relocation for actual API reasons, such as because some C API requires it. Having the `std::is_trivially_relocatable` trait allows those programmers to static_assert that what they're doing is actually safe.)

my $.02,
–Arthur