diff --git a/Cargo.lock b/Cargo.lock
index 8957e223b10..cee2b385648 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2946,7 +2946,7 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustc_borrowck"
+name = "rustc_ast_borrowck"
 version = "0.0.0"
 dependencies = [
  "graphviz 0.0.0",
@@ -2954,7 +2954,6 @@ dependencies = [
  "rustc 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
- "rustc_mir 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
@@ -3045,7 +3044,7 @@ dependencies = [
  "rustc 0.0.0",
  "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_allocator 0.0.0",
- "rustc_borrowck 0.0.0",
+ "rustc_ast_borrowck 0.0.0",
  "rustc_codegen_utils 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
@@ -3110,7 +3109,7 @@ dependencies = [
  "rustc 0.0.0",
  "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_allocator 0.0.0",
- "rustc_borrowck 0.0.0",
+ "rustc_ast_borrowck 0.0.0",
  "rustc_codegen_ssa 0.0.0",
  "rustc_codegen_utils 0.0.0",
  "rustc_data_structures 0.0.0",
diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs
index 2799f9424d9..60c24eeae7b 100644
--- a/src/librustc/middle/borrowck.rs
+++ b/src/librustc/middle/borrowck.rs
@@ -1,6 +1,4 @@
 use crate::ich::StableHashingContext;
-use crate::hir::HirId;
-use crate::util::nodemap::FxHashSet;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                            StableHasherResult};
@@ -18,7 +16,6 @@ impl_stable_hash_for!(enum self::SignalledError { SawSomeError, NoErrorsSeen });
 
 #[derive(Debug, Default, RustcEncodable, RustcDecodable)]
 pub struct BorrowCheckResult {
-    pub used_mut_nodes: FxHashSet<HirId>,
     pub signalled_any_error: SignalledError,
 }
 
@@ -27,10 +24,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
                                           hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         let BorrowCheckResult {
-            ref used_mut_nodes,
             ref signalled_any_error,
         } = *self;
-        used_mut_nodes.hash_stable(hcx, hasher);
         signalled_any_error.hash_stable(hcx, hasher);
     }
 }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 66d8a2cc111..ddad276f8a7 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -66,7 +66,6 @@ use crate::hir::def::{CtorOf, Res, DefKind, CtorKind};
 use crate::ty::adjustment;
 use crate::ty::{self, DefIdTree, Ty, TyCtxt};
 use crate::ty::fold::TypeFoldable;
-use crate::ty::layout::VariantIdx;
 
 use crate::hir::{MutImmutable, MutMutable, PatKind};
 use crate::hir::pat_util::EnumerateAndAdjustIterator;
@@ -79,7 +78,6 @@ use std::borrow::Cow;
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::indexed_vec::Idx;
 use std::rc::Rc;
 use crate::util::nodemap::ItemLocalSet;
 
@@ -198,79 +196,6 @@ pub struct cmt_<'tcx> {
 
 pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
 
-pub enum ImmutabilityBlame<'tcx> {
-    ImmLocal(hir::HirId),
-    ClosureEnv(LocalDefId),
-    LocalDeref(hir::HirId),
-    AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef)
-}
-
-impl<'tcx> cmt_<'tcx> {
-    fn resolve_field(&self, field_index: usize) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
-    {
-        let adt_def = match self.ty.sty {
-            ty::Adt(def, _) => def,
-            ty::Tuple(..) => return None,
-            // closures get `Categorization::Upvar` rather than `Categorization::Interior`
-            _ =>  bug!("interior cmt {:?} is not an ADT", self)
-        };
-        let variant_def = match self.cat {
-            Categorization::Downcast(_, variant_did) => {
-                adt_def.variant_with_id(variant_did)
-            }
-            _ => {
-                assert_eq!(adt_def.variants.len(), 1);
-                &adt_def.variants[VariantIdx::new(0)]
-            }
-        };
-        Some((adt_def, &variant_def.fields[field_index]))
-    }
-
-    pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
-        match self.cat {
-            Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) => {
-                // try to figure out where the immutable reference came from
-                match base_cmt.cat {
-                    Categorization::Local(hir_id) =>
-                        Some(ImmutabilityBlame::LocalDeref(hir_id)),
-                    Categorization::Interior(ref base_cmt, InteriorField(field_index)) => {
-                        base_cmt.resolve_field(field_index.0).map(|(adt_def, field_def)| {
-                            ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)
-                        })
-                    }
-                    Categorization::Upvar(Upvar { id, .. }) => {
-                        if let NoteClosureEnv(..) = self.note {
-                            Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id))
-                        } else {
-                            None
-                        }
-                    }
-                    _ => None
-                }
-            }
-            Categorization::Local(hir_id) => {
-                Some(ImmutabilityBlame::ImmLocal(hir_id))
-            }
-            Categorization::Rvalue(..) |
-            Categorization::Upvar(..) |
-            Categorization::Deref(_, UnsafePtr(..)) => {
-                // This should not be reachable up to inference limitations.
-                None
-            }
-            Categorization::Interior(ref base_cmt, _) |
-            Categorization::Downcast(ref base_cmt, _) |
-            Categorization::Deref(ref base_cmt, _) => {
-                base_cmt.immutability_blame()
-            }
-            Categorization::ThreadLocal(..) |
-            Categorization::StaticItem => {
-                // Do we want to do something here?
-                None
-            }
-        }
-    }
-}
-
 pub trait HirNode {
     fn hir_id(&self) -> hir::HirId;
     fn span(&self) -> Span;
diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_ast_borrowck/Cargo.toml
similarity index 87%
rename from src/librustc_borrowck/Cargo.toml
rename to src/librustc_ast_borrowck/Cargo.toml
index e9abc17202e..024b2640e1e 100644
--- a/src/librustc_borrowck/Cargo.toml
+++ b/src/librustc_ast_borrowck/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 authors = ["The Rust Project Developers"]
-name = "rustc_borrowck"
+name = "rustc_ast_borrowck"
 version = "0.0.0"
 edition = "2018"
 
 [lib]
-name = "rustc_borrowck"
+name = "rustc_ast_borrowck"
 path = "lib.rs"
 test = false
 doctest = false
@@ -18,6 +18,5 @@ syntax_pos = { path = "../libsyntax_pos" }
 # refers to the borrowck-specific graphviz adapter traits.
 dot = { path = "../libgraphviz", package = "graphviz" }
 rustc = { path = "../librustc" }
-rustc_mir = { path = "../librustc_mir" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_ast_borrowck/borrowck/README.md
similarity index 100%
rename from src/librustc_borrowck/borrowck/README.md
rename to src/librustc_ast_borrowck/borrowck/README.md
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_ast_borrowck/borrowck/check_loans.rs
similarity index 60%
rename from src/librustc_borrowck/borrowck/check_loans.rs
rename to src/librustc_ast_borrowck/borrowck/check_loans.rs
index a098cd17612..3d824ee6ce1 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_ast_borrowck/borrowck/check_loans.rs
@@ -7,8 +7,6 @@
 // 3. assignments do not affect things loaned out as immutable
 // 4. moves do not affect things loaned out in any way
 
-use UseError::*;
-
 use crate::borrowck::*;
 use crate::borrowck::InteriorKind::{InteriorElement, InteriorField};
 use rustc::middle::expr_use_visitor as euv;
@@ -20,7 +18,6 @@ use rustc::ty::{self, TyCtxt, RegionKind};
 use syntax_pos::Span;
 use rustc::hir;
 use rustc::hir::Node;
-use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
 use log::debug;
 
 use std::rc::Rc;
@@ -89,13 +86,12 @@ struct CheckLoanCtxt<'a, 'tcx> {
 impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
     fn consume(&mut self,
                consume_id: hir::HirId,
-               consume_span: Span,
+               _: Span,
                cmt: &mc::cmt_<'tcx>,
                mode: euv::ConsumeMode) {
-        debug!("consume(consume_id={}, cmt={:?}, mode={:?})",
-               consume_id, cmt, mode);
+        debug!("consume(consume_id={}, cmt={:?})", consume_id, cmt);
 
-        self.consume_common(consume_id.local_id, consume_span, cmt, mode);
+        self.consume_common(consume_id.local_id, cmt, mode);
     }
 
     fn matched_pat(&mut self,
@@ -107,12 +103,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
                    consume_pat: &hir::Pat,
                    cmt: &mc::cmt_<'tcx>,
                    mode: euv::ConsumeMode) {
-        debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})",
-               consume_pat,
-               cmt,
-               mode);
+        debug!("consume_pat(consume_pat={:?}, cmt={:?})", consume_pat, cmt);
 
-        self.consume_common(consume_pat.hir_id.local_id, consume_pat.span, cmt, mode);
+        self.consume_common(consume_pat.hir_id.local_id, cmt, mode);
     }
 
     fn borrow(&mut self,
@@ -129,11 +122,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
                bk, loan_cause);
 
         if let Some(lp) = opt_loan_path(cmt) {
-            let moved_value_use_kind = match loan_cause {
-                euv::ClosureCapture(_) => MovedInCapture,
-                _ => MovedInUse,
-            };
-            self.check_if_path_is_moved(borrow_id.local_id, borrow_span, moved_value_use_kind, &lp);
+            self.check_if_path_is_moved(borrow_id.local_id, &lp);
         }
 
         self.check_for_conflicting_loans(borrow_id.local_id);
@@ -143,7 +132,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
 
     fn mutate(&mut self,
               assignment_id: hir::HirId,
-              assignment_span: Span,
+              _: Span,
               assignee_cmt: &mc::cmt_<'tcx>,
               mode: euv::MutateMode)
     {
@@ -157,23 +146,18 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
                     // have to be *FULLY* initialized, but we still
                     // must be careful lest it contains derefs of
                     // pointers.
-                    self.check_if_assigned_path_is_moved(assignee_cmt.hir_id.local_id,
-                                                         assignment_span,
-                                                         MovedInUse,
-                                                         &lp);
+                    self.check_if_assigned_path_is_moved(assignee_cmt.hir_id.local_id, &lp);
                 }
                 MutateMode::WriteAndRead => {
                     // In a case like `path += 1`, then path must be
                     // fully initialized, since we will read it before
                     // we write it.
                     self.check_if_path_is_moved(assignee_cmt.hir_id.local_id,
-                                                assignment_span,
-                                                MovedInUse,
                                                 &lp);
                 }
             }
         }
-        self.check_assignment(assignment_id.local_id, assignment_span, assignee_cmt);
+        self.check_assignment(assignment_id.local_id, assignee_cmt);
     }
 
     fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) { }
@@ -218,12 +202,6 @@ pub fn check_loans<'a, 'tcx>(
         .consume_body(body);
 }
 
-#[derive(PartialEq)]
-enum UseError<'tcx> {
-    UseOk,
-    UseWhileBorrowed(/*loan*/Rc<LoanPath<'tcx>>, /*loan*/Span)
-}
-
 fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
                            borrow_kind2: ty::BorrowKind)
                            -> bool {
@@ -433,15 +411,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             return;
         }
 
-        if let Some(yield_span) = self.bccx
-                                      .region_scope_tree
-                                      .yield_in_scope_for_expr(scope,
-                                                               cmt.hir_id,
-                                                               self.bccx.body)
+        if let Some(_) = self.bccx.region_scope_tree
+            .yield_in_scope_for_expr(scope, cmt.hir_id, self.bccx.body)
         {
-            self.bccx.cannot_borrow_across_generator_yield(borrow_span,
-                                                           yield_span,
-                                                           Origin::Ast).emit();
             self.bccx.signal_error();
         }
     }
@@ -478,10 +450,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn report_error_if_loans_conflict(&self,
-                                          old_loan: &Loan<'tcx>,
-                                          new_loan: &Loan<'tcx>)
-                                          -> bool {
+    pub fn report_error_if_loans_conflict(
+        &self,
+        old_loan: &Loan<'tcx>,
+        new_loan: &Loan<'tcx>,
+    ) -> bool {
         //! Checks whether `old_loan` and `new_loan` can safely be issued
         //! simultaneously.
 
@@ -493,266 +466,87 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         assert!(self.bccx.region_scope_tree.scopes_intersect(old_loan.kill_scope,
                                                        new_loan.kill_scope));
 
-        let err_old_new = self.report_error_if_loan_conflicts_with_restriction(
-            old_loan, new_loan, old_loan, new_loan).err();
-        let err_new_old = self.report_error_if_loan_conflicts_with_restriction(
-            new_loan, old_loan, old_loan, new_loan).err();
-
-        match (err_old_new, err_new_old) {
-            (Some(mut err), None) | (None, Some(mut err)) => {
-                err.emit();
-                self.bccx.signal_error();
-            }
-            (Some(mut err_old), Some(mut err_new)) => {
-                err_old.emit();
-                self.bccx.signal_error();
-                err_new.cancel();
-            }
-            (None, None) => return true,
-        }
-
-        false
+        self.report_error_if_loan_conflicts_with_restriction(
+            old_loan, new_loan)
+        && self.report_error_if_loan_conflicts_with_restriction(
+                new_loan, old_loan)
     }
 
-    pub fn report_error_if_loan_conflicts_with_restriction(&self,
-                                                           loan1: &Loan<'tcx>,
-                                                           loan2: &Loan<'tcx>,
-                                                           old_loan: &Loan<'tcx>,
-                                                           new_loan: &Loan<'tcx>)
-                                                           -> Result<(), DiagnosticBuilder<'a>> {
+    pub fn report_error_if_loan_conflicts_with_restriction(
+        &self,
+        loan1: &Loan<'tcx>,
+        loan2: &Loan<'tcx>,
+    ) -> bool {
         //! Checks whether the restrictions introduced by `loan1` would
-        //! prohibit `loan2`. Returns false if an error is reported.
-
+        //! prohibit `loan2`.
         debug!("report_error_if_loan_conflicts_with_restriction(\
                 loan1={:?}, loan2={:?})",
                loan1,
                loan2);
 
         if compatible_borrow_kinds(loan1.kind, loan2.kind) {
-            return Ok(());
+            return true;
         }
 
         let loan2_base_path = owned_ptr_base_path_rc(&loan2.loan_path);
         for restr_path in &loan1.restricted_paths {
             if *restr_path != loan2_base_path { continue; }
 
-            // If new_loan is something like `x.a`, and old_loan is something like `x.b`, we would
-            // normally generate a rather confusing message (in this case, for multiple mutable
-            // borrows):
-            //
-            //     error: cannot borrow `x.b` as mutable more than once at a time
-            //     note: previous borrow of `x.a` occurs here; the mutable borrow prevents
-            //     subsequent moves, borrows, or modification of `x.a` until the borrow ends
-            //
-            // What we want to do instead is get the 'common ancestor' of the two borrow paths and
-            // use that for most of the message instead, giving is something like this:
-            //
-            //     error: cannot borrow `x` as mutable more than once at a time
-            //     note: previous borrow of `x` occurs here (through borrowing `x.a`); the mutable
-            //     borrow prevents subsequent moves, borrows, or modification of `x` until the
-            //     borrow ends
-
-            let common = new_loan.loan_path.common(&old_loan.loan_path);
-            let (nl, ol, new_loan_msg, old_loan_msg) = {
-                if new_loan.loan_path.has_fork(&old_loan.loan_path) && common.is_some() {
-                    let nl = self.bccx.loan_path_to_string(&common.unwrap());
-                    let ol = nl.clone();
-                    let new_loan_msg = self.bccx.loan_path_to_string(&new_loan.loan_path);
-                    let old_loan_msg = self.bccx.loan_path_to_string(&old_loan.loan_path);
-                    (nl, ol, new_loan_msg, old_loan_msg)
-                } else {
-                    (self.bccx.loan_path_to_string(&new_loan.loan_path),
-                     self.bccx.loan_path_to_string(&old_loan.loan_path),
-                     String::new(),
-                     String::new())
-                }
-            };
-
-            let ol_pronoun = if new_loan.loan_path == old_loan.loan_path {
-                "it".to_string()
-            } else {
-                format!("`{}`", ol)
-            };
-
-            // We want to assemble all the relevant locations for the error.
-            //
-            // 1. Where did the new loan occur.
-            //    - if due to closure creation, where was the variable used in closure?
-            // 2. Where did old loan occur.
-            // 3. Where does old loan expire.
-
-            let previous_end_span =
-                Some(self.tcx().sess.source_map().end_point(
-                        old_loan.kill_scope.span(self.tcx(), &self.bccx.region_scope_tree)));
-
-            let mut err = match (new_loan.kind, old_loan.kind) {
-                (ty::MutBorrow, ty::MutBorrow) =>
-                    self.bccx.cannot_mutably_borrow_multiply(
-                        new_loan.span, &nl, &new_loan_msg, old_loan.span, &old_loan_msg,
-                        previous_end_span, Origin::Ast),
-                (ty::UniqueImmBorrow, ty::UniqueImmBorrow) =>
-                    self.bccx.cannot_uniquely_borrow_by_two_closures(
-                        new_loan.span, &nl, old_loan.span, previous_end_span, Origin::Ast),
-                (ty::UniqueImmBorrow, _) =>
-                    self.bccx.cannot_uniquely_borrow_by_one_closure(
-                        new_loan.span, "closure", &nl, &new_loan_msg,
-                        old_loan.span, &ol_pronoun, &old_loan_msg, previous_end_span, Origin::Ast),
-                (_, ty::UniqueImmBorrow) => {
-                    let new_loan_str = &new_loan.kind.to_user_str();
-                    self.bccx.cannot_reborrow_already_uniquely_borrowed(
-                        new_loan.span, "closure", &nl, &new_loan_msg, new_loan_str,
-                        old_loan.span, &old_loan_msg, previous_end_span, "", Origin::Ast)
-                }
-                (..) =>
-                    self.bccx.cannot_reborrow_already_borrowed(
-                        new_loan.span,
-                        &nl, &new_loan_msg, &new_loan.kind.to_user_str(),
-                        old_loan.span, &ol_pronoun, &old_loan.kind.to_user_str(), &old_loan_msg,
-                        previous_end_span, Origin::Ast)
-            };
-
-            match new_loan.cause {
-                euv::ClosureCapture(span) => {
-                    err.span_label(
-                        span,
-                        format!("borrow occurs due to use of `{}` in closure", nl));
-                }
-                _ => { }
-            }
-
-            match old_loan.cause {
-                euv::ClosureCapture(span) => {
-                    err.span_label(
-                        span,
-                        format!("previous borrow occurs due to use of `{}` in closure",
-                                 ol));
-                }
-                _ => { }
-            }
-
-            return Err(err);
+            self.bccx.signal_error();
+            return false;
         }
 
-        Ok(())
+        true
     }
 
-    fn consume_common(&self,
-                      id: hir::ItemLocalId,
-                      span: Span,
-                      cmt: &mc::cmt_<'tcx>,
-                      mode: euv::ConsumeMode) {
+    fn consume_common(
+        &self,
+        id: hir::ItemLocalId,
+        cmt: &mc::cmt_<'tcx>,
+        mode: euv::ConsumeMode,
+    ) {
         if let Some(lp) = opt_loan_path(cmt) {
-            let moved_value_use_kind = match mode {
+            match mode {
                 euv::Copy => {
-                    self.check_for_copy_of_frozen_path(id, span, &lp);
-                    MovedInUse
+                    self.check_for_copy_of_frozen_path(id, &lp);
                 }
                 euv::Move(_) => {
-                    match self.move_data.kind_of_move_of_path(id, &lp) {
-                        None => {
-                            // Sometimes moves don't have a move kind;
-                            // this either means that the original move
-                            // was from something illegal to move,
-                            // or was moved from referent of an unsafe
-                            // pointer or something like that.
-                            MovedInUse
-                        }
-                        Some(move_kind) => {
-                            self.check_for_move_of_borrowed_path(id, span,
-                                                                 &lp, move_kind);
-                            if move_kind == move_data::Captured {
-                                MovedInCapture
-                            } else {
-                                MovedInUse
-                            }
-                        }
+                    // Sometimes moves aren't from a move path;
+                    // this either means that the original move
+                    // was from something illegal to move,
+                    // or was moved from referent of an unsafe
+                    // pointer or something like that.
+                    if self.move_data.is_move_path(id, &lp) {
+                        self.check_for_move_of_borrowed_path(id, &lp);
                     }
                 }
-            };
-
-            self.check_if_path_is_moved(id, span, moved_value_use_kind, &lp);
+            }
+            self.check_if_path_is_moved(id, &lp);
         }
     }
 
     fn check_for_copy_of_frozen_path(&self,
                                      id: hir::ItemLocalId,
-                                     span: Span,
                                      copy_path: &LoanPath<'tcx>) {
-        match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
-            UseOk => { }
-            UseWhileBorrowed(loan_path, loan_span) => {
-                let desc = self.bccx.loan_path_to_string(copy_path);
-                self.bccx.cannot_use_when_mutably_borrowed(
-                        span, &desc,
-                        loan_span, &self.bccx.loan_path_to_string(&loan_path),
-                        Origin::Ast)
-                    .emit();
-                self.bccx.signal_error();
-            }
-        }
+        self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow);
     }
 
     fn check_for_move_of_borrowed_path(&self,
                                        id: hir::ItemLocalId,
-                                       span: Span,
-                                       move_path: &LoanPath<'tcx>,
-                                       move_kind: move_data::MoveKind) {
+                                       move_path: &LoanPath<'tcx>) {
         // We want to detect if there are any loans at all, so we search for
         // any loans incompatible with MutBorrrow, since all other kinds of
         // loans are incompatible with that.
-        match self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow) {
-            UseOk => { }
-            UseWhileBorrowed(loan_path, loan_span) => {
-                let mut err = match move_kind {
-                    move_data::Captured => {
-                        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",
-                                    &self.bccx.loan_path_to_string(&loan_path))
-                            );
-                        err.span_label(
-                            span,
-                            "move into closure occurs here"
-                            );
-                        err
-                    }
-                    move_data::Declared |
-                    move_data::MoveExpr |
-                    move_data::MovePat => {
-                        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",
-                                    &self.bccx.loan_path_to_string(&loan_path))
-                            );
-                        err.span_label(
-                            span,
-                            format!("move out of `{}` occurs here",
-                                &self.bccx.loan_path_to_string(move_path))
-                            );
-                        err
-                    }
-                };
-
-                err.emit();
-                self.bccx.signal_error();
-            }
-        }
+        self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow);
     }
 
