]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/drop-flags.md
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / doc / nomicon / drop-flags.md
1 % Drop Flags
2
3 The examples in the previous section introduce an interesting problem for Rust.
4 We have seen that's possible to conditionally initialize, deinitialize, and
5 reinitialize locations of memory totally safely. For Copy types, this isn't
6 particularly notable since they're just a random pile of bits. However types
7 with destructors are a different story: Rust needs to know whether to call a
8 destructor whenever a variable is assigned to, or a variable goes out of scope.
9 How can it do this with conditional initialization?
10
11 Note that this is not a problem that all assignments need worry about. In
12 particular, assigning through a dereference unconditionally drops, and assigning
13 in a `let` unconditionally doesn't drop:
14
15 ```
16 let mut x = Box::new(0); // let makes a fresh variable, so never need to drop
17 let y = &mut x;
18 *y = Box::new(1); // Deref assumes the referent is initialized, so always drops
19 ```
20
21 This is only a problem when overwriting a previously initialized variable or
22 one of its subfields.
23
24 It turns out that Rust actually tracks whether a type should be dropped or not
25 *at runtime*. As a variable becomes initialized and uninitialized, a *drop flag*
26 for that variable is toggled. When a variable might need to be dropped, this
27 flag is evaluated to determine if it should be dropped.
28
29 Of course, it is often the case that a value's initialization state can be
30 statically known at every point in the program. If this is the case, then the
31 compiler can theoretically generate more efficient code! For instance, straight-
32 line code has such *static drop semantics*:
33
34 ```rust
35 let mut x = Box::new(0); // x was uninit; just overwrite.
36 let mut y = x; // y was uninit; just overwrite and make x uninit.
37 x = Box::new(0); // x was uninit; just overwrite.
38 y = x; // y was init; Drop y, overwrite it, and make x uninit!
39 // y goes out of scope; y was init; Drop y!
40 // x goes out of scope; x was uninit; do nothing.
41 ```
42
43 Similarly, branched code where all branches have the same behaviour with respect
44 to initialization has static drop semantics:
45
46 ```rust
47 # let condition = true;
48 let mut x = Box::new(0); // x was uninit; just overwrite.
49 if condition {
50 drop(x) // x gets moved out; make x uninit.
51 } else {
52 println!("{}", x);
53 drop(x) // x gets moved out; make x uninit.
54 }
55 x = Box::new(0); // x was uninit; just overwrite.
56 // x goes out of scope; x was init; Drop x!
57 ```
58
59 However code like this *requires* runtime information to correctly Drop:
60
61 ```rust
62 # let condition = true;
63 let x;
64 if condition {
65 x = Box::new(0); // x was uninit; just overwrite.
66 println!("{}", x);
67 }
68 // x goes out of scope; x might be uninit;
69 // check the flag!
70 ```
71
72 Of course, in this case it's trivial to retrieve static drop semantics:
73
74 ```rust
75 # let condition = true;
76 if condition {
77 let x = Box::new(0);
78 println!("{}", x);
79 }
80 ```
81
82 As of Rust 1.0, the drop flags are actually not-so-secretly stashed in a hidden
83 field of any type that implements Drop. Rust sets the drop flag by overwriting
84 the entire value with a particular bit pattern. This is pretty obviously Not
85 The Fastest and causes a bunch of trouble with optimizing code. It's legacy from
86 a time when you could do much more complex conditional initialization.
87
88 As such work is currently under way to move the flags out onto the stack frame
89 where they more reasonably belong. Unfortunately, this work will take some time
90 as it requires fairly substantial changes to the compiler.
91
92 Regardless, Rust programs don't need to worry about uninitialized values on
93 the stack for correctness. Although they might care for performance. Thankfully,
94 Rust makes it easy to take control here! Uninitialized values are there, and
95 you can work with them in Safe Rust, but you're never in danger.