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