-    pub fn analyze_restrictions_on_use(&self,
+    fn analyze_restrictions_on_use(&self,
                                        expr_id: hir::ItemLocalId,
                                        use_path: &LoanPath<'tcx>,
-                                       borrow_kind: ty::BorrowKind)
-                                       -> UseError<'tcx> {
+                                       borrow_kind: ty::BorrowKind) {
         debug!("analyze_restrictions_on_use(expr_id={:?}, use_path={:?})",
                expr_id, use_path);
 
-        let mut ret = UseOk;
-
         let scope = region::Scope {
             id: expr_id,
             data: region::ScopeData::Node
@@ -760,38 +554,28 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         self.each_in_scope_loan_affecting_path(
             scope, use_path, |loan| {
             if !compatible_borrow_kinds(loan.kind, borrow_kind) {
-                ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
+                self.bccx.signal_error();
                 false
             } else {
                 true
             }
         });
-
-        return ret;
     }
 
     /// Reports an error if `expr` (which should be a path)
     /// is using a moved/uninitialized value
     fn check_if_path_is_moved(&self,
                               id: hir::ItemLocalId,
-                              span: Span,
-                              use_kind: MovedValueUseKind,
                               lp: &Rc<LoanPath<'tcx>>) {
-        debug!("check_if_path_is_moved(id={:?}, use_kind={:?}, lp={:?})",
-               id, use_kind, lp);
+        debug!("check_if_path_is_moved(id={:?}, lp={:?})", id, lp);
 
         // FIXME: if you find yourself tempted to cut and paste
         // the body below and then specializing the error reporting,
         // consider refactoring this instead!
 
         let base_lp = owned_ptr_base_path_rc(lp);
-        self.move_data.each_move_of(id, &base_lp, |the_move, moved_lp| {
-            self.bccx.report_use_of_moved_value(
-                span,
-                use_kind,
-                &lp,
-                the_move,
-                moved_lp);
+        self.move_data.each_move_of(id, &base_lp, |_, _| {
+            self.bccx.signal_error();
             false
         });
     }
@@ -820,8 +604,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     /// ```
     fn check_if_assigned_path_is_moved(&self,
                                        id: hir::ItemLocalId,
-                                       span: Span,
-                                       use_kind: MovedValueUseKind,
                                        lp: &Rc<LoanPath<'tcx>>)
     {
         match lp.kind {
@@ -830,8 +612,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             }
             LpDowncast(ref lp_base, _) => {
                 // assigning to `(P->Variant).f` is ok if assigning to `P` is ok
-                self.check_if_assigned_path_is_moved(id, span,
-                                                     use_kind, lp_base);
+                self.check_if_assigned_path_is_moved(id, lp_base);
             }
             LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
                 match lp_base.to_type().sty {
@@ -845,9 +626,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                         let loan_path = owned_ptr_base_path_rc(lp_base);
                         self.move_data.each_move_of(id, &loan_path, |_, _| {
                             self.bccx
-                                .report_partial_reinitialization_of_uninitialized_structure(
-                                    span,
-                                    &loan_path);
+                                .signal_error();
                             false
                         });
                         return;
@@ -856,21 +635,19 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                 }
 
                 // assigning to `P.f` is ok if assigning to `P` is ok
-                self.check_if_assigned_path_is_moved(id, span,
-                                                     use_kind, lp_base);
+                self.check_if_assigned_path_is_moved(id, lp_base);
             }
             LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) |
             LpExtend(ref lp_base, _, LpDeref(_)) => {
                 // assigning to `P[i]` requires `P` is initialized
                 // assigning to `(*P)` requires `P` is initialized
-                self.check_if_path_is_moved(id, span, use_kind, lp_base);
+                self.check_if_path_is_moved(id, lp_base);
             }
         }
     }
 
     fn check_assignment(&self,
                         assignment_id: hir::ItemLocalId,
-                        assignment_span: Span,
                         assignee_cmt: &mc::cmt_<'tcx>) {
         debug!("check_assignment(assignee_cmt={:?})", assignee_cmt);
 
@@ -880,8 +657,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                 id: assignment_id,
                 data: region::ScopeData::Node
             };
-            self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
-                self.report_illegal_mutation(assignment_span, &loan_path, loan);
+            self.each_in_scope_loan_affecting_path(scope, &loan_path, |_| {
+                self.bccx.signal_error();
                 false
             });
         }
@@ -889,30 +666,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         // Check for reassignments to (immutable) local variables. This
         // needs to be done here instead of in check_loans because we
         // depend on move data.
-        if let Categorization::Local(hir_id) = assignee_cmt.cat {
+        if let Categorization::Local(_) = assignee_cmt.cat {
             let lp = opt_loan_path(assignee_cmt).unwrap();
-            self.move_data.each_assignment_of(assignment_id, &lp, |assign| {
-                if assignee_cmt.mutbl.is_mutable() {
-                    self.bccx.used_mut_nodes.borrow_mut().insert(hir_id);
-                } else {
-                    self.bccx.report_reassigned_immutable_variable(
-                        assignment_span,
-                        &lp,
-                        assign);
+            self.move_data.each_assignment_of(assignment_id, &lp, |_| {
+                if !assignee_cmt.mutbl.is_mutable() {
+                    self.bccx.signal_error();
                 }
                 false
             });
             return
         }
     }
-
-    pub fn report_illegal_mutation(&self,
-                                   span: Span,
-                                   loan_path: &LoanPath<'tcx>,
-                                   loan: &Loan<'_>) {
-        self.bccx.cannot_assign_to_borrowed(
-            span, loan.span, &self.bccx.loan_path_to_string(loan_path), Origin::Ast)
-            .emit();
-        self.bccx.signal_error();
-    }
 }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_ast_borrowck/borrowck/gather_loans/gather_moves.rs
similarity index 54%
rename from src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
rename to src/librustc_ast_borrowck/borrowck/gather_loans/gather_moves.rs
index 658e4307348..617161109b5 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_ast_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -1,10 +1,7 @@
 //! Computes moves.
 
 use crate::borrowck::*;
-use crate::borrowck::gather_loans::move_error::MovePlace;
-use crate::borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
 use crate::borrowck::move_data::*;
-use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
@@ -12,56 +9,11 @@ use rustc::ty::{self, Ty};
 
 use std::rc::Rc;
 use syntax_pos::Span;
-use rustc::hir::*;
-use rustc::hir::Node;
 use log::debug;
 
 struct GatherMoveInfo<'c, 'tcx> {
     id: hir::ItemLocalId,
-    kind: MoveKind,
     cmt: &'c mc::cmt_<'tcx>,
-    span_path_opt: Option<MovePlace<'tcx>>,
-}
-
-/// Represents the kind of pattern
-#[derive(Debug, Clone, Copy)]
-pub enum PatternSource<'tcx> {
-    MatchExpr(&'tcx Expr),
-    LetDecl(&'tcx Local),
-    Other,
-}
-
-/// Analyzes the context where the pattern appears to determine the
-/// kind of hint we want to give. In particular, if the pattern is in a `match`
-/// or nested within other patterns, we want to suggest a `ref` binding:
-///
-///     let (a, b) = v[0]; // like the `a` and `b` patterns here
-///     match v[0] { a => ... } // or the `a` pattern here
-///
-/// But if the pattern is the outermost pattern in a `let`, we would rather
-/// suggest that the author add a `&` to the initializer:
-///
-///     let x = v[0]; // suggest `&v[0]` here
-///
-/// In this latter case, this function will return `PatternSource::LetDecl`
-/// with a reference to the let
-fn get_pattern_source<'tcx>(tcx: TyCtxt<'tcx>, pat: &Pat) -> PatternSource<'tcx> {
-
-    let parent = tcx.hir().get_parent_node(pat.hir_id);
-
-    match tcx.hir().get(parent) {
-        Node::Expr(ref e) => {
-            // the enclosing expression must be a `match` or something else
-            assert!(match e.node {
-                        ExprKind::Match(..) => true,
-                        _ => return PatternSource::Other,
-                    });
-            PatternSource::MatchExpr(e)
-        }
-        Node::Local(local) => PatternSource::LetDecl(local),
-        _ => return PatternSource::Other,
-
-    }
 }
 
 pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
@@ -69,82 +21,54 @@ pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                              var_id: hir::HirId,
                              var_ty: Ty<'tcx>) {
     let loan_path = Rc::new(LoanPath::new(LpVar(var_id), var_ty));
-    move_data.add_move(bccx.tcx, loan_path, var_id.local_id, Declared);
+    move_data.add_move(bccx.tcx, loan_path, var_id.local_id);
 }
 
 pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                        move_data: &MoveData<'tcx>,
-                                       move_error_collector: &mut MoveErrorCollector<'tcx>,
                                        move_expr_id: hir::ItemLocalId,
-                                       cmt: &mc::cmt_<'tcx>,
-                                       move_reason: euv::MoveReason) {
-    let kind = match move_reason {
-        euv::DirectRefMove | euv::PatBindingMove => MoveExpr,
-        euv::CaptureMove => Captured
-    };
+                                       cmt: &mc::cmt_<'tcx>) {
     let move_info = GatherMoveInfo {
         id: move_expr_id,
-        kind,
         cmt,
-        span_path_opt: None,
     };
-    gather_move(bccx, move_data, move_error_collector, move_info);
+    gather_move(bccx, move_data, move_info);
 }
 
 pub fn gather_move_from_pat<'a, 'c, 'tcx>(
     bccx: &BorrowckCtxt<'a, 'tcx>,
     move_data: &MoveData<'tcx>,
-    move_error_collector: &mut MoveErrorCollector<'tcx>,
     move_pat: &hir::Pat,
     cmt: &'c mc::cmt_<'tcx>,
 ) {
-    let source = get_pattern_source(bccx.tcx,move_pat);
-    let pat_span_path_opt = match move_pat.node {
-        PatKind::Binding(_, _, ident, _) => {
-            Some(MovePlace {
-                     span: move_pat.span,
-                     name: ident.name,
-                     pat_source: source,
-                 })
-        }
-        _ => None,
-    };
     let move_info = GatherMoveInfo {
         id: move_pat.hir_id.local_id,
-        kind: MovePat,
         cmt,
-        span_path_opt: pat_span_path_opt,
     };
 
-    debug!("gather_move_from_pat: move_pat={:?} source={:?}",
-           move_pat,
-           source);
+    debug!("gather_move_from_pat: move_pat={:?}", move_pat);
 
-    gather_move(bccx, move_data, move_error_collector, move_info);
+    gather_move(bccx, move_data, move_info);
 }
 
 fn gather_move<'a, 'c, 'tcx>(
     bccx: &BorrowckCtxt<'a, 'tcx>,
     move_data: &MoveData<'tcx>,
-    move_error_collector: &mut MoveErrorCollector<'tcx>,
     move_info: GatherMoveInfo<'c, 'tcx>,
 ) {
     debug!("gather_move(move_id={:?}, cmt={:?})",
            move_info.id, move_info.cmt);
 
     let potentially_illegal_move = check_and_get_illegal_move_origin(bccx, move_info.cmt);
-    if let Some(illegal_move_origin) = potentially_illegal_move {
-        debug!("illegal_move_origin={:?}", illegal_move_origin);
-        let error = MoveError::with_move_info(Rc::new(illegal_move_origin),
-                                              move_info.span_path_opt);
-        move_error_collector.add_error(error);
+    if let Some(_) = potentially_illegal_move {
+        bccx.signal_error();
         return;
     }
 
     match opt_loan_path(&move_info.cmt) {
         Some(loan_path) => {
             move_data.add_move(bccx.tcx, loan_path,
-                               move_info.id, move_info.kind);
+                               move_info.id);
         }
         None => {
             // move from rvalue or raw pointer, hence ok
diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_ast_borrowck/borrowck/gather_loans/lifetime.rs
similarity index 80%
rename from src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
rename to src/librustc_ast_borrowck/borrowck/gather_loans/lifetime.rs
index 3122a6060fb..ff7dd66793d 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc_ast_borrowck/borrowck/gather_loans/lifetime.rs
@@ -3,21 +3,17 @@
 
 use crate::borrowck::*;
 use rustc::hir::HirId;
-use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::region;
 use rustc::ty;
 
-use syntax_pos::Span;
 use log::debug;
 
 type R = Result<(),()>;
 
 pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     item_scope: region::Scope,
-                                    span: Span,
-                                    cause: euv::LoanCause,
                                     cmt: &'a mc::cmt_<'tcx>,
                                     loan_region: ty::Region<'tcx>)
                                     -> Result<(),()> {
@@ -26,12 +22,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     //! and is scope of `cmt` otherwise.
     debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})",
            cmt, loan_region);
-    let ctxt = GuaranteeLifetimeContext {bccx: bccx,
-                                         item_scope,
-                                         span,
-                                         cause,
-                                         loan_region,
-                                         cmt_original: cmt};
+    let ctxt = GuaranteeLifetimeContext { bccx, item_scope, loan_region };
     ctxt.check(cmt, None)
 }
 
@@ -44,10 +35,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx> {
     // the scope of the function body for the enclosing item
     item_scope: region::Scope,
 
-    span: Span,
-    cause: euv::LoanCause,
     loan_region: ty::Region<'tcx>,
-    cmt_original: &'a mc::cmt_<'tcx>
 }
 
 impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
@@ -85,7 +73,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
         //! Reports an error if `loan_region` is larger than `max_scope`
 
         if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
-            Err(self.report_error(err_out_of_scope(max_scope, self.loan_region, self.cause)))
+            Err(self.bccx.signal_error())
         } else {
             Ok(())
         }
@@ -122,11 +110,4 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
             }
         }
     }
-
-    fn report_error(&self, code: bckerr_code<'tcx>) {
-        self.bccx.report(BckError { cmt: self.cmt_original,
-                                    span: self.span,
-                                    cause: BorrowViolation(self.cause),
-                                    code: code });
-    }
 }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_ast_borrowck/borrowck/gather_loans/mod.rs
similarity index 73%
rename from src/librustc_borrowck/borrowck/gather_loans/mod.rs
rename to src/librustc_ast_borrowck/borrowck/gather_loans/mod.rs
index 887011d3476..16fef705ec9 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_ast_borrowck/borrowck/gather_loans/mod.rs
@@ -23,7 +23,6 @@ use restrictions::RestrictionResult;
 mod lifetime;
 mod restrictions;
 mod gather_moves;
-mod move_error;
 
 pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     body: hir::BodyId)
@@ -38,7 +37,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             data: region::ScopeData::Node
         },
         move_data: MoveData::default(),
-        move_error_collector: move_error::MoveErrorCollector::new(),
     };
 
     let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
@@ -51,7 +49,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                              Some(rvalue_promotable_map))
         .consume_body(bccx.body);
 
-    glcx.report_potential_errors();
     let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
     (all_loans, move_data)
 }
@@ -59,7 +56,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 struct GatherLoanCtxt<'a, 'tcx> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
     move_data: move_data::MoveData<'tcx>,
-    move_error_collector: move_error::MoveErrorCollector<'tcx>,
     all_loans: Vec<Loan<'tcx>>,
     /// `item_ub` is used as an upper-bound on the lifetime whenever we
     /// ask for the scope of an expression categorized as an upvar.
@@ -76,10 +72,10 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
                consume_id, cmt, mode);
 
         match mode {
-            euv::Move(move_reason) => {
+            euv::Move(_) => {
                 gather_moves::gather_move_from_expr(
-                    self.bccx, &self.move_data, &mut self.move_error_collector,
-                    consume_id.local_id, cmt, move_reason);
+                    self.bccx, &self.move_data,
+                    consume_id.local_id, cmt);
             }
             euv::Copy => { }
         }
@@ -110,13 +106,13 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
         }
 
         gather_moves::gather_move_from_pat(
-            self.bccx, &self.move_data, &mut self.move_error_collector,
+            self.bccx, &self.move_data,
             consume_pat, cmt);
     }
 
     fn borrow(&mut self,
               borrow_id: hir::HirId,
-              borrow_span: Span,
+              _: Span,
               cmt: &mc::cmt_<'tcx>,
               loan_region: ty::Region<'tcx>,
               bk: ty::BorrowKind,
@@ -128,11 +124,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
                bk, loan_cause);
 
         self.guarantee_valid(borrow_id.local_id,
-                             borrow_span,
                              cmt,
                              bk,
-                             loan_region,
-                             loan_cause);
+                             loan_region);
     }
 
     fn mutate(&mut self,
@@ -174,8 +168,6 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
 
 /// Implements the A-* rules in README.md.
 fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
-                                borrow_span: Span,
-                                loan_cause: AliasableViolationKind,
                                 cmt: &mc::cmt_<'tcx>,
                                 req_kind: ty::BorrowKind)
                                 -> Result<(),()> {
@@ -198,13 +190,9 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             // user knows what they're doing in these cases.
             Ok(())
         }
-        (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
-        (mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => {
-            bccx.report_aliasability_violation(
-                        borrow_span,
-                        loan_cause,
-                        alias_cause,
-                        cmt);
+        (mc::Aliasability::FreelyAliasable(_), ty::UniqueImmBorrow) |
+        (mc::Aliasability::FreelyAliasable(_), ty::MutBorrow) => {
+            bccx.signal_error();
             Err(())
         }
         (..) => {
@@ -215,13 +203,10 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
 /// Implements the M-* rules in README.md.
 fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
-                              borrow_span: Span,
-                              cause: AliasableViolationKind,
                               cmt: &mc::cmt_<'tcx>,
                               req_kind: ty::BorrowKind)
                               -> Result<(),()> {
-    debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}",
-           cause, cmt, req_kind);
+    debug!("check_mutability(cmt={:?} req_kind={:?}", cmt, req_kind);
     match req_kind {
         ty::UniqueImmBorrow | ty::ImmBorrow => {
             match cmt.mutbl {
@@ -239,10 +224,7 @@ fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         ty::MutBorrow => {
             // Only mutable data can be lent as mutable.
             if !cmt.mutbl.is_mutable() {
-                Err(bccx.report(BckError { span: borrow_span,
-                                           cause,
-                                           cmt,
-                                           code: err_mutbl }))
+                Err(bccx.signal_error())
             } else {
                 Ok(())
             }
@@ -268,26 +250,18 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
             // mutable - this is checked in check_loans.
         } else {
             // Check that we don't allow assignments to non-mutable data.
-            if check_mutability(self.bccx, assignment_span, MutabilityViolation,
-                                cmt, ty::MutBorrow).is_err() {
+            if check_mutability(self.bccx, cmt, ty::MutBorrow).is_err() {
                 return; // reported an error, no sense in reporting more.
             }
         }
 
         // Check that we don't allow assignments to aliasable data
-        if check_aliasability(self.bccx, assignment_span, MutabilityViolation,
-                              cmt, ty::MutBorrow).is_err() {
+        if check_aliasability(self.bccx, cmt, ty::MutBorrow).is_err() {
             return; // reported an error, no sense in reporting more.
         }
 
         match opt_lp {
             Some(lp) => {
-                if let Categorization::Local(..) = cmt.cat {
-                    // Only re-assignments to locals require it to be
-                    // mutable - this is checked in check_loans.
-                } else {
-                    self.mark_loan_path_as_mutated(&lp);
-                }
                 gather_moves::gather_assignment(self.bccx, &self.move_data,
                                                 assignment_id.local_id,
                                                 assignment_span,
@@ -306,11 +280,9 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
     /// `req_loan_map`.
     fn guarantee_valid(&mut self,
                        borrow_id: hir::ItemLocalId,
-                       borrow_span: Span,
                        cmt: &mc::cmt_<'tcx>,
                        req_kind: ty::BorrowKind,
-                       loan_region: ty::Region<'tcx>,
-                       cause: euv::LoanCause) {
+                       loan_region: ty::Region<'tcx>) {
         debug!("guarantee_valid(borrow_id={:?}, cmt={:?}, \
                 req_mutbl={:?}, loan_region={:?})",
                borrow_id,
@@ -326,27 +298,23 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
 
         // Check that the lifetime of the borrow does not exceed
         // the lifetime of the data being borrowed.
-        if lifetime::guarantee_lifetime(self.bccx, self.item_ub,
-                                        borrow_span, cause, cmt, loan_region).is_err() {
+        if lifetime::guarantee_lifetime(self.bccx, self.item_ub, cmt, loan_region).is_err() {
             return; // reported an error, no sense in reporting more.
         }
 
         // Check that we don't allow mutable borrows of non-mutable data.
-        if check_mutability(self.bccx, borrow_span, BorrowViolation(cause),
-                            cmt, req_kind).is_err() {
+        if check_mutability(self.bccx, cmt, req_kind).is_err() {
             return; // reported an error, no sense in reporting more.
         }
 
         // Check that we don't allow mutable borrows of aliasable data.
-        if check_aliasability(self.bccx, borrow_span, BorrowViolation(cause),
-                              cmt, req_kind).is_err() {
+        if check_aliasability(self.bccx, cmt, req_kind).is_err() {
             return; // reported an error, no sense in reporting more.
         }
 
         // Compute the restrictions that are required to enforce the
         // loan is safe.
-        let restr = restrictions::compute_restrictions(
-            self.bccx, borrow_span, cause, &cmt, loan_region);
+        let restr = restrictions::compute_restrictions(self.bccx, &cmt, loan_region);
 
         debug!("guarantee_valid(): restrictions={:?}", restr);
 
@@ -395,19 +363,13 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                 let kill_scope = self.compute_kill_scope(loan_scope, &loan_path);
                 debug!("kill_scope = {:?}", kill_scope);
 
-                if req_kind == ty::MutBorrow {
-                    self.mark_loan_path_as_mutated(&loan_path);
-                }
-
                 Loan {
                     index: self.all_loans.len(),
                     loan_path,
                     kind: req_kind,
                     gen_scope,
                     kill_scope,
-                    span: borrow_span,
                     restricted_paths,
-                    cause,
                 }
             }
         };
@@ -419,70 +381,6 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
         // let loan_gen_scope = loan.gen_scope;
         // let loan_kill_scope = loan.kill_scope;
         self.all_loans.push(loan);
-
-        // if loan_gen_scope != borrow_id {
-            // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls
-            //
-            // Typically, the scope of the loan includes the point at
-            // which the loan is originated. This
-            // This is a subtle case. See the test case
-            // <compile-fail/borrowck-bad-nested-calls-free.rs>
-            // to see what we are guarding against.
-
-            //let restr = restrictions::compute_restrictions(
-            //    self.bccx, borrow_span, cmt, RESTR_EMPTY);
-            //let loan = {
-            //    Loan {
-            //        index: self.all_loans.len(),
-            //        loan_path,
-            //        cmt,
-            //        mutbl: ConstMutability,
-            //        gen_scope: borrow_id,
-            //        kill_scope,
-            //        span: borrow_span,
-            //        restrictions,
-            //    }
-        // }
-    }
-
-    pub fn mark_loan_path_as_mutated(&self, loan_path: &LoanPath<'_>) {
-        //! For mutable loans of content whose mutability derives
-        //! from a local variable, mark the mutability decl as necessary.
-
-        let mut wrapped_path = Some(loan_path);
-        let mut through_borrow = false;
-
-        while let Some(current_path) = wrapped_path {
-            wrapped_path = match current_path.kind {
-                LpVar(hir_id) => {
-                    if !through_borrow {
-                        self.bccx.used_mut_nodes.borrow_mut().insert(hir_id);
-                    }
-                    None
-                }
-                LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => {
-                    self.bccx.used_mut_nodes.borrow_mut().insert(hir_id);
-                    None
-                }
-                LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) |
-                LpExtend(ref base, mc::McDeclared, LpDeref(pointer_kind)) => {
-                    if pointer_kind != mc::Unique {
-                        through_borrow = true;
-                    }
-                    Some(base)
-                }
-                LpDowncast(ref base, _) |
-                LpExtend(ref base, mc::McInherited, _) |
-                LpExtend(ref base, mc::McDeclared, _) => {
-                    Some(base)
-                }
-                LpExtend(_, mc::McImmutable, _) => {
-                    // Nothing to do.
-                    None
-                }
-            }
-        }
-
     }
 
     pub fn compute_gen_scope(&self,
@@ -532,8 +430,4 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
             loan_scope
         }
     }
-
-    pub fn report_potential_errors(&self) {
-        self.move_error_collector.report_potential_errors(self.bccx);
-    }
 }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_ast_borrowck/borrowck/gather_loans/restrictions.rs
similarity index 91%
rename from src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
rename to src/librustc_ast_borrowck/borrowck/gather_loans/restrictions.rs
index 371e6c55a73..545c27b17bd 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_ast_borrowck/borrowck/gather_loans/restrictions.rs
@@ -1,11 +1,9 @@
 //! Computes the restrictions that result from a borrow.
 
 use crate::borrowck::*;
-use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::ty;
-use syntax_pos::Span;
 use log::debug;
 
 use crate::borrowck::ToInteriorKind;
@@ -19,17 +17,10 @@ pub enum RestrictionResult<'tcx> {
 }
 
 pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
-                                      span: Span,
-                                      cause: euv::LoanCause,
                                       cmt: &mc::cmt_<'tcx>,
                                       loan_region: ty::Region<'tcx>)
                                       -> RestrictionResult<'tcx> {
-    let ctxt = RestrictionsContext {
-        bccx,
-        span,
-        cause,
-        loan_region,
-    };
+    let ctxt = RestrictionsContext { bccx, loan_region };
 
     ctxt.restrict(cmt)
 }
@@ -39,9 +30,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
 struct RestrictionsContext<'a, 'tcx> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
-    span: Span,
     loan_region: ty::Region<'tcx>,
-    cause: euv::LoanCause,
 }
 
 impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
@@ -149,13 +138,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
                     mc::BorrowedPtr(bk, lt) => {
                         // R-Deref-[Mut-]Borrowed
                         if !self.bccx.is_subregion_of(self.loan_region, lt) {
-                            self.bccx.report(
-                                BckError {
-                                    span: self.span,
-                                    cause: BorrowViolation(self.cause),
-                                    cmt: &cmt_base,
-                                    code: err_borrowed_pointer_too_short(
-                                        self.loan_region, lt)});
+                            self.bccx.signal_error();
                             return RestrictionResult::Safe;
                         }
 
diff --git a/src/librustc_ast_borrowck/borrowck/mod.rs b/src/librustc_ast_borrowck/borrowck/mod.rs
new file mode 100644
index 00000000000..f8ad8baa597
--- /dev/null
+++ b/src/librustc_ast_borrowck/borrowck/mod.rs
@@ -0,0 +1,614 @@
+//! See The Book chapter on the borrow checker for more details.
+
+#![allow(non_camel_case_types)]
+
+pub use LoanPathKind::*;
+pub use LoanPathElem::*;
+
+use InteriorKind::*;
+
+use rustc::hir::HirId;
+use rustc::hir::Node;
+use rustc::cfg;
+use rustc::middle::borrowck::{BorrowCheckResult, SignalledError};
+use rustc::hir::def_id::{DefId, LocalDefId};
+use rustc::middle::mem_categorization as mc;
+use rustc::middle::mem_categorization::Categorization;
+use rustc::middle::region;
+use rustc::middle::free_region::RegionRelations;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::query::Providers;
+
+use std::borrow::Cow;
+use std::cell::{Cell};
+use std::fmt;
+use std::rc::Rc;
+use std::hash::{Hash, Hasher};
+use log::debug;
+
+use rustc::hir;
+
+use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
+
+pub mod check_loans;
+
+pub mod gather_loans;
+
+pub mod move_data;
+
+#[derive(Clone, Copy)]
+pub struct LoanDataFlowOperator;
+
+pub type LoanDataFlow<'tcx> = DataFlowContext<'tcx, LoanDataFlowOperator>;
+
+pub fn check_crate(tcx: TyCtxt<'_>) {
+    tcx.par_body_owners(|body_owner_def_id| {
+        tcx.ensure().borrowck(body_owner_def_id);
+    });
+}
+
+pub fn provide(providers: &mut Providers<'_>) {
+    *providers = Providers {
+        borrowck,
+        ..*providers
+    };
+}
+
+/// Collection of conclusions determined via borrow checker analyses.
+pub struct AnalysisData<'tcx> {
+    pub all_loans: Vec<Loan<'tcx>>,
+    pub loans: DataFlowContext<'tcx, LoanDataFlowOperator>,
+    pub move_data: move_data::FlowedMoveData<'tcx>,
+}
+
+fn borrowck(tcx: TyCtxt<'_>, owner_def_id: DefId) -> &BorrowCheckResult {
+    assert!(tcx.use_ast_borrowck() || tcx.migrate_borrowck());
+
+    debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
+
+    let owner_id = tcx.hir().as_local_hir_id(owner_def_id).unwrap();
+
+    match tcx.hir().get(owner_id) {
+        Node::Ctor(..) => {
+            // We get invoked with anything that has MIR, but some of
+            // those things (notably the synthesized constructors from
+            // tuple structs/variants) do not have an associated body
+            // and do not need borrowchecking.
+            return tcx.arena.alloc(BorrowCheckResult {
+                signalled_any_error: SignalledError::NoErrorsSeen,
+            })
+        }
+        _ => { }
+    }
+
+    let body_id = tcx.hir().body_owned_by(owner_id);
+    let tables = tcx.typeck_tables_of(owner_def_id);
+    let region_scope_tree = tcx.region_scope_tree(owner_def_id);
+    let body = tcx.hir().body(body_id);
+    let mut bccx = BorrowckCtxt {
+        tcx,
+        tables,
+        region_scope_tree,
+        owner_def_id,
+        body,
+        signalled_any_error: Cell::new(SignalledError::NoErrorsSeen),
+    };
+
+    // Eventually, borrowck will always read the MIR, but at the
+    // moment we do not. So, for now, we always force MIR to be
+    // constructed for a given fn, since this may result in errors
+    // being reported and we want that to happen.
+    //
+    // Note that `mir_validated` is a "stealable" result; the
+    // thief, `optimized_mir()`, forces borrowck, so we know that
+    // is not yet stolen.
+    tcx.ensure().mir_validated(owner_def_id);
+
+    // option dance because you can't capture an uninitialized variable
+    // by mut-ref.
+    let mut cfg = None;
+    if let Some(AnalysisData { all_loans,
+                               loans: loan_dfcx,
+                               move_data: flowed_moves }) =
+        build_borrowck_dataflow_data(&mut bccx, false, body_id,
+                                     |bccx| {
+                                         cfg = Some(cfg::CFG::new(bccx.tcx, &body));
+                                         cfg.as_mut().unwrap()
+                                     })
+    {
+        check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
+    }
+
+    tcx.arena.alloc(BorrowCheckResult {
+        signalled_any_error: bccx.signalled_any_error.into_inner(),
+    })
+}
+
+fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tcx>,
+                                                 force_analysis: bool,
+                                                 body_id: hir::BodyId,
+                                                 get_cfg: F)
+                                                 -> Option<AnalysisData<'tcx>>
+    where F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG
+{
+    // Check the body of fn items.
+    let (all_loans, move_data) =
+        gather_loans::gather_loans_in_fn(this, body_id);
+
+    if !force_analysis && move_data.is_empty() && all_loans.is_empty() {
+        // large arrays of data inserted as constants can take a lot of
+        // time and memory to borrow-check - see issue #36799. However,
+        // they don't have places, so no borrow-check is actually needed.
+        // Recognize that case and skip borrow-checking.
+        debug!("skipping loan propagation for {:?} because of no loans", body_id);
+        return None;
+    } else {
+        debug!("propagating loans in {:?}", body_id);
+    }
+
+    let cfg = get_cfg(this);
+    let mut loan_dfcx =
+        DataFlowContext::new(this.tcx,
+                             "borrowck",
+                             Some(this.body),
+                             cfg,
+                             LoanDataFlowOperator,
+                             all_loans.len());
+    for (loan_idx, loan) in all_loans.iter().enumerate() {
+        loan_dfcx.add_gen(loan.gen_scope.item_local_id(), loan_idx);
+        loan_dfcx.add_kill(KillFrom::ScopeEnd,
+                           loan.kill_scope.item_local_id(),
+                           loan_idx);
+    }
+    loan_dfcx.add_kills_from_flow_exits(cfg);
+    loan_dfcx.propagate(cfg, this.body);
+
+    let flowed_moves = move_data::FlowedMoveData::new(move_data,
+                                                      this,
+                                                      cfg,
+                                                      this.body);
+
+    Some(AnalysisData { all_loans,
+                        loans: loan_dfcx,
+                        move_data:flowed_moves })
+}
+
+/// Accessor for introspective clients inspecting `AnalysisData` and
+/// the `BorrowckCtxt` itself , e.g., the flowgraph visualizer.
+pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body_id: hir::BodyId,
+    cfg: &cfg::CFG)
+    -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'tcx>)
+{
+    let owner_id = tcx.hir().body_owner(body_id);
+    let owner_def_id = tcx.hir().local_def_id(owner_id);
+    let tables = tcx.typeck_tables_of(owner_def_id);
+    let region_scope_tree = tcx.region_scope_tree(owner_def_id);
+    let body = tcx.hir().body(body_id);
+    let mut bccx = BorrowckCtxt {
+        tcx,
+        tables,
+        region_scope_tree,
+        owner_def_id,
+        body,
+        signalled_any_error: Cell::new(SignalledError::NoErrorsSeen),
+    };
+
+    let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg);
+    (bccx, dataflow_data.unwrap())
+}
+
+// ----------------------------------------------------------------------
+// Type definitions
+
+pub struct BorrowckCtxt<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+
+    // tables for the current thing we are checking; set to
+    // Some in `borrowck_fn` and cleared later
+    tables: &'a ty::TypeckTables<'tcx>,
+
+    region_scope_tree: &'tcx region::ScopeTree,
+
+    owner_def_id: DefId,
+
+    body: &'tcx hir::Body,
+
+    signalled_any_error: Cell<SignalledError>,
+}
+
+
+impl<'a, 'tcx: 'a> BorrowckCtxt<'a, 'tcx> {
+    fn signal_error(&self) {
+        self.signalled_any_error.set(SignalledError::SawSomeError);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Loans and loan paths
+
+/// Record of a loan that was issued.
+pub struct Loan<'tcx> {
+    index: usize,
+    loan_path: Rc<LoanPath<'tcx>>,
+    kind: ty::BorrowKind,
+    restricted_paths: Vec<Rc<LoanPath<'tcx>>>,
+
+    /// gen_scope indicates where loan is introduced. Typically the
+    /// loan is introduced at the point of the borrow, but in some
+    /// cases, notably method arguments, the loan may be introduced
+    /// only later, once it comes into scope. See also
+    /// `GatherLoanCtxt::compute_gen_scope`.
+    gen_scope: region::Scope,
+
+    /// kill_scope indicates when the loan goes out of scope. This is
+    /// either when the lifetime expires or when the local variable
+    /// which roots the loan-path goes out of scope, whichever happens
+    /// faster. See also `GatherLoanCtxt::compute_kill_scope`.
+    kill_scope: region::Scope,
+}
+
+impl<'tcx> Loan<'tcx> {
+    pub fn loan_path(&self) -> Rc<LoanPath<'tcx>> {
+        self.loan_path.clone()
+    }
+}
+
+#[derive(Eq)]
+pub struct LoanPath<'tcx> {
+    kind: LoanPathKind<'tcx>,
+    ty: Ty<'tcx>,
+}
+
+impl<'tcx> PartialEq for LoanPath<'tcx> {
+    fn eq(&self, that: &LoanPath<'tcx>) -> bool {
+        self.kind == that.kind
+    }
+}
+
+impl<'tcx> Hash for LoanPath<'tcx> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.kind.hash(state);
+    }
+}
+
+#[derive(PartialEq, Eq, Hash, Debug)]
+pub enum LoanPathKind<'tcx> {
+    LpVar(hir::HirId),                          // `x` in README.md
+    LpUpvar(ty::UpvarId),                       // `x` captured by-value into closure
+    LpDowncast(Rc<LoanPath<'tcx>>, DefId), // `x` downcast to particular enum variant
+    LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem<'tcx>)
+}
+
+impl<'tcx> LoanPath<'tcx> {
+    fn new(kind: LoanPathKind<'tcx>, ty: Ty<'tcx>) -> LoanPath<'tcx> {
+        LoanPath { kind: kind, ty: ty }
+    }
+
+    fn to_type(&self) -> Ty<'tcx> { self.ty }
+}
+
+// FIXME (pnkfelix): See discussion here
+// https://github.com/pnkfelix/rust/commit/
+//     b2b39e8700e37ad32b486b9a8409b50a8a53aa51#commitcomment-7892003
+const DOWNCAST_PRINTED_OPERATOR: &'static str = " as ";
+
+// A local, "cleaned" version of `mc::InteriorKind` that drops
+// information that is not relevant to loan-path analysis. (In
+// particular, the distinction between how precisely an array-element
+// is tracked is irrelevant here.)
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub enum InteriorKind {
+    InteriorField(mc::FieldIndex),
+    InteriorElement,
+}
+
+trait ToInteriorKind { fn cleaned(self) -> InteriorKind; }
+impl ToInteriorKind for mc::InteriorKind {
+    fn cleaned(self) -> InteriorKind {
+        match self {
+            mc::InteriorField(name) => InteriorField(name),
+            mc::InteriorElement(_) => InteriorElement,
+        }
+    }
+}
+
+// This can be:
+// - a pointer dereference (`*P` in README.md)
+// - a field reference, with an optional definition of the containing
+//   enum variant (`P.f` in README.md)
+// `DefId` is present when the field is part of struct that is in
+// a variant of an enum. For instance in:
+// `enum E { X { foo: u32 }, Y { foo: u32 }}`
+// each `foo` is qualified by the definitition id of the variant (`X` or `Y`).
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum LoanPathElem<'tcx> {
+    LpDeref(mc::PointerKind<'tcx>),
+    LpInterior(Option<DefId>, InteriorKind),
+}
+
+fn closure_to_block(closure_id: LocalDefId, tcx: TyCtxt<'_>) -> HirId {
+    let closure_id = tcx.hir().local_def_id_to_hir_id(closure_id);
+    match tcx.hir().get(closure_id) {
+        Node::Expr(expr) => match expr.node {
+            hir::ExprKind::Closure(.., body_id, _, _) => {
+                body_id.hir_id
+            }
+            _ => {
+                bug!("encountered non-closure id: {}", closure_id)
+            }
+        },
+        _ => bug!("encountered non-expr id: {}", closure_id)
+    }
+}
+
+impl<'a, 'tcx> LoanPath<'tcx> {
+    pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::Scope {
+        match self.kind {
+            LpVar(hir_id) => {
+                bccx.region_scope_tree.var_scope(hir_id.local_id)
+            }
+            LpUpvar(upvar_id) => {
+                let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx);
+                region::Scope { id: block_id.local_id, data: region::ScopeData::Node }
+            }
+            LpDowncast(ref base, _) |
+            LpExtend(ref base, ..) => base.kill_scope(bccx),
+        }
+    }
+}
+
+// Avoid "cannot borrow immutable field `self.x` as mutable" as that implies that a field *can* be
+// mutable independently of the struct it belongs to. (#35937)
+pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt_<'tcx>) -> (Option<Rc<LoanPath<'tcx>>>, bool) {
+    let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
+
+    match cmt.cat {
+        Categorization::Rvalue(..) |
+        Categorization::ThreadLocal(..) |
+        Categorization::StaticItem => {
+            (None, false)
+        }
+
+        Categorization::Local(id) => {
+            (Some(new_lp(LpVar(id))), false)
+        }
+
+        Categorization::Upvar(mc::Upvar { id, .. }) => {
+            (Some(new_lp(LpUpvar(id))), false)
+        }
+
+        Categorization::Deref(ref cmt_base, pk) => {
+            let lp = opt_loan_path_is_field(cmt_base);
+            (lp.0.map(|lp| {
+                new_lp(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
+            }), lp.1)
+        }
+
+        Categorization::Interior(ref cmt_base, ik) => {
+            (opt_loan_path(cmt_base).map(|lp| {
+                let opt_variant_id = match cmt_base.cat {
+                    Categorization::Downcast(_, did) =>  Some(did),
+                    _ => None
+                };
+                new_lp(LpExtend(lp, cmt.mutbl, LpInterior(opt_variant_id, ik.cleaned())))
+            }), true)
+        }
+
+        Categorization::Downcast(ref cmt_base, variant_def_id) => {
+            let lp = opt_loan_path_is_field(cmt_base);
+            (lp.0.map(|lp| {
+                new_lp(LpDowncast(lp, variant_def_id))
+            }), lp.1)
+        }
+    }
+}
+
+/// Computes the `LoanPath` (if any) for a `cmt`.
+/// Note that this logic is somewhat duplicated in
+/// the method `compute()` found in `gather_loans::restrictions`,
+/// which allows it to share common loan path pieces as it
+/// traverses the CMT.
+pub fn opt_loan_path<'tcx>(cmt: &mc::cmt_<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {
+    opt_loan_path_is_field(cmt).0
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Misc
+
+impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
+    pub fn is_subregion_of(&self,
+                           r_sub: ty::Region<'tcx>,
+                           r_sup: ty::Region<'tcx>)
+                           -> bool
+    {
+        let region_rels = RegionRelations::new(self.tcx,
+                                               self.owner_def_id,
+                                               &self.region_scope_tree,
+                                               &self.tables.free_region_map);
+        region_rels.is_subregion_of(r_sub, r_sup)
+    }
+
+    pub fn append_loan_path_to_string(&self,
+                                      loan_path: &LoanPath<'tcx>,
+                                      out: &mut String) {
+        match loan_path.kind {
+            LpUpvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id: id }, closure_expr_id: _ }) => {
+                out.push_str(&self.tcx.hir().name(id).as_str());
+            }
+            LpVar(id) => {
+                out.push_str(&self.tcx.hir().name(id).as_str());
+            }
+
+            LpDowncast(ref lp_base, variant_def_id) => {
+                out.push('(');
+                self.append_loan_path_to_string(&lp_base, out);
+                out.push_str(DOWNCAST_PRINTED_OPERATOR);
+                out.push_str(&self.tcx.def_path_str(variant_def_id));
+                out.push(')');
+            }
+
+            LpExtend(ref lp_base, _, LpInterior(_, InteriorField(mc::FieldIndex(_, info)))) => {
+                self.append_autoderefd_loan_path_to_string(&lp_base, out);
+                out.push('.');
+                out.push_str(&info.as_str());
+            }
+
+            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => {
+                self.append_autoderefd_loan_path_to_string(&lp_base, out);
+                out.push_str("[..]");
+            }
+
+            LpExtend(ref lp_base, _, LpDeref(_)) => {
+                out.push('*');
+                self.append_loan_path_to_string(&lp_base, out);
+            }
+        }
+    }
+
+    pub fn append_autoderefd_loan_path_to_string(&self,
+                                                 loan_path: &LoanPath<'tcx>,
+                                                 out: &mut String) {
+        match loan_path.kind {
+            LpExtend(ref lp_base, _, LpDeref(_)) => {
+                // For a path like `(*x).f` or `(*x)[3]`, autoderef
+                // rules would normally allow users to omit the `*x`.
+                // So just serialize such paths to `x.f` or x[3]` respectively.
+                self.append_autoderefd_loan_path_to_string(&lp_base, out)
+            }
+
+            LpDowncast(ref lp_base, variant_def_id) => {
+                out.push('(');
+                self.append_autoderefd_loan_path_to_string(&lp_base, out);
+                out.push_str(DOWNCAST_PRINTED_OPERATOR);
+                out.push_str(&self.tcx.def_path_str(variant_def_id));
+                out.push(')');
+            }
+
+            LpVar(..) | LpUpvar(..) | LpExtend(.., LpInterior(..)) => {
+                self.append_loan_path_to_string(loan_path, out)
+            }
+        }
+    }
+
+    pub fn loan_path_to_string(&self, loan_path: &LoanPath<'tcx>) -> String {
+        let mut result = String::new();
+        self.append_loan_path_to_string(loan_path, &mut result);
+        result
+    }
+
+    pub fn cmt_to_cow_str(&self, cmt: &mc::cmt_<'tcx>) -> Cow<'static, str> {
+        cmt.descriptive_string(self.tcx)
+    }
+
+    pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
+        match opt_loan_path(cmt) {
+            Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)),
+            None => self.cmt_to_cow_str(cmt).into_owned(),
+        }
+    }
+}
+
+impl BitwiseOperator for LoanDataFlowOperator {
+    #[inline]
+    fn join(&self, succ: usize, pred: usize) -> usize {
+        succ | pred // loans from both preds are in scope
+    }
+}
+
+impl DataFlowOperator for LoanDataFlowOperator {
+    #[inline]
+    fn initial_value(&self) -> bool {
+        false // no loans in scope by default
+    }
+}
+
+impl fmt::Debug for InteriorKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            InteriorField(mc::FieldIndex(_, info)) => write!(f, "{}", info),
+            InteriorElement => write!(f, "[]"),
+        }
+    }
+}
+
+impl<'tcx> fmt::Debug for Loan<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Loan_{}({:?}, {:?}, {:?}-{:?}, {:?})",
+               self.index,
+               self.loan_path,
+               self.kind,
+               self.gen_scope,
+               self.kill_scope,
+               self.restricted_paths)
+    }
+}
+
+impl<'tcx> fmt::Debug for LoanPath<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.kind {
+            LpVar(id) => {
+                write!(f, "$({})", ty::tls::with(|tcx| tcx.hir().node_to_string(id)))
+            }
+
+            LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath {hir_id: var_id}, closure_expr_id }) => {
+                let s = ty::tls::with(|tcx| {
+                    tcx.hir().node_to_string(var_id)
+                });
+                write!(f, "$({} captured by id={:?})", s, closure_expr_id)
+            }
+
+            LpDowncast(ref lp, variant_def_id) => {
+                let variant_str = if variant_def_id.is_local() {
+                    ty::tls::with(|tcx| tcx.def_path_str(variant_def_id))
+                } else {
+                    format!("{:?}", variant_def_id)
+                };
+                write!(f, "({:?}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
+            }
+
+            LpExtend(ref lp, _, LpDeref(_)) => {
+                write!(f, "{:?}.*", lp)
+            }
+
+            LpExtend(ref lp, _, LpInterior(_, ref interior)) => {
+                write!(f, "{:?}.{:?}", lp, interior)
+            }
+        }
+    }
+}
+
+impl<'tcx> fmt::Display for LoanPath<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.kind {
+            LpVar(id) => {
+                write!(f, "$({})", ty::tls::with(|tcx| tcx.hir().hir_to_user_string(id)))
+            }
+
+            LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => {
+                let s = ty::tls::with(|tcx| {
+                    tcx.hir().node_to_string(hir_id)
+                });
+                write!(f, "$({} captured by closure)", s)
+            }
+
+            LpDowncast(ref lp, variant_def_id) => {
+                let variant_str = if variant_def_id.is_local() {
+                    ty::tls::with(|tcx| tcx.def_path_str(variant_def_id))
+                } else {
+                    format!("{:?}", variant_def_id)
+                };
+                write!(f, "({}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
+            }
+
+            LpExtend(ref lp, _, LpDeref(_)) => {
+                write!(f, "{}.*", lp)
+            }
+
+            LpExtend(ref lp, _, LpInterior(_, ref interior)) => {
+                write!(f, "{}.{:?}", lp, interior)
+            }
+        }
+    }
+}
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_ast_borrowck/borrowck/move_data.rs
similarity index 96%
rename from src/librustc_borrowck/borrowck/move_data.rs
rename to src/librustc_ast_borrowck/borrowck/move_data.rs
index 9feea64f182..887a0e2f20e 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_ast_borrowck/borrowck/move_data.rs
@@ -1,8 +1,6 @@
 //! Data structures used for tracking moves. Please see the extensive
 //! comments in the section "Moves and initialization" in `README.md`.
 
-pub use MoveKind::*;
-
 use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
 
 use crate::borrowck::*;
@@ -101,13 +99,6 @@ pub struct MovePath<'tcx> {
     pub next_sibling: MovePathIndex,
 }
 
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum MoveKind {
-    Declared,   // When declared, variables start out "moved".
-    MoveExpr,   // Expression or binding that moves a variable
-    MovePat,    // By-move binding
-    Captured    // Closure creation that moves a value
-}
 
 #[derive(Copy, Clone)]
 pub struct Move {
@@ -117,9 +108,6 @@ pub struct Move {
     /// ID of node that is doing the move.
     pub id: hir::ItemLocalId,
 
-    /// Kind of move, for error messages.
-    pub kind: MoveKind,
-
     /// Next node in linked list of moves from `path`, or `InvalidMoveIndex`
     pub next_move: MoveIndex
 }
@@ -315,7 +303,6 @@ impl MoveData<'tcx> {
         tcx: TyCtxt<'tcx>,
         orig_lp: Rc<LoanPath<'tcx>>,
         id: hir::ItemLocalId,
-        kind: MoveKind,
     ) {
         // Moving one union field automatically moves all its fields. Also move siblings of
         // all parent union fields, moves do not propagate upwards automatically.
@@ -331,7 +318,7 @@ impl MoveData<'tcx> {
                             let sibling_lp_kind =
                                 LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
                             let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err));
-                            self.add_move_helper(tcx, sibling_lp, id, kind);
+                            self.add_move_helper(tcx, sibling_lp, id);
                         }
                     }
                 }
@@ -339,7 +326,7 @@ impl MoveData<'tcx> {
             lp = base_lp.clone();
         }
 
-        self.add_move_helper(tcx, orig_lp, id, kind);
+        self.add_move_helper(tcx, orig_lp, id);
     }
 
     fn add_move_helper(
@@ -347,12 +334,8 @@ impl MoveData<'tcx> {
         tcx: TyCtxt<'tcx>,
         lp: Rc<LoanPath<'tcx>>,
         id: hir::ItemLocalId,
-        kind: MoveKind,
     ) {
-        debug!("add_move(lp={:?}, id={:?}, kind={:?})",
-               lp,
-               id,
-               kind);
+        debug!("add_move(lp={:?}, id={:?})", lp, id);
 
         let path_index = self.move_path(tcx, lp);
         let move_index = MoveIndex(self.moves.borrow().len());
@@ -363,7 +346,6 @@ impl MoveData<'tcx> {
         self.moves.borrow_mut().push(Move {
             path: path_index,
             id,
-            kind,
             next_move,
         });
     }
@@ -611,19 +593,16 @@ impl<'tcx> FlowedMoveData<'tcx> {
         }
     }
 
-    pub fn kind_of_move_of_path(&self,
-                                id: hir::ItemLocalId,
-                                loan_path: &Rc<LoanPath<'tcx>>)
-                                -> Option<MoveKind> {
+    pub fn is_move_path(&self, id: hir::ItemLocalId, loan_path: &Rc<LoanPath<'tcx>>) -> bool {
         //! Returns the kind of a move of `loan_path` by `id`, if one exists.
 
-        let mut ret = None;
+        let mut ret = false;
         if let Some(loan_path_index) = self.move_data.path_map.borrow().get(&*loan_path) {
             self.dfcx_moves.each_gen_bit(id, |move_index| {
                 let the_move = self.move_data.moves.borrow();
                 let the_move = (*the_move)[move_index];
                 if the_move.path == *loan_path_index {
-                    ret = Some(the_move.kind);
+                    ret = true;
                     false
                 } else {
                     true
diff --git a/src/librustc_borrowck/dataflow.rs b/src/librustc_ast_borrowck/dataflow.rs
similarity index 100%
rename from src/librustc_borrowck/dataflow.rs
rename to src/librustc_ast_borrowck/dataflow.rs
diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_ast_borrowck/graphviz.rs
similarity index 100%
rename from src/librustc_borrowck/graphviz.rs
rename to src/librustc_ast_borrowck/graphviz.rs
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_ast_borrowck/lib.rs
similarity index 100%
rename from src/librustc_borrowck/lib.rs
rename to src/librustc_ast_borrowck/lib.rs
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
deleted file mode 100644
index 58be2cf76c7..00000000000
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-use crate::borrowck::BorrowckCtxt;
-use rustc::middle::mem_categorization as mc;
-use rustc::middle::mem_categorization::Categorization;
-use rustc::middle::mem_categorization::NoteClosureEnv;
-use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
-use rustc::ty;
-use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
-use syntax::ast;
-use syntax_pos;
-use errors::{DiagnosticBuilder, Applicability};
-use crate::borrowck::gather_loans::gather_moves::PatternSource;
-use log::debug;
-
-pub struct MoveErrorCollector<'tcx> {
-    errors: Vec<MoveError<'tcx>>
-}
-
-impl<'tcx> MoveErrorCollector<'tcx> {
-    pub fn new() -> MoveErrorCollector<'tcx> {
-        MoveErrorCollector {
-            errors: Vec::new()
-        }
-    }
-
-    pub fn add_error(&mut self, error: MoveError<'tcx>) {
-        self.errors.push(error);
-    }
-
-    pub fn report_potential_errors<'a>(&self, bccx: &BorrowckCtxt<'a, 'tcx>) {
-        report_move_errors(bccx, &self.errors)
-    }
-}
-
-pub struct MoveError<'tcx> {
-    move_from: mc::cmt<'tcx>,
-    move_to: Option<MovePlace<'tcx>>
-}
-
-impl<'tcx> MoveError<'tcx> {
-    pub fn with_move_info(move_from: mc::cmt<'tcx>,
-                          move_to: Option<MovePlace<'tcx>>)
-                          -> MoveError<'tcx> {
-        MoveError {
-            move_from,
-            move_to,
-        }
-    }
-}
-
-#[derive(Clone)]
-pub struct MovePlace<'tcx> {
-    pub span: syntax_pos::Span,
-    pub name: ast::Name,
-    pub pat_source: PatternSource<'tcx>,
-}
-
-pub struct GroupedMoveErrors<'tcx> {
-    move_from: mc::cmt<'tcx>,
-    move_to_places: Vec<MovePlace<'tcx>>
-}
-
-fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveError<'tcx>]) {
-    let grouped_errors = group_errors_with_same_origin(errors);
-    for error in &grouped_errors {
-        let mut err = report_cannot_move_out_of(bccx, error.move_from.clone());
-        let mut is_first_note = true;
-        match error.move_to_places.get(0) {
-            Some(&MovePlace { pat_source: PatternSource::LetDecl(ref e), .. }) => {
-                // ignore patterns that are found at the top-level of a `let`;
-                // see `get_pattern_source()` for details
-                let initializer =
-                    e.init.as_ref().expect("should have an initializer to get an error");
-                if let Ok(snippet) = bccx.tcx.sess.source_map().span_to_snippet(initializer.span) {
-                    err.span_suggestion(
-                        initializer.span,
-                        "consider using a reference instead",
-                        format!("&{}", snippet),
-                        Applicability::MaybeIncorrect // using a reference may not be the right fix
-                    );
-                }
-            }
-            _ => {
-                for move_to in &error.move_to_places {
-
-                    err = note_move_destination(err, move_to.span, move_to.name, is_first_note);
-                    is_first_note = false;
-                }
-            }
-        }
-        if let NoteClosureEnv(upvar_id) = error.move_from.note {
-            err.span_label(bccx.tcx.hir().span(upvar_id.var_path.hir_id),
-                           "captured outer variable");
-        }
-        err.emit();
-        bccx.signal_error();
-    }
-}
-
-fn group_errors_with_same_origin<'tcx>(errors: &[MoveError<'tcx>])
-                                       -> Vec<GroupedMoveErrors<'tcx>> {
-    let mut grouped_errors = Vec::new();
-    for error in errors {
-        append_to_grouped_errors(&mut grouped_errors, error)
-    }
-    return grouped_errors;
-
-    fn append_to_grouped_errors<'tcx>(grouped_errors: &mut Vec<GroupedMoveErrors<'tcx>>,
-                                      error: &MoveError<'tcx>) {
-        let move_from_id = error.move_from.hir_id;
-        debug!("append_to_grouped_errors(move_from_id={:?})", move_from_id);
-        let move_to = if error.move_to.is_some() {
-            vec![error.move_to.clone().unwrap()]
-        } else {
-            Vec::new()
-        };
-        for ge in &mut *grouped_errors {
-            if move_from_id == ge.move_from.hir_id && error.move_to.is_some() {
-                debug!("appending move_to to list");
-                ge.move_to_places.extend(move_to);
-                return
-            }
-        }
-        debug!("found a new move from location");
-        grouped_errors.push(GroupedMoveErrors {
-            move_from: error.move_from.clone(),
-            move_to_places: move_to
-        })
-    }
-}
-
-// (keep in sync with gather_moves::check_and_get_illegal_move_origin )
-fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>,
-                                       move_from: mc::cmt<'tcx>)
-                                       -> DiagnosticBuilder<'a> {
-    match move_from.cat {
-        Categorization::Deref(_, mc::BorrowedPtr(..)) |
-        Categorization::Deref(_, mc::UnsafePtr(..)) |
-        Categorization::Deref(_, mc::Unique) |
-        Categorization::ThreadLocal(..) |
-        Categorization::StaticItem => {
-            bccx.cannot_move_out_of(
-                move_from.span, &move_from.descriptive_string(bccx.tcx), Origin::Ast)
-        }
-        Categorization::Interior(ref b, mc::InteriorElement(ik)) => {
-            bccx.cannot_move_out_of_interior_noncopy(
-                move_from.span, b.ty, Some(ik == Kind::Index), Origin::Ast)
-        }
-
-        Categorization::Downcast(ref b, _) |
-        Categorization::Interior(ref b, mc::InteriorField(_)) => {
-            match b.ty.sty {
-                ty::Adt(def, _) if def.has_dtor(bccx.tcx) => {
-                    bccx.cannot_move_out_of_interior_of_drop(
-                        move_from.span, b.ty, Origin::Ast)
-                }
-                _ => {
-                    span_bug!(move_from.span, "this path should not cause illegal move");
-                }
-            }
-        }
-
-        Categorization::Rvalue(..) |
-        Categorization::Local(..) |
-        Categorization::Upvar(..) => {
-            span_bug!(move_from.span, "this path should not cause illegal move");
-        }
-    }
-}
-
-fn note_move_destination(mut err: DiagnosticBuilder<'_>,
-                         move_to_span: syntax_pos::Span,
-                         pat_name: ast::Name,
-                         is_first_note: bool) -> DiagnosticBuilder<'_> {
-    if is_first_note {
-        err.span_label(
-            move_to_span,
-            format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`",
-                     pat_name));
-        err
-    } else {
-        err.span_label(move_to_span,
-                      format!("...and here (use `ref {0}` or `ref mut {0}`)",
-                               pat_name));
-        err
-    }
-}
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
deleted file mode 100644
index 9a581cb03ec..00000000000
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ /dev/null
@@ -1,1573 +0,0 @@
-//! See The Book chapter on the borrow checker for more details.
-
-#![allow(non_camel_case_types)]
-
-pub use LoanPathKind::*;
-pub use LoanPathElem::*;
-pub use bckerr_code::*;
-pub use AliasableViolationKind::*;
-pub use MovedValueUseKind::*;
-
-use InteriorKind::*;
-
-use rustc::hir::HirId;
-use rustc::hir::Node;
-use rustc::hir::map::blocks::FnLikeNode;
-use rustc::cfg;
-use rustc::middle::borrowck::{BorrowCheckResult, SignalledError};
-use rustc::hir::def_id::{DefId, LocalDefId};
-use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::mem_categorization as mc;
-use rustc::middle::mem_categorization::Categorization;
-use rustc::middle::mem_categorization::ImmutabilityBlame;
-use rustc::middle::region;
-use rustc::middle::free_region::RegionRelations;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::query::Providers;
-use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
-use rustc_mir::util::suggest_ref_mut;
-use rustc::util::nodemap::FxHashSet;
-
-use std::borrow::Cow;
-use std::cell::{Cell, RefCell};
-use std::fmt;
-use std::rc::Rc;
-use std::hash::{Hash, Hasher};
-use syntax::source_map::DesugaringKind;
-use syntax_pos::{MultiSpan, Span};
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
-use log::debug;
-
-use rustc::hir;
-
-use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom};
-
-pub mod check_loans;
-
-pub mod gather_loans;
-
-pub mod move_data;
-
-#[derive(Clone, Copy)]
-pub struct LoanDataFlowOperator;
-
-pub type LoanDataFlow<'tcx> = DataFlowContext<'tcx, LoanDataFlowOperator>;
-
-pub fn check_crate(tcx: TyCtxt<'_>) {
-    tcx.par_body_owners(|body_owner_def_id| {
-        tcx.ensure().borrowck(body_owner_def_id);
-    });
-}
-
-pub fn provide(providers: &mut Providers<'_>) {
-    *providers = Providers {
-        borrowck,
-        ..*providers
-    };
-}
-
-/// Collection of conclusions determined via borrow checker analyses.
-pub struct AnalysisData<'tcx> {
-    pub all_loans: Vec<Loan<'tcx>>,
-    pub loans: DataFlowContext<'tcx, LoanDataFlowOperator>,
-    pub move_data: move_data::FlowedMoveData<'tcx>,
-}
-
-fn borrowck(tcx: TyCtxt<'_>, owner_def_id: DefId) -> &BorrowCheckResult {
-    assert!(tcx.use_ast_borrowck() || tcx.migrate_borrowck());
-
-    debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
-
-    let owner_id = tcx.hir().as_local_hir_id(owner_def_id).unwrap();
-
-    match tcx.hir().get(owner_id) {
-        Node::Ctor(..) => {
-            // We get invoked with anything that has MIR, but some of
-            // those things (notably the synthesized constructors from
-            // tuple structs/variants) do not have an associated body
-            // and do not need borrowchecking.
-            return tcx.arena.alloc(BorrowCheckResult {
-                used_mut_nodes: Default::default(),
-                signalled_any_error: SignalledError::NoErrorsSeen,
-            })
-        }
-        _ => { }
-    }
-
-    let body_id = tcx.hir().body_owned_by(owner_id);
-    let tables = tcx.typeck_tables_of(owner_def_id);
-    let region_scope_tree = tcx.region_scope_tree(owner_def_id);
-    let body = tcx.hir().body(body_id);
-    let mut bccx = BorrowckCtxt {
-        tcx,
-        tables,
-        region_scope_tree,
-        owner_def_id,
-        body,
-        used_mut_nodes: Default::default(),
-        signalled_any_error: Cell::new(SignalledError::NoErrorsSeen),
-    };
-
-    // Eventually, borrowck will always read the MIR, but at the
-    // moment we do not. So, for now, we always force MIR to be
-    // constructed for a given fn, since this may result in errors
-    // being reported and we want that to happen.
-    //
-    // Note that `mir_validated` is a "stealable" result; the
-    // thief, `optimized_mir()`, forces borrowck, so we know that
-    // is not yet stolen.
-    tcx.ensure().mir_validated(owner_def_id);
-
-    // option dance because you can't capture an uninitialized variable
-    // by mut-ref.
-    let mut cfg = None;
-    if let Some(AnalysisData { all_loans,
-                               loans: loan_dfcx,
-                               move_data: flowed_moves }) =
-        build_borrowck_dataflow_data(&mut bccx, false, body_id,
-                                     |bccx| {
-                                         cfg = Some(cfg::CFG::new(bccx.tcx, &body));
-                                         cfg.as_mut().unwrap()
-                                     })
-    {
-        check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
-    }
-
-    tcx.arena.alloc(BorrowCheckResult {
-        used_mut_nodes: bccx.used_mut_nodes.into_inner(),
-        signalled_any_error: bccx.signalled_any_error.into_inner(),
-    })
-}
-
-fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(
-    this: &mut BorrowckCtxt<'a, 'tcx>,
-    force_analysis: bool,
-    body_id: hir::BodyId,
-    get_cfg: F,
-) -> Option<AnalysisData<'tcx>>
-where
-    F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG,
-{
-    // Check the body of fn items.
-    let (all_loans, move_data) =
-        gather_loans::gather_loans_in_fn(this, body_id);
-
-    if !force_analysis && move_data.is_empty() && all_loans.is_empty() {
-        // large arrays of data inserted as constants can take a lot of
-        // time and memory to borrow-check - see issue #36799. However,
-        // they don't have places, so no borrow-check is actually needed.
-        // Recognize that case and skip borrow-checking.
-        debug!("skipping loan propagation for {:?} because of no loans", body_id);
-        return None;
-    } else {
-        debug!("propagating loans in {:?}", body_id);
-    }
-
-    let cfg = get_cfg(this);
-    let mut loan_dfcx =
-        DataFlowContext::new(this.tcx,
-                             "borrowck",
-                             Some(this.body),
-                             cfg,
-                             LoanDataFlowOperator,
-                             all_loans.len());
-    for (loan_idx, loan) in all_loans.iter().enumerate() {
-        loan_dfcx.add_gen(loan.gen_scope.item_local_id(), loan_idx);
-        loan_dfcx.add_kill(KillFrom::ScopeEnd,
-                           loan.kill_scope.item_local_id(),
-                           loan_idx);
-    }
-    loan_dfcx.add_kills_from_flow_exits(cfg);
-    loan_dfcx.propagate(cfg, this.body);
-
-    let flowed_moves = move_data::FlowedMoveData::new(move_data,
-                                                      this,
-                                                      cfg,
-                                                      this.body);
-
-    Some(AnalysisData { all_loans,
-                        loans: loan_dfcx,
-                        move_data:flowed_moves })
-}
-
-/// Accessor for introspective clients inspecting `AnalysisData` and
-/// the `BorrowckCtxt` itself , e.g., the flowgraph visualizer.
-pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body_id: hir::BodyId,
-    cfg: &cfg::CFG,
-) -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'tcx>) {
-    let owner_id = tcx.hir().body_owner(body_id);
-    let owner_def_id = tcx.hir().local_def_id(owner_id);
-    let tables = tcx.typeck_tables_of(owner_def_id);
-    let region_scope_tree = tcx.region_scope_tree(owner_def_id);
-    let body = tcx.hir().body(body_id);
-    let mut bccx = BorrowckCtxt {
-        tcx,
-        tables,
-        region_scope_tree,
-        owner_def_id,
-        body,
-        used_mut_nodes: Default::default(),
-        signalled_any_error: Cell::new(SignalledError::NoErrorsSeen),
-    };
-
-    let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg);
-    (bccx, dataflow_data.unwrap())
-}
-
-// ----------------------------------------------------------------------
-// Type definitions
-
-pub struct BorrowckCtxt<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-
-    // tables for the current thing we are checking; set to
-    // Some in `borrowck_fn` and cleared later
-    tables: &'a ty::TypeckTables<'tcx>,
-
-    region_scope_tree: &'tcx region::ScopeTree,
-
-    owner_def_id: DefId,
-
-    body: &'tcx hir::Body,
-
-    used_mut_nodes: RefCell<FxHashSet<HirId>>,
-
-    signalled_any_error: Cell<SignalledError>,
-}
-
-impl BorrowckCtxt<'_, 'tcx> {
-    fn signal_error(&self) {
-        self.signalled_any_error.set(SignalledError::SawSomeError);
-    }
-}
-
-impl BorrowckErrors<'a> for &'a BorrowckCtxt<'_, 'tcx> {
-    fn struct_span_err_with_code<S: Into<MultiSpan>>(self,
-                                                     sp: S,
-                                                     msg: &str,
-                                                     code: DiagnosticId)
-                                                     -> DiagnosticBuilder<'a>
-    {
-        self.tcx.sess.struct_span_err_with_code(sp, msg, code)
-    }
-
-    fn struct_span_err<S: Into<MultiSpan>>(self,
-                                           sp: S,
-                                           msg: &str)
-                                           -> DiagnosticBuilder<'a>
-    {
-        self.tcx.sess.struct_span_err(sp, msg)
-    }
-
-    fn cancel_if_wrong_origin(self,
-                              mut diag: DiagnosticBuilder<'a>,
-                              o: Origin)
-                              -> DiagnosticBuilder<'a>
-    {
-        if !o.should_emit_errors(self.tcx.borrowck_mode()) {
-            self.tcx.sess.diagnostic().cancel(&mut diag);
-        }
-        diag
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Loans and loan paths
-
-/// Record of a loan that was issued.
-pub struct Loan<'tcx> {
-    index: usize,
-    loan_path: Rc<LoanPath<'tcx>>,
-    kind: ty::BorrowKind,
-    restricted_paths: Vec<Rc<LoanPath<'tcx>>>,
-
-    /// gen_scope indicates where loan is introduced. Typically the
-    /// loan is introduced at the point of the borrow, but in some
-    /// cases, notably method arguments, the loan may be introduced
-    /// only later, once it comes into scope. See also
-    /// `GatherLoanCtxt::compute_gen_scope`.
-    gen_scope: region::Scope,
-
-    /// kill_scope indicates when the loan goes out of scope. This is
-    /// either when the lifetime expires or when the local variable
-    /// which roots the loan-path goes out of scope, whichever happens
-    /// faster. See also `GatherLoanCtxt::compute_kill_scope`.
-    kill_scope: region::Scope,
-    span: Span,
-    cause: euv::LoanCause,
-}
-
-impl<'tcx> Loan<'tcx> {
-    pub fn loan_path(&self) -> Rc<LoanPath<'tcx>> {
-        self.loan_path.clone()
-    }
-}
-
-#[derive(Eq)]
-pub struct LoanPath<'tcx> {
-    kind: LoanPathKind<'tcx>,
-    ty: Ty<'tcx>,
-}
-
-impl<'tcx> PartialEq for LoanPath<'tcx> {
-    fn eq(&self, that: &LoanPath<'tcx>) -> bool {
-        self.kind == that.kind
-    }
-}
-
-impl<'tcx> Hash for LoanPath<'tcx> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.kind.hash(state);
-    }
-}
-
-#[derive(PartialEq, Eq, Hash, Debug)]
-pub enum LoanPathKind<'tcx> {
-    LpVar(hir::HirId),                          // `x` in README.md
-    LpUpvar(ty::UpvarId),                       // `x` captured by-value into closure
-    LpDowncast(Rc<LoanPath<'tcx>>, DefId), // `x` downcast to particular enum variant
-    LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem<'tcx>)
-}
-
-impl<'tcx> LoanPath<'tcx> {
-    fn new(kind: LoanPathKind<'tcx>, ty: Ty<'tcx>) -> LoanPath<'tcx> {
-        LoanPath { kind: kind, ty: ty }
-    }
-
-    fn to_type(&self) -> Ty<'tcx> { self.ty }
-
-    fn has_downcast(&self) -> bool {
-        match self.kind {
-            LpDowncast(_, _) => true,
-            LpExtend(ref lp, _, LpInterior(_, _)) => {
-                lp.has_downcast()
-            }
-            _ => false,
-        }
-    }
-}
-
-// FIXME (pnkfelix): See discussion here
-// https://github.com/pnkfelix/rust/commit/
-//     b2b39e8700e37ad32b486b9a8409b50a8a53aa51#commitcomment-7892003
-const DOWNCAST_PRINTED_OPERATOR: &'static str = " as ";
-
-// A local, "cleaned" version of `mc::InteriorKind` that drops
-// information that is not relevant to loan-path analysis. (In
-// particular, the distinction between how precisely an array-element
-// is tracked is irrelevant here.)
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub enum InteriorKind {
-    InteriorField(mc::FieldIndex),
-    InteriorElement,
-}
-
-trait ToInteriorKind { fn cleaned(self) -> InteriorKind; }
-impl ToInteriorKind for mc::InteriorKind {
-    fn cleaned(self) -> InteriorKind {
-        match self {
-            mc::InteriorField(name) => InteriorField(name),
-            mc::InteriorElement(_) => InteriorElement,
-        }
-    }
-}
-
-// This can be:
-// - a pointer dereference (`*P` in README.md)
-// - a field reference, with an optional definition of the containing
-//   enum variant (`P.f` in README.md)
-// `DefId` is present when the field is part of struct that is in
-// a variant of an enum. For instance in:
-// `enum E { X { foo: u32 }, Y { foo: u32 }}`
-// each `foo` is qualified by the definitition id of the variant (`X` or `Y`).
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub enum LoanPathElem<'tcx> {
-    LpDeref(mc::PointerKind<'tcx>),
-    LpInterior(Option<DefId>, InteriorKind),
-}
-
-fn closure_to_block(closure_id: LocalDefId, tcx: TyCtxt<'_>) -> HirId {
-    let closure_id = tcx.hir().local_def_id_to_hir_id(closure_id);
-    match tcx.hir().get(closure_id) {
-        Node::Expr(expr) => match expr.node {
-            hir::ExprKind::Closure(.., body_id, _, _) => {
-                body_id.hir_id
-            }
-            _ => {
-                bug!("encountered non-closure id: {}", closure_id)
-            }
-        },
-        _ => bug!("encountered non-expr id: {}", closure_id)
-    }
-}
-
-impl LoanPath<'tcx> {
-    pub fn kill_scope(&self, bccx: &BorrowckCtxt<'_, 'tcx>) -> region::Scope {
-        match self.kind {
-            LpVar(hir_id) => {
-                bccx.region_scope_tree.var_scope(hir_id.local_id)
-            }
-            LpUpvar(upvar_id) => {
-                let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx);
-                region::Scope { id: block_id.local_id, data: region::ScopeData::Node }
-            }
-            LpDowncast(ref base, _) |
-            LpExtend(ref base, ..) => base.kill_scope(bccx),
-        }
-    }
-
-    fn has_fork(&self, other: &LoanPath<'tcx>) -> bool {
-        match (&self.kind, &other.kind) {
-            (&LpExtend(ref base, _, LpInterior(opt_variant_id, id)),
-             &LpExtend(ref base2, _, LpInterior(opt_variant_id2, id2))) =>
-                if id == id2 && opt_variant_id == opt_variant_id2 {
-                    base.has_fork(&base2)
-                } else {
-                    true
-                },
-            (&LpExtend(ref base, _, LpDeref(_)), _) => base.has_fork(other),
-            (_, &LpExtend(ref base, _, LpDeref(_))) => self.has_fork(&base),
-            _ => false,
-        }
-    }
-
-    fn depth(&self) -> usize {
-        match self.kind {
-            LpExtend(ref base, _, LpDeref(_)) => base.depth(),
-            LpExtend(ref base, _, LpInterior(..)) => base.depth() + 1,
-            _ => 0,
-        }
-    }
-
-    fn common(&self, other: &LoanPath<'tcx>) -> Option<LoanPath<'tcx>> {
-        match (&self.kind, &other.kind) {
-            (&LpExtend(ref base, a, LpInterior(opt_variant_id, id)),
-             &LpExtend(ref base2, _, LpInterior(opt_variant_id2, id2))) => {
-                if id == id2 && opt_variant_id == opt_variant_id2 {
-                    base.common(&base2).map(|x| {
-                        let xd = x.depth();
-                        if base.depth() == xd && base2.depth() == xd {
-                            LoanPath {
-                                kind: LpExtend(Rc::new(x), a, LpInterior(opt_variant_id, id)),
-                                ty: self.ty,
-                            }
-                        } else {
-                            x
-                        }
-                    })
-                } else {
-                    base.common(&base2)
-                }
-            }
-            (&LpExtend(ref base, _, LpDeref(_)), _) => base.common(other),
-            (_, &LpExtend(ref other, _, LpDeref(_))) => self.common(&other),
-            (&LpVar(id), &LpVar(id2)) => {
-                if id == id2 {
-                    Some(LoanPath { kind: LpVar(id), ty: self.ty })
-                } else {
-                    None
-                }
-            }
-            (&LpUpvar(id), &LpUpvar(id2)) => {
-                if id == id2 {
-                    Some(LoanPath { kind: LpUpvar(id), ty: self.ty })
-                } else {
-                    None
-                }
-            }
-            _ => None,
-        }
-    }
-}
-
-// Avoid "cannot borrow immutable field `self.x` as mutable" as that implies that a field *can* be
-// mutable independently of the struct it belongs to. (#35937)
-pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt_<'tcx>) -> (Option<Rc<LoanPath<'tcx>>>, bool) {
-    let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
-
-    match cmt.cat {
-        Categorization::Rvalue(..) |
-        Categorization::ThreadLocal(..) |
-        Categorization::StaticItem => {
-            (None, false)
-        }
-
-        Categorization::Local(id) => {
-            (Some(new_lp(LpVar(id))), false)
-        }
-
-        Categorization::Upvar(mc::Upvar { id, .. }) => {
-            (Some(new_lp(LpUpvar(id))), false)
-        }
-
-        Categorization::Deref(ref cmt_base, pk) => {
-            let lp = opt_loan_path_is_field(cmt_base);
-            (lp.0.map(|lp| {
-                new_lp(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
-            }), lp.1)
-        }
-
-        Categorization::Interior(ref cmt_base, ik) => {
-            (opt_loan_path(cmt_base).map(|lp| {
-                let opt_variant_id = match cmt_base.cat {
-                    Categorization::Downcast(_, did) =>  Some(did),
-                    _ => None
-                };
-                new_lp(LpExtend(lp, cmt.mutbl, LpInterior(opt_variant_id, ik.cleaned())))
-            }), true)
-        }
-
-        Categorization::Downcast(ref cmt_base, variant_def_id) => {
-            let lp = opt_loan_path_is_field(cmt_base);
-            (lp.0.map(|lp| {
-                new_lp(LpDowncast(lp, variant_def_id))
-            }), lp.1)
-        }
-    }
-}
-
-/// Computes the `LoanPath` (if any) for a `cmt`.
-/// Note that this logic is somewhat duplicated in
-/// the method `compute()` found in `gather_loans::restrictions`,
-/// which allows it to share common loan path pieces as it
-/// traverses the CMT.
-pub fn opt_loan_path<'tcx>(cmt: &mc::cmt_<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {
-    opt_loan_path_is_field(cmt).0
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Errors
-
-// Errors that can occur
-#[derive(Debug, PartialEq)]
-pub enum bckerr_code<'tcx> {
-    err_mutbl,
-    /// superscope, subscope, loan cause
-    err_out_of_scope(ty::Region<'tcx>, ty::Region<'tcx>, euv::LoanCause),
-    err_borrowed_pointer_too_short(ty::Region<'tcx>, ty::Region<'tcx>), // loan, ptr
-}
-
-// Combination of an error code and the categorization of the expression
-// that caused it
-#[derive(Debug, PartialEq)]
-pub struct BckError<'c, 'tcx> {
-    span: Span,
-    cause: AliasableViolationKind,
-    cmt: &'c mc::cmt_<'tcx>,
-    code: bckerr_code<'tcx>
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum AliasableViolationKind {
-    MutabilityViolation,
-    BorrowViolation(euv::LoanCause)
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum MovedValueUseKind {
-    MovedInUse,
-    MovedInCapture,
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Misc
-
-impl BorrowckCtxt<'_, 'tcx> {
-    pub fn is_subregion_of(&self,
-                           r_sub: ty::Region<'tcx>,
-                           r_sup: ty::Region<'tcx>)
-                           -> bool
-    {
-        let region_rels = RegionRelations::new(self.tcx,
-                                               self.owner_def_id,
-                                               &self.region_scope_tree,
-                                               &self.tables.free_region_map);
-        region_rels.is_subregion_of(r_sub, r_sup)
-    }
-
-    pub fn report(&self, err: BckError<'a, 'tcx>) {
-        // Catch and handle some particular cases.
-        match (&err.code, &err.cause) {
-            (&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _),
-             &BorrowViolation(euv::ClosureCapture(span))) |
-            (&err_out_of_scope(&ty::ReScope(_), &ty::ReEarlyBound(..), _),
-             &BorrowViolation(euv::ClosureCapture(span))) |
-            (&err_out_of_scope(&ty::ReScope(_), &ty::ReFree(..), _),
-             &BorrowViolation(euv::ClosureCapture(span))) => {
-                return self.report_out_of_scope_escaping_closure_capture(&err, span);
-            }
-            _ => { }
-        }
-
-        self.report_bckerr(&err);
-    }
-
-    pub fn report_use_of_moved_value(&self,
-                                     use_span: Span,
-                                     use_kind: MovedValueUseKind,
-                                     lp: &LoanPath<'tcx>,
-                                     the_move: &move_data::Move,
-                                     moved_lp: &LoanPath<'tcx>) {
-        let (verb, verb_participle) = match use_kind {
-            MovedInUse => ("use", "used"),
-            MovedInCapture => ("capture", "captured"),
-        };
-
-        let (_ol, _moved_lp_msg, mut err, need_note) = match the_move.kind {
-            move_data::Declared => {
-                // If this is an uninitialized variable, just emit a simple warning
-                // and return.
-                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();
-                self.signal_error();
-                return;
-            }
-            _ => {
-                // If moved_lp is something like `x.a`, and lp is something like `x.b`, we would
-                // normally generate a rather confusing message:
-                //
-                //     error: use of moved value: `x.b`
-                //     note: `x.a` moved here...
-                //
-                // What we want to do instead is get the 'common ancestor' of the two moves and
-                // use that for most of the message instead, giving is something like this:
-                //
-                //     error: use of moved value: `x`
-                //     note: `x` moved here (through moving `x.a`)...
-
-                let common = moved_lp.common(lp);
-                let has_common = common.is_some();
-                let has_fork = moved_lp.has_fork(lp);
-                let (nl, ol, moved_lp_msg) =
-                    if has_fork && has_common {
-                        let nl = self.loan_path_to_string(&common.unwrap());
-                        let ol = nl.clone();
-                        let moved_lp_msg = format!(" (through moving `{}`)",
-                                                   self.loan_path_to_string(moved_lp));
-                        (nl, ol, moved_lp_msg)
-                    } else {
-                        (self.loan_path_to_string(lp),
-                         self.loan_path_to_string(moved_lp),
-                         String::new())
-                    };
-
-                let partial = moved_lp.depth() > lp.depth();
-                let msg = if !has_fork && partial { "partially " }
-                          else if has_fork && !has_common { "collaterally "}
-                else { "" };
-                let mut err = self.cannot_act_on_moved_value(use_span,
-                                                             verb,
-                                                             msg,
-                                                             Some(nl),
-                                                             Origin::Ast);
-                let need_note = match lp.ty.sty {
-                    ty::Closure(id, _) => {
-                        let hir_id = self.tcx.hir().as_local_hir_id(id).unwrap();
-                        if let Some((span, name)) = self.tables.closure_kind_origins().get(hir_id) {
-                            err.span_note(*span, &format!(
-                                "closure cannot be invoked more than once because \
-                                it moves the variable `{}` out of its environment",
-                                name
-                            ));
-                            false
-                        } else {
-                            true
-                        }
-                    }
-                    _ => true,
-                };
-                (ol, moved_lp_msg, err, need_note)
-            }
-        };
-
-        // Get type of value and span where it was previously
-        // moved.
-        let hir_id = hir::HirId {
-            owner: self.body.value.hir_id.owner,
-            local_id: the_move.id
-        };
-        let (move_span, move_note) = match the_move.kind {
-            move_data::Declared => {
-                unreachable!();
-            }
-
-            move_data::MoveExpr |
-            move_data::MovePat => (self.tcx.hir().span(hir_id), ""),
-
-            move_data::Captured =>
-                (match self.tcx.hir().expect_expr(hir_id).node {
-                    hir::ExprKind::Closure(.., fn_decl_span, _) => fn_decl_span,
-                    ref r => bug!("Captured({:?}) maps to non-closure: {:?}",
-                                  the_move.id, r),
-                }, " (into closure)"),
-        };
-
-        // Annotate the use and the move in the span. Watch out for
-        // the case where the use and the move are the same. This
-        // means the use is in a loop.
-        err = if use_span == move_span {
-            err.span_label(
-                use_span,
-                format!("value moved{} here in previous iteration of loop",
-                         move_note));
-            err
-        } else {
-            err.span_label(use_span, format!("value {} here after move", verb_participle));
-            err.span_label(move_span, format!("value moved{} here", move_note));
-            err
-        };
-
-        if need_note {
-            err.note(&format!(
-                "move occurs because {} has type `{}`, which does not implement the `Copy` trait",
-                if moved_lp.has_downcast() {
-                    "the value".to_string()
-                } else {
-                    format!("`{}`", self.loan_path_to_string(moved_lp))
-                },
-                moved_lp.ty));
-        }
-        if let (Some(DesugaringKind::ForLoop), Ok(snippet)) = (
-            move_span.desugaring_kind(),
-            self.tcx.sess.source_map().span_to_snippet(move_span),
-         ) {
-            if !snippet.starts_with("&") {
-                err.span_suggestion(
-                    move_span,
-                    "consider borrowing this to avoid moving it into the for loop",
-                    format!("&{}", snippet),
-                    Applicability::MaybeIncorrect,
-                );
-            }
-        }
-
-        // Note: we used to suggest adding a `ref binding` or calling
-        // `clone` but those suggestions have been removed because
-        // they are often not what you actually want to do, and were
-        // not considered particularly helpful.
-
-        err.emit();
-        self.signal_error();
-    }
-
-    pub fn report_partial_reinitialization_of_uninitialized_structure(
-            &self,
-            span: Span,
-            lp: &LoanPath<'tcx>) {
-        self.cannot_partially_reinit_an_uninit_struct(span,
-                                                      &self.loan_path_to_string(lp),
-                                                      Origin::Ast)
-            .emit();
-        self.signal_error();
-    }
-
-    pub fn report_reassigned_immutable_variable(&self,
-                                                span: Span,
-                                                lp: &LoanPath<'tcx>,
-                                                assign:
-                                                &move_data::Assignment) {
-        let mut err = self.cannot_reassign_immutable(span,
-                                                     &self.loan_path_to_string(lp),
-                                                     false,
-                                                     Origin::Ast);
-        err.span_label(span, "cannot assign twice to immutable variable");
-        if span != assign.span {
-            err.span_label(assign.span, format!("first assignment to `{}`",
-                                                self.loan_path_to_string(lp)));
-        }
-        err.emit();
-        self.signal_error();
-    }
-
-    fn report_bckerr(&self, err: &BckError<'a, 'tcx>) {
-        let error_span = err.span.clone();
-
-        match err.code {
-            err_mutbl => {
-                let descr: Cow<'static, str> = match err.cmt.note {
-                    mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
-                        self.cmt_to_cow_str(&err.cmt)
-                    }
-                    _ => match opt_loan_path_is_field(&err.cmt) {
-                        (None, true) => {
-                            format!("{} of {} binding",
-                                    self.cmt_to_cow_str(&err.cmt),
-                                    err.cmt.mutbl.to_user_str()).into()
-
-                        }
-                        (None, false) => {
-                            format!("{} {}",
-                                    err.cmt.mutbl.to_user_str(),
-                                    self.cmt_to_cow_str(&err.cmt)).into()
-
-                        }
-                        (Some(lp), true) => {
-                            format!("{} `{}` of {} binding",
-                                    self.cmt_to_cow_str(&err.cmt),
-                                    self.loan_path_to_string(&lp),
-                                    err.cmt.mutbl.to_user_str()).into()
-                        }
-                        (Some(lp), false) => {
-                            format!("{} {} `{}`",
-                                    err.cmt.mutbl.to_user_str(),
-                                    self.cmt_to_cow_str(&err.cmt),
-                                    self.loan_path_to_string(&lp)).into()
-                        }
-                    }
-                };
-
-                let mut db = match err.cause {
-                    MutabilityViolation => {
-                        let mut db = self.cannot_assign(error_span, &descr, Origin::Ast);
-                        if let mc::NoteClosureEnv(upvar_id) = err.cmt.note {
-                            let hir_id = upvar_id.var_path.hir_id;
-                            let sp = self.tcx.hir().span(hir_id);
-                            let fn_closure_msg = "`Fn` closures cannot capture their enclosing \
-                                                  environment for modifications";
-                            match (self.tcx.sess.source_map().span_to_snippet(sp), &err.cmt.cat) {
-                                (_, &Categorization::Upvar(mc::Upvar {
-                                    kind: ty::ClosureKind::Fn, ..
-                                })) => {
-                                    db.note(fn_closure_msg);
-                                    // we should point at the cause for this closure being
-                                    // identified as `Fn` (like in signature of method this
-                                    // closure was passed into)
-                                }
-                                (Ok(ref snippet), ref cat) => {
-                                    let msg = &format!("consider making `{}` mutable", snippet);
-                                    let suggestion = format!("mut {}", snippet);
-
-                                    if let &Categorization::Deref(ref cmt, _) = cat {
-                                        if let Categorization::Upvar(mc::Upvar {
-                                            kind: ty::ClosureKind::Fn, ..
-                                        }) = cmt.cat {
-                                            db.note(fn_closure_msg);
-                                        } else {
-                                            db.span_suggestion(
-                                                sp,
-                                                msg,
-                                                suggestion,
-                                                Applicability::Unspecified,
-                                            );
-                                        }
-                                    } else {
-                                        db.span_suggestion(
-                                            sp,
-                                            msg,
-                                            suggestion,
-                                            Applicability::Unspecified,
-                                        );
-                                    }
-                                }
-                                _ => {
-                                    db.span_help(sp, "consider making this binding mutable");
-                                }
-                            }
-                        }
-
-                        db
-                    }
-                    BorrowViolation(euv::ClosureCapture(_)) => {
-                        self.closure_cannot_assign_to_borrowed(error_span, &descr, Origin::Ast)
-                    }
-                    BorrowViolation(euv::OverloadedOperator) |
-                    BorrowViolation(euv::AddrOf) |
-                    BorrowViolation(euv::RefBinding) |
-                    BorrowViolation(euv::AutoRef) |
-                    BorrowViolation(euv::AutoUnsafe) |
-                    BorrowViolation(euv::ForLoop) |
-                    BorrowViolation(euv::MatchDiscriminant) => {
-                        self.cannot_borrow_path_as_mutable(error_span, &descr, Origin::Ast)
-                    }
-                    BorrowViolation(euv::ClosureInvocation) => {
-                        span_bug!(err.span, "err_mutbl with a closure invocation");
-                    }
-                };
-
-                // We add a special note about `IndexMut`, if the source of this error
-                // is the fact that `Index` is implemented, but `IndexMut` is not. Needing
-                // to implement two traits for "one operator" is not very intuitive for
-                // many programmers.
-                if err.cmt.note == mc::NoteIndex {
-                    let node = self.tcx.hir().get(err.cmt.hir_id);
-
-                    // This pattern probably always matches.
-                    if let Node::Expr(
-                        hir::Expr { node: hir::ExprKind::Index(lhs, _), ..}
-                    ) = node {
-                        let ty = self.tables.expr_ty(lhs);
-
-                        db.help(&format!(
-                            "trait `IndexMut` is required to modify indexed content, but \
-                             it is not implemented for `{}`",
-                            ty
-                        ));
-                    }
-                }
-
-                self.note_and_explain_mutbl_error(&mut db, &err, &error_span);
-                self.note_immutability_blame(
-                    &mut db,
-                    err.cmt.immutability_blame(),
-                    err.cmt.hir_id
-                );
-                db.emit();
-                self.signal_error();
-            }
-            err_out_of_scope(super_scope, sub_scope, cause) => {
-                let msg = match opt_loan_path(&err.cmt) {
-                    None => "borrowed value".to_string(),
-                    Some(lp) => {
-                        format!("`{}`", self.loan_path_to_string(&lp))
-                    }
-                };
-
-                let mut db = self.path_does_not_live_long_enough(error_span, &msg, Origin::Ast);
-                let value_kind = match err.cmt.cat {
-                    mc::Categorization::Rvalue(..) => "temporary value",
-                    _ => "borrowed value",
-                };
-
-                let is_closure = match cause {
-                    euv::ClosureCapture(s) => {
-                        // The primary span starts out as the closure creation point.
-                        // Change the primary span here to highlight the use of the variable
-                        // in the closure, because it seems more natural. Highlight
-                        // closure creation point as a secondary span.
-                        match db.span.primary_span() {
-                            Some(primary) => {
-                                db.span = MultiSpan::from_span(s);
-                                db.span_label(primary, "capture occurs here");
-                                db.span_label(s, format!("{} does not live long enough",
-                                                         value_kind));
-                                true
-                            }
-                            None => false
-                        }
-                    }
-                    _ => {
-                        db.span_label(error_span, format!("{} does not live long enough",
-                                                          value_kind));
-                        false
-                    }
-                };
-
-                let sub_span = self.region_end_span(sub_scope);
-                let super_span = self.region_end_span(super_scope);
-
-                match (sub_span, super_span) {
-                    (Some(s1), Some(s2)) if s1 == s2 => {
-                        if !is_closure {
-                            let msg = match opt_loan_path(&err.cmt) {
-                                None => value_kind.to_string(),
-                                Some(lp) => {
-                                    format!("`{}`", self.loan_path_to_string(&lp))
-                                }
-                            };
-                            db.span_label(s1,
-                                          format!("{} dropped here while still borrowed", msg));
-                        } else {
-                            db.span_label(s1, format!("{} dropped before borrower", value_kind));
-                        }
-                        db.note("values in a scope are dropped in the opposite order \
-                                they are created");
-                    }
-                    (Some(s1), Some(s2)) if !is_closure => {
-                        let msg = match opt_loan_path(&err.cmt) {
-                            None => value_kind.to_string(),
-                            Some(lp) => {
-                                format!("`{}`", self.loan_path_to_string(&lp))
-                            }
-                        };
-                        db.span_label(s2, format!("{} dropped here while still borrowed", msg));
-                        db.span_label(s1, format!("{} needs to live until here", value_kind));
-                    }
-                    _ => {
-                        match sub_span {
-                            Some(s) => {
-                                db.span_label(s, format!("{} needs to live until here",
-                                                          value_kind));
-                            }
-                            None => {
-                                self.tcx.note_and_explain_region(
-                                    &self.region_scope_tree,
-                                    &mut db,
-                                    "borrowed value must be valid for ",
-                                    sub_scope,
-                                    "...");
-                            }
-                        }
-                        match super_span {
-                            Some(s) => {
-                                db.span_label(s, format!("{} only lives until here", value_kind));
-                            }
-                            None => {
-                                self.tcx.note_and_explain_region(
-                                    &self.region_scope_tree,
-                                    &mut db,
-                                    "...but borrowed value is only valid for ",
-                                    super_scope,
-                                    "");
-                            }
-                        }
-                    }
-                }
-
-                if let ty::ReScope(scope) = *super_scope {
-                    let hir_id = scope.hir_id(&self.region_scope_tree);
-                    match self.tcx.hir().find(hir_id) {
-                        Some(Node::Stmt(_)) => {
-                            if *sub_scope != ty::ReStatic {
-                                db.note("consider using a `let` binding to increase its lifetime");
-                            }
-
-                        }
-                        _ => {}
-                    }
-                }
-
-                db.emit();
-                self.signal_error();
-            }
-            err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
-                let descr = self.cmt_to_path_or_string(err.cmt);
-                let mut db = self.lifetime_too_short_for_reborrow(error_span, &descr, Origin::Ast);
-                let descr: Cow<'static, str> = match opt_loan_path(&err.cmt) {
-                    Some(lp) => {
-                        format!("`{}`", self.loan_path_to_string(&lp)).into()
-                    }
-                    None => self.cmt_to_cow_str(&err.cmt)
-                };
-                self.tcx.note_and_explain_region(
-                    &self.region_scope_tree,
-                    &mut db,
-                    &format!("{} would have to be valid for ",
-                            descr),
-                    loan_scope,
-                    "...");
-                self.tcx.note_and_explain_region(
-                    &self.region_scope_tree,
-                    &mut db,
-                    &format!("...but {} is only valid for ", descr),
-                    ptr_scope,
-                    "");
-
-                db.emit();
-                self.signal_error();
-            }
-        }
-    }
-
-    pub fn report_aliasability_violation(&self,
-                                         span: Span,
-                                         kind: AliasableViolationKind,
-                                         cause: mc::AliasableReason,
-                                         cmt: &mc::cmt_<'tcx>) {
-        let mut is_closure = false;
-        let prefix = match kind {
-            MutabilityViolation => {
-                "cannot assign to data"
-            }
-            BorrowViolation(euv::ClosureCapture(_)) |
-            BorrowViolation(euv::OverloadedOperator) |
-            BorrowViolation(euv::AddrOf) |
-            BorrowViolation(euv::AutoRef) |
-            BorrowViolation(euv::AutoUnsafe) |
-            BorrowViolation(euv::RefBinding) |
-            BorrowViolation(euv::MatchDiscriminant) => {
-                "cannot borrow data mutably"
-            }
-            BorrowViolation(euv::ClosureInvocation) => {
-                is_closure = true;
-                "closure invocation"
-            }
-
-            BorrowViolation(euv::ForLoop) => {
-                "`for` loop"
-            }
-        };
-
-        match cause {
-            mc::AliasableStaticMut => {
-                // This path cannot occur. `static mut X` is not checked
-                // for aliasability violations.
-                span_bug!(span, "aliasability violation for static mut `{}`", prefix)
-            }
-            mc::AliasableStatic | mc::AliasableBorrowed => {}
-        };
-        let blame = cmt.immutability_blame();
-        let mut err = match blame {
-            Some(ImmutabilityBlame::ClosureEnv(id)) => {
-                // FIXME: the distinction between these 2 messages looks wrong.
-                let help_msg = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
-                    // The aliasability violation with closure captures can
-                    // happen for nested closures, so we know the enclosing
-                    // closure incorrectly accepts an `Fn` while it needs to
-                    // be `FnMut`.
-                    "consider changing this to accept closures that implement `FnMut`"
-
-                } else {
-                    "consider changing this closure to take self by mutable reference"
-                };
-                let hir_id = self.tcx.hir().local_def_id_to_hir_id(id);
-                let help_span = self.tcx.hir().span(hir_id);
-                self.cannot_act_on_capture_in_sharable_fn(span,
-                                                          prefix,
-                                                          (help_span, help_msg),
-                                                          Origin::Ast)
-            }
-            _ =>  {
-                self.cannot_assign_into_immutable_reference(span, prefix,
-                                                            Origin::Ast)
-            }
-        };
-        self.note_immutability_blame(
-            &mut err,
-            blame,
-            cmt.hir_id
-        );
-
-        if is_closure {
-            err.help("closures behind references must be called via `&mut`");
-        }
-        err.emit();
-        self.signal_error();
-    }
-
-    /// Given a type, if it is an immutable reference, return a suggestion to make it mutable
-    fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option<String> {
-        // Check whether the argument is an immutable reference
-        debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self);
-        if let hir::TyKind::Rptr(lifetime, hir::MutTy {
-            mutbl: hir::Mutability::MutImmutable,
-            ref ty
-        }) = pty.node {
-            // Account for existing lifetimes when generating the message
-            let pointee_snippet = match self.tcx.sess.source_map().span_to_snippet(ty.span) {
-                Ok(snippet) => snippet,
-                _ => return None
-            };
-
-            let lifetime_snippet = if !lifetime.is_elided() {
-                format!("{} ", match self.tcx.sess.source_map().span_to_snippet(lifetime.span) {
-                    Ok(lifetime_snippet) => lifetime_snippet,
-                    _ => return None
-                })
-            } else {
-                String::new()
-            };
-            Some(format!("use `&{}mut {}` here to make mutable",
-                         lifetime_snippet,
-                         if is_implicit_self { "self" } else { &*pointee_snippet }))
-        } else {
-            None
-        }
-    }
-
-    fn local_binding_mode(&self, hir_id: hir::HirId) -> ty::BindingMode {
-        let pat = match self.tcx.hir().get(hir_id) {
-            Node::Binding(pat) => pat,
-            node => bug!("bad node for local: {:?}", node)
-        };
-
-        match pat.node {
-            hir::PatKind::Binding(..) => {
-                *self.tables
-                     .pat_binding_modes()
-                     .get(pat.hir_id)
-                     .expect("missing binding mode")
-            }
-            _ => bug!("local is not a binding: {:?}", pat)
-        }
-    }
-
-    fn local_ty(&self, hir_id: hir::HirId) -> (Option<&hir::Ty>, bool) {
-        let parent = self.tcx.hir().get_parent_node(hir_id);
-        let parent_node = self.tcx.hir().get(parent);
-
-        // The parent node is like a fn
-        if let Some(fn_like) = FnLikeNode::from_node(parent_node) {
-            // `nid`'s parent's `Body`
-            let fn_body = self.tcx.hir().body(fn_like.body());
-            // Get the position of `node_id` in the arguments list
-            let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.hir_id == hir_id);
-            if let Some(i) = arg_pos {
-                // The argument's `Ty`
-                (Some(&fn_like.decl().inputs[i]),
-                 i == 0 && fn_like.decl().implicit_self.has_implicit_self())
-            } else {
-                (None, false)
-            }
-        } else {
-            (None, false)
-        }
-    }
-
-    fn note_immutability_blame(&self,
-                               db: &mut DiagnosticBuilder<'_>,
-                               blame: Option<ImmutabilityBlame<'_>>,
-                               error_hir_id: hir::HirId) {
-        match blame {
-            None => {}
-            Some(ImmutabilityBlame::ClosureEnv(_)) => {}
-            Some(ImmutabilityBlame::ImmLocal(hir_id)) => {
-                self.note_immutable_local(db, error_hir_id, hir_id)
-            }
-            Some(ImmutabilityBlame::LocalDeref(hir_id)) => {
-                match self.local_binding_mode(hir_id) {
-                    ty::BindByReference(..) => {
-                        let let_span = self.tcx.hir().span(hir_id);
-                        let suggestion = suggest_ref_mut(self.tcx, let_span);
-                        if let Some(replace_str) = suggestion {
-                            db.span_suggestion(
-                                let_span,
-                                "use a mutable reference instead",
-                                replace_str,
-                                // I believe this can be machine applicable,
-                                // but if there are multiple attempted uses of an immutable
-                                // reference, I don't know how rustfix handles it, it might
-                                // attempt fixing them multiple times.
-                                //                              @estebank
-                                Applicability::Unspecified,
-                            );
-                        }
-                    }
-                    ty::BindByValue(..) => {
-                        if let (Some(local_ty), is_implicit_self) = self.local_ty(hir_id) {
-                            if let Some(msg) =
-                                 self.suggest_mut_for_immutable(local_ty, is_implicit_self) {
-                                db.span_label(local_ty.span, msg);
-                            }
-                        }
-                    }
-                }
-            }
-            Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => {
-                let hir_id = match self.tcx.hir().as_local_hir_id(field.did) {
-                    Some(hir_id) => hir_id,
-                    None => return
-                };
-
-                if let Node::Field(ref field) = self.tcx.hir().get(hir_id) {
-                    if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) {
-                        db.span_label(field.ty.span, msg);
-                    }
-                }
-            }
-        }
-    }
-
-     // Suggest a fix when trying to mutably borrow an immutable local
-     // binding: either to make the binding mutable (if its type is
-     // not a mutable reference) or to avoid borrowing altogether
-    fn note_immutable_local(&self,
-                            db: &mut DiagnosticBuilder<'_>,
-                            borrowed_hir_id: hir::HirId,
-                            binding_hir_id: hir::HirId) {
-        let let_span = self.tcx.hir().span(binding_hir_id);
-        if let ty::BindByValue(..) = self.local_binding_mode(binding_hir_id) {
-            if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(let_span) {
-                let (ty, is_implicit_self) = self.local_ty(binding_hir_id);
-                if is_implicit_self && snippet != "self" {
-                    // avoid suggesting `mut &self`.
-                    return
-                }
-                if let Some(&hir::TyKind::Rptr(
-                    _,
-                    hir::MutTy {
-                        mutbl: hir::MutMutable,
-                        ..
-                    },
-                )) = ty.map(|t| &t.node)
-                {
-                    let borrow_expr_id = self.tcx.hir().get_parent_node(borrowed_hir_id);
-                    db.span_suggestion(
-                        self.tcx.hir().span(borrow_expr_id),
-                        "consider removing the `&mut`, as it is an \
-                        immutable binding to a mutable reference",
-                        snippet,
-                        Applicability::MachineApplicable,
-                    );
-                } else {
-                    db.span_suggestion(
-                        let_span,
-                        "make this binding mutable",
-                        format!("mut {}", snippet),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-        }
-    }
-
-    fn report_out_of_scope_escaping_closure_capture(&self,
-                                                    err: &BckError<'a, 'tcx>,
-                                                    capture_span: Span)
-    {
-        let cmt_path_or_string = self.cmt_to_path_or_string(&err.cmt);
-
-        let suggestion =
-            match self.tcx.sess.source_map().span_to_snippet(err.span) {
-                Ok(string) => format!("move {}", string),
-                Err(_) => "move |<args>| <body>".to_string()
-            };
-
-        self.cannot_capture_in_long_lived_closure(err.span,
-                                                  &cmt_path_or_string,
-                                                  capture_span,
-                                                  Origin::Ast)
-            .span_suggestion(
-                 err.span,
-                 &format!("to force the closure to take ownership of {} \
-                           (and any other referenced variables), \
-                           use the `move` keyword",
-                           cmt_path_or_string),
-                 suggestion,
-                 Applicability::MachineApplicable,
-            )
-            .emit();
-        self.signal_error();
-    }
-
-    fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {
-        match *region {
-            ty::ReScope(scope) => {
-                Some(self.tcx.sess.source_map().end_point(
-                        scope.span(self.tcx, &self.region_scope_tree)))
-            }
-            _ => None
-        }
-    }
-
-    fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder<'_>, err: &BckError<'a, 'tcx>,
-                                    error_span: &Span) {
-        match err.cmt.note {
-            mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => {
-                // If this is an `Fn` closure, it simply can't mutate upvars.
-                // If it's an `FnMut` closure, the original variable was declared immutable.
-                // We need to determine which is the case here.
-                let kind = match err.cmt.upvar_cat().unwrap() {
-                    Categorization::Upvar(mc::Upvar { kind, .. }) => kind,
-                    _ => bug!()
-                };
-                if *kind == ty::ClosureKind::Fn {
-                    let closure_hir_id =
-                        self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id);
-                    db.span_help(self.tcx.hir().span(closure_hir_id),
-                                 "consider changing this closure to take \
-                                  self by mutable reference");
-                }
-            }
-            _ => {
-                if let Categorization::Deref(..) = err.cmt.cat {
-                    db.span_label(*error_span, "cannot borrow as mutable");
-                } else if let Categorization::Local(local_id) = err.cmt.cat {
-                    let span = self.tcx.hir().span(local_id);
-                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                        if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
-                            db.span_label(*error_span, "cannot reborrow mutably");
-                            db.span_label(*error_span, "try removing `&mut` here");
-                        } else {
-                            db.span_label(*error_span, "cannot borrow mutably");
-                        }
-                    } else {
-                        db.span_label(*error_span, "cannot borrow mutably");
-                    }
-                } else if let Categorization::Interior(ref cmt, _) = err.cmt.cat {
-                    if let mc::MutabilityCategory::McImmutable = cmt.mutbl {
-                        db.span_label(*error_span,
-                                      "cannot mutably borrow field of immutable binding");
-                    }
-                }
-            }
-        }
-    }
-    pub fn append_loan_path_to_string(&self,
-                                      loan_path: &LoanPath<'tcx>,
-                                      out: &mut String) {
-        match loan_path.kind {
-            LpUpvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id: id }, closure_expr_id: _ }) => {
-                out.push_str(&self.tcx.hir().name(id).as_str());
-            }
-            LpVar(id) => {
-                out.push_str(&self.tcx.hir().name(id).as_str());
-            }
-
-            LpDowncast(ref lp_base, variant_def_id) => {
-                out.push('(');
-                self.append_loan_path_to_string(&lp_base, out);
-                out.push_str(DOWNCAST_PRINTED_OPERATOR);
-                out.push_str(&self.tcx.def_path_str(variant_def_id));
-                out.push(')');
-            }
-
-            LpExtend(ref lp_base, _, LpInterior(_, InteriorField(mc::FieldIndex(_, info)))) => {
-                self.append_autoderefd_loan_path_to_string(&lp_base, out);
-                out.push('.');
-                out.push_str(&info.as_str());
-            }
-
-            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => {
-                self.append_autoderefd_loan_path_to_string(&lp_base, out);
-                out.push_str("[..]");
-            }
-
-            LpExtend(ref lp_base, _, LpDeref(_)) => {
-                out.push('*');
-                self.append_loan_path_to_string(&lp_base, out);
-            }
-        }
-    }
-
-    pub fn append_autoderefd_loan_path_to_string(&self,
-                                                 loan_path: &LoanPath<'tcx>,
-                                                 out: &mut String) {
-        match loan_path.kind {
-            LpExtend(ref lp_base, _, LpDeref(_)) => {
-                // For a path like `(*x).f` or `(*x)[3]`, autoderef
-                // rules would normally allow users to omit the `*x`.
-                // So just serialize such paths to `x.f` or x[3]` respectively.
-                self.append_autoderefd_loan_path_to_string(&lp_base, out)
-            }
-
-            LpDowncast(ref lp_base, variant_def_id) => {
-                out.push('(');
-                self.append_autoderefd_loan_path_to_string(&lp_base, out);
-                out.push_str(DOWNCAST_PRINTED_OPERATOR);
-                out.push_str(&self.tcx.def_path_str(variant_def_id));
-                out.push(')');
-            }
-
-            LpVar(..) | LpUpvar(..) | LpExtend(.., LpInterior(..)) => {
-                self.append_loan_path_to_string(loan_path, out)
-            }
-        }
-    }
-
-    pub fn loan_path_to_string(&self, loan_path: &LoanPath<'tcx>) -> String {
-        let mut result = String::new();
-        self.append_loan_path_to_string(loan_path, &mut result);
-        result
-    }
-
-    pub fn cmt_to_cow_str(&self, cmt: &mc::cmt_<'tcx>) -> Cow<'static, str> {
-        cmt.descriptive_string(self.tcx)
-    }
-
-    pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
-        match opt_loan_path(cmt) {
-            Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)),
-            None => self.cmt_to_cow_str(cmt).into_owned(),
-        }
-    }
-}
-
-impl BitwiseOperator for LoanDataFlowOperator {
-    #[inline]
-    fn join(&self, succ: usize, pred: usize) -> usize {
-        succ | pred // loans from both preds are in scope
-    }
-}
-
-impl DataFlowOperator for LoanDataFlowOperator {
-    #[inline]
-    fn initial_value(&self) -> bool {
-        false // no loans in scope by default
-    }
-}
-
-impl fmt::Debug for InteriorKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            InteriorField(mc::FieldIndex(_, info)) => write!(f, "{}", info),
-            InteriorElement => write!(f, "[]"),
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for Loan<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "Loan_{}({:?}, {:?}, {:?}-{:?}, {:?})",
-               self.index,
-               self.loan_path,
-               self.kind,
-               self.gen_scope,
-               self.kill_scope,
-               self.restricted_paths)
-    }
-}
-
-impl<'tcx> fmt::Debug for LoanPath<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.kind {
-            LpVar(id) => {
-                write!(f, "$({})", ty::tls::with(|tcx| tcx.hir().node_to_string(id)))
-            }
-
-            LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath {hir_id: var_id}, closure_expr_id }) => {
-                let s = ty::tls::with(|tcx| {
-                    tcx.hir().node_to_string(var_id)
-                });
-                write!(f, "$({} captured by id={:?})", s, closure_expr_id)
-            }
-
-            LpDowncast(ref lp, variant_def_id) => {
-                let variant_str = if variant_def_id.is_local() {
-                    ty::tls::with(|tcx| tcx.def_path_str(variant_def_id))
-                } else {
-                    format!("{:?}", variant_def_id)
-                };
-                write!(f, "({:?}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
-            }
-
-            LpExtend(ref lp, _, LpDeref(_)) => {
-                write!(f, "{:?}.*", lp)
-            }
-
-            LpExtend(ref lp, _, LpInterior(_, ref interior)) => {
-                write!(f, "{:?}.{:?}", lp, interior)
-            }
-        }
-    }
-}
-
-impl<'tcx> fmt::Display for LoanPath<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.kind {
-            LpVar(id) => {
-                write!(f, "$({})", ty::tls::with(|tcx| tcx.hir().hir_to_user_string(id)))
-            }
-
-            LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => {
-                let s = ty::tls::with(|tcx| {
-                    tcx.hir().node_to_string(hir_id)
-                });
-                write!(f, "$({} captured by closure)", s)
-            }
-
-            LpDowncast(ref lp, variant_def_id) => {
-                let variant_str = if variant_def_id.is_local() {
-                    ty::tls::with(|tcx| tcx.def_path_str(variant_def_id))
-                } else {
-                    format!("{:?}", variant_def_id)
-                };
-                write!(f, "({}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
-            }
-
-            LpExtend(ref lp, _, LpDeref(_)) => {
-                write!(f, "{}.*", lp)
-            }
-
-            LpExtend(ref lp, _, LpInterior(_, ref interior)) => {
-                write!(f, "{}.{:?}", lp, interior)
-            }
-        }
-    }
-}
diff --git a/src/librustc_borrowck/error_codes.rs b/src/librustc_borrowck/error_codes.rs
deleted file mode 100644
index 44d8a23fcb9..00000000000
--- a/src/librustc_borrowck/error_codes.rs
+++ /dev/null
@@ -1 +0,0 @@
-#![allow(non_snake_case)]
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index 9a8473e1409..d4c30dc6c45 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -18,7 +18,7 @@ rayon = { version = "0.2.0", package = "rustc-rayon" }
 rustc = { path = "../librustc" }
 rustc_allocator = { path = "../librustc_allocator" }
 rustc_target = { path = "../librustc_target" }
-rustc_borrowck = { path = "../librustc_borrowck" }
+rustc_ast_borrowck = { path = "../librustc_ast_borrowck" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_incremental = { path = "../librustc_incremental" }
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 51b161c3768..af000376044 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -12,8 +12,8 @@ use rustc::session::config::Input;
 use rustc::ty::{self, TyCtxt};
 use rustc::util::common::ErrorReported;
 use rustc_interface::util::ReplaceBodyWithLoop;
-use rustc_borrowck as borrowck;
-use rustc_borrowck::graphviz as borrowck_dot;
+use rustc_ast_borrowck as borrowck;
+use rustc_ast_borrowck::graphviz as borrowck_dot;
 use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
 
 use syntax::ast;
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index 2712355d537..a0efec5ee7a 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -19,7 +19,7 @@ syntax_pos = { path = "../libsyntax_pos" }
 serialize = { path = "../libserialize" }
 rustc = { path = "../librustc" }
 rustc_allocator = { path = "../librustc_allocator" }
-rustc_borrowck = { path = "../librustc_borrowck" }
+rustc_ast_borrowck = { path = "../librustc_ast_borrowck" }
 rustc_incremental = { path = "../librustc_incremental" }
 rustc_traits = { path = "../librustc_traits" }
 rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 9a5eb2b93d5..bb58d134989 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -19,7 +19,7 @@ use rustc::session::{CompileResult, CrateDisambiguator, Session};
 use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType};
 use rustc::session::search_paths::PathKind;
 use rustc_allocator as allocator;
