]> git.lizzy.rs Git - rust.git/blob - src/librustc_borrowck/diagnostics.rs
Auto merge of #44060 - taleks:issue-43205, r=arielb1
[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,E0373
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,E0373
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 E0382: r##"
67 This error occurs when an attempt is made to use a variable after its contents
68 have been moved elsewhere. For example:
69
70 ```compile_fail,E0382
71 struct MyStruct { s: u32 }
72
73 fn main() {
74     let mut x = MyStruct{ s: 5u32 };
75     let y = x;
76     x.s = 6;
77     println!("{}", x.s);
78 }
79 ```
80
81 Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
82 of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
83 of workarounds like `Rc`, a value cannot be owned by more than one variable.
84
85 If we own the type, the easiest way to address this problem is to implement
86 `Copy` and `Clone` on it, as shown below. This allows `y` to copy the
87 information in `x`, while leaving the original version owned by `x`. Subsequent
88 changes to `x` will not be reflected when accessing `y`.
89
90 ```
91 #[derive(Copy, Clone)]
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 Alternatively, if we don't control the struct's definition, or mutable shared
103 ownership is truly required, we can use `Rc` and `RefCell`:
104
105 ```
106 use std::cell::RefCell;
107 use std::rc::Rc;
108
109 struct MyStruct { s: u32 }
110
111 fn main() {
112     let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
113     let y = x.clone();
114     x.borrow_mut().s = 6;
115     println!("{}", x.borrow().s);
116 }
117 ```
118
119 With this approach, x and y share ownership of the data via the `Rc` (reference
120 count type). `RefCell` essentially performs runtime borrow checking: ensuring
121 that at most one writer or multiple readers can access the data at any one time.
122
123 If you wish to learn more about ownership in Rust, start with the chapter in the
124 Book:
125
126 https://doc.rust-lang.org/book/first-edition/ownership.html
127 "##,
128
129 E0383: r##"
130 This error occurs when an attempt is made to partially reinitialize a
131 structure that is currently uninitialized.
132
133 For example, this can happen when a drop has taken place:
134
135 ```compile_fail,E0383
136 struct Foo {
137     a: u32,
138 }
139 impl Drop for Foo {
140     fn drop(&mut self) { /* ... */ }
141 }
142
143 let mut x = Foo { a: 1 };
144 drop(x); // `x` is now uninitialized
145 x.a = 2; // error, partial reinitialization of uninitialized structure `t`
146 ```
147
148 This error can be fixed by fully reinitializing the structure in question:
149
150 ```
151 struct Foo {
152     a: u32,
153 }
154 impl Drop for Foo {
155     fn drop(&mut self) { /* ... */ }
156 }
157
158 let mut x = Foo { a: 1 };
159 drop(x);
160 x = Foo { a: 2 };
161 ```
162 "##,
163
164 /*E0386: r##"
165 This error occurs when an attempt is made to mutate the target of a mutable
166 reference stored inside an immutable container.
167
168 For example, this can happen when storing a `&mut` inside an immutable `Box`:
169
170 ```compile_fail,E0386
171 let mut x: i64 = 1;
172 let y: Box<_> = Box::new(&mut x);
173 **y = 2; // error, cannot assign to data in an immutable container
174 ```
175
176 This error can be fixed by making the container mutable:
177
178 ```
179 let mut x: i64 = 1;
180 let mut y: Box<_> = Box::new(&mut x);
181 **y = 2;
182 ```
183
184 It can also be fixed by using a type with interior mutability, such as `Cell`
185 or `RefCell`:
186
187 ```
188 use std::cell::Cell;
189
190 let x: i64 = 1;
191 let y: Box<Cell<_>> = Box::new(Cell::new(x));
192 y.set(2);
193 ```
194 "##,*/
195
196 E0387: r##"
197 This error occurs when an attempt is made to mutate or mutably reference data
198 that a closure has captured immutably. Examples of this error are shown below:
199
200 ```compile_fail,E0387
201 // Accepts a function or a closure that captures its environment immutably.
202 // Closures passed to foo will not be able to mutate their closed-over state.
203 fn foo<F: Fn()>(f: F) { }
204
205 // Attempts to mutate closed-over data. Error message reads:
206 // `cannot assign to data in a captured outer variable...`
207 fn mutable() {
208     let mut x = 0u32;
209     foo(|| x = 2);
210 }
211
212 // Attempts to take a mutable reference to closed-over data.  Error message
213 // reads: `cannot borrow data mutably in a captured outer variable...`
214 fn mut_addr() {
215     let mut x = 0u32;
216     foo(|| { let y = &mut x; });
217 }
218 ```
219
220 The problem here is that foo is defined as accepting a parameter of type `Fn`.
221 Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
222 they capture their context immutably.
223
224 If the definition of `foo` is under your control, the simplest solution is to
225 capture the data mutably. This can be done by defining `foo` to take FnMut
226 rather than Fn:
227
228 ```
229 fn foo<F: FnMut()>(f: F) { }
230 ```
231
232 Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
233 interior mutability through a shared reference. Our example's `mutable`
234 function could be redefined as below:
235
236 ```
237 use std::cell::Cell;
238
239 fn foo<F: Fn()>(f: F) { }
240
241 fn mutable() {
242     let x = Cell::new(0u32);
243     foo(|| x.set(2));
244 }
245 ```
246
247 You can read more about cell types in the API documentation:
248
249 https://doc.rust-lang.org/std/cell/
250 "##,
251
252 E0388: r##"
253 E0388 was removed and is no longer issued.
254 "##,
255
256 E0389: r##"
257 An attempt was made to mutate data using a non-mutable reference. This
258 commonly occurs when attempting to assign to a non-mutable reference of a
259 mutable reference (`&(&mut T)`).
260
261 Example of erroneous code:
262
263 ```compile_fail,E0389
264 struct FancyNum {
265     num: u8,
266 }
267
268 fn main() {
269     let mut fancy = FancyNum{ num: 5 };
270     let fancy_ref = &(&mut fancy);
271     fancy_ref.num = 6; // error: cannot assign to data in a `&` reference
272     println!("{}", fancy_ref.num);
273 }
274 ```
275
276 Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an
277 immutable reference to a value borrows it immutably. There can be multiple
278 references of type `&(&mut T)` that point to the same value, so they must be
279 immutable to prevent multiple mutable references to the same value.
280
281 To fix this, either remove the outer reference:
282
283 ```
284 struct FancyNum {
285     num: u8,
286 }
287
288 fn main() {
289     let mut fancy = FancyNum{ num: 5 };
290
291     let fancy_ref = &mut fancy;
292     // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum)
293
294     fancy_ref.num = 6; // No error!
295
296     println!("{}", fancy_ref.num);
297 }
298 ```
299
300 Or make the outer reference mutable:
301
302 ```
303 struct FancyNum {
304     num: u8
305 }
306
307 fn main() {
308     let mut fancy = FancyNum{ num: 5 };
309
310     let fancy_ref = &mut (&mut fancy);
311     // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum)
312
313     fancy_ref.num = 6; // No error!
314
315     println!("{}", fancy_ref.num);
316 }
317 ```
318 "##,
319
320 E0507: r##"
321 You tried to move out of a value which was borrowed. Erroneous code example:
322
323 ```compile_fail,E0507
324 use std::cell::RefCell;
325
326 struct TheDarkKnight;
327
328 impl TheDarkKnight {
329     fn nothing_is_true(self) {}
330 }
331
332 fn main() {
333     let x = RefCell::new(TheDarkKnight);
334
335     x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
336 }
337 ```
338
339 Here, the `nothing_is_true` method takes the ownership of `self`. However,
340 `self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
341 which is a borrow of the content owned by the `RefCell`. To fix this error,
342 you have three choices:
343
344 * Try to avoid moving the variable.
345 * Somehow reclaim the ownership.
346 * Implement the `Copy` trait on the type.
347
348 Examples:
349
350 ```
351 use std::cell::RefCell;
352
353 struct TheDarkKnight;
354
355 impl TheDarkKnight {
356     fn nothing_is_true(&self) {} // First case, we don't take ownership
357 }
358
359 fn main() {
360     let x = RefCell::new(TheDarkKnight);
361
362     x.borrow().nothing_is_true(); // ok!
363 }
364 ```
365
366 Or:
367
368 ```
369 use std::cell::RefCell;
370
371 struct TheDarkKnight;
372
373 impl TheDarkKnight {
374     fn nothing_is_true(self) {}
375 }
376
377 fn main() {
378     let x = RefCell::new(TheDarkKnight);
379     let x = x.into_inner(); // we get back ownership
380
381     x.nothing_is_true(); // ok!
382 }
383 ```
384
385 Or:
386
387 ```
388 use std::cell::RefCell;
389
390 #[derive(Clone, Copy)] // we implement the Copy trait
391 struct TheDarkKnight;
392
393 impl TheDarkKnight {
394     fn nothing_is_true(self) {}
395 }
396
397 fn main() {
398     let x = RefCell::new(TheDarkKnight);
399
400     x.borrow().nothing_is_true(); // ok!
401 }
402 ```
403
404 Moving a member out of a mutably borrowed struct will also cause E0507 error:
405
406 ```compile_fail,E0507
407 struct TheDarkKnight;
408
409 impl TheDarkKnight {
410     fn nothing_is_true(self) {}
411 }
412
413 struct Batcave {
414     knight: TheDarkKnight
415 }
416
417 fn main() {
418     let mut cave = Batcave {
419         knight: TheDarkKnight
420     };
421     let borrowed = &mut cave;
422
423     borrowed.knight.nothing_is_true(); // E0507
424 }
425 ```
426
427 It is fine only if you put something back. `mem::replace` can be used for that:
428
429 ```
430 # struct TheDarkKnight;
431 # impl TheDarkKnight { fn nothing_is_true(self) {} }
432 # struct Batcave { knight: TheDarkKnight }
433 use std::mem;
434
435 let mut cave = Batcave {
436     knight: TheDarkKnight
437 };
438 let borrowed = &mut cave;
439
440 mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
441 ```
442
443 You can find more information about borrowing in the rust-book:
444 http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
445 "##,
446
447 E0508: r##"
448 A value was moved out of a non-copy fixed-size array.
449
450 Example of erroneous code:
451
452 ```compile_fail,E0508
453 struct NonCopy;
454
455 fn main() {
456     let array = [NonCopy; 1];
457     let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`,
458                            //        a non-copy fixed-size array
459 }
460 ```
461
462 The first element was moved out of the array, but this is not
463 possible because `NonCopy` does not implement the `Copy` trait.
464
465 Consider borrowing the element instead of moving it:
466
467 ```
468 struct NonCopy;
469
470 fn main() {
471     let array = [NonCopy; 1];
472     let _value = &array[0]; // Borrowing is allowed, unlike moving.
473 }
474 ```
475
476 Alternatively, if your type implements `Clone` and you need to own the value,
477 consider borrowing and then cloning:
478
479 ```
480 #[derive(Clone)]
481 struct NonCopy;
482
483 fn main() {
484     let array = [NonCopy; 1];
485     // Now you can clone the array element.
486     let _value = array[0].clone();
487 }
488 ```
489 "##,
490
491 E0509: r##"
492 This error occurs when an attempt is made to move out of a value whose type
493 implements the `Drop` trait.
494
495 Example of erroneous code:
496
497 ```compile_fail,E0509
498 struct FancyNum {
499     num: usize
500 }
501
502 struct DropStruct {
503     fancy: FancyNum
504 }
505
506 impl Drop for DropStruct {
507     fn drop(&mut self) {
508         // Destruct DropStruct, possibly using FancyNum
509     }
510 }
511
512 fn main() {
513     let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
514     let fancy_field = drop_struct.fancy; // Error E0509
515     println!("Fancy: {}", fancy_field.num);
516     // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
517 }
518 ```
519
520 Here, we tried to move a field out of a struct of type `DropStruct` which
521 implements the `Drop` trait. However, a struct cannot be dropped if one or
522 more of its fields have been moved.
523
524 Structs implementing the `Drop` trait have an implicit destructor that gets
525 called when they go out of scope. This destructor may use the fields of the
526 struct, so moving out of the struct could make it impossible to run the
527 destructor. Therefore, we must think of all values whose type implements the
528 `Drop` trait as single units whose fields cannot be moved.
529
530 This error can be fixed by creating a reference to the fields of a struct,
531 enum, or tuple using the `ref` keyword:
532
533 ```
534 struct FancyNum {
535     num: usize
536 }
537
538 struct DropStruct {
539     fancy: FancyNum
540 }
541
542 impl Drop for DropStruct {
543     fn drop(&mut self) {
544         // Destruct DropStruct, possibly using FancyNum
545     }
546 }
547
548 fn main() {
549     let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
550     let ref fancy_field = drop_struct.fancy; // No more errors!
551     println!("Fancy: {}", fancy_field.num);
552     // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
553 }
554 ```
555
556 Note that this technique can also be used in the arms of a match expression:
557
558 ```
559 struct FancyNum {
560     num: usize
561 }
562
563 enum DropEnum {
564     Fancy(FancyNum)
565 }
566
567 impl Drop for DropEnum {
568     fn drop(&mut self) {
569         // Destruct DropEnum, possibly using FancyNum
570     }
571 }
572
573 fn main() {
574     // Creates and enum of type `DropEnum`, which implements `Drop`
575     let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
576     match drop_enum {
577         // Creates a reference to the inside of `DropEnum::Fancy`
578         DropEnum::Fancy(ref fancy_field) => // No error!
579             println!("It was fancy-- {}!", fancy_field.num),
580     }
581     // implicit call to `drop_enum.drop()` as drop_enum goes out of scope
582 }
583 ```
584 "##,
585
586 E0595: r##"
587 Closures cannot mutate immutable captured variables.
588
589 Erroneous code example:
590
591 ```compile_fail,E0595
592 let x = 3; // error: closure cannot assign to immutable local variable `x`
593 let mut c = || { x += 1 };
594 ```
595
596 Make the variable binding mutable:
597
598 ```
599 let mut x = 3; // ok!
600 let mut c = || { x += 1 };
601 ```
602 "##,
603
604 E0596: r##"
605 This error occurs because you tried to mutably borrow a non-mutable variable.
606
607 Example of erroneous code:
608
609 ```compile_fail,E0596
610 let x = 1;
611 let y = &mut x; // error: cannot borrow mutably
612 ```
613
614 In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it
615 fails. To fix this error, you need to make `x` mutable:
616
617 ```
618 let mut x = 1;
619 let y = &mut x; // ok!
620 ```
621 "##,
622
623 E0597: r##"
624 This error occurs because a borrow was made inside a variable which has a
625 greater lifetime than the borrowed one.
626
627 Example of erroneous code:
628
629 ```compile_fail,E0597
630 struct Foo<'a> {
631     x: Option<&'a u32>,
632 }
633
634 let mut x = Foo { x: None };
635 let y = 0;
636 x.x = Some(&y); // error: `y` does not live long enough
637 ```
638
639 In here, `x` is created before `y` and therefore has a greater lifetime. Always
640 keep in mind that values in a scope are dropped in the opposite order they are
641 created. So to fix the previous example, just make the `y` lifetime greater than
642 the `x`'s one:
643
644 ```
645 struct Foo<'a> {
646     x: Option<&'a u32>,
647 }
648
649 let y = 0;
650 let mut x = Foo { x: None };
651 x.x = Some(&y);
652 ```
653 "##,
654
655 }
656
657 register_diagnostics! {
658 //    E0385, // {} in an aliasable location
659     E0594, // cannot assign to {}
660     E0598, // lifetime of {} is too short to guarantee its contents can be...
661 }