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.
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.
11 #![allow(non_snake_case)]
13 register_long_diagnostics! {
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
21 fn foo() -> Box<Fn(u32) -> u32> {
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
32 Another situation where this might be encountered is when spawning threads:
39 let thr = std::thread::spawn(|| {
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.
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:
56 fn foo() -> Box<Fn(u32) -> u32> {
58 Box::new(move |y| x + y)
62 Now that the closure has its own copy of the data, there's no need to worry
67 It is not allowed to use or capture an uninitialized variable. For example:
72 let y = x; // error, use of possibly uninitialized variable
76 To fix this, ensure that any declared variables are initialized before being
88 This error occurs when an attempt is made to use a variable after its contents
89 have been moved elsewhere. For example:
92 struct MyStruct { s: u32 }
95 let mut x = MyStruct{ s: 5u32 };
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.
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`.
112 #[derive(Copy, Clone)]
113 struct MyStruct { s: u32 }
116 let mut x = MyStruct{ s: 5u32 };
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`:
127 use std::cell::RefCell;
130 struct MyStruct { s: u32 }
133 let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
135 x.borrow_mut().s = 6;
136 println!("{}", x.borrow().s);
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.
144 If you wish to learn more about ownership in Rust, start with the chapter in the
147 https://doc.rust-lang.org/book/ownership.html
151 This error occurs when an attempt is made to partially reinitialize a
152 structure that is currently uninitialized.
154 For example, this can happen when a drop has taken place:
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`
166 This error can be fixed by fully reinitializing the structure in question:
173 let mut x = Foo { a: 1 };
180 This error occurs when an attempt is made to reassign an immutable variable.
186 x = 5; // error, reassignment of immutable variable
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:
202 This error occurs when an attempt is made to mutate the target of a mutable
203 reference stored inside an immutable container.
205 For example, this can happen when storing a `&mut` inside an immutable `Box`:
209 let y: Box<_> = Box::new(&mut x);
210 **y = 2; // error, cannot assign to data in an immutable container
213 This error can be fixed by making the container mutable:
217 let mut y: Box<_> = Box::new(&mut x);
221 It can also be fixed by using a type with interior mutability, such as `Cell`
228 let y: Box<Cell<_>> = Box::new(Cell::new(x));
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:
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) { }
242 // Attempts to mutate closed-over data. Error message reads:
243 // `cannot assign to data in a captured outer variable...`
249 // Attempts to take a mutable reference to closed-over data. Error message
250 // reads: `cannot borrow data mutably in a captured outer variable...`
253 foo(|| { let y = &mut x; });
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.
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
266 fn foo<F: FnMut()>(f: F) { }
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:
276 fn foo<F: Fn()>(f: F) { }
279 let x = Cell::new(0u32);
284 You can read more about cell types in the API documentation:
286 https://doc.rust-lang.org/std/cell/
290 A variable was borrowed as mutable more than once. Erroneous code example:
296 // error: cannot borrow `i` as mutable more than once at a time
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:
307 let mut x = &mut i; // ok!
312 let b = &i; // still ok!
313 let c = &i; // still ok!
318 You tried to move out of a value which was borrowed. Erroneous code example:
321 use std::cell::RefCell;
323 struct TheDarkKnight;
326 fn nothing_is_true(self) {}
330 let x = RefCell::new(TheDarkKnight);
332 x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
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:
341 * Try to avoid moving the variable.
342 * Somehow reclaim the ownership.
343 * Implement the `Copy` trait on the type.
348 use std::cell::RefCell;
350 struct TheDarkKnight;
353 fn nothing_is_true(&self) {} // First case, we don't take ownership
357 let x = RefCell::new(TheDarkKnight);
359 x.borrow().nothing_is_true(); // ok!
366 use std::cell::RefCell;
368 struct TheDarkKnight;
371 fn nothing_is_true(self) {}
375 let x = RefCell::new(TheDarkKnight);
376 let x = x.into_inner(); // we get back ownership
378 x.nothing_is_true(); // ok!
385 use std::cell::RefCell;
387 #[derive(Clone, Copy)] // we implement the Copy trait
388 struct TheDarkKnight;
391 fn nothing_is_true(self) {}
395 let x = RefCell::new(TheDarkKnight);
397 x.borrow().nothing_is_true(); // ok!
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:
405 struct TheDarkKnight;
408 fn nothing_is_true(self) {}
412 knight: TheDarkKnight
418 let mut cave = Batcave {
419 knight: TheDarkKnight
421 let borrowed = &mut cave;
423 borrowed.knight.nothing_is_true(); // E0507
424 mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
428 You can find more information about borrowing in the rust-book:
429 http://doc.rust-lang.org/stable/book/references-and-borrowing.html
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