]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/src/checked-uninit.md
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / doc / nomicon / src / checked-uninit.md
1 # Checked Uninitialized Memory
2
3 Like C, all stack variables in Rust are uninitialized until a value is
4 explicitly assigned to them. Unlike C, Rust statically prevents you from ever
5 reading them until you do:
6
7 ```rust,ignore
8 fn main() {
9 let x: i32;
10 println!("{}", x);
11 }
12 ```
13
14 ```text
15 |
16 3 | println!("{}", x);
17 | ^ use of possibly uninitialized `x`
18 ```
19
20 This is based off of a basic branch analysis: every branch must assign a value
21 to `x` before it is first used. Interestingly, Rust doesn't require the variable
22 to be mutable to perform a delayed initialization if every branch assigns
23 exactly once. However the analysis does not take advantage of constant analysis
24 or anything like that. So this compiles:
25
26 ```rust
27 fn main() {
28 let x: i32;
29
30 if true {
31 x = 1;
32 } else {
33 x = 2;
34 }
35
36 println!("{}", x);
37 }
38 ```
39
40 but this doesn't:
41
42 ```rust,ignore
43 fn main() {
44 let x: i32;
45 if true {
46 x = 1;
47 }
48 println!("{}", x);
49 }
50 ```
51
52 ```text
53 |
54 6 | println!("{}", x);
55 | ^ use of possibly uninitialized `x`
56 ```
57
58 while this does:
59
60 ```rust
61 fn main() {
62 let x: i32;
63 if true {
64 x = 1;
65 println!("{}", x);
66 }
67 // Don't care that there are branches where it's not initialized
68 // since we don't use the value in those branches
69 }
70 ```
71
72 Of course, while the analysis doesn't consider actual values, it does
73 have a relatively sophisticated understanding of dependencies and control
74 flow. For instance, this works:
75
76 ```rust
77 let x: i32;
78
79 loop {
80 // Rust doesn't understand that this branch will be taken unconditionally,
81 // because it relies on actual values.
82 if true {
83 // But it does understand that it will only be taken once because
84 // we unconditionally break out of it. Therefore `x` doesn't
85 // need to be marked as mutable.
86 x = 0;
87 break;
88 }
89 }
90 // It also knows that it's impossible to get here without reaching the break.
91 // And therefore that `x` must be initialized here!
92 println!("{}", x);
93 ```
94
95 If a value is moved out of a variable, that variable becomes logically
96 uninitialized if the type of the value isn't Copy. That is:
97
98 ```rust
99 fn main() {
100 let x = 0;
101 let y = Box::new(0);
102 let z1 = x; // x is still valid because i32 is Copy
103 let z2 = y; // y is now logically uninitialized because Box isn't Copy
104 }
105 ```
106
107 However reassigning `y` in this example *would* require `y` to be marked as
108 mutable, as a Safe Rust program could observe that the value of `y` changed:
109
110 ```rust
111 fn main() {
112 let mut y = Box::new(0);
113 let z = y; // y is now logically uninitialized because Box isn't Copy
114 y = Box::new(1); // reinitialize y
115 }
116 ```
117
118 Otherwise it's like `y` is a brand new variable.