Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the Rust compiler know whether a value has been moved or not?

Tags:

rust

A simple example:

struct A;

fn main() {
    test(2);
    test(1);
}

fn test(i: i32) {
    println!("test");
    let a = A;
    if i == 2 {
        us(a);
    }
    println!("end");
}

impl Drop for A {
    fn drop(&mut self) {
        println!("drop");
    }
}

#[allow(unused_variables)]
fn us(a: A){
    println!("use");
}

When I run it, the output is:

test
use
drop
end
test
end
drop

I understand in the test(2) case, a is moved at us(a), so it's output is "test-use-drop-end".

However, in the test(1), the output is "test-end-drop", meaning that the compiler knows that a was not moved.

If us(a) is called, it will be unnecessary to drop a in test(i), it will be dropped in us(a); and if us(a) is not called, a must be dropped after println!("end").

Since it's impossible for the compiler to know whether us(a) is called or not, how does compiler know whether a.drop() shall be called or not after println!("end")?

like image 248
yyyy Avatar asked Jan 14 '16 08:01

yyyy


1 Answers

This is explained in the Rustnomicon:

As of Rust 1.0, the drop flags are actually not-so-secretly stashed in a hidden field of any type that implements Drop.

The hidden field tells whether the current value has been dropped, or not, and if it has not then it is. Thus, this is known at run-time, and requires a bit of book keeping.


Looking to the future, there is a RFC to remove these hidden fields.

The idea of the RFC is to replace the hidden fields by:

  1. Identifying unconditional drops (those don't need any run-time check)
  2. Stash a hidden field on the stack, in the function frame, for those values conditionally being dropped

This new strategy has several advantages over the old one:

  • the main advantage being that #[repr(C)] will now always give a representation equivalent to the C's one even if the struct implements Drop
  • another important advantage is saving memory (by NOT inflating the struct size)
  • another slight advantage is a possible slight speed gain due to unconditional drops and better caching (from reducing memory size)
like image 151
Matthieu M. Avatar answered Oct 18 '22 03:10

Matthieu M.