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:
Felix S. Klock II 2017-07-03 17:25:03 +02:00
parent 4fc3765c54
commit 8e79fc72cb
9 changed files with 800 additions and 599 deletions

1
src/Cargo.lock generated
View File

@ -1452,6 +1452,7 @@ dependencies = [
"rustc_const_eval 0.0.0",
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]

View File

@ -29,6 +29,7 @@ use rustc::ty::{self, TyCtxt};
use syntax::ast;
use syntax_pos::Span;
use rustc::hir;
use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
use std::rc::Rc;
@ -465,10 +466,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
let mut err = match (new_loan.kind, old_loan.kind) {
(ty::MutBorrow, ty::MutBorrow) => {
let mut err = struct_span_err!(self.bccx, new_loan.span, E0499,
"cannot borrow `{}`{} as mutable \
more than once at a time",
nl, new_loan_msg);
let mut err = self.bccx.cannot_mutably_borrow_multiply(
new_loan.span, &nl, &new_loan_msg, Origin::Ast);
if new_loan.span == old_loan.span {
// Both borrows are happening in the same place
@ -496,10 +495,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) => {
let mut err = struct_span_err!(self.bccx, new_loan.span, E0524,
"two closures require unique access to `{}` \
at the same time",
nl);
let mut err = self.bccx.cannot_uniquely_borrow_by_two_closures(
new_loan.span, &nl, Origin::Ast);
err.span_label(
old_loan.span,
"first closure is constructed here");
@ -513,10 +510,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
(ty::UniqueImmBorrow, _) => {
let mut err = struct_span_err!(self.bccx, new_loan.span, E0500,
"closure requires unique access to `{}` \
but {} is already borrowed{}",
nl, ol_pronoun, old_loan_msg);
let mut err = self.bccx.cannot_uniquely_borrow_by_one_closure(
new_loan.span, &nl, &ol_pronoun, &old_loan_msg, Origin::Ast);
err.span_label(
new_loan.span,
format!("closure construction occurs here{}", new_loan_msg));
@ -530,10 +525,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
(_, ty::UniqueImmBorrow) => {
let mut err = struct_span_err!(self.bccx, new_loan.span, E0501,
"cannot borrow `{}`{} as {} because \
previous closure requires unique access",
nl, new_loan_msg, new_loan.kind.to_user_str());
let new_loan_str = &new_loan.kind.to_user_str();
let mut err = self.bccx.cannot_reborrow_already_uniquely_borrowed(
new_loan.span, &nl, &new_loan_msg, new_loan_str, Origin::Ast);
err.span_label(
new_loan.span,
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,
"cannot borrow `{}`{} as {} because \
{} is also borrowed as {}{}",
nl,
new_loan_msg,
new_loan.kind.to_user_str(),
ol_pronoun,
old_loan.kind.to_user_str(),
old_loan_msg);
let mut err = self.bccx.cannot_reborrow_already_borrowed(
new_loan.span,
&nl, &new_loan_msg, &new_loan.kind.to_user_str(),
&ol_pronoun, &old_loan.kind.to_user_str(), &old_loan_msg, Origin::Ast);
err.span_label(
new_loan.span,
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) {
UseOk => { }
UseWhileBorrowed(loan_path, loan_span) => {
struct_span_err!(self.bccx, span, E0503,
"cannot use `{}` because it was mutably borrowed",
&self.bccx.loan_path_to_string(copy_path))
let desc = self.bccx.loan_path_to_string(copy_path);
self.bccx.cannot_use_when_mutably_borrowed(span, &desc, Origin::Ast)
.span_label(loan_span,
format!("borrow of `{}` occurs here",
&self.bccx.loan_path_to_string(&loan_path))
@ -673,9 +661,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
UseWhileBorrowed(loan_path, loan_span) => {
let mut err = match move_kind {
move_data::Captured => {
let mut err = struct_span_err!(self.bccx, span, E0504,
"cannot move `{}` into closure because it is borrowed",
&self.bccx.loan_path_to_string(move_path));
let mut err = self.bccx.cannot_move_into_closure(
span, &self.bccx.loan_path_to_string(move_path), Origin::Ast);
err.span_label(
loan_span,
format!("borrow of `{}` occurs here",
@ -690,9 +677,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
move_data::Declared |
move_data::MoveExpr |
move_data::MovePat => {
let mut err = struct_span_err!(self.bccx, span, E0505,
"cannot move out of `{}` because it is borrowed",
&self.bccx.loan_path_to_string(move_path));
let desc = self.bccx.loan_path_to_string(move_path);
let mut err = self.bccx.cannot_move_when_borrowed(span, &desc, Origin::Ast);
err.span_label(
loan_span,
format!("borrow of `{}` occurs here",
@ -874,9 +860,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
span: Span,
loan_path: &LoanPath<'tcx>,
loan: &Loan) {
struct_span_err!(self.bccx, span, E0506,
"cannot assign to `{}` because it is borrowed",
self.bccx.loan_path_to_string(loan_path))
self.bccx.cannot_assign_to_borrowed(
span, &self.bccx.loan_path_to_string(loan_path), Origin::Ast)
.span_label(loan.span,
format!("borrow of `{}` occurs here",
self.bccx.loan_path_to_string(loan_path)))

View File

@ -37,6 +37,8 @@ use rustc::middle::free_region::RegionRelations;
use rustc::ty::{self, TyCtxt};
use rustc::ty::maps::Providers;
use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
use std::fmt;
use std::rc::Rc;
use std::hash::{Hash, Hasher};
@ -218,6 +220,25 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> {
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
@ -549,14 +570,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
move_data::Declared => {
// If this is an uninitialized variable, just emit a simple warning
// and return.
struct_span_err!(
self.tcx.sess, use_span, E0381,
"{} of possibly uninitialized variable: `{}`",
verb,
self.loan_path_to_string(lp))
.span_label(use_span, format!("use of possibly uninitialized `{}`",
self.loan_path_to_string(lp)))
.emit();
self.cannot_act_on_uninitialized_variable(use_span,
verb,
&self.loan_path_to_string(lp),
Origin::Ast)
.span_label(use_span, format!("use of possibly uninitialized `{}`",
self.loan_path_to_string(lp)))
.emit();
return;
}
_ => {
@ -683,10 +703,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
lp: &LoanPath<'tcx>,
assign:
&move_data::Assignment) {
let mut err = struct_span_err!(
self.tcx.sess, span, E0384,
"re-assignment of immutable variable `{}`",
self.loan_path_to_string(lp));
let mut err = self.cannot_reassign_immutable(span,
&self.loan_path_to_string(lp),
Origin::Ast);
err.span_label(span, "re-assignment of immutable variable");
if span != assign.span {
err.span_label(assign.span, format!("first assignment to `{}`",

View File

@ -63,27 +63,6 @@ Now that the closure has its own copy of the data, there's no need to worry
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##"
This error occurs when an attempt is made to use a variable after its contents
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##"
This error occurs when an attempt is made to mutate the target of a mutable
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##"
You tried to move out of a value which was borrowed. Erroneous code example:
@ -1205,7 +656,6 @@ x.x = Some(&y);
register_diagnostics! {
// E0385, // {} in an aliasable location
E0524, // two closures require unique access to `..` at the same time
E0594, // cannot assign to {}
E0598, // lifetime of {} is too short to guarantee its contents can be...
}

View File

@ -15,6 +15,7 @@ rustc = { path = "../librustc" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
rustc_bitflags = { path = "../librustc_bitflags" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }

View File

@ -195,6 +195,50 @@ instead of using a `const fn`, or refactoring the code to a functional style to
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##"
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! {
E0524, // two closures require unique access to `..` at the same time
E0526, // shuffle indices are not constant
E0625, // thread-local statics cannot be accessed at compile-time
}

View File

@ -32,6 +32,7 @@ extern crate graphviz as dot;
#[macro_use]
extern crate rustc;
extern crate rustc_data_structures;
extern crate rustc_errors;
#[macro_use]
#[no_link]
extern crate rustc_bitflags;

View 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)
}
}

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub mod borrowck_errors;
pub mod elaborate_drops;
pub mod def_use;
pub mod patch;