# Move out of deref for \`ManuallyDrop\`

**URL:** https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216
**Category:** language design
**Created:** [July 24, 2023, 2:58pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216 "2023-07-24T14:58:34Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)
#### Post date: [July 24, 2023, 2:58pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/1 "2023-07-24T14:58:34Z")

</div>

(This idea was previously mentioned by @whitequark in [this pre-RFC](https://internals.rust-lang.org/t/pre-rfc-destructuring-values-that-impl-drop/10450), as the final bullet of the "Alternatives" section.)

A common use for `ManuallyDrop` is for when one wants to get the fields of a struct by value, without calling drop glue for the struct as a whole. However, in current Rust, only `Box` allows moving out of deref, so one must resort to `unsafe` tricks like `ptr::read` to emulate it; for example I had to do this [here](https://github.com/smol-rs/async-lock/blob/8045684f996b15b3dd9bfd621cfc3864d3760923/src/rwlock.rs#L879-L883).

It would be nice if the move-out-of-deref behavior of `Box<T>` was extended to `ManuallyDrop<T>`, with the additional capability to perform partial moves out of `T` even if `T: Drop`. This would allow eliminating all use of `unsafe` from code like that linked above. That example could be rewritten like so:

```rust
fn into_arc(guard: Self) -> Arc<RwLock<T>> {
    let guard = ManuallyDrop::new(guard);
    guard.lock
}

```

(One potential wrinkle is that `unsafe` APIs could theoretically be relying on the inability to perform such moves in safe code for soundness. I think it is unlikely that anyone is doing this in practice, however.)

---

<div class="post-metadata">

### Author: ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)
#### Post date: [July 24, 2023, 3:37pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/2 "2023-07-24T15:37:50Z")

</div>

The move-out-of-deref behavior of `Box<T>` is hard coded in the compiler and only works because of how special `Box` is in the compiler. I did strongly prefer if no other type gets the same treatment.

---

<div class="post-metadata">

### Author: ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)
#### Post date: [July 24, 2023, 3:39pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/3 "2023-07-24T15:39:52Z")

</div>

`ManuallyDrop` is already compiler magic, and likely will continue to be forever. So I don't think a position of "avoid all compiler magic" is justified in this instance.

---

<div class="post-metadata">

### Author: ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)
#### Post date: [July 24, 2023, 3:47pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/4 "2023-07-24T15:47:17Z")

</div>

However it's a compiler magic that's long been desired for _lots_ of other types, and everyone agrees, as far as I know, that there should be some kind of "`DerefMove`" that enables this behaviour.

So the "how should we do this for `ManuallyDrop`" seems to me like it should be "well we should figure out `DerefMove` and use it here", rather than "let's add something else to the magic deref bucket".

---

<div class="post-metadata">

### Author: ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)
#### Post date: [July 24, 2023, 3:50pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/5 "2023-07-24T15:50:31Z")

</div>

My proposal would allow partial moves out of the `T` inside `ManuallyDrop<T>` _even if `T: Drop`_, which is something that a more general `DerefMove` would not permit on its own. Compiler magic would remain necessary.

---

<div class="post-metadata">

### Author: ![jrose](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jrose/32/9591_2.png) [@jrose](https://internals.rust-lang.org/u/jrose)
#### Post date: [July 24, 2023, 4:46pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/6 "2023-07-24T16:46:02Z")

</div>

One purpose of DerefMove would be to allow things like `&move dyn FnOnce` to be used, so yes, I think the general idea is that you’d be able to move `T: Drop` values as well.

---

<div class="post-metadata">

### Author: ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)
#### Post date: [July 24, 2023, 4:51pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/7 "2023-07-24T16:51:31Z")

</div>

That would be a full move, not a partial move.

---

<div class="post-metadata">

### Author: ![jrose](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jrose/32/9591_2.png) [@jrose](https://internals.rust-lang.org/u/jrose)
#### Post date: [July 24, 2023, 5:03pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/8 "2023-07-24T17:03:36Z")

</div>

It’s a partial move in the parent frame. You want to be able to do something ~~like~~ equivalent to (contrived)

```rust
let pairOfFns = getTwoFns();
f(&move pairOfFns.0);

```

Or did you switch which T you were talking about? I assumed you meant the T inside `ManuallyDrop<T>`, but maybe you meant the entire type `ManuallyDrop<Inner>` or `Box<Inner>`.

---

<div class="post-metadata">

### Author: ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)
#### Post date: [July 24, 2023, 5:31pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/9 "2023-07-24T17:31:10Z")

</div>

I am not 100% certain what is going on in your example, but what I intend is:

```rust
struct Foo(String, String);

impl Drop for Foo {
    fn drop(&mut self) {}
}

let foo = Foo("a".to_owned(), "b".to_owned());
let manual = ManuallyDrop::new(foo);
let a = manual.0; // Partial move

```

---

<div class="post-metadata">

### Author: ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)
#### Post date: [July 24, 2023, 6:09pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/10 "2023-07-24T18:09:14Z")

</div>

(NOT A CONTRIBUTION)

On the other hand, DerefMove has been discussed since at least 2015 and has made almost no progress toward shipping because of the difficulty of providing this API. Adding one more already-lang-item type, with a particularly strong motivation, to a behavioral special case that already exists, may be a prudent trade off.

---

<div class="post-metadata">

### Author: ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)
#### Post date: [July 24, 2023, 7:00pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/11 "2023-07-24T19:00:48Z")

</div>

The real question is why do we need ManuallyDrop just to move a single field out of a struct. Now, there is likely no other way to do it if you intend to drop the struct later. But many uses of ManuallyDrop are for the Drop impls themselves, where the struct will be destroyed anyway. Ideally the compiler should just know not to call recursive drop on already moved-from fields.

I know there were many discussions about this issue, but having read some of them, I am left with no understanding what is the current status of this change, and what are the blocking issues. It seemed like it just dropped off the radar at some point, with ManuallyDrop being a good-enough solution.

Similarly, there were proposals about allowing to destruct structs into their fields without calling Drop on the struct itself.

Does anyone know what happened to those proposals?

---

<div class="post-metadata">

### Author: ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)
#### Post date: [July 24, 2023, 9:32pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/12 "2023-07-24T21:32:55Z")

</div>

It's not about the recursive drop, if a type is `impl Drop` then it must be a complete value when `Drop::drop` is called on it, if you move a field out then the compiler cannot insert the normal drop call for the value itself. `ManuallyDrop` can be used as a marker "yes, I know this type would normally call `Drop`, but in this case I want to skip that and destructure it manually".

One issue I see is that `ManuallyDrop` seems to suppress the recursive-field-drop too, presumably in [the last example](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/9) this would leak the `"b".to_owned()` since it was never moved from.

---

<div class="post-metadata">

### Author: ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)
#### Post date: [July 25, 2023, 6:40am UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/13 "2023-07-25T06:40:04Z")

</div>

That's not what I'm talking about.

1. [This](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3f9d65997aea6f64226b145935ef943c) code doesn't compile, even though the compiler could allow to destruct Foo into components and omit drop glue for `x`.

```rust
fn main() {
    struct Foo(Vec<u32>);
    impl Drop for Foo {
        fn drop(&mut self) {}
    }
    let x = Foo(vec![]);
    let Foo(y) = x;
}

```

1. In Drop impls, there is no issue of passing in an incomplete object. The object was already passed in, but I can't move a field out of it, because the method takes a `&mut self`, and because the compiler expects to drop all fields recursively.

---

<div class="post-metadata">

### Author: ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)
#### Post date: [July 25, 2023, 8:04am UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/14 "2023-07-25T08:04:44Z")

</div>

> [@afetisov](#):
>
> In Drop impls, there is no issue of passing in an incomplete object.

```rust
struct Foo(String, String);

impl Drop for Foo {
  fn drop(&mut self) {
    std::mem::take(&mut self.0);
  }
}

let mut foo = Foo("a".into_owned(), "b".into_owned());
drop(foo.0);
// Double-free when `drop(&mut foo)` runs

```

---

<div class="post-metadata">

### Author: ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)
#### Post date: [July 25, 2023, 9:54am UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/15 "2023-07-25T09:54:18Z")

</div>

You're not even trying to understand what I wrote.

---

<div class="post-metadata">

### Author: ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)
#### Post date: [July 25, 2023, 9:57am UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/16 "2023-07-25T09:57:13Z")

</div>

I tried, but I don’t understand why you think it’s ok to call `Drop` on a partially moved value, you are definitely able to move a field out as demonstrated since you are given `&mut self`.

---

<div class="post-metadata">

### Author: ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)
#### Post date: [July 25, 2023, 10:01am UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/17 "2023-07-25T10:01:44Z")

</div>

> [@afetisov](#):
>
> [This](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3f9d65997aea6f64226b145935ef943c) code doesn't compile, even though the compiler could allow to destruct Foo into components and omit drop glue for `x`

Whether `x` has drop glue called would then depend on whether `Foo.0: Copy`, which seems like a massive footgun.

---

<div class="post-metadata">

### Author: ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)
#### Post date: [July 25, 2023, 10:10am UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/18 "2023-07-25T10:10:27Z")

</div>

I'm not suggesting dropping a partially moved value. I'm suggesting allowing to omit drop if a value was partially moved. For correctness reasons, this should require some explicit syntax, like a fully destructuring binding or some special keyword, but otherwise the concept is sound.

For values inside of Drop impl, the Self is _already_ being dropped, so the objection also doesn't apply.

---

<div class="post-metadata">

### Author: ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)
#### Post date: [July 25, 2023, 10:22am UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/19 "2023-07-25T10:22:41Z")

</div>

> [@afetisov](#):
>
> I'm suggesting allowing to omit drop if a value was partially moved. For correctness reasons, this should require some explicit syntax, like a fully destructuring binding or some special keyword, but otherwise the concept is sound.

That’s what my understanding of _this_ proposal is, using `ManuallyDrop` as the explicit syntax to omit the `Drop` call and then allow for partial moving.

---

<div class="post-metadata">

### Author: ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)
#### Post date: [July 30, 2023, 10:08pm UTC](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216/20 "2023-07-30T22:08:02Z")

</div>

RFC posted: [Move out of deref for `ManuallyDrop` by Jules-Bertholet · Pull Request #3466 · rust-lang/rfcs · GitHub](https://github.com/rust-lang/rfcs/pull/3466)

[Next page](https://internals.rust-lang.org/t/move-out-of-deref-for-manuallydrop/19216.md?page=2)
