]> git.lizzy.rs Git - rust.git/blob - src/librustc_borrowck/diagnostics.rs
Auto merge of #31684 - tmiasko:alternate-stack, r=alexcrichton
[rust.git] / src / librustc_borrowck / diagnostics.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(non_snake_case)]
12
13 register_long_diagnostics! {
14
15 E0373: r##"
16 This error occurs when an attempt is made to use data captured by a closure,
17 when that data may no longer exist. It's most commonly seen when attempting to
18 return a closure:
19
20 ```compile_fail
21 fn foo() -> Box<Fn(u32) -> u32> {
22     let x = 0u32;
23     Box::new(|y| x + y)
24 }
25 ```
26
27 Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
28 closed-over data by reference. This means that once `foo()` returns, `x` no
29 longer exists. An attempt to access `x` within the closure would thus be
30 unsafe.
31
32 Another situation where this might be encountered is when spawning threads:
33
34 ```compile_fail
35 fn foo() {
36     let x = 0u32;
37     let y = 1u32;
38
39     let thr = std::thread::spawn(|| {
40         x + y
41     });
42 }
43 ```
44
45 Since our new thread runs in parallel, the stack frame containing `x` and `y`
46 may well have disappeared by the time we try to use them. Even if we call
47 `thr.join()` within foo (which blocks until `thr` has completed, ensuring the
48 stack frame won't disappear), we will not succeed: the compiler cannot prove
49 that this behaviour is safe, and so won't let us do it.
50
51 The solution to this problem is usually to switch to using a `move` closure.
52 This approach moves (or copies, where possible) data into the closure, rather
53 than taking references to it. For example:
54
55 ```
56 fn foo() -> Box<Fn(u32) -> u32> {
57     let x = 0u32;
58     Box::new(move |y| x + y)
59 }
60 ```
61
62 Now that the closure has its own copy of the data, there's no need to worry
63 about safety.
64 "##,
65
66 E0381: r##"
67 It is not allowed to use or capture an uninitialized variable. For example:
68
69 ```compile_fail
70 fn main() {
71     let x: i32;
72     let y = x; // error, use of possibly uninitialized variable
73 }
74 ```
75
76 To fix this, ensure that any declared variables are initialized before being
77 used. Example:
78
79 ```
80 fn main() {
81     let x: i32 = 0;
82     let y = x; // ok!
83 }
84 ```
85 "##,
86
87 E0382: r##"
88 This error occurs when an attempt is made to use a variable after its contents
89 have been moved elsewhere. For example:
90
91 ```compile_fail
92 struct MyStruct { s: u32 }
93
94 fn main() {
95     let mut x = MyStruct{ s: 5u32 };
96     let y = x;
97     x.s = 6;
98     println!("{}", x.s);
99 }
100 ```
101
102 Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
103 of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
104 of workarounds like `Rc`, a value cannot be owned by more than one variable.
105
106 If we own the type, the easiest way to address this problem is to implement
107 `Copy` and `Clone` on it, as shown below. This allows `y` to copy the
108 information in `x`, while leaving the original version owned by `x`. Subsequent
109 changes to `x` will not be reflected when accessing `y`.
110
111 ```
112 #[derive(Copy, Clone)]
113 struct MyStruct { s: u32 }
114
115 fn main() {
116     let mut x = MyStruct{ s: 5u32 };
117     let y = x;
118     x.s = 6;
119     println!("{}", x.s);
120 }
121 ```
122
123 Alternatively, if we don't control the struct's definition, or mutable shared
124 ownership is truly required, we can use `Rc` and `RefCell`:
125
126 ```
127 use std::cell::RefCell;
128 use std::rc::Rc;
129
130 struct MyStruct { s: u32 }
131
132 fn main() {
133     let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
134     let y = x.clone();
135     x.borrow_mut().s = 6;
136     println!("{}", x.borrow().s);
137 }
138 ```
139
140 With this approach, x and y share ownership of the data via the `Rc` (reference
141 count type). `RefCell` essentially performs runtime borrow checking: ensuring
142 that at most one writer or multiple readers can access the data at any one time.
143
144 If you wish to learn more about ownership in Rust, start with the chapter in the
145 Book:
146
147 https://doc.rust-lang.org/book/ownership.html
148 "##,
149
150 E0383: r##"
151 This error occurs when an attempt is made to partially reinitialize a
152 structure that is currently uninitialized.
153
154 For example, this can happen when a drop has taken place:
155
156 ```compile_fail
157 struct Foo {
158     a: u32,
159 }
160
161 let mut x = Foo { a: 1 };
162 drop(x); // `x` is now uninitialized
163 x.a = 2; // error, partial reinitialization of uninitialized structure `t`
164 ```
165
166 This error can be fixed by fully reinitializing the structure in question:
167
168 ```
169 struct Foo {
170     a: u32,
171 }
172
173 let mut x = Foo { a: 1 };
174 drop(x);
175 x = Foo { a: 2 };
176 ```
177 "##,
178
179 E0384: r##"
180 This error occurs when an attempt is made to reassign an immutable variable.
181 For example:
182
183 ```compile_fail
184 fn main(){
185     let x = 3;
186     x = 5; // error, reassignment of immutable variable
187 }
188 ```
189
190 By default, variables in Rust are immutable. To fix this error, add the keyword
191 `mut` after the keyword `let` when declaring the variable. For example:
192
193 ```
194 fn main(){
195     let mut x = 3;
196     x = 5;
197 }
198 ```
199 "##,
200
201 E0386: r##"
202 This error occurs when an attempt is made to mutate the target of a mutable
203 reference stored inside an immutable container.
204
205 For example, this can happen when storing a `&mut` inside an immutable `Box`:
206
207 ```compile_fail
208 let mut x: i64 = 1;
209 let y: Box<_> = Box::new(&mut x);
210 **y = 2; // error, cannot assign to data in an immutable container
211 ```
212
213 This error can be fixed by making the container mutable:
214
215 ```
216 let mut x: i64 = 1;
217 let mut y: Box<_> = Box::new(&mut x);
218 **y = 2;
219 ```
220
221 It can also be fixed by using a type with interior mutability, such as `Cell`
222 or `RefCell`:
223
224 ```
225 use std::cell::Cell;
226
227 let x: i64 = 1;
228 let y: Box<Cell<_>> = Box::new(Cell::new(x));
229 y.set(2);
230 ```
231 "##,
232
233 E0387: r##"
234 This error occurs when an attempt is made to mutate or mutably reference data
235 that a closure has captured immutably. Examples of this error are shown below:
236
237 ```compile_fail
238 // Accepts a function or a closure that captures its environment immutably.
239 // Closures passed to foo will not be able to mutate their closed-over state.
240 fn foo<F: Fn()>(f: F) { }
241
242 // Attempts to mutate closed-over data. Error message reads:
243 // `cannot assign to data in a captured outer variable...`
244 fn mutable() {
245     let mut x = 0u32;
246     foo(|| x = 2);
247 }
248
249 // Attempts to take a mutable reference to closed-over data.  Error message
250 // reads: `cannot borrow data mutably in a captured outer variable...`
251 fn mut_addr() {
252     let mut x = 0u32;
253     foo(|| { let y = &mut x; });
254 }
255 ```
256
257 The problem here is that foo is defined as accepting a parameter of type `Fn`.
258 Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
259 they capture their context immutably.
260
261 If the definition of `foo` is under your control, the simplest solution is to
262 capture the data mutably. This can be done by defining `foo` to take FnMut
263 rather than Fn:
264
265 ```
266 fn foo<F: FnMut()>(f: F) { }
267 ```
268
269 Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
270 interior mutability through a shared reference. Our example's `mutable`
271 function could be redefined as below:
272
273 ```
274 use std::cell::Cell;
275
276 fn foo<F: Fn()>(f: F) { }
277
278 fn mutable() {
279     let x = Cell::new(0u32);
280     foo(|| x.set(2));
281 }
282 ```
283
284 You can read more about cell types in the API documentation:
285
286 https://doc.rust-lang.org/std/cell/
287 "##,
288
289 E0499: r##"
290 A variable was borrowed as mutable more than once. Erroneous code example:
291
292 ```compile_fail
293 let mut i = 0;
294 let mut x = &mut i;
295 let mut a = &mut i;
296 // error: cannot borrow `i` as mutable more than once at a time
297 ```
298
299 Please note that in rust, you can either have many immutable references, or one
300 mutable reference. Take a look at
301 https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more
302 information. Example:
303
304
305 ```
306 let mut i = 0;
307 let mut x = &mut i; // ok!
308
309 // or:
310 let mut i = 0;
311 let a = &i; // ok!
312 let b = &i; // still ok!
313 let c = &i; // still ok!
314 ```
315 "##,
316
317 E0507: r##"
318 You tried to move out of a value which was borrowed. Erroneous code example:
319
320 ```compile_fail
321 use std::cell::RefCell;
322
323 struct TheDarkKnight;
324
325 impl TheDarkKnight {
326     fn nothing_is_true(self) {}
327 }
328
329 fn main() {
330     let x = RefCell::new(TheDarkKnight);
331
332     x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
333 }
334 ```
335
336 Here, the `nothing_is_true` method takes the ownership of `self`. However,
337 `self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
338 which is a borrow of the content owned by the `RefCell`. To fix this error,
339 you have three choices:
340
341 * Try to avoid moving the variable.
342 * Somehow reclaim the ownership.
343 * Implement the `Copy` trait on the type.
344
345 Examples:
346
347 ```
348 use std::cell::RefCell;
349
350 struct TheDarkKnight;
351
352 impl TheDarkKnight {
353     fn nothing_is_true(&self) {} // First case, we don't take ownership
354 }
355
356 fn main() {
357     let x = RefCell::new(TheDarkKnight);
358
359     x.borrow().nothing_is_true(); // ok!
360 }
361 ```
362
363 Or:
364
365 ```
366 use std::cell::RefCell;
367
368 struct TheDarkKnight;
369
370 impl TheDarkKnight {
371     fn nothing_is_true(self) {}
372 }
373
374 fn main() {
375     let x = RefCell::new(TheDarkKnight);
376     let x = x.into_inner(); // we get back ownership
377
378     x.nothing_is_true(); // ok!
379 }
380 ```
381
382 Or:
383
384 ```
385 use std::cell::RefCell;
386
387 #[derive(Clone, Copy)] // we implement the Copy trait
388 struct TheDarkKnight;
389
390 impl TheDarkKnight {
391     fn nothing_is_true(self) {}
392 }
393
394 fn main() {
395     let x = RefCell::new(TheDarkKnight);
396
397     x.borrow().nothing_is_true(); // ok!
398 }
399 ```
400
401 Moving out of a member of a mutably borrowed struct is fine if you put something
402 back. `mem::replace` can be used for that:
403
404 ```ignore
405 struct TheDarkKnight;
406
407 impl TheDarkKnight {
408     fn nothing_is_true(self) {}
409 }
410
411 struct Batcave {
412     knight: TheDarkKnight
413 }
414
415 fn main() {
416     use std::mem;
417
418     let mut cave = Batcave {
419         knight: TheDarkKnight
420     };
421     let borrowed = &mut cave;
422
423     borrowed.knight.nothing_is_true(); // E0507
424     mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
425 }
426 ```
427
428 You can find more information about borrowing in the rust-book:
429 http://doc.rust-lang.org/stable/book/references-and-borrowing.html
430 "##,
431
432 }
433
434 register_diagnostics! {
435     E0385, // {} in an aliasable location
436     E0388, // {} in a static location
437     E0389, // {} in a `&` reference
438     E0500, // closure requires unique access to `..` but .. is already borrowed
439     E0501, // cannot borrow `..`.. as .. because previous closure requires unique access
440     E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
441     E0503, // cannot use `..` because it was mutably borrowed
442     E0504, // cannot move `..` into closure because it is borrowed
443     E0505, // cannot move out of `..` because it is borrowed
444     E0506, // cannot assign to `..` because it is borrowed
445     E0508, // cannot move out of type `..`, a non-copy fixed-size array
446     E0509, // cannot move out of type `..`, which defines the `Drop` trait
447 }