D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 14638 - The last (in lexical order) copy of an object must be a move
Summary: The last (in lexical order) copy of an object must be a move
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P4 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-06-01 04:31 UTC by Andrei Alexandrescu
Modified: 2024-12-13 18:43 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Andrei Alexandrescu 2015-06-01 04:31:46 UTC
Consider (also http://dpaste.dzfl.pl/87e95af25781):

struct S1
{
    this(this) { assert(0); }
}

struct S2
{
    @disable this(this);
}

void fun(S1 s)
{
    gun(s);
}

void gun(S1 s)
{
}

void hun(S2 s)
{
    iun(s);
}

void iun(S2 s)
{
}

void main()
{
    fun(S1());
    hun(S2());
}

This code creates an S1 and an S2 as rvalues and passes them by value into functions. These functions in turn forward the values to other functions, also by value, after which they make no more use of the values.

If a conversion to an rvalue is the last (statically determined) operation on a value in the lexical scope of a variable, then that copy should count as a move. That should be guaranteed, not an optimization.

This rule would automatically enable a lot of sensible code to work with noncopyable values.  This matter is a semi-blocker for std.allocator because most allocators are noncopyable.

BTW this does not need to go into guessing the last dynamic use. For example:

void hun(S2 s)
{
    iun(s); // last dynamic use
    if (false)
    {
        writeln(s); // last static use
    }
}

In this case, the call to iun() may create a copy even though an analysis shows the last static use can never happen. Eliding the last dynamic copy may be implemented as an optimization. Checking for @disable should still be inserted regardless of the optimization.
Comment 1 Jonathan M Davis 2015-06-01 14:00:03 UTC
So, basically, you want RVO to be guaranteed to occur rather than it being considered an optimization (and thus being optional)?
Comment 2 Jonathan M Davis 2015-06-01 14:04:44 UTC
Oh, wait. No, this is not just RVO. You're not even returning in the example. Clearly, I paid too much attention to the text and not the example. Not enough sleep, I guess...
Comment 3 Jonathan M Davis 2015-06-01 14:13:59 UTC
It's my understanding (though I could be wrong) that the

void main()
{
    fun(S1());
    hun(S2());
}

part at least is guaranteed to do a move, since you're dealing with temporaries. I would have expected the rest of it to do moves as well like you're requesting, but I don't remember how guaranteed it's supposed to be. Clearly, the compiler doesn't seem to think that it's guaranteed though, since it's not doing it.

Regardless, I agree with this. We need to make it so that moves are guaranteed where we can for both performance reasons and for noncopyable objects (and the noncopyable objects pretty much throw it in your face when it doesn't do a move).

However, I don't understand what you mean by dynamic and static uses. Is a dynamic use one that may or may not be the last one hit depending on what occurs after it, whereas a static use is guaranteed to be the last use if it's hit?
Comment 4 Andrei Alexandrescu 2015-06-01 15:26:07 UTC
(In reply to Jonathan M Davis from comment #3)
> However, I don't understand what you mean by dynamic and static uses. Is a
> dynamic use one that may or may not be the last one hit depending on what
> occurs after it, whereas a static use is guaranteed to be the last use if
> it's hit?

Static is as you read the code in lexical order, dynamic is as it actually gets executed.
Comment 5 dlangBugzillaToGithub 2024-12-13 18:43:05 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/18995

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB