about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/Cargo.lock1
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs59
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs43
-rw-r--r--src/librustc_borrowck/diagnostics.rs550
-rw-r--r--src/librustc_mir/Cargo.toml1
-rw-r--r--src/librustc_mir/diagnostics.rs551
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_mir/util/borrowck_errors.rs192
-rw-r--r--src/librustc_mir/util/mod.rs1
9 files changed, 800 insertions, 599 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index c175198c227..b5db5ce3613 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -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",
 ]
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index c8237717325..4058f3198af 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -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)))
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 9514b9b39fd..8c79534d209 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -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 `{}`",
diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs
index fea9d0d6f13..1f1fc4cc65f 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -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...
 }
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index 6e42e02d510..49e626c5400 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -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" }
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index 34170a6609c..83a8ce34c69 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -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
 }
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index ea8624930e5..143ad784171 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -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;
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
new file mode 100644
index 00000000000..9de30726586
--- /dev/null
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -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)
+    }
+}
diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs
index 4386bab38c0..f0d837e1362 100644
--- a/src/librustc_mir/util/mod.rs
+++ b/src/librustc_mir/util/mod.rs
@@ -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;