I'm not sure I understand what you're asking. I'm certainly not saying that all drop implementations should be guaranteed not to move memory around, only that it should be possible to implement drop for a type that can't be moved. One would obviously be very limited as to when and how one could use such a type. That's why I'm suggesting that everything would have a Move
bound by default, similarly to how Sized
works. A generic struct or function that wanted to use ptr::read
obviously wouldn't specify : ?Move
.
@pnkfelix The way I see it is that there is no real problem with an infinitely recurring drop impl, even with linear types (c.f. loop { } : â„
). The warning exists not to prevent doing such a thing, but to prevent doing these things by mistake. As such, it is fine for it to be sloppy/overzealous (e.g. âYou are dropping T in impl of Drop
for T here, you might want to make sure that is intentionalâ). Moreover the warning can be tweaked over time without any effect on backwards compatibility.
@eddyb I would be less interested in &move
if it was just needed for drop, but I feel Rust, as a systems language, really deserves to be more aware of uninitialized memory (eventually), and once you do try to give it that awareness, &out
and &in
/&move
really demand to exist.
Under a privacy approach, the idea would be that if one can see all the fields in a type, they can effectively move it by dropping and rebuilding it. &move
in the context of non-movable types is important to make a clean story on âunprivilegedâ code that cannot see all the fields being able to call out to a âprivilegedâ function that consumes/moves the non-movable type. With a drop using &move
, unless the drop impl wants to wipe the memory or something, that self is passed by reference and not possible by value is besides the point, and perhaps an undesirable performance hit.
What about just letting std::mem::forget()
enable those semantics?
struct Foo {
x: Box<u32>,
}
impl Drop for Foo { ... }
fn f1() -> Box<u32> {
let foo = Foo { x: Box::new(0u32) };
// would not compile, the whole `foo` needs to move into the Drop glue.
foo.x
}
fn f2() -> Box<u32> {
let foo = Foo { x: Box::new(0u32) };
let rv = foo.x;
// prevent the drop glue from being inserted for foo, so partial moves from
// foo are allowed.
unsafe { std::mem::forget(foo) };
rv
}
The idea is that the drop glue can be treated as a consumer of the struct
, so that it's the move into the drop-glue that prevents partial moves out, rather than it being the fact of Drop
being implemented... You could have partial moves out iff the drop glue is prevented from execution.
I think this is backwards-compatible with today's forget
definition: if you don't have any partial-moves out (which you can't, today), then you get today's behavior. Thoughts?
If drop does not get called on destructing, there should be no problem with this.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.