Inconsistent `Drop` rules while reassigning `mut` variables

Suppose we have a basic struct like this:

struct Foo<'a> {
    buf: &'a mut [u8]
}
impl<'a> Foo<'a> {
    fn new(buf: &'a mut [u8]) -> Self {
        Self { buf}
    }
}

impl<'a> Drop for Foo<'a> {
    fn drop(&mut self) {}
}

If I try to do this then the compiler complains:

fn bad_func(buf: &mut [u8]) {
    let mut x = Foo::new(buf);
    x = Foo::new(buf);
}

Okay fine, I'm not allowed to do that. But if I call mem::drop before the reassignment, then it works:

fn good_func(buf: &mut [u8]) {
    let mut x = Foo::new(buf);
    std::mem::drop(x);
    x = Foo::new(buf);
}

Do it a second time and it errors:

fn weird_func(buf: &mut [u8]) {
    let mut x = Foo::new(buf);
    std::mem::drop(x);
    x = Foo::new(buf);

    std::mem::drop(x);
    x = Foo::new(buf);
}

Some quick additional info:

fn consume<T>(_: T) {}

pub fn weird_func(buf: &mut [u8]) {
    let mut x = Foo::new(buf);
    consume(x);
    x = Foo::new(buf);
    &x;  // even adding a simple `&x` will re-trigger the error.
}
1 Like

The bad drop error is known, let me see if I can dig it up... here it is. Or technically this one, but they probably have the same underlying cause.

1 Like

that’s fascinating. That issue shows an almost identical example that doesn’t compile. And indeed, this difference seems to be relevant in order to make it compile:

fn main() {
    let mut s = "hi".to_string();
    let r = &mut s;

    fn f(r: &mut String) {

        let mut v = Dropper(r);
        drop(v);
-       v = Dropper(r);
+       v = Dropper::new(r);
    }
}

struct Dropper<'a>(&'a mut String);

impl Drop for Dropper<'_> {
    fn drop(&mut self) {
        self.0.push_str("dropped!");
    }
}

impl<'a> Dropper<'a> {
    fn new(s: &'a mut String) -> Self {
        Dropper(s)
    }
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.