-
-
Notifications
You must be signed in to change notification settings - Fork 609
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add __rvalue(expression) builtin #17050
base: master
Are you sure you want to change the base?
Conversation
Thanks for your pull request, @WalterBright! Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + dmd#17050" |
0f383fd
to
60c0f9e
Compare
082c48d
to
6e0e44f
Compare
Can this |
Will the call to S s;
__rvalue(s)
use(s); be either
? I prefer option 2 and is the closest to what Rust does. Can it be implemented with constant-time overhead by adding a status bit to the (parameter) variable declaration indicating that its contents has been invalidated by a move? I recently saw a https://youtu.be/08gvuBC-MIE?t=1839 in which Jon Kalb admits that the standard committe made a mistake by forcing moved from object to in a so called "fully formed state" instead of a so called "partially formed state". As this prevents certain kinds of optimizations. For details see https://youtu.be/08gvuBC-MIE?t=1839. |
@nordlow I'll write a proper document for this after I figure out just what the end result will be! |
86b02a7
to
8ccedfb
Compare
Thanks. Please see updates to my comment at #17050 (comment). |
My opinion on move semantics is that once you've moved s to t, then s's lifetime is over, and it should be in the default initialized state (a concept C++ doesn't have). |
Is this realized by
|
Have you considered it making it a compiler error to access |
Yes, but it requires Data Flow Analysis, which is slow. |
Ok, thanks. Afaict, the complexity of supporting Rust-style r-value semantics depends on the context in which S use(S);
S x;
auto y = __rvalue(x)
use(y); // allowed
use(x); // disallowed such a analysis could be implemented in the compiler with negligible overhead using an extra status bit in the But in the general case I realize now that the compiler needs to recurse into all function calls that are passed l-values by reference as arguments. Do you have a good reference to which data flow analysis in general and its applications such as this one? |
I currently experimenting with using static if (__traits(compiles, { int x; const y = __rvalue(x); })) {
import core.stdc.string : memcpy;
T move(T)(return scope ref T source) @trusted {
scope(exit) {
static immutable init = T.init;
memcpy(&source, &init, T.sizeof);
}
return __rvalue(source);
}
void move(T)(ref T source, ref T destination) @trusted {
scope(exit) {
static immutable init = T.init;
memcpy(&source, &init, T.sizeof);
}
destination = __rvalue(source);
}
} else
public import core.lifetime : move;
/// unary move()
pure nothrow @nogc @safe unittest {
auto x = S(42);
assert(x == S(42));
const y = move(x);
assert(y == S(42));
assert(x == S.init);
}
/// binary move()
pure nothrow @nogc @safe unittest {
auto x = S(42);
assert(x == S(42));
S y;
move(x, y);
assert(y == S(42));
assert(x == S.init);
}
version(unittest) {
struct S { @disable this(this); int x; }
} a suitable rewrite of the |
__rvalue() is a bad name for a move() intrinsic, the answer you seek is yes, __rvalue is exactly a replacement for move(), and it should be named move(). I'll argue for this before it's merged, but we're making very good progress here! :) |
Also no, this can't be 'wrapped', it's an intrinsic; it needs to be renamed move, you can't wrap it in a function named move. |
The end goal is to completely delete core.lifetime. Don't try to shoehorn this in there; that stuff is all dead. |
What about the binary overload of I'm asking because this MR needs to include the druntime modifications to It's important to note that current behaviour of
I'm not sure this is in line with the behavior of See https://dlang.org/phobos/core_lifetime.html#.move for details. Luckily druntime is now part of the dmd repo. |
I agree with @nordlow that |
Nevertheless, I personally believe it is highly preferable to make all the overloads of Btw, I'm working on migrating |
Such certainly looks tempting, but it falls short as soon as the flow control becomes non-trivial. The flow analysis I know comes from class notes in a class I took on optimizations. |
emplace() will be replaced with the placement new operator, I posted a DIP on it in the development forum. |
Currently it will get destructed twice. |
This work is heavily based on Timon Gehr's and Manu Evans' contributions. |
Another case naturally resolved with caller-destruction! |
8ccedfb
to
192c872
Compare
I've started working with this branch and trying to build out the peripheral stuff. struct S
{
this(typeof(this) s) { writeln("move"); }
this(ref typeof(this) s) { writeln("copy"); }
}
This error is erroneous; it is not only valid, but it is indeed the entire point of this work. Given the struct above, we should be able to write: void main()
{
S x;
S a = x;
S b = __rvalue(x);
} And this should emit the output:
|
There's also still this issue: struct S
{
int i, j, k;
this(S s)
{
S* a = &s; // if i assign the addresses to locals...
S* b = &x;
assert(a is b); // this works
assert(&s is &x); // this doesn't work
}
}
__gshared S x;
void main()
{
// S t = __rvalue(x); // this doesn't work; it should call the constructor, but it doesn't
S t2 = S(__rvalue(x)); // this does call the constructor...
} It's weird that if I assign the pointers to locals and compare them, it's fine, but if I compare the Also, the first statement in main doesn't call the constructor like it should. |
I can't do anything with |
Ok I will check them out. |
This adds the
__rvalue(expression)
builtin, which causesexpression
to be treated as an rvalue, even if it is an lvalue.