-use rustc_borrowck as borrowck;
+use rustc_ast_borrowck as borrowck;
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use rustc_codegen_utils::link::filename_for_metadata;
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index f1aaa857dd3..bce6761e2ca 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -1,34 +1,13 @@
-use rustc::session::config::BorrowckMode;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_errors::{DiagnosticBuilder, DiagnosticId};
 use syntax_pos::{MultiSpan, Span};
 
-use std::fmt;
-
+// FIXME(chrisvittal) remove Origin entirely
 #[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 {
-        // FIXME(chrisvittal) remove Origin entirely
-        // Print no origin info
-        Ok(())
-    }
-}
-
-impl Origin {
-    /// Whether we should emit errors for the origin in the given mode
-    pub fn should_emit_errors(self, mode: BorrowckMode) -> bool {
-        match self {
-            Origin::Ast => mode.use_ast(),
-            Origin::Mir => true,
-        }
-    }
-}
-
 pub trait BorrowckErrors<'cx>: Sized + Copy {
     fn struct_span_err_with_code<S: Into<MultiSpan>>(
         self,
@@ -39,32 +18,19 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
 
     fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx>;
 
-    /// Cancels the given error if we shouldn't emit errors for a given
-    /// origin in the current mode.
-    ///
-    /// Always make sure that the error gets passed through this function
-    /// before you return it.
-    fn cancel_if_wrong_origin(
-        self,
-        diag: DiagnosticBuilder<'cx>,
-        o: Origin,
-    ) -> DiagnosticBuilder<'cx>;
-
     fn cannot_move_when_borrowed(
         self,
         span: Span,
         desc: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0505,
-            "cannot move out of `{}` because it is borrowed{OGN}",
+            "cannot move out of `{}` because it is borrowed",
             desc,
-            OGN = o
-        );
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn cannot_use_when_mutably_borrowed(
@@ -73,15 +39,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         desc: &str,
         borrow_span: Span,
         borrow_desc: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             span,
             E0503,
-            "cannot use `{}` because it was mutably borrowed{OGN}",
+            "cannot use `{}` because it was mutably borrowed",
             desc,
-            OGN = o
         );
 
         err.span_label(
@@ -89,8 +54,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
             format!("borrow of `{}` occurs here", borrow_desc),
         );
         err.span_label(span, format!("use of borrowed `{}`", borrow_desc));
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_act_on_uninitialized_variable(
@@ -98,18 +62,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         span: Span,
         verb: &str,
         desc: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0381,
-            "{} of possibly uninitialized variable: `{}`{OGN}",
+            "{} of possibly uninitialized variable: `{}`",
             verb,
             desc,
-            OGN = o
-        );
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn cannot_mutably_borrow_multiply(
@@ -120,7 +82,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         old_loan_span: Span,
         old_opt_via: &str,
         old_load_end_span: Option<Span>,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let via = |msg: &str|
             if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
@@ -128,10 +90,9 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
             self,
             new_loan_span,
             E0499,
-            "cannot borrow `{}`{} as mutable more than once at a time{OGN}",
+            "cannot borrow `{}`{} as mutable more than once at a time",
             desc,
             via(opt_via),
-            OGN = o
         );
         if old_loan_span == new_loan_span {
             // Both borrows are happening in the same place
@@ -160,7 +121,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
                 err.span_label(old_load_end_span, "first borrow ends here");
             }
         }
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_uniquely_borrow_by_two_closures(
@@ -169,15 +130,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         desc: &str,
         old_loan_span: Span,
         old_load_end_span: Option<Span>,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             new_loan_span,
             E0524,
-            "two closures require unique access to `{}` at the same time{OGN}",
+            "two closures require unique access to `{}` at the same time",
             desc,
-            OGN = o
         );
         if old_loan_span == new_loan_span {
             err.span_label(
@@ -191,7 +151,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         if let Some(old_load_end_span) = old_load_end_span {
             err.span_label(old_load_end_span, "borrow from first closure ends here");
         }
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_uniquely_borrow_by_one_closure(
@@ -204,17 +164,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         noun_old: &str,
         old_opt_via: &str,
         previous_end_span: Option<Span>,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             new_loan_span,
             E0500,
-            "closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
+            "closure requires unique access to `{}` but {} is already borrowed{}",
             desc_new,
             noun_old,
             old_opt_via,
-            OGN = o
         );
         err.span_label(
             new_loan_span,
@@ -224,7 +183,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         if let Some(previous_end_span) = previous_end_span {
             err.span_label(previous_end_span, "borrow ends here");
         }
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_reborrow_already_uniquely_borrowed(
@@ -238,18 +197,17 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         old_opt_via: &str,
         previous_end_span: Option<Span>,
         second_borrow_desc: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             new_loan_span,
             E0501,
             "cannot borrow `{}`{} as {} because previous closure \
-             requires unique access{OGN}",
+             requires unique access",
             desc_new,
             opt_via,
             kind_new,
-            OGN = o
         );
         err.span_label(
             new_loan_span,
@@ -262,7 +220,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         if let Some(previous_end_span) = previous_end_span {
             err.span_label(previous_end_span, "borrow from closure ends here");
         }
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_reborrow_already_borrowed(
@@ -276,7 +234,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         kind_old: &str,
         msg_old: &str,
         old_load_end_span: Option<Span>,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let via = |msg: &str|
             if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
@@ -285,14 +243,13 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
             span,
             E0502,
             "cannot borrow `{}`{} as {} because {} is also borrowed \
-             as {}{}{OGN}",
+             as {}{}",
             desc_new,
             via(msg_new),
             kind_new,
             noun_old,
             kind_old,
             via(msg_old),
-            OGN = o
         );
 
         if msg_new == "" {
@@ -317,8 +274,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         if let Some(old_load_end_span) = old_load_end_span {
             err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
         }
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_assign_to_borrowed(
@@ -326,15 +282,14 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         span: Span,
         borrow_span: Span,
         desc: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             span,
             E0506,
-            "cannot assign to `{}` because it is borrowed{OGN}",
+            "cannot assign to `{}` because it is borrowed",
             desc,
-            OGN = o
         );
 
         err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
@@ -342,21 +297,17 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
             span,
             format!("assignment to borrowed `{}` occurs here", desc),
         );
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
-    fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+    fn cannot_move_into_closure(self, span: Span, desc: &str, _: Origin) -> DiagnosticBuilder<'cx> {
+        struct_span_err!(
             self,
             span,
             E0504,
-            "cannot move `{}` into closure because it is borrowed{OGN}",
+            "cannot move `{}` into closure because it is borrowed",
             desc,
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn cannot_reassign_immutable(
@@ -364,29 +315,25 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         span: Span,
         desc: &str,
         is_arg: bool,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let msg = if is_arg {
             "to immutable argument"
         } else {
             "twice to immutable variable"
         };
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0384,
-            "cannot assign {} `{}`{OGN}",
+            "cannot assign {} `{}`",
             msg,
             desc,
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
-    fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
-        self.cancel_if_wrong_origin(err, o)
+    fn cannot_assign(self, span: Span, desc: &str, _: Origin) -> DiagnosticBuilder<'cx> {
+        struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
     }
 
     fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
@@ -397,18 +344,15 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         self,
         move_from_span: Span,
         move_from_desc: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             move_from_span,
             E0507,
-            "cannot move out of {}{OGN}",
+            "cannot move out of {}",
             move_from_desc,
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     /// Signal an error due to an attempt to move out of the interior
@@ -419,7 +363,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         move_from_span: Span,
         ty: Ty<'_>,
         is_index: Option<bool>,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let type_name = match (&ty.sty, is_index) {
             (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
@@ -430,33 +374,29 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
             self,
             move_from_span,
             E0508,
-            "cannot move out of type `{}`, a non-copy {}{OGN}",
+            "cannot move out of type `{}`, a non-copy {}",
             ty,
             type_name,
-            OGN = o
         );
         err.span_label(move_from_span, "cannot move out of here");
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_move_out_of_interior_of_drop(
         self,
         move_from_span: Span,
         container_ty: Ty<'_>,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             move_from_span,
             E0509,
-            "cannot move out of type `{}`, which implements the `Drop` trait{OGN}",
+            "cannot move out of type `{}`, which implements the `Drop` trait",
             container_ty,
-            OGN = o
         );
         err.span_label(move_from_span, "cannot move out of here");
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_act_on_moved_value(
@@ -465,60 +405,51 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         verb: &str,
         optional_adverb_for_moved: &str,
         moved_path: Option<String>,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let moved_path = moved_path
             .map(|mp| format!(": `{}`", mp))
             .unwrap_or_default();
 
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             use_span,
             E0382,
-            "{} of {}moved value{}{OGN}",
+            "{} of {}moved value{}",
             verb,
             optional_adverb_for_moved,
             moved_path,
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn cannot_partially_reinit_an_uninit_struct(
         self,
         span: Span,
         uninit_path: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0383,
-            "partial reinitialization of uninitialized structure `{}`{OGN}",
+            "partial reinitialization of uninitialized structure `{}`",
             uninit_path,
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn closure_cannot_assign_to_borrowed(
         self,
         span: Span,
         descr: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0595,
-            "closure cannot assign to {}{OGN}",
+            "closure cannot assign to {}",
             descr,
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn cannot_borrow_path_as_mutable_because(
@@ -526,19 +457,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         span: Span,
         path: &str,
         reason: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0596,
-            "cannot borrow {} as mutable{}{OGN}",
+            "cannot borrow {} as mutable{}",
             path,
             reason,
-            OGN = o,
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn cannot_borrow_path_as_mutable(
@@ -556,73 +484,63 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         match_span: Span,
         match_place: &str,
         action: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             mutate_span,
             E0510,
-            "cannot {} `{}` in match guard{OGN}",
+            "cannot {} `{}` in match guard",
             action,
             match_place,
-            OGN = o
         );
         err.span_label(mutate_span, format!("cannot {}", action));
         err.span_label(match_span, String::from("value is immutable in match guard"));
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_borrow_across_generator_yield(
         self,
         span: Span,
         yield_span: Span,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             span,
             E0626,
-            "borrow may still be in use when generator yields{OGN}",
-            OGN = o
+            "borrow may still be in use when generator yields",
         );
         err.span_label(yield_span, "possible yield occurs here");
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_borrow_across_destructor(
         self,
         borrow_span: Span,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             borrow_span,
             E0713,
-            "borrow may still be in use when destructor runs{OGN}",
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+            "borrow may still be in use when destructor runs",
+        )
     }
 
     fn path_does_not_live_long_enough(
         self,
         span: Span,
         path: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0597,
-            "{} does not live long enough{OGN}",
+            "{} does not live long enough",
             path,
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn cannot_return_reference_to_local(
@@ -631,17 +549,16 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         return_kind: &str,
         reference_desc: &str,
         path_desc: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             span,
             E0515,
-            "cannot {RETURN} {REFERENCE} {LOCAL}{OGN}",
+            "cannot {RETURN} {REFERENCE} {LOCAL}",
             RETURN=return_kind,
             REFERENCE=reference_desc,
             LOCAL=path_desc,
-            OGN = o
         );
 
         err.span_label(
@@ -649,26 +566,23 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
             format!("{}s a {} data owned by the current function", return_kind, reference_desc),
         );
 
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn lifetime_too_short_for_reborrow(
         self,
         span: Span,
         path: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0598,
             "lifetime of {} is too short to guarantee \
-             its contents can be safely reborrowed{OGN}",
+             its contents can be safely reborrowed",
             path,
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn cannot_act_on_capture_in_sharable_fn(
@@ -676,39 +590,35 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         span: Span,
         bad_thing: &str,
         help: (Span, &str),
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let (help_span, help_msg) = help;
         let mut err = struct_span_err!(
             self,
             span,
             E0387,
-            "{} in a captured outer variable in an `Fn` closure{OGN}",
+            "{} in a captured outer variable in an `Fn` closure",
             bad_thing,
-            OGN = o
         );
         err.span_help(help_span, help_msg);
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_assign_into_immutable_reference(
         self,
         span: Span,
         bad_thing: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
             span,
             E0389,
-            "{} in a `&` reference{OGN}",
+            "{} in a `&` reference",
             bad_thing,
-            OGN = o
         );
         err.span_label(span, "assignment into an immutable reference");
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn cannot_capture_in_long_lived_closure(
@@ -716,7 +626,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         closure_span: Span,
         borrowed_path: &str,
         capture_span: Span,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
             self,
@@ -724,67 +634,56 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
             E0373,
             "closure may outlive the current function, \
              but it borrows {}, \
-             which is owned by the current function{OGN}",
+             which is owned by the current function",
             borrowed_path,
-            OGN = o
         );
         err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
             .span_label(
                 closure_span,
                 format!("may outlive borrowed value {}", borrowed_path),
             );
-
-        self.cancel_if_wrong_origin(err, o)
+        err
     }
 
     fn borrowed_data_escapes_closure(
         self,
         escape_span: Span,
         escapes_from: &str,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             escape_span,
             E0521,
-            "borrowed data escapes outside of {}{OGN}",
+            "borrowed data escapes outside of {}",
             escapes_from,
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+        )
     }
 
     fn thread_local_value_does_not_live_long_enough(
         self,
         span: Span,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0712,
-            "thread-local variable borrowed past end of function{OGN}",
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+            "thread-local variable borrowed past end of function",
+        )
     }
 
     fn temporary_value_borrowed_for_too_long(
         self,
         span: Span,
-        o: Origin,
+        _: Origin,
     ) -> DiagnosticBuilder<'cx> {
-        let err = struct_span_err!(
+        struct_span_err!(
             self,
             span,
             E0716,
-            "temporary value dropped while borrowed{OGN}",
-            OGN = o
-        );
-
-        self.cancel_if_wrong_origin(err, o)
+            "temporary value dropped while borrowed",
+        )
     }
 }
 
@@ -801,15 +700,4 @@ impl BorrowckErrors<'tcx> for TyCtxt<'tcx> {
     fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'tcx> {
         self.sess.struct_span_err(sp, msg)
     }
-
-    fn cancel_if_wrong_origin(
-        self,
-        mut diag: DiagnosticBuilder<'tcx>,
-        o: Origin,
-    ) -> DiagnosticBuilder<'tcx> {
-        if !o.should_emit_errors(self.borrowck_mode()) {
-            self.sess.diagnostic().cancel(&mut diag);
-        }
-        diag
-    }
 }