This question is tied up in several discussions:
However it's all somewhat messy and mixed with other questions, making it all a bit hard to follow. Part of the question is where move operands are even allowed and which places they may work on.
rust-lang/rust#112564 has some nice examples demonstrating that move is already meaningful today for function calls, and Miri fails to properly model that. I am not aware of similar examples for other uses of move (in regular MIR assignments). We should at least have a spec explaining today's codegen (and implement it in Miri); I don't know if there are plans for the future here that would require a tighter spec than that.
The function call example lends itself to a semantics like this. At a high level, move would mean "load the value from the given place, and then deallocate the place it came from, before allocating any of the new memory needed for this statement -- that way the old memory may actually be reused for the new allocation".
However this only makes sense for certain place expressions (move(local.field) would have to be disallowed). And how does it look like for MIR assignments?
local2 = Aggregate(... move(local) ...)
could mean "load the MiniRust Value from local, then dealloc local like StorageDead, then StorageLive local2, then store the value in there". But when would that be useful? If local2 was already live before, there's no advantage over just doing
local2 = Aggregate(... copy(local) ...)
StorageDead(local)
so supposedly this should only be used for initializing a value?
Using custom MIR, can we have concrete examples of move in an assignment causing behavior that Miri cannot currently explain? (Specifically, having memory reused instead of doing a memcpy.) If no, could we in principle entirely get rid of move everywhere except for function calls? Cc @bjorn3
This question is tied up in several discussions:
However it's all somewhat messy and mixed with other questions, making it all a bit hard to follow. Part of the question is where
moveoperands are even allowed and which places they may work on.rust-lang/rust#112564 has some nice examples demonstrating that
moveis already meaningful today for function calls, and Miri fails to properly model that. I am not aware of similar examples for other uses ofmove(in regular MIR assignments). We should at least have a spec explaining today's codegen (and implement it in Miri); I don't know if there are plans for the future here that would require a tighter spec than that.The function call example lends itself to a semantics like this. At a high level,
movewould mean "load the value from the given place, and then deallocate the place it came from, before allocating any of the new memory needed for this statement -- that way the old memory may actually be reused for the new allocation".However this only makes sense for certain place expressions (
move(local.field)would have to be disallowed). And how does it look like for MIR assignments?could mean "load the MiniRust
Valuefromlocal, then dealloclocallike StorageDead, then StorageLivelocal2, then store the value in there". But when would that be useful? Iflocal2was already live before, there's no advantage over just doingso supposedly this should only be used for initializing a value?
Using custom MIR, can we have concrete examples of
movein an assignment causing behavior that Miri cannot currently explain? (Specifically, having memory reused instead of doing amemcpy.) If no, could we in principle entirely get rid ofmoveeverywhere except for function calls? Cc @bjorn3