mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-04 19:12:50 +00:00
Move borrowck error msg construction to module in rustc_mir
(for later reuse by mir borrowck).
post-rebase: Do not put "(Ast)" suffix in error msg unless passed `-Z borrowck-mir`. (But unconditionally include "(Mir)" suffix for mir-borrowck errors.)
This commit is contained in:
parent
4fc3765c54
commit
8e79fc72cb
1
src/Cargo.lock
generated
1
src/Cargo.lock
generated
@ -1452,6 +1452,7 @@ dependencies = [
|
|||||||
"rustc_const_eval 0.0.0",
|
"rustc_const_eval 0.0.0",
|
||||||
"rustc_const_math 0.0.0",
|
"rustc_const_math 0.0.0",
|
||||||
"rustc_data_structures 0.0.0",
|
"rustc_data_structures 0.0.0",
|
||||||
|
"rustc_errors 0.0.0",
|
||||||
"syntax 0.0.0",
|
"syntax 0.0.0",
|
||||||
"syntax_pos 0.0.0",
|
"syntax_pos 0.0.0",
|
||||||
]
|
]
|
||||||
|
@ -29,6 +29,7 @@ use rustc::ty::{self, TyCtxt};
|
|||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -465,10 +466,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let mut err = match (new_loan.kind, old_loan.kind) {
|
let mut err = match (new_loan.kind, old_loan.kind) {
|
||||||
(ty::MutBorrow, ty::MutBorrow) => {
|
(ty::MutBorrow, ty::MutBorrow) => {
|
||||||
let mut err = struct_span_err!(self.bccx, new_loan.span, E0499,
|
let mut err = self.bccx.cannot_mutably_borrow_multiply(
|
||||||
"cannot borrow `{}`{} as mutable \
|
new_loan.span, &nl, &new_loan_msg, Origin::Ast);
|
||||||
more than once at a time",
|
|
||||||
nl, new_loan_msg);
|
|
||||||
|
|
||||||
if new_loan.span == old_loan.span {
|
if new_loan.span == old_loan.span {
|
||||||
// Both borrows are happening in the same place
|
// Both borrows are happening in the same place
|
||||||
@ -496,10 +495,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) => {
|
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) => {
|
||||||
let mut err = struct_span_err!(self.bccx, new_loan.span, E0524,
|
let mut err = self.bccx.cannot_uniquely_borrow_by_two_closures(
|
||||||
"two closures require unique access to `{}` \
|
new_loan.span, &nl, Origin::Ast);
|
||||||
at the same time",
|
|
||||||
nl);
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
old_loan.span,
|
old_loan.span,
|
||||||
"first closure is constructed here");
|
"first closure is constructed here");
|
||||||
@ -513,10 +510,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(ty::UniqueImmBorrow, _) => {
|
(ty::UniqueImmBorrow, _) => {
|
||||||
let mut err = struct_span_err!(self.bccx, new_loan.span, E0500,
|
let mut err = self.bccx.cannot_uniquely_borrow_by_one_closure(
|
||||||
"closure requires unique access to `{}` \
|
new_loan.span, &nl, &ol_pronoun, &old_loan_msg, Origin::Ast);
|
||||||
but {} is already borrowed{}",
|
|
||||||
nl, ol_pronoun, old_loan_msg);
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
new_loan.span,
|
new_loan.span,
|
||||||
format!("closure construction occurs here{}", new_loan_msg));
|
format!("closure construction occurs here{}", new_loan_msg));
|
||||||
@ -530,10 +525,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(_, ty::UniqueImmBorrow) => {
|
(_, ty::UniqueImmBorrow) => {
|
||||||
let mut err = struct_span_err!(self.bccx, new_loan.span, E0501,
|
let new_loan_str = &new_loan.kind.to_user_str();
|
||||||
"cannot borrow `{}`{} as {} because \
|
let mut err = self.bccx.cannot_reborrow_already_uniquely_borrowed(
|
||||||
previous closure requires unique access",
|
new_loan.span, &nl, &new_loan_msg, new_loan_str, Origin::Ast);
|
||||||
nl, new_loan_msg, new_loan.kind.to_user_str());
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
new_loan.span,
|
new_loan.span,
|
||||||
format!("borrow occurs here{}", new_loan_msg));
|
format!("borrow occurs here{}", new_loan_msg));
|
||||||
@ -547,15 +541,10 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(..) => {
|
(..) => {
|
||||||
let mut err = struct_span_err!(self.bccx, new_loan.span, E0502,
|
let mut err = self.bccx.cannot_reborrow_already_borrowed(
|
||||||
"cannot borrow `{}`{} as {} because \
|
new_loan.span,
|
||||||
{} is also borrowed as {}{}",
|
&nl, &new_loan_msg, &new_loan.kind.to_user_str(),
|
||||||
nl,
|
&ol_pronoun, &old_loan.kind.to_user_str(), &old_loan_msg, Origin::Ast);
|
||||||
new_loan_msg,
|
|
||||||
new_loan.kind.to_user_str(),
|
|
||||||
ol_pronoun,
|
|
||||||
old_loan.kind.to_user_str(),
|
|
||||||
old_loan_msg);
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
new_loan.span,
|
new_loan.span,
|
||||||
format!("{} borrow occurs here{}",
|
format!("{} borrow occurs here{}",
|
||||||
@ -645,9 +634,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||||||
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
|
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
|
||||||
UseOk => { }
|
UseOk => { }
|
||||||
UseWhileBorrowed(loan_path, loan_span) => {
|
UseWhileBorrowed(loan_path, loan_span) => {
|
||||||
struct_span_err!(self.bccx, span, E0503,
|
let desc = self.bccx.loan_path_to_string(copy_path);
|
||||||
"cannot use `{}` because it was mutably borrowed",
|
self.bccx.cannot_use_when_mutably_borrowed(span, &desc, Origin::Ast)
|
||||||
&self.bccx.loan_path_to_string(copy_path))
|
|
||||||
.span_label(loan_span,
|
.span_label(loan_span,
|
||||||
format!("borrow of `{}` occurs here",
|
format!("borrow of `{}` occurs here",
|
||||||
&self.bccx.loan_path_to_string(&loan_path))
|
&self.bccx.loan_path_to_string(&loan_path))
|
||||||
@ -673,9 +661,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||||||
UseWhileBorrowed(loan_path, loan_span) => {
|
UseWhileBorrowed(loan_path, loan_span) => {
|
||||||
let mut err = match move_kind {
|
let mut err = match move_kind {
|
||||||
move_data::Captured => {
|
move_data::Captured => {
|
||||||
let mut err = struct_span_err!(self.bccx, span, E0504,
|
let mut err = self.bccx.cannot_move_into_closure(
|
||||||
"cannot move `{}` into closure because it is borrowed",
|
span, &self.bccx.loan_path_to_string(move_path), Origin::Ast);
|
||||||
&self.bccx.loan_path_to_string(move_path));
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
loan_span,
|
loan_span,
|
||||||
format!("borrow of `{}` occurs here",
|
format!("borrow of `{}` occurs here",
|
||||||
@ -690,9 +677,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||||||
move_data::Declared |
|
move_data::Declared |
|
||||||
move_data::MoveExpr |
|
move_data::MoveExpr |
|
||||||
move_data::MovePat => {
|
move_data::MovePat => {
|
||||||
let mut err = struct_span_err!(self.bccx, span, E0505,
|
let desc = self.bccx.loan_path_to_string(move_path);
|
||||||
"cannot move out of `{}` because it is borrowed",
|
let mut err = self.bccx.cannot_move_when_borrowed(span, &desc, Origin::Ast);
|
||||||
&self.bccx.loan_path_to_string(move_path));
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
loan_span,
|
loan_span,
|
||||||
format!("borrow of `{}` occurs here",
|
format!("borrow of `{}` occurs here",
|
||||||
@ -874,9 +860,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
loan_path: &LoanPath<'tcx>,
|
loan_path: &LoanPath<'tcx>,
|
||||||
loan: &Loan) {
|
loan: &Loan) {
|
||||||
struct_span_err!(self.bccx, span, E0506,
|
self.bccx.cannot_assign_to_borrowed(
|
||||||
"cannot assign to `{}` because it is borrowed",
|
span, &self.bccx.loan_path_to_string(loan_path), Origin::Ast)
|
||||||
self.bccx.loan_path_to_string(loan_path))
|
|
||||||
.span_label(loan.span,
|
.span_label(loan.span,
|
||||||
format!("borrow of `{}` occurs here",
|
format!("borrow of `{}` occurs here",
|
||||||
self.bccx.loan_path_to_string(loan_path)))
|
self.bccx.loan_path_to_string(loan_path)))
|
||||||
|
@ -37,6 +37,8 @@ use rustc::middle::free_region::RegionRelations;
|
|||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::ty::maps::Providers;
|
use rustc::ty::maps::Providers;
|
||||||
|
|
||||||
|
use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
@ -218,6 +220,25 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> {
|
|||||||
owner_def_id: DefId,
|
owner_def_id: DefId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> {
|
||||||
|
fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
|
||||||
|
sp: S,
|
||||||
|
msg: &str,
|
||||||
|
code: &str)
|
||||||
|
-> DiagnosticBuilder<'a>
|
||||||
|
{
|
||||||
|
self.tcx.sess.struct_span_err_with_code(sp, msg, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
|
||||||
|
sp: S,
|
||||||
|
msg: &str)
|
||||||
|
-> DiagnosticBuilder<'a>
|
||||||
|
{
|
||||||
|
self.tcx.sess.struct_span_err(sp, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Loans and loan paths
|
// Loans and loan paths
|
||||||
|
|
||||||
@ -549,14 +570,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||||||
move_data::Declared => {
|
move_data::Declared => {
|
||||||
// If this is an uninitialized variable, just emit a simple warning
|
// If this is an uninitialized variable, just emit a simple warning
|
||||||
// and return.
|
// and return.
|
||||||
struct_span_err!(
|
self.cannot_act_on_uninitialized_variable(use_span,
|
||||||
self.tcx.sess, use_span, E0381,
|
verb,
|
||||||
"{} of possibly uninitialized variable: `{}`",
|
&self.loan_path_to_string(lp),
|
||||||
verb,
|
Origin::Ast)
|
||||||
self.loan_path_to_string(lp))
|
.span_label(use_span, format!("use of possibly uninitialized `{}`",
|
||||||
.span_label(use_span, format!("use of possibly uninitialized `{}`",
|
self.loan_path_to_string(lp)))
|
||||||
self.loan_path_to_string(lp)))
|
.emit();
|
||||||
.emit();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -683,10 +703,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||||||
lp: &LoanPath<'tcx>,
|
lp: &LoanPath<'tcx>,
|
||||||
assign:
|
assign:
|
||||||
&move_data::Assignment) {
|
&move_data::Assignment) {
|
||||||
let mut err = struct_span_err!(
|
let mut err = self.cannot_reassign_immutable(span,
|
||||||
self.tcx.sess, span, E0384,
|
&self.loan_path_to_string(lp),
|
||||||
"re-assignment of immutable variable `{}`",
|
Origin::Ast);
|
||||||
self.loan_path_to_string(lp));
|
|
||||||
err.span_label(span, "re-assignment of immutable variable");
|
err.span_label(span, "re-assignment of immutable variable");
|
||||||
if span != assign.span {
|
if span != assign.span {
|
||||||
err.span_label(assign.span, format!("first assignment to `{}`",
|
err.span_label(assign.span, format!("first assignment to `{}`",
|
||||||
|
@ -63,27 +63,6 @@ Now that the closure has its own copy of the data, there's no need to worry
|
|||||||
about safety.
|
about safety.
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0381: r##"
|
|
||||||
It is not allowed to use or capture an uninitialized variable. For example:
|
|
||||||
|
|
||||||
```compile_fail,E0381
|
|
||||||
fn main() {
|
|
||||||
let x: i32;
|
|
||||||
let y = x; // error, use of possibly uninitialized variable
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To fix this, ensure that any declared variables are initialized before being
|
|
||||||
used. Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn main() {
|
|
||||||
let x: i32 = 0;
|
|
||||||
let y = x; // ok!
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0382: r##"
|
E0382: r##"
|
||||||
This error occurs when an attempt is made to use a variable after its contents
|
This error occurs when an attempt is made to use a variable after its contents
|
||||||
have been moved elsewhere. For example:
|
have been moved elsewhere. For example:
|
||||||
@ -182,28 +161,6 @@ x = Foo { a: 2 };
|
|||||||
```
|
```
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0384: r##"
|
|
||||||
This error occurs when an attempt is made to reassign an immutable variable.
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```compile_fail,E0384
|
|
||||||
fn main() {
|
|
||||||
let x = 3;
|
|
||||||
x = 5; // error, reassignment of immutable variable
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
By default, variables in Rust are immutable. To fix this error, add the keyword
|
|
||||||
`mut` after the keyword `let` when declaring the variable. For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn main() {
|
|
||||||
let mut x = 3;
|
|
||||||
x = 5;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
/*E0386: r##"
|
/*E0386: r##"
|
||||||
This error occurs when an attempt is made to mutate the target of a mutable
|
This error occurs when an attempt is made to mutate the target of a mutable
|
||||||
reference stored inside an immutable container.
|
reference stored inside an immutable container.
|
||||||
@ -360,512 +317,6 @@ fn main() {
|
|||||||
```
|
```
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
E0499: r##"
|
|
||||||
A variable was borrowed as mutable more than once. Erroneous code example:
|
|
||||||
|
|
||||||
```compile_fail,E0499
|
|
||||||
let mut i = 0;
|
|
||||||
let mut x = &mut i;
|
|
||||||
let mut a = &mut i;
|
|
||||||
// error: cannot borrow `i` as mutable more than once at a time
|
|
||||||
```
|
|
||||||
|
|
||||||
Please note that in rust, you can either have many immutable references, or one
|
|
||||||
mutable reference. Take a look at
|
|
||||||
https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
|
|
||||||
for more information. Example:
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
let mut i = 0;
|
|
||||||
let mut x = &mut i; // ok!
|
|
||||||
|
|
||||||
// or:
|
|
||||||
let mut i = 0;
|
|
||||||
let a = &i; // ok!
|
|
||||||
let b = &i; // still ok!
|
|
||||||
let c = &i; // still ok!
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0500: r##"
|
|
||||||
A borrowed variable was used in another closure. Example of erroneous code:
|
|
||||||
|
|
||||||
```compile_fail
|
|
||||||
fn you_know_nothing(jon_snow: &mut i32) {
|
|
||||||
let nights_watch = || {
|
|
||||||
*jon_snow = 2;
|
|
||||||
};
|
|
||||||
let starks = || {
|
|
||||||
*jon_snow = 3; // error: closure requires unique access to `jon_snow`
|
|
||||||
// but it is already borrowed
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In here, `jon_snow` is already borrowed by the `nights_watch` closure, so it
|
|
||||||
cannot be borrowed by the `starks` closure at the same time. To fix this issue,
|
|
||||||
you can put the closure in its own scope:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn you_know_nothing(jon_snow: &mut i32) {
|
|
||||||
{
|
|
||||||
let nights_watch = || {
|
|
||||||
*jon_snow = 2;
|
|
||||||
};
|
|
||||||
} // At this point, `jon_snow` is free.
|
|
||||||
let starks = || {
|
|
||||||
*jon_snow = 3;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or, if the type implements the `Clone` trait, you can clone it between
|
|
||||||
closures:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn you_know_nothing(jon_snow: &mut i32) {
|
|
||||||
let mut jon_copy = jon_snow.clone();
|
|
||||||
let nights_watch = || {
|
|
||||||
jon_copy = 2;
|
|
||||||
};
|
|
||||||
let starks = || {
|
|
||||||
*jon_snow = 3;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0501: r##"
|
|
||||||
This error indicates that a mutable variable is being used while it is still
|
|
||||||
captured by a closure. Because the closure has borrowed the variable, it is not
|
|
||||||
available for use until the closure goes out of scope.
|
|
||||||
|
|
||||||
Note that a capture will either move or borrow a variable, but in this
|
|
||||||
situation, the closure is borrowing the variable. Take a look at
|
|
||||||
http://rustbyexample.com/fn/closures/capture.html for more information about
|
|
||||||
capturing.
|
|
||||||
|
|
||||||
Example of erroneous code:
|
|
||||||
|
|
||||||
```compile_fail,E0501
|
|
||||||
fn inside_closure(x: &mut i32) {
|
|
||||||
// Actions which require unique access
|
|
||||||
}
|
|
||||||
|
|
||||||
fn outside_closure(x: &mut i32) {
|
|
||||||
// Actions which require unique access
|
|
||||||
}
|
|
||||||
|
|
||||||
fn foo(a: &mut i32) {
|
|
||||||
let bar = || {
|
|
||||||
inside_closure(a)
|
|
||||||
};
|
|
||||||
outside_closure(a); // error: cannot borrow `*a` as mutable because previous
|
|
||||||
// closure requires unique access.
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To fix this error, you can place the closure in its own scope:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn inside_closure(x: &mut i32) {}
|
|
||||||
fn outside_closure(x: &mut i32) {}
|
|
||||||
|
|
||||||
fn foo(a: &mut i32) {
|
|
||||||
{
|
|
||||||
let bar = || {
|
|
||||||
inside_closure(a)
|
|
||||||
};
|
|
||||||
} // borrow on `a` ends.
|
|
||||||
outside_closure(a); // ok!
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or you can pass the variable as a parameter to the closure:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn inside_closure(x: &mut i32) {}
|
|
||||||
fn outside_closure(x: &mut i32) {}
|
|
||||||
|
|
||||||
fn foo(a: &mut i32) {
|
|
||||||
let bar = |s: &mut i32| {
|
|
||||||
inside_closure(s)
|
|
||||||
};
|
|
||||||
outside_closure(a);
|
|
||||||
bar(a);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
It may be possible to define the closure later:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn inside_closure(x: &mut i32) {}
|
|
||||||
fn outside_closure(x: &mut i32) {}
|
|
||||||
|
|
||||||
fn foo(a: &mut i32) {
|
|
||||||
outside_closure(a);
|
|
||||||
let bar = || {
|
|
||||||
inside_closure(a)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0502: r##"
|
|
||||||
This error indicates that you are trying to borrow a variable as mutable when it
|
|
||||||
has already been borrowed as immutable.
|
|
||||||
|
|
||||||
Example of erroneous code:
|
|
||||||
|
|
||||||
```compile_fail,E0502
|
|
||||||
fn bar(x: &mut i32) {}
|
|
||||||
fn foo(a: &mut i32) {
|
|
||||||
let ref y = a; // a is borrowed as immutable.
|
|
||||||
bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
|
|
||||||
// as immutable
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To fix this error, ensure that you don't have any other references to the
|
|
||||||
variable before trying to access it mutably:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn bar(x: &mut i32) {}
|
|
||||||
fn foo(a: &mut i32) {
|
|
||||||
bar(a);
|
|
||||||
let ref y = a; // ok!
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For more information on the rust ownership system, take a look at
|
|
||||||
https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html.
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0503: r##"
|
|
||||||
A value was used after it was mutably borrowed.
|
|
||||||
|
|
||||||
Example of erroneous code:
|
|
||||||
|
|
||||||
```compile_fail,E0503
|
|
||||||
fn main() {
|
|
||||||
let mut value = 3;
|
|
||||||
// Create a mutable borrow of `value`. This borrow
|
|
||||||
// lives until the end of this function.
|
|
||||||
let _borrow = &mut value;
|
|
||||||
let _sum = value + 1; // error: cannot use `value` because
|
|
||||||
// it was mutably borrowed
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example, `value` is mutably borrowed by `borrow` and cannot be
|
|
||||||
used to calculate `sum`. This is not possible because this would violate
|
|
||||||
Rust's mutability rules.
|
|
||||||
|
|
||||||
You can fix this error by limiting the scope of the borrow:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn main() {
|
|
||||||
let mut value = 3;
|
|
||||||
// By creating a new block, you can limit the scope
|
|
||||||
// of the reference.
|
|
||||||
{
|
|
||||||
let _borrow = &mut value; // Use `_borrow` inside this block.
|
|
||||||
}
|
|
||||||
// The block has ended and with it the borrow.
|
|
||||||
// You can now use `value` again.
|
|
||||||
let _sum = value + 1;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or by cloning `value` before borrowing it:
|
|
||||||
|
|
||||||
```
|
|
||||||
fn main() {
|
|
||||||
let mut value = 3;
|
|
||||||
// We clone `value`, creating a copy.
|
|
||||||
let value_cloned = value.clone();
|
|
||||||
// The mutable borrow is a reference to `value` and
|
|
||||||
// not to `value_cloned`...
|
|
||||||
let _borrow = &mut value;
|
|
||||||
// ... which means we can still use `value_cloned`,
|
|
||||||
let _sum = value_cloned + 1;
|
|
||||||
// even though the borrow only ends here.
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can find more information about borrowing in the rust-book:
|
|
||||||
http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0504: r##"
|
|
||||||
This error occurs when an attempt is made to move a borrowed variable into a
|
|
||||||
closure.
|
|
||||||
|
|
||||||
Example of erroneous code:
|
|
||||||
|
|
||||||
```compile_fail,E0504
|
|
||||||
struct FancyNum {
|
|
||||||
num: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let fancy_num = FancyNum { num: 5 };
|
|
||||||
let fancy_ref = &fancy_num;
|
|
||||||
|
|
||||||
let x = move || {
|
|
||||||
println!("child function: {}", fancy_num.num);
|
|
||||||
// error: cannot move `fancy_num` into closure because it is borrowed
|
|
||||||
};
|
|
||||||
|
|
||||||
x();
|
|
||||||
println!("main function: {}", fancy_ref.num);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into
|
|
||||||
the closure `x`. There is no way to move a value into a closure while it is
|
|
||||||
borrowed, as that would invalidate the borrow.
|
|
||||||
|
|
||||||
If the closure can't outlive the value being moved, try using a reference
|
|
||||||
rather than moving:
|
|
||||||
|
|
||||||
```
|
|
||||||
struct FancyNum {
|
|
||||||
num: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let fancy_num = FancyNum { num: 5 };
|
|
||||||
let fancy_ref = &fancy_num;
|
|
||||||
|
|
||||||
let x = move || {
|
|
||||||
// fancy_ref is usable here because it doesn't move `fancy_num`
|
|
||||||
println!("child function: {}", fancy_ref.num);
|
|
||||||
};
|
|
||||||
|
|
||||||
x();
|
|
||||||
|
|
||||||
println!("main function: {}", fancy_num.num);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If the value has to be borrowed and then moved, try limiting the lifetime of
|
|
||||||
the borrow using a scoped block:
|
|
||||||
|
|
||||||
```
|
|
||||||
struct FancyNum {
|
|
||||||
num: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let fancy_num = FancyNum { num: 5 };
|
|
||||||
|
|
||||||
{
|
|
||||||
let fancy_ref = &fancy_num;
|
|
||||||
println!("main function: {}", fancy_ref.num);
|
|
||||||
// `fancy_ref` goes out of scope here
|
|
||||||
}
|
|
||||||
|
|
||||||
let x = move || {
|
|
||||||
// `fancy_num` can be moved now (no more references exist)
|
|
||||||
println!("child function: {}", fancy_num.num);
|
|
||||||
};
|
|
||||||
|
|
||||||
x();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If the lifetime of a reference isn't enough, such as in the case of threading,
|
|
||||||
consider using an `Arc` to create a reference-counted value:
|
|
||||||
|
|
||||||
```
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
struct FancyNum {
|
|
||||||
num: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let fancy_ref1 = Arc::new(FancyNum { num: 5 });
|
|
||||||
let fancy_ref2 = fancy_ref1.clone();
|
|
||||||
|
|
||||||
let x = thread::spawn(move || {
|
|
||||||
// `fancy_ref1` can be moved and has a `'static` lifetime
|
|
||||||
println!("child thread: {}", fancy_ref1.num);
|
|
||||||
});
|
|
||||||
|
|
||||||
x.join().expect("child thread should finish");
|
|
||||||
println!("main thread: {}", fancy_ref2.num);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0505: r##"
|
|
||||||
A value was moved out while it was still borrowed.
|
|
||||||
|
|
||||||
Erroneous code example:
|
|
||||||
|
|
||||||
```compile_fail,E0505
|
|
||||||
struct Value {}
|
|
||||||
|
|
||||||
fn eat(val: Value) {}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let x = Value{};
|
|
||||||
{
|
|
||||||
let _ref_to_val: &Value = &x;
|
|
||||||
eat(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here, the function `eat` takes the ownership of `x`. However,
|
|
||||||
`x` cannot be moved because it was borrowed to `_ref_to_val`.
|
|
||||||
To fix that you can do few different things:
|
|
||||||
|
|
||||||
* Try to avoid moving the variable.
|
|
||||||
* Release borrow before move.
|
|
||||||
* Implement the `Copy` trait on the type.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
```
|
|
||||||
struct Value {}
|
|
||||||
|
|
||||||
fn eat(val: &Value) {}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let x = Value{};
|
|
||||||
{
|
|
||||||
let _ref_to_val: &Value = &x;
|
|
||||||
eat(&x); // pass by reference, if it's possible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or:
|
|
||||||
|
|
||||||
```
|
|
||||||
struct Value {}
|
|
||||||
|
|
||||||
fn eat(val: Value) {}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let x = Value{};
|
|
||||||
{
|
|
||||||
let _ref_to_val: &Value = &x;
|
|
||||||
}
|
|
||||||
eat(x); // release borrow and then move it.
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or:
|
|
||||||
|
|
||||||
```
|
|
||||||
#[derive(Clone, Copy)] // implement Copy trait
|
|
||||||
struct Value {}
|
|
||||||
|
|
||||||
fn eat(val: Value) {}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let x = Value{};
|
|
||||||
{
|
|
||||||
let _ref_to_val: &Value = &x;
|
|
||||||
eat(x); // it will be copied here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can find more information about borrowing in the rust-book:
|
|
||||||
http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0506: r##"
|
|
||||||
This error occurs when an attempt is made to assign to a borrowed value.
|
|
||||||
|
|
||||||
Example of erroneous code:
|
|
||||||
|
|
||||||
```compile_fail,E0506
|
|
||||||
struct FancyNum {
|
|
||||||
num: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut fancy_num = FancyNum { num: 5 };
|
|
||||||
let fancy_ref = &fancy_num;
|
|
||||||
fancy_num = FancyNum { num: 6 };
|
|
||||||
// error: cannot assign to `fancy_num` because it is borrowed
|
|
||||||
|
|
||||||
println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't
|
|
||||||
be assigned to a new value as it would invalidate the reference.
|
|
||||||
|
|
||||||
Alternatively, we can move out of `fancy_num` into a second `fancy_num`:
|
|
||||||
|
|
||||||
```
|
|
||||||
struct FancyNum {
|
|
||||||
num: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut fancy_num = FancyNum { num: 5 };
|
|
||||||
let moved_num = fancy_num;
|
|
||||||
fancy_num = FancyNum { num: 6 };
|
|
||||||
|
|
||||||
println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If the value has to be borrowed, try limiting the lifetime of the borrow using
|
|
||||||
a scoped block:
|
|
||||||
|
|
||||||
```
|
|
||||||
struct FancyNum {
|
|
||||||
num: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut fancy_num = FancyNum { num: 5 };
|
|
||||||
|
|
||||||
{
|
|
||||||
let fancy_ref = &fancy_num;
|
|
||||||
println!("Ref: {}", fancy_ref.num);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Works because `fancy_ref` is no longer in scope
|
|
||||||
fancy_num = FancyNum { num: 6 };
|
|
||||||
println!("Num: {}", fancy_num.num);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or by moving the reference into a function:
|
|
||||||
|
|
||||||
```
|
|
||||||
struct FancyNum {
|
|
||||||
num: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut fancy_num = FancyNum { num: 5 };
|
|
||||||
|
|
||||||
print_fancy_ref(&fancy_num);
|
|
||||||
|
|
||||||
// Works because function borrow has ended
|
|
||||||
fancy_num = FancyNum { num: 6 };
|
|
||||||
println!("Num: {}", fancy_num.num);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_fancy_ref(fancy_ref: &FancyNum){
|
|
||||||
println!("Ref: {}", fancy_ref.num);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"##,
|
|
||||||
|
|
||||||
E0507: r##"
|
E0507: r##"
|
||||||
You tried to move out of a value which was borrowed. Erroneous code example:
|
You tried to move out of a value which was borrowed. Erroneous code example:
|
||||||
|
|
||||||
@ -1205,7 +656,6 @@ x.x = Some(&y);
|
|||||||
|
|
||||||
register_diagnostics! {
|
register_diagnostics! {
|
||||||
// E0385, // {} in an aliasable location
|
// E0385, // {} in an aliasable location
|
||||||
E0524, // two closures require unique access to `..` at the same time
|
|
||||||
E0594, // cannot assign to {}
|
E0594, // cannot assign to {}
|
||||||
E0598, // lifetime of {} is too short to guarantee its contents can be...
|
E0598, // lifetime of {} is too short to guarantee its contents can be...
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ rustc = { path = "../librustc" }
|
|||||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||||
rustc_const_math = { path = "../librustc_const_math" }
|
rustc_const_math = { path = "../librustc_const_math" }
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
|
rustc_errors = { path = "../librustc_errors" }
|
||||||
rustc_bitflags = { path = "../librustc_bitflags" }
|
rustc_bitflags = { path = "../librustc_bitflags" }
|
||||||
syntax = { path = "../libsyntax" }
|
syntax = { path = "../libsyntax" }
|
||||||
syntax_pos = { path = "../libsyntax_pos" }
|
syntax_pos = { path = "../libsyntax_pos" }
|
||||||
|
@ -195,6 +195,50 @@ instead of using a `const fn`, or refactoring the code to a functional style to
|
|||||||
avoid mutation if possible.
|
avoid mutation if possible.
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
|
E0381: r##"
|
||||||
|
It is not allowed to use or capture an uninitialized variable. For example:
|
||||||
|
|
||||||
|
```compile_fail,E0381
|
||||||
|
fn main() {
|
||||||
|
let x: i32;
|
||||||
|
let y = x; // error, use of possibly uninitialized variable
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To fix this, ensure that any declared variables are initialized before being
|
||||||
|
used. Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn main() {
|
||||||
|
let x: i32 = 0;
|
||||||
|
let y = x; // ok!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0384: r##"
|
||||||
|
This error occurs when an attempt is made to reassign an immutable variable.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```compile_fail,E0384
|
||||||
|
fn main() {
|
||||||
|
let x = 3;
|
||||||
|
x = 5; // error, reassignment of immutable variable
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, variables in Rust are immutable. To fix this error, add the keyword
|
||||||
|
`mut` after the keyword `let` when declaring the variable. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn main() {
|
||||||
|
let mut x = 3;
|
||||||
|
x = 5;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
|
|
||||||
E0394: r##"
|
E0394: r##"
|
||||||
A static was referred to by value by another static.
|
A static was referred to by value by another static.
|
||||||
|
|
||||||
@ -438,9 +482,516 @@ static A : &'static u32 = &S.a; // ok!
|
|||||||
```
|
```
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
|
E0499: r##"
|
||||||
|
A variable was borrowed as mutable more than once. Erroneous code example:
|
||||||
|
|
||||||
|
```compile_fail,E0499
|
||||||
|
let mut i = 0;
|
||||||
|
let mut x = &mut i;
|
||||||
|
let mut a = &mut i;
|
||||||
|
// error: cannot borrow `i` as mutable more than once at a time
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note that in rust, you can either have many immutable references, or one
|
||||||
|
mutable reference. Take a look at
|
||||||
|
https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more
|
||||||
|
information. Example:
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
let mut i = 0;
|
||||||
|
let mut x = &mut i; // ok!
|
||||||
|
|
||||||
|
// or:
|
||||||
|
let mut i = 0;
|
||||||
|
let a = &i; // ok!
|
||||||
|
let b = &i; // still ok!
|
||||||
|
let c = &i; // still ok!
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0500: r##"
|
||||||
|
A borrowed variable was used in another closure. Example of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail
|
||||||
|
fn you_know_nothing(jon_snow: &mut i32) {
|
||||||
|
let nights_watch = || {
|
||||||
|
*jon_snow = 2;
|
||||||
|
};
|
||||||
|
let starks = || {
|
||||||
|
*jon_snow = 3; // error: closure requires unique access to `jon_snow`
|
||||||
|
// but it is already borrowed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In here, `jon_snow` is already borrowed by the `nights_watch` closure, so it
|
||||||
|
cannot be borrowed by the `starks` closure at the same time. To fix this issue,
|
||||||
|
you can put the closure in its own scope:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn you_know_nothing(jon_snow: &mut i32) {
|
||||||
|
{
|
||||||
|
let nights_watch = || {
|
||||||
|
*jon_snow = 2;
|
||||||
|
};
|
||||||
|
} // At this point, `jon_snow` is free.
|
||||||
|
let starks = || {
|
||||||
|
*jon_snow = 3;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, if the type implements the `Clone` trait, you can clone it between
|
||||||
|
closures:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn you_know_nothing(jon_snow: &mut i32) {
|
||||||
|
let mut jon_copy = jon_snow.clone();
|
||||||
|
let nights_watch = || {
|
||||||
|
jon_copy = 2;
|
||||||
|
};
|
||||||
|
let starks = || {
|
||||||
|
*jon_snow = 3;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0501: r##"
|
||||||
|
This error indicates that a mutable variable is being used while it is still
|
||||||
|
captured by a closure. Because the closure has borrowed the variable, it is not
|
||||||
|
available for use until the closure goes out of scope.
|
||||||
|
|
||||||
|
Note that a capture will either move or borrow a variable, but in this
|
||||||
|
situation, the closure is borrowing the variable. Take a look at
|
||||||
|
http://rustbyexample.com/fn/closures/capture.html for more information about
|
||||||
|
capturing.
|
||||||
|
|
||||||
|
Example of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail,E0501
|
||||||
|
fn inside_closure(x: &mut i32) {
|
||||||
|
// Actions which require unique access
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outside_closure(x: &mut i32) {
|
||||||
|
// Actions which require unique access
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(a: &mut i32) {
|
||||||
|
let bar = || {
|
||||||
|
inside_closure(a)
|
||||||
|
};
|
||||||
|
outside_closure(a); // error: cannot borrow `*a` as mutable because previous
|
||||||
|
// closure requires unique access.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To fix this error, you can place the closure in its own scope:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn inside_closure(x: &mut i32) {}
|
||||||
|
fn outside_closure(x: &mut i32) {}
|
||||||
|
|
||||||
|
fn foo(a: &mut i32) {
|
||||||
|
{
|
||||||
|
let bar = || {
|
||||||
|
inside_closure(a)
|
||||||
|
};
|
||||||
|
} // borrow on `a` ends.
|
||||||
|
outside_closure(a); // ok!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or you can pass the variable as a parameter to the closure:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn inside_closure(x: &mut i32) {}
|
||||||
|
fn outside_closure(x: &mut i32) {}
|
||||||
|
|
||||||
|
fn foo(a: &mut i32) {
|
||||||
|
let bar = |s: &mut i32| {
|
||||||
|
inside_closure(s)
|
||||||
|
};
|
||||||
|
outside_closure(a);
|
||||||
|
bar(a);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It may be possible to define the closure later:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn inside_closure(x: &mut i32) {}
|
||||||
|
fn outside_closure(x: &mut i32) {}
|
||||||
|
|
||||||
|
fn foo(a: &mut i32) {
|
||||||
|
outside_closure(a);
|
||||||
|
let bar = || {
|
||||||
|
inside_closure(a)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0502: r##"
|
||||||
|
This error indicates that you are trying to borrow a variable as mutable when it
|
||||||
|
has already been borrowed as immutable.
|
||||||
|
|
||||||
|
Example of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail,E0502
|
||||||
|
fn bar(x: &mut i32) {}
|
||||||
|
fn foo(a: &mut i32) {
|
||||||
|
let ref y = a; // a is borrowed as immutable.
|
||||||
|
bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
|
||||||
|
// as immutable
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To fix this error, ensure that you don't have any other references to the
|
||||||
|
variable before trying to access it mutably:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn bar(x: &mut i32) {}
|
||||||
|
fn foo(a: &mut i32) {
|
||||||
|
bar(a);
|
||||||
|
let ref y = a; // ok!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information on the rust ownership system, take a look at
|
||||||
|
https://doc.rust-lang.org/stable/book/references-and-borrowing.html.
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0503: r##"
|
||||||
|
A value was used after it was mutably borrowed.
|
||||||
|
|
||||||
|
Example of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail,E0503
|
||||||
|
fn main() {
|
||||||
|
let mut value = 3;
|
||||||
|
// Create a mutable borrow of `value`. This borrow
|
||||||
|
// lives until the end of this function.
|
||||||
|
let _borrow = &mut value;
|
||||||
|
let _sum = value + 1; // error: cannot use `value` because
|
||||||
|
// it was mutably borrowed
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, `value` is mutably borrowed by `borrow` and cannot be
|
||||||
|
used to calculate `sum`. This is not possible because this would violate
|
||||||
|
Rust's mutability rules.
|
||||||
|
|
||||||
|
You can fix this error by limiting the scope of the borrow:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn main() {
|
||||||
|
let mut value = 3;
|
||||||
|
// By creating a new block, you can limit the scope
|
||||||
|
// of the reference.
|
||||||
|
{
|
||||||
|
let _borrow = &mut value; // Use `_borrow` inside this block.
|
||||||
|
}
|
||||||
|
// The block has ended and with it the borrow.
|
||||||
|
// You can now use `value` again.
|
||||||
|
let _sum = value + 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or by cloning `value` before borrowing it:
|
||||||
|
|
||||||
|
```
|
||||||
|
fn main() {
|
||||||
|
let mut value = 3;
|
||||||
|
// We clone `value`, creating a copy.
|
||||||
|
let value_cloned = value.clone();
|
||||||
|
// The mutable borrow is a reference to `value` and
|
||||||
|
// not to `value_cloned`...
|
||||||
|
let _borrow = &mut value;
|
||||||
|
// ... which means we can still use `value_cloned`,
|
||||||
|
let _sum = value_cloned + 1;
|
||||||
|
// even though the borrow only ends here.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find more information about borrowing in the rust-book:
|
||||||
|
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0504: r##"
|
||||||
|
This error occurs when an attempt is made to move a borrowed variable into a
|
||||||
|
closure.
|
||||||
|
|
||||||
|
Example of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail,E0504
|
||||||
|
struct FancyNum {
|
||||||
|
num: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let fancy_num = FancyNum { num: 5 };
|
||||||
|
let fancy_ref = &fancy_num;
|
||||||
|
|
||||||
|
let x = move || {
|
||||||
|
println!("child function: {}", fancy_num.num);
|
||||||
|
// error: cannot move `fancy_num` into closure because it is borrowed
|
||||||
|
};
|
||||||
|
|
||||||
|
x();
|
||||||
|
println!("main function: {}", fancy_ref.num);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into
|
||||||
|
the closure `x`. There is no way to move a value into a closure while it is
|
||||||
|
borrowed, as that would invalidate the borrow.
|
||||||
|
|
||||||
|
If the closure can't outlive the value being moved, try using a reference
|
||||||
|
rather than moving:
|
||||||
|
|
||||||
|
```
|
||||||
|
struct FancyNum {
|
||||||
|
num: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let fancy_num = FancyNum { num: 5 };
|
||||||
|
let fancy_ref = &fancy_num;
|
||||||
|
|
||||||
|
let x = move || {
|
||||||
|
// fancy_ref is usable here because it doesn't move `fancy_num`
|
||||||
|
println!("child function: {}", fancy_ref.num);
|
||||||
|
};
|
||||||
|
|
||||||
|
x();
|
||||||
|
|
||||||
|
println!("main function: {}", fancy_num.num);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the value has to be borrowed and then moved, try limiting the lifetime of
|
||||||
|
the borrow using a scoped block:
|
||||||
|
|
||||||
|
```
|
||||||
|
struct FancyNum {
|
||||||
|
num: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let fancy_num = FancyNum { num: 5 };
|
||||||
|
|
||||||
|
{
|
||||||
|
let fancy_ref = &fancy_num;
|
||||||
|
println!("main function: {}", fancy_ref.num);
|
||||||
|
// `fancy_ref` goes out of scope here
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = move || {
|
||||||
|
// `fancy_num` can be moved now (no more references exist)
|
||||||
|
println!("child function: {}", fancy_num.num);
|
||||||
|
};
|
||||||
|
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the lifetime of a reference isn't enough, such as in the case of threading,
|
||||||
|
consider using an `Arc` to create a reference-counted value:
|
||||||
|
|
||||||
|
```
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
struct FancyNum {
|
||||||
|
num: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let fancy_ref1 = Arc::new(FancyNum { num: 5 });
|
||||||
|
let fancy_ref2 = fancy_ref1.clone();
|
||||||
|
|
||||||
|
let x = thread::spawn(move || {
|
||||||
|
// `fancy_ref1` can be moved and has a `'static` lifetime
|
||||||
|
println!("child thread: {}", fancy_ref1.num);
|
||||||
|
});
|
||||||
|
|
||||||
|
x.join().expect("child thread should finish");
|
||||||
|
println!("main thread: {}", fancy_ref2.num);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0505: r##"
|
||||||
|
A value was moved out while it was still borrowed.
|
||||||
|
|
||||||
|
Erroneous code example:
|
||||||
|
|
||||||
|
```compile_fail,E0505
|
||||||
|
struct Value {}
|
||||||
|
|
||||||
|
fn eat(val: Value) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Value{};
|
||||||
|
{
|
||||||
|
let _ref_to_val: &Value = &x;
|
||||||
|
eat(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here, the function `eat` takes the ownership of `x`. However,
|
||||||
|
`x` cannot be moved because it was borrowed to `_ref_to_val`.
|
||||||
|
To fix that you can do few different things:
|
||||||
|
|
||||||
|
* Try to avoid moving the variable.
|
||||||
|
* Release borrow before move.
|
||||||
|
* Implement the `Copy` trait on the type.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```
|
||||||
|
struct Value {}
|
||||||
|
|
||||||
|
fn eat(val: &Value) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Value{};
|
||||||
|
{
|
||||||
|
let _ref_to_val: &Value = &x;
|
||||||
|
eat(&x); // pass by reference, if it's possible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or:
|
||||||
|
|
||||||
|
```
|
||||||
|
struct Value {}
|
||||||
|
|
||||||
|
fn eat(val: Value) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Value{};
|
||||||
|
{
|
||||||
|
let _ref_to_val: &Value = &x;
|
||||||
|
}
|
||||||
|
eat(x); // release borrow and then move it.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or:
|
||||||
|
|
||||||
|
```
|
||||||
|
#[derive(Clone, Copy)] // implement Copy trait
|
||||||
|
struct Value {}
|
||||||
|
|
||||||
|
fn eat(val: Value) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Value{};
|
||||||
|
{
|
||||||
|
let _ref_to_val: &Value = &x;
|
||||||
|
eat(x); // it will be copied here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find more information about borrowing in the rust-book:
|
||||||
|
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
|
||||||
|
"##,
|
||||||
|
|
||||||
|
E0506: r##"
|
||||||
|
This error occurs when an attempt is made to assign to a borrowed value.
|
||||||
|
|
||||||
|
Example of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail,E0506
|
||||||
|
struct FancyNum {
|
||||||
|
num: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut fancy_num = FancyNum { num: 5 };
|
||||||
|
let fancy_ref = &fancy_num;
|
||||||
|
fancy_num = FancyNum { num: 6 };
|
||||||
|
// error: cannot assign to `fancy_num` because it is borrowed
|
||||||
|
|
||||||
|
println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't
|
||||||
|
be assigned to a new value as it would invalidate the reference.
|
||||||
|
|
||||||
|
Alternatively, we can move out of `fancy_num` into a second `fancy_num`:
|
||||||
|
|
||||||
|
```
|
||||||
|
struct FancyNum {
|
||||||
|
num: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut fancy_num = FancyNum { num: 5 };
|
||||||
|
let moved_num = fancy_num;
|
||||||
|
fancy_num = FancyNum { num: 6 };
|
||||||
|
|
||||||
|
println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the value has to be borrowed, try limiting the lifetime of the borrow using
|
||||||
|
a scoped block:
|
||||||
|
|
||||||
|
```
|
||||||
|
struct FancyNum {
|
||||||
|
num: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut fancy_num = FancyNum { num: 5 };
|
||||||
|
|
||||||
|
{
|
||||||
|
let fancy_ref = &fancy_num;
|
||||||
|
println!("Ref: {}", fancy_ref.num);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Works because `fancy_ref` is no longer in scope
|
||||||
|
fancy_num = FancyNum { num: 6 };
|
||||||
|
println!("Num: {}", fancy_num.num);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or by moving the reference into a function:
|
||||||
|
|
||||||
|
```
|
||||||
|
struct FancyNum {
|
||||||
|
num: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut fancy_num = FancyNum { num: 5 };
|
||||||
|
|
||||||
|
print_fancy_ref(&fancy_num);
|
||||||
|
|
||||||
|
// Works because function borrow has ended
|
||||||
|
fancy_num = FancyNum { num: 6 };
|
||||||
|
println!("Num: {}", fancy_num.num);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_fancy_ref(fancy_ref: &FancyNum){
|
||||||
|
println!("Ref: {}", fancy_ref.num);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
register_diagnostics! {
|
register_diagnostics! {
|
||||||
|
E0524, // two closures require unique access to `..` at the same time
|
||||||
E0526, // shuffle indices are not constant
|
E0526, // shuffle indices are not constant
|
||||||
E0625, // thread-local statics cannot be accessed at compile-time
|
E0625, // thread-local statics cannot be accessed at compile-time
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ extern crate graphviz as dot;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
extern crate rustc_data_structures;
|
extern crate rustc_data_structures;
|
||||||
|
extern crate rustc_errors;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
#[no_link]
|
#[no_link]
|
||||||
extern crate rustc_bitflags;
|
extern crate rustc_bitflags;
|
||||||
|
192
src/librustc_mir/util/borrowck_errors.rs
Normal file
192
src/librustc_mir/util/borrowck_errors.rs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use rustc::ty::{self, TyCtxt};
|
||||||
|
use rustc_errors::DiagnosticBuilder;
|
||||||
|
use syntax_pos::{MultiSpan, Span};
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum Origin { Ast, Mir }
|
||||||
|
|
||||||
|
impl fmt::Display for Origin {
|
||||||
|
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Origin::Mir => write!(w, " (Mir)"),
|
||||||
|
Origin::Ast => ty::tls::with_opt(|opt_tcx| {
|
||||||
|
// If user passed `-Z borrowck-mir`, then include an
|
||||||
|
// AST origin as part of the error report
|
||||||
|
if let Some(tcx) = opt_tcx {
|
||||||
|
if tcx.sess.opts.debugging_opts.borrowck_mir {
|
||||||
|
return write!(w, " (Ast)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// otherwise, do not include the origin (i.e., print
|
||||||
|
// nothing at all)
|
||||||
|
Ok(())
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait BorrowckErrors {
|
||||||
|
fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
|
||||||
|
sp: S,
|
||||||
|
msg: &str,
|
||||||
|
code: &str)
|
||||||
|
-> DiagnosticBuilder<'a>;
|
||||||
|
|
||||||
|
fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
|
||||||
|
sp: S,
|
||||||
|
msg: &str)
|
||||||
|
-> DiagnosticBuilder<'a>;
|
||||||
|
|
||||||
|
fn cannot_move_when_borrowed(&self, span: Span, desc: &str, o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0505,
|
||||||
|
"cannot move out of `{}` because it is borrowed{OGN}",
|
||||||
|
desc, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_use_when_mutably_borrowed(&self, span: Span, desc: &str, o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0503,
|
||||||
|
"cannot use `{}` because it was mutably borrowed{OGN}",
|
||||||
|
desc, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_act_on_uninitialized_variable(&self,
|
||||||
|
span: Span,
|
||||||
|
verb: &str,
|
||||||
|
desc: &str,
|
||||||
|
o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0381,
|
||||||
|
"{} of possibly uninitialized variable: `{}`{OGN}",
|
||||||
|
verb, desc, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_mutably_borrow_multiply(&self,
|
||||||
|
span: Span,
|
||||||
|
desc: &str,
|
||||||
|
opt_via: &str,
|
||||||
|
o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0499,
|
||||||
|
"cannot borrow `{}`{} as mutable more than once at a time{OGN}",
|
||||||
|
desc, opt_via, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_uniquely_borrow_by_two_closures(&self, span: Span, desc: &str, o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0524,
|
||||||
|
"two closures require unique access to `{}` at the same time{OGN}",
|
||||||
|
desc, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_uniquely_borrow_by_one_closure(&self,
|
||||||
|
span: Span,
|
||||||
|
desc_new: &str,
|
||||||
|
noun_old: &str,
|
||||||
|
msg_old: &str,
|
||||||
|
o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0500,
|
||||||
|
"closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
|
||||||
|
desc_new, noun_old, msg_old, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_reborrow_already_uniquely_borrowed(&self,
|
||||||
|
span: Span,
|
||||||
|
desc_new: &str,
|
||||||
|
msg_new: &str,
|
||||||
|
kind_new: &str,
|
||||||
|
o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0501,
|
||||||
|
"cannot borrow `{}`{} as {} because previous closure \
|
||||||
|
requires unique access{OGN}",
|
||||||
|
desc_new, msg_new, kind_new, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_reborrow_already_borrowed(&self,
|
||||||
|
span: Span,
|
||||||
|
desc_new: &str,
|
||||||
|
msg_new: &str,
|
||||||
|
kind_new: &str,
|
||||||
|
noun_old: &str,
|
||||||
|
kind_old: &str,
|
||||||
|
msg_old: &str,
|
||||||
|
o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0502,
|
||||||
|
"cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
|
||||||
|
desc_new, msg_new, kind_new, noun_old, kind_old, msg_old, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_assign_to_borrowed(&self, span: Span, desc: &str, o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0506,
|
||||||
|
"cannot assign to `{}` because it is borrowed{OGN}",
|
||||||
|
desc, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_move_into_closure(&self, span: Span, desc: &str, o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0504,
|
||||||
|
"cannot move `{}` into closure because it is borrowed{OGN}",
|
||||||
|
desc, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_reassign_immutable(&self, span: Span, desc: &str, o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
struct_span_err!(self, span, E0384,
|
||||||
|
"re-assignment of immutable variable `{}`{OGN}",
|
||||||
|
desc, OGN=o)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cannot_assign_static(&self, span: Span, desc: &str, o: Origin)
|
||||||
|
-> DiagnosticBuilder
|
||||||
|
{
|
||||||
|
self.struct_span_err(span, &format!("cannot assign to immutable static item {}{OGN}",
|
||||||
|
desc, OGN=o))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, 'tcx, 'gcx> BorrowckErrors for TyCtxt<'b, 'tcx, 'gcx> {
|
||||||
|
fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
|
||||||
|
sp: S,
|
||||||
|
msg: &str,
|
||||||
|
code: &str)
|
||||||
|
-> DiagnosticBuilder<'a>
|
||||||
|
{
|
||||||
|
self.sess.struct_span_err_with_code(sp, msg, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
|
||||||
|
sp: S,
|
||||||
|
msg: &str)
|
||||||
|
-> DiagnosticBuilder<'a>
|
||||||
|
{
|
||||||
|
self.sess.struct_span_err(sp, msg)
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
pub mod borrowck_errors;
|
||||||
pub mod elaborate_drops;
|
pub mod elaborate_drops;
|
||||||
pub mod def_use;
|
pub mod def_use;
|
||||||
pub mod patch;
|
pub mod patch;
|
||||||
|
Loading…
Reference in New Issue
Block a user