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