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 by issues.dlang — 2015-06-01T14:00:03Z
So, basically, you want RVO to be guaranteed to occur rather than it being considered an optimization (and thus being optional)?
Comment #2 by issues.dlang — 2015-06-01T14:04:44Z
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 by issues.dlang — 2015-06-01T14:13:59Z
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 by andrei — 2015-06-01T15:26:07Z
(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 by robert.schadek — 2024-12-13T18:43:05Z