about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Daniel Faria <Nashenas88@users.noreply.github.com>2019-10-24 00:38:01 -0400
committerPaul Daniel Faria <Nashenas88@users.noreply.github.com>2019-12-02 08:31:35 -0500
commitab98c595eaa07249e2ebbf37c9123b33fc6a892f (patch)
treef39badabf4198291c1899b4a4486f90146ab79f2
parent2eed90a621f40aa3a2d56eda16f25315d17c4ca8 (diff)
downloadrust-ab98c595eaa07249e2ebbf37c9123b33fc6a892f.tar.gz
rust-ab98c595eaa07249e2ebbf37c9123b33fc6a892f.zip
Fix a large number of Body -> (ReadOnly)BodyCache type errors, add predecessor_locations fn to ReadOnlyBodyCache
-rw-r--r--src/librustc/mir/cache.rs64
-rw-r--r--src/librustc_mir/borrow_check/borrow_set.rs16
-rw-r--r--src/librustc_mir/borrow_check/conflict_errors.rs56
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs32
-rw-r--r--src/librustc_mir/borrow_check/mod.rs75
-rw-r--r--src/librustc_mir/borrow_check/move_errors.rs20
-rw-r--r--src/librustc_mir/borrow_check/mutability_errors.rs24
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs20
-rw-r--r--src/librustc_mir/borrow_check/nll/invalidation.rs10
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs31
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/values.rs8
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs10
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs20
-rw-r--r--src/librustc_mir/borrow_check/prefixes.rs2
-rw-r--r--src/librustc_mir/borrow_check/used_muts.rs2
15 files changed, 207 insertions, 183 deletions
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index 63d8eba971b..c0c5f77fe6e 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -33,6 +33,41 @@ pub struct Cache {
 //    }
 //}
 
+macro_rules! get_predecessors {
+    (mut $self:ident, $block:expr, $body:expr) => {
+        $self.predecessors_for($block, $body)
+    };
+    ($self:ident, $block:expr, $body:expr) => {
+        $self.unwrap_predecessors_for($block)
+    };
+}
+
+macro_rules! impl_predecessor_locations {
+    ( ( $($pub:ident)? )  $name:ident $($mutability:ident)?) => {
+        $($pub)? fn $name<'a>(&'a $($mutability)? self, loc: Location, body: &'a Body<'a>) -> impl Iterator<Item = Location> + 'a {
+            let if_zero_locations = if loc.statement_index == 0 {
+                let predecessor_blocks = get_predecessors!($($mutability)? self, loc.block, body);
+                let num_predecessor_blocks = predecessor_blocks.len();
+                Some(
+                    (0..num_predecessor_blocks)
+                        .map(move |i| predecessor_blocks[i])
+                        .map(move |bb| body.terminator_loc(bb)),
+                )
+            } else {
+                None
+            };
+
+            let if_not_zero_locations = if loc.statement_index == 0 {
+                None
+            } else {
+                Some(Location { block: loc.block, statement_index: loc.statement_index - 1 })
+            };
+
+            if_zero_locations.into_iter().flatten().chain(if_not_zero_locations)
+        }
+    };
+}
+
 impl Cache {
     pub fn new() -> Self {
         Self {
@@ -80,27 +115,9 @@ impl Cache {
     }
 
     #[inline]
-    pub fn predecessor_locations<'a>(&'a mut self, loc: Location, body: &'a Body<'a>) -> impl Iterator<Item = Location> + 'a {
-        let if_zero_locations = if loc.statement_index == 0 {
-            let predecessor_blocks = self.predecessors_for(loc.block, body);
-            let num_predecessor_blocks = predecessor_blocks.len();
-            Some(
-                (0..num_predecessor_blocks)
-                    .map(move |i| predecessor_blocks[i])
-                    .map(move |bb| body.terminator_loc(bb)),
-            )
-        } else {
-            None
-        };
-
-        let if_not_zero_locations = if loc.statement_index == 0 {
-            None
-        } else {
-            Some(Location { block: loc.block, statement_index: loc.statement_index - 1 })
-        };
-
-        if_zero_locations.into_iter().flatten().chain(if_not_zero_locations)
-    }
+    impl_predecessor_locations!((pub) predecessor_locations mut);
+
+    impl_predecessor_locations!(() unwrap_predecessor_locations);
 
     #[inline]
     pub fn basic_blocks_mut<'a, 'tcx>(&mut self, body: &'a mut Body<'tcx>) -> &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
@@ -241,6 +258,11 @@ impl ReadOnlyBodyCache<'a, 'tcx> {
     }
 
     #[inline]
+    pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ {
+        self.cache.unwrap_predecessor_locations(loc, self.body)
+    }
+
+    #[inline]
     pub fn body(&self) -> &'a Body<'tcx> {
         self.body
     }
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index 94323431990..6191a93d228 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -5,7 +5,7 @@ use crate::dataflow::indexes::BorrowIndex;
 use crate::dataflow::move_paths::MoveData;
 use rustc::mir::traversal;
 use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext};
-use rustc::mir::{self, Location, Body, Local};
+use rustc::mir::{self, Location, Body, Local, ReadOnlyBodyCache};
 use rustc::ty::{RegionVid, TyCtxt};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_index::vec::IndexVec;
@@ -90,7 +90,7 @@ crate enum LocalsStateAtExit {
 impl LocalsStateAtExit {
     fn build(
         locals_are_invalidated_at_exit: bool,
-        body: &Body<'tcx>,
+        body_cache: &ReadOnlyBodyCache<'_, 'tcx>,
         move_data: &MoveData<'tcx>
     ) -> Self {
         struct HasStorageDead(BitSet<Local>);
@@ -106,8 +106,8 @@ impl LocalsStateAtExit {
         if locals_are_invalidated_at_exit {
             LocalsStateAtExit::AllAreInvalidated
         } else {
-            let mut has_storage_dead = HasStorageDead(BitSet::new_empty(body.local_decls.len()));
-            has_storage_dead.visit_body(body);
+            let mut has_storage_dead = HasStorageDead(BitSet::new_empty(body_cache.local_decls.len()));
+            has_storage_dead.visit_body(body_cache);
             let mut has_storage_dead_or_moved = has_storage_dead.0;
             for move_out in &move_data.moves {
                 if let Some(index) = move_data.base_local(move_out.path) {
@@ -123,23 +123,23 @@ impl LocalsStateAtExit {
 impl<'tcx> BorrowSet<'tcx> {
     pub fn build(
         tcx: TyCtxt<'tcx>,
-        body: &Body<'tcx>,
+        body_cache: &ReadOnlyBodyCache<'_, 'tcx>,
         locals_are_invalidated_at_exit: bool,
         move_data: &MoveData<'tcx>,
     ) -> Self {
         let mut visitor = GatherBorrows {
             tcx,
-            body,
+            body: body_cache.body(),
             idx_vec: IndexVec::new(),
             location_map: Default::default(),
             activation_map: Default::default(),
             local_map: Default::default(),
             pending_activations: Default::default(),
             locals_state_at_exit:
-                LocalsStateAtExit::build(locals_are_invalidated_at_exit, body, move_data),
+                LocalsStateAtExit::build(locals_are_invalidated_at_exit, body_cache, move_data),
         };
 
-        for (block, block_data) in traversal::preorder(body) {
+        for (block, block_data) in traversal::preorder(body_cache) {
             visitor.visit_basic_block_data(block, block_data);
         }
 
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
index 48f8ad9bbd8..b44ef1c1706 100644
--- a/src/librustc_mir/borrow_check/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/conflict_errors.rs
@@ -206,7 +206,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
 
             let ty =
-                Place::ty_from(used_place.base, used_place.projection, self.body, self.infcx.tcx)
+                Place::ty_from(used_place.base, used_place.projection, self.body_cache.body(), self.infcx.tcx)
                     .ty;
             let needs_note = match ty.kind {
                 ty::Closure(id, _) => {
@@ -222,7 +222,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let mpi = self.move_data.moves[move_out_indices[0]].path;
                 let place = &self.move_data.move_paths[mpi].place;
 
-                let ty = place.ty(self.body, self.infcx.tcx).ty;
+                let ty = place.ty(self.body_cache.body(), self.infcx.tcx).ty;
                 let opt_name =
                     self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
                 let note_msg = match opt_name {
@@ -314,7 +314,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             None,
         ).add_explanation_to_diagnostic(
             self.infcx.tcx,
-            self.body,
+            &self.body_cache,
             &self.local_names,
             &mut err,
             "",
@@ -356,7 +356,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         self.explain_why_borrow_contains_point(location, borrow, None)
             .add_explanation_to_diagnostic(
                 self.infcx.tcx,
-                self.body,
+                &self.body_cache,
                 &self.local_names,
                 &mut err,
                 "",
@@ -578,7 +578,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         explanation.add_explanation_to_diagnostic(
             self.infcx.tcx,
-            self.body,
+            &self.body_cache,
             &self.local_names,
             &mut err,
             first_borrow_desc,
@@ -619,7 +619,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // Define a small closure that we can use to check if the type of a place
         // is a union.
         let union_ty = |place_base, place_projection| {
-            let ty = Place::ty_from(place_base, place_projection, self.body, self.infcx.tcx).ty;
+            let ty = Place::ty_from(place_base, place_projection, self.body_cache.body(), self.infcx.tcx).ty;
             ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
         };
         let describe_place = |place| self.describe_place(place).unwrap_or_else(|| "_".to_owned());
@@ -738,7 +738,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         assert!(root_place.projection.is_empty());
         let proper_span = match root_place.base {
-            PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
+            PlaceBase::Local(local) => self.body_cache.local_decls[*local].source_info.span,
             _ => drop_span,
         };
 
@@ -965,7 +965,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             } else {
                 explanation.add_explanation_to_diagnostic(
                     self.infcx.tcx,
-                    self.body,
+                    &self.body_cache,
                     &self.local_names,
                     &mut err,
                     "",
@@ -991,7 +991,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             );
 
             explanation.add_explanation_to_diagnostic(
-                self.infcx.tcx, self.body, &self.local_names, &mut err, "", None);
+                self.infcx.tcx, &self.body_cache, &self.local_names, &mut err, "", None);
         }
 
         err
@@ -1051,7 +1051,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         explanation.add_explanation_to_diagnostic(
             self.infcx.tcx,
-            self.body,
+            &self.body_cache,
             &self.local_names,
             &mut err,
             "",
@@ -1138,7 +1138,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
         explanation.add_explanation_to_diagnostic(
             self.infcx.tcx,
-            self.body,
+            &self.body_cache,
             &self.local_names,
             &mut err,
             "",
@@ -1174,7 +1174,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         };
 
         // FIXME use a better heuristic than Spans
-        let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span {
+        let reference_desc = if return_span == self.body_cache.source_info(borrow.reserve_location).span {
             "reference to"
         } else {
             "value referencing"
@@ -1182,7 +1182,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
             let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
-                match self.body.local_kind(local) {
+                match self.body_cache.local_kind(local) {
                     LocalKind::ReturnPointer
                     | LocalKind::Temp => bug!("temporary or return pointer with a name"),
                     LocalKind::Var => "local variable ",
@@ -1215,7 +1215,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             } else {
                 bug!("try_report_cannot_return_reference_to_local: not a local")
             };
-            match self.body.local_kind(*local) {
+            match self.body_cache.local_kind(*local) {
                 LocalKind::ReturnPointer | LocalKind::Temp => (
                     "temporary value".to_string(),
                     "temporary value created here".to_string(),
@@ -1372,10 +1372,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
-        let body = self.body;
-
         let mut stack = Vec::new();
-        stack.extend(body.predecessor_locations(location).map(|predecessor| {
+        stack.extend(self.body_cache.predecessor_locations(location).map(|predecessor| {
             let is_back_edge = location.dominates(predecessor, &self.dominators);
             (predecessor, is_back_edge)
         }));
@@ -1394,7 +1392,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
 
             // check for moves
-            let stmt_kind = body[location.block]
+            let stmt_kind = self.body_cache[location.block]
                 .statements
                 .get(location.statement_index)
                 .map(|s| &s.kind);
@@ -1449,7 +1447,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let mut any_match = false;
             drop_flag_effects::for_location_inits(
                 self.infcx.tcx,
-                self.body,
+                &self.body_cache,
                 self.move_data,
                 location,
                 |m| {
@@ -1462,7 +1460,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 continue 'dfs;
             }
 
-            stack.extend(body.predecessor_locations(location).map(|predecessor| {
+            stack.extend(self.body_cache.predecessor_locations(location).map(|predecessor| {
                 let back_edge = location.dominates(predecessor, &self.dominators);
                 (predecessor, is_back_edge || back_edge)
             }));
@@ -1514,7 +1512,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         self.explain_why_borrow_contains_point(location, loan, None)
             .add_explanation_to_diagnostic(
                 self.infcx.tcx,
-                self.body,
+                &self.body_cache,
                 &self.local_names,
                 &mut err,
                 "",
@@ -1539,8 +1537,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     ) {
         let (from_arg, local_decl, local_name) = match err_place.as_local() {
             Some(local) => (
-                self.body.local_kind(local) == LocalKind::Arg,
-                Some(&self.body.local_decls[local]),
+                self.body_cache.local_kind(local) == LocalKind::Arg,
+                Some(&self.body_cache.local_decls[local]),
                 self.local_names[local],
             ),
             None => (false, None, None),
@@ -1625,7 +1623,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         StorageDeadOrDrop::LocalStorageDead
                         | StorageDeadOrDrop::BoxedStorageDead => {
                             assert!(
-                                Place::ty_from(&place.base, proj_base, self.body, tcx).ty.is_box(),
+                                Place::ty_from(&place.base, proj_base, self.body_cache.body(), tcx).ty.is_box(),
                                 "Drop of value behind a reference or raw pointer"
                             );
                             StorageDeadOrDrop::BoxedStorageDead
@@ -1633,7 +1631,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         StorageDeadOrDrop::Destructor(_) => base_access,
                     },
                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
-                        let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
+                        let base_ty = Place::ty_from(&place.base, proj_base, self.body_cache.body(), tcx).ty;
                         match base_ty.kind {
                             ty::Adt(def, _) if def.has_dtor(tcx) => {
                                 // Report the outermost adt with a destructor
@@ -1721,7 +1719,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             location
         );
         if let Some(&Statement { kind: StatementKind::Assign(box(ref reservation, _)), ..})
-             = &self.body[location.block].statements.get(location.statement_index)
+             = &self.body_cache[location.block].statements.get(location.statement_index)
         {
             debug!(
                 "annotate_argument_and_return_for_borrow: reservation={:?}",
@@ -1729,14 +1727,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             );
             // Check that the initial assignment of the reserve location is into a temporary.
             let mut target = match reservation.as_local() {
-                Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
+                Some(local) if self.body_cache.local_kind(local) == LocalKind::Temp => local,
                 _ => return None,
             };
 
             // Next, look through the rest of the block, checking if we are assigning the
             // `target` (that is, the place that contains our borrow) to anything.
             let mut annotated_closure = None;
-            for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
+            for stmt in &self.body_cache[location.block].statements[location.statement_index + 1..] {
                 debug!(
                     "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
                     target, stmt
@@ -1861,7 +1859,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
 
             // Check the terminator if we didn't find anything in the statements.
-            let terminator = &self.body[location.block].terminator();
+            let terminator = &self.body_cache[location.block].terminator();
             debug!(
                 "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
                 target, terminator
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index a555e0b74c2..8267e5c1c4b 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -39,7 +39,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     ) {
         debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
         let mut target = place.local_or_deref_local();
-        for stmt in &self.body[location.block].statements[location.statement_index..] {
+        for stmt in &self.body_cache[location.block].statements[location.statement_index..] {
             debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
             if let StatementKind::Assign(box(into, Rvalue::Use(from))) = &stmt.kind {
                 debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
@@ -53,7 +53,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
 
         // Check if we are attempting to call a closure after it has been invoked.
-        let terminator = self.body[location.block].terminator();
+        let terminator = self.body_cache[location.block].terminator();
         debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
         if let TerminatorKind::Call {
             func: Operand::Constant(box Constant {
@@ -76,7 +76,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 };
 
                 debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
-                if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind {
+                if let ty::Closure(did, _) = self.body_cache.local_decls[closure].ty.kind {
                     let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap();
 
                     if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
@@ -99,7 +99,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         // Check if we are just moving a closure after it has been invoked.
         if let Some(target) = target {
-            if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind {
+            if let ty::Closure(did, _) = self.body_cache.local_decls[target].ty.kind {
                 let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap();
 
                 if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did)
@@ -332,7 +332,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
     /// a name, or its name was generated by the compiler, then `Err` is returned
     fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
-        let decl = &self.body.local_decls[local];
+        let decl = &self.body_cache.local_decls[local];
         match self.local_names[local] {
             Some(name) if !decl.from_compiler_desugaring() => {
                 buf.push_str(&name.as_str());
@@ -350,7 +350,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 base: PlaceBase::Local(local),
                 projection: [],
             } => {
-                let local = &self.body.local_decls[*local];
+                let local = &self.body_cache.local_decls[*local];
                 self.describe_field_from_ty(&local.ty, field, None)
             }
             PlaceRef {
@@ -370,7 +370,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 }
                 ProjectionElem::Downcast(_, variant_index) => {
                     let base_ty =
-                        Place::ty_from(place.base, place.projection, self.body, self.infcx.tcx).ty;
+                        Place::ty_from(place.base, place.projection, self.body_cache.body(), self.infcx.tcx).ty;
                     self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
                 }
                 ProjectionElem::Field(_, field_type) => {
@@ -481,7 +481,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         _ => continue,
                     };
 
-                    let bbd = &self.body[loc.block];
+                    let bbd = &self.body_cache[loc.block];
                     let is_terminator = bbd.statements.len() == loc.statement_index;
                     debug!(
                         "borrowed_content_source: loc={:?} is_terminator={:?}",
@@ -499,7 +499,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         ..
                     }) = bbd.terminator {
                         if let Some(source)
-                            = BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
+                            = BorrowedContentSource::from_call(func.ty(self.body_cache.body(), tcx), tcx)
                         {
                             return source;
                         }
@@ -512,7 +512,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         // If we didn't find an overloaded deref or index, then assume it's a
         // built in deref and check the type of the base.
-        let base_ty = Place::ty_from(deref_base.base, deref_base.projection, self.body, tcx).ty;
+        let base_ty = Place::ty_from(deref_base.base, deref_base.projection, self.body_cache.body(), tcx).ty;
         if base_ty.is_unsafe_ptr() {
             BorrowedContentSource::DerefRawPointer
         } else if base_ty.is_mutable_ptr() {
@@ -767,9 +767,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     ) -> UseSpans {
         use self::UseSpans::*;
 
-        let stmt = match self.body[location.block].statements.get(location.statement_index) {
+        let stmt = match self.body_cache[location.block].statements.get(location.statement_index) {
             Some(stmt) => stmt,
-            None => return OtherUse(self.body.source_info(location).span),
+            None => return OtherUse(self.body_cache.source_info(location).span),
         };
 
         debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
@@ -807,7 +807,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         use self::UseSpans::*;
         debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
 
-        let target = match self.body[location.block]
+        let target = match self.body_cache[location.block]
             .statements
             .get(location.statement_index)
         {
@@ -824,12 +824,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             _ => return OtherUse(use_span),
         };
 
-        if self.body.local_kind(target) != LocalKind::Temp {
+        if self.body_cache.local_kind(target) != LocalKind::Temp {
             // operands are always temporaries.
             return OtherUse(use_span);
         }
 
-        for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
+        for stmt in &self.body_cache[location.block].statements[location.statement_index + 1..] {
             if let StatementKind::Assign(
                 box(_, Rvalue::Aggregate(ref kind, ref places))
             ) = stmt.kind {
@@ -901,7 +901,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Helper to retrieve span(s) of given borrow from the current MIR
     /// representation
     pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans {
-        let span = self.body.source_info(borrow.reserve_location).span;
+        let span = self.body_cache.source_info(borrow.reserve_location).span;
         self.borrow_spans(span, borrow.reserve_location)
     }
 }
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index f861a423ae2..0c1b0c4e14e 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -10,7 +10,7 @@ use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
 use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc::mir::{
     ClearCrossCrate, Local, Location, Body, BodyCache, Mutability, Operand, Place, PlaceBase,
-    PlaceElem, PlaceRef, Static, StaticKind
+    PlaceElem, PlaceRef, ReadOnlyBodyCache, Static, StaticKind
 };
 use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
 use rustc::mir::{Terminator, TerminatorKind};
@@ -163,16 +163,19 @@ fn do_mir_borrowck<'a, 'tcx>(
     // be modified (in place) to contain non-lexical lifetimes. It
     // will have a lifetime tied to the inference context.
     let mut body: Body<'tcx> = input_body.clone();
-    let mut promoted: IndexVec<Promoted, Body<'tcx>> = input_promoted.clone();
+    // TODO(pfaria) this very likely won't work because
+    let promoted: IndexVec<Promoted, Body<'tcx>> = input_promoted.clone();
+    let mut promoted_cache: IndexVec<Promoted, BodyCache<&mut Body<'tcx>>> = promoted.iter_mut().map(|body| BodyCache::new(body)).collect();
+    let mut body_cache = BodyCache::new(&mut body);
     let free_regions =
-        nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted);
+        nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body_cache, &mut promoted_cache);
+    let body_cache = BodyCache::new(&body).read_only(); // no further changes
 
-    let body_cache = &BodyCache::new(&body); // no further changes
-    let location_table = &LocationTable::new(body_cache);
+    let location_table = &LocationTable::new(&body_cache);
 
     let mut errors_buffer = Vec::new();
     let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) =
-        match MoveData::gather_moves(body_cache, tcx) {
+        match MoveData::gather_moves(&body_cache, tcx) {
             Ok(move_data) => (move_data, None),
             Err((move_data, move_errors)) => (move_data, Some(move_errors)),
         };
@@ -185,24 +188,24 @@ fn do_mir_borrowck<'a, 'tcx>(
     let dead_unwinds = BitSet::new_empty(body_cache.basic_blocks().len());
     let mut flow_inits = FlowAtLocation::new(do_dataflow(
         tcx,
-        body_cache,
+        &body_cache,
         def_id,
         &attributes,
         &dead_unwinds,
-        MaybeInitializedPlaces::new(tcx, body_cache, &mdpe),
+        MaybeInitializedPlaces::new(tcx, &body_cache, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
     ));
 
     let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure();
     let borrow_set = Rc::new(BorrowSet::build(
-            tcx, body_cache, locals_are_invalidated_at_exit, &mdpe.move_data));
+            tcx, &body_cache, locals_are_invalidated_at_exit, &mdpe.move_data));
 
     // If we are in non-lexical mode, compute the non-lexical lifetimes.
     let (regioncx, polonius_output, opt_closure_req) = nll::compute_regions(
         infcx,
         def_id,
         free_regions,
-        body_cache,
+        &body_cache,
         &promoted,
         &local_names,
         &upvars,
@@ -223,29 +226,29 @@ fn do_mir_borrowck<'a, 'tcx>(
 
     let flow_borrows = FlowAtLocation::new(do_dataflow(
         tcx,
-        body_cache,
+        &body_cache,
         def_id,
         &attributes,
         &dead_unwinds,
-        Borrows::new(tcx, body_cache, param_env, regioncx.clone(), &borrow_set),
+        Borrows::new(tcx, &body_cache, param_env, regioncx.clone(), &borrow_set),
         |rs, i| DebugFormatted::new(&rs.location(i)),
     ));
     let flow_uninits = FlowAtLocation::new(do_dataflow(
         tcx,
-        body_cache,
+        &body_cache,
         def_id,
         &attributes,
         &dead_unwinds,
-        MaybeUninitializedPlaces::new(tcx, body_cache, &mdpe),
+        MaybeUninitializedPlaces::new(tcx, &body_cache, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
     ));
     let flow_ever_inits = FlowAtLocation::new(do_dataflow(
         tcx,
-        body_cache,
+        &body_cache,
         def_id,
         &attributes,
         &dead_unwinds,
-        EverInitializedPlaces::new(tcx, body_cache, &mdpe),
+        EverInitializedPlaces::new(tcx, &body_cache, &mdpe),
         |bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
     ));
 
@@ -302,7 +305,7 @@ fn do_mir_borrowck<'a, 'tcx>(
             mbcx.report_conflicting_borrow(location, (&place, span), bk, &borrow);
 
         let scope = mbcx.body.source_info(location).scope;
-        let lint_root = match &mbcx.body.source_scopes[scope].local_data {
+        let lint_root = match &mbcx.body_cache.source_scopes[scope].local_data {
             ClearCrossCrate::Set(data) => data.lint_root,
             _ => id,
         };
@@ -324,21 +327,21 @@ fn do_mir_borrowck<'a, 'tcx>(
     // would have a chance of erroneously adding non-user-defined mutable vars
     // to the set.
     let temporary_used_locals: FxHashSet<Local> = mbcx.used_mut.iter()
-        .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
+        .filter(|&local| !mbcx.body_cache.local_decls[*local].is_user_variable())
         .cloned()
         .collect();
     // For the remaining unused locals that are marked as mutable, we avoid linting any that
     // were never initialized. These locals may have been removed as unreachable code; or will be
     // linted as unused variables.
-    let unused_mut_locals = mbcx.body.mut_vars_iter()
+    let unused_mut_locals = mbcx.body_cache.mut_vars_iter()
         .filter(|local| !mbcx.used_mut.contains(local))
         .collect();
     mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
 
     debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
     let used_mut = mbcx.used_mut;
-    for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
-        let local_decl = &mbcx.body.local_decls[local];
+    for local in mbcx.body_cache.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
+        let local_decl = &mbcx.body_cache.local_decls[local];
         let lint_root = match &mbcx.body.source_scopes[local_decl.source_info.scope].local_data {
             ClearCrossCrate::Set(data) => data.lint_root,
             _ => continue,
@@ -399,7 +402,7 @@ fn do_mir_borrowck<'a, 'tcx>(
 
 crate struct MirBorrowckCtxt<'cx, 'tcx> {
     crate infcx: &'cx InferCtxt<'cx, 'tcx>,
-    body_cache: BodyCache<&'cx Body<'tcx>>,
+    body_cache: ReadOnlyBodyCache<'cx, 'tcx>,
     mir_def_id: DefId,
     param_env: ty::ParamEnv<'tcx>,
     move_data: &'cx MoveData<'tcx>,
@@ -490,7 +493,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
     type FlowState = Flows<'cx, 'tcx>;
 
     fn body(&self) -> &'cx Body<'tcx> {
-        self.body_cache
+        &self.body_cache
     }
 
     fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) {
@@ -640,7 +643,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
                 let tcx = self.infcx.tcx;
 
                 // Compute the type with accurate region information.
-                let drop_place_ty = drop_place.ty(self.body_cache, self.infcx.tcx);
+                let drop_place_ty = drop_place.ty(self.body_cache.body(), self.infcx.tcx);
 
                 // Erase the regions.
                 let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty;
@@ -984,7 +987,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         let mut error_reported = false;
         let tcx = self.infcx.tcx;
-        let body = self.body_cache;
+        let body = self.body_cache.body();
         let param_env = self.param_env;
         let location_table = self.location_table.start_index(location);
         let borrow_set = self.borrow_set.clone();
@@ -1150,7 +1153,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // (e.g., `x = ...`) so long as it has never been initialized
         // before (at this point in the flow).
         if let Some(local) = place_span.0.as_local() {
-            if let Mutability::Not = self.body.local_decls[local].mutability {
+            if let Mutability::Not = self.body+cache.local_decls[local].mutability {
                 // check for reassignments to immutable local variables
                 self.check_if_reassignment_to_immutable_state(
                     location,
@@ -1303,7 +1306,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         match *operand {
             Operand::Move(ref place) | Operand::Copy(ref place) => {
                 match place.as_local() {
-                    Some(local) if !self.body.local_decls[local].is_user_variable() => {
+                    Some(local) if !self.body_cache.local_decls[local].is_user_variable() => {
                         if self.body.local_decls[local].ty.is_mutable_ptr() {
                             // The variable will be marked as mutable by the borrow.
                             return;
@@ -1335,7 +1338,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             _ => bug!("temporary initialized in arguments"),
                         };
 
-                        let bbd = &self.body[loc.block];
+                        let bbd = &self.body_cache[loc.block];
                         let stmt = &bbd.statements[loc.statement_index];
                         debug!("temporary assigned in: stmt={:?}", stmt);
 
@@ -1454,7 +1457,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         if places_conflict::borrow_conflicts_with_place(
             self.infcx.tcx,
             self.param_env,
-            self.body,
+            &self.body_cache,
             place,
             borrow.kind,
             root_place,
@@ -1534,7 +1537,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
             // And, if so, report an error.
             let init = &self.move_data.inits[init_index];
-            let span = init.span(&self.body);
+            let span = init.span(&self.body_cache);
             self.report_illegal_reassignment(
                 location, place_span, span, place_span.0
             );
@@ -1745,7 +1748,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     // assigning to `P.f` requires `P` itself
                     // be already initialized
                     let tcx = self.infcx.tcx;
-                    let base_ty = Place::ty_from(&place.base, proj_base, self.body, tcx).ty;
+                    let base_ty = Place::ty_from(&place.base, proj_base, self.body(), tcx).ty;
                     match base_ty.kind {
                         ty::Adt(def, _) if def.has_dtor(tcx) => {
                             self.check_if_path_or_subpath_is_moved(
@@ -1852,12 +1855,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // of the union - we should error in that case.
                 let tcx = this.infcx.tcx;
                 if let ty::Adt(def, _) =
-                    Place::ty_from(base.base, base.projection, this.body, tcx).ty.kind
+                    Place::ty_from(base.base, base.projection, this.body(), tcx).ty.kind
                 {
                     if def.is_union() {
                         if this.move_data.path_map[mpi].iter().any(|moi| {
                             this.move_data.moves[*moi].source.is_predecessor_of(
-                                location, this.body,
+                                location, &this.body_cache,
                             )
                         }) {
                             return;
@@ -2061,7 +2064,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 base: PlaceBase::Local(local),
                 projection: [],
             } => {
-                let local = &self.body.local_decls[*local];
+                let local = &self.body_cache.local_decls[*local];
                 match local.mutability {
                     Mutability::Not => match is_local_mutation_allowed {
                         LocalMutationIsAllowed::Yes => Ok(RootPlace {
@@ -2122,7 +2125,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 match elem {
                     ProjectionElem::Deref => {
                         let base_ty =
-                            Place::ty_from(place.base, proj_base, self.body, self.infcx.tcx).ty;
+                            Place::ty_from(place.base, proj_base, self.body(), self.infcx.tcx).ty;
 
                         // Check the kind of deref to decide
                         match base_ty.kind {
@@ -2262,7 +2265,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         match place_projection {
             [base @ .., ProjectionElem::Field(field, _ty)] => {
                 let tcx = self.infcx.tcx;
-                let base_ty = Place::ty_from(place_ref.base, base, self.body, tcx).ty;
+                let base_ty = Place::ty_from(place_ref.base, base, self.body(), tcx).ty;
 
                 if (base_ty.is_closure() || base_ty.is_generator()) &&
                     (!by_ref || self.upvars[field.index()].by_ref) {
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs
index bf61eb9f0c5..5907da09c67 100644
--- a/src/librustc_mir/borrow_check/move_errors.rs
+++ b/src/librustc_mir/borrow_check/move_errors.rs
@@ -90,13 +90,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 // flow could be used.
                 if let Some(StatementKind::Assign(
                     box(place, Rvalue::Use(Operand::Move(move_from)))
-                )) = self.body.basic_blocks()[location.block]
+                )) = self.body_cache.basic_blocks()[location.block]
                     .statements
                     .get(location.statement_index)
                     .map(|stmt| &stmt.kind)
                 {
                     if let Some(local) = place.as_local() {
-                        let local_decl = &self.body.local_decls[local];
+                        let local_decl = &self.body_cache.local_decls[local];
                         // opt_match_place is the
                         // match_span is the span of the expression being matched on
                         // match *x.y { ... }        match_place is Some(*x.y)
@@ -112,7 +112,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                 pat_span: _,
                             },
                         ))) = local_decl.local_info {
-                            let stmt_source_info = self.body.source_info(location);
+                            let stmt_source_info = self.body_cache.source_info(location);
                             self.append_binding_error(
                                 grouped_errors,
                                 kind,
@@ -300,7 +300,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         // Inspect the type of the content behind the
         // borrow to provide feedback about why this
         // was a move rather than a copy.
-        let ty = deref_target_place.ty(self.body, self.infcx.tcx).ty;
+        let ty = deref_target_place.ty(self.body_cache.body(), self.infcx.tcx).ty;
         let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
             .find_map(|p| self.is_upvar_field_projection(p));
 
@@ -318,7 +318,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             base: PlaceBase::Local(local),
             projection: [],
         } = deref_base {
-            let decl = &self.body.local_decls[*local];
+            let decl = &self.body_cache.local_decls[*local];
             if decl.is_ref_for_guard() {
                 let mut err = self.cannot_move_out_of(
                     span,
@@ -411,7 +411,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         };
         let move_ty = format!(
             "{:?}",
-            move_place.ty(self.body, self.infcx.tcx).ty,
+            move_place.ty(self.body_cache.body(), self.infcx.tcx).ty,
         );
         if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
             let is_option = move_ty.starts_with("std::option::Option");
@@ -454,7 +454,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 }
 
                 if binds_to.is_empty() {
-                    let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
+                    let place_ty = move_from.ty(self.body_cache.body(), self.infcx.tcx).ty;
                     let place_desc = match self.describe_place(move_from.as_ref()) {
                         Some(desc) => format!("`{}`", desc),
                         None => format!("value"),
@@ -482,7 +482,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             // No binding. Nothing to suggest.
             GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => {
                 let span = use_spans.var_or_use();
-                let place_ty = original_path.ty(self.body, self.infcx.tcx).ty;
+                let place_ty = original_path.ty(self.body_cache.body(), self.infcx.tcx).ty;
                 let place_desc = match self.describe_place(original_path.as_ref()) {
                     Some(desc) => format!("`{}`", desc),
                     None => format!("value"),
@@ -510,7 +510,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     ) {
         let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
         for local in binds_to {
-            let bind_to = &self.body.local_decls[*local];
+            let bind_to = &self.body_cache.local_decls[*local];
             if let LocalInfo::User(
                 ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
                     pat_span,
@@ -559,7 +559,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         binds_to: &[Local],
     ) {
         for (j, local) in binds_to.into_iter().enumerate() {
-            let bind_to = &self.body.local_decls[*local];
+            let bind_to = &self.body_cache.local_decls[*local];
             let binding_span = bind_to.source_info.span;
 
             if j == 0 {
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
index bf070c3f07d..654666882cc 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/mutability_errors.rs
@@ -61,7 +61,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(&the_place_err.base, proj_base, self.body, self.infcx.tcx).ty
+                    Place::ty_from(&the_place_err.base, proj_base, self.body_cache.body(), self.infcx.tcx).ty
                 ));
 
                 item_msg = format!("`{}`", access_place_desc.unwrap());
@@ -106,12 +106,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     proj_base.is_empty() &&
                     !self.upvars.is_empty() {
                     item_msg = format!("`{}`", access_place_desc.unwrap());
-                    debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
+                    debug_assert!(self.body_cache.local_decls[Local::new(1)].ty.is_region_ptr());
                     debug_assert!(is_closure_or_generator(
                         Place::ty_from(
                             the_place_err.base,
                             the_place_err.projection,
-                            self.body,
+                            self.body_cache.body(),
                             self.infcx.tcx
                         )
                         .ty
@@ -225,7 +225,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 if let Some((span, message)) = annotate_struct_field(
                     self.infcx.tcx,
-                    Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty,
+                    Place::ty_from(base, proj_base, self.body_cache.body(), self.infcx.tcx).ty,
                     field,
                 ) {
                     err.span_suggestion(
@@ -242,7 +242,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 base: PlaceBase::Local(local),
                 projection: [],
             } if {
-                self.body.local_decls.get(*local).map(|local_decl| {
+                self.body_cache.local_decls.get(*local).map(|local_decl| {
                     if let LocalInfo::User(ClearCrossCrate::Set(
                         mir::BindingForm::ImplicitSelf(kind)
                     )) = local_decl.local_info {
@@ -277,12 +277,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             PlaceRef {
                 base: PlaceBase::Local(local),
                 projection: [],
-            } if self.body.local_decls[*local].can_be_made_mutable() => {
+            } if self.body_cache.local_decls[*local].can_be_made_mutable() => {
                 // ... but it doesn't make sense to suggest it on
                 // variables that are `ref x`, `ref mut x`, `&self`,
                 // or `&mut self` (such variables are simply not
                 // mutable).
-                let local_decl = &self.body.local_decls[*local];
+                let local_decl = &self.body_cache.local_decls[*local];
                 assert_eq!(local_decl.mutability, Mutability::Not);
 
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
@@ -300,7 +300,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(base, proj_base, self.body, self.infcx.tcx).ty
+                    Place::ty_from(base, proj_base, self.body_cache.body(), self.infcx.tcx).ty
                 ));
 
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
@@ -346,7 +346,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             PlaceRef {
                 base: PlaceBase::Local(local),
                 projection: [ProjectionElem::Deref],
-            } if self.body.local_decls[*local].is_ref_for_guard() => {
+            } if self.body_cache.local_decls[*local].is_ref_for_guard() => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
                 err.note(
                     "variables bound in patterns are immutable until the end of the pattern guard",
@@ -363,7 +363,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 projection: [ProjectionElem::Deref],
             } if self.body.local_decls[*local].is_user_variable() =>
             {
-                let local_decl = &self.body.local_decls[*local];
+                let local_decl = &self.body_cache.local_decls[*local];
                 let suggestion = match local_decl.local_info {
                     LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_))) => {
                         Some(suggest_ampmut_self(self.infcx.tcx, local_decl))
@@ -377,7 +377,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         },
                     ))) => Some(suggest_ampmut(
                         self.infcx.tcx,
-                        self.body,
+                        &self.body_cache,
                         *local,
                         local_decl,
                         opt_ty_info,
@@ -451,7 +451,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
                 err.span_help(
-                    self.body.span,
+                    self.body_cache.span,
                     "consider changing this to accept closures that implement `FnMut`"
                 );
             }
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
index c7058531958..4097bfeeb35 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -237,7 +237,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         );
 
         let regioncx = &self.nonlexical_regioncx;
-        let body = self.body;
+        let body = self.body_cache.body();
         let tcx = self.infcx.tcx;
 
         let borrow_region_vid = borrow.region;
@@ -297,9 +297,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 if let Some(region) = regioncx.to_error_region_vid(borrow_region_vid) {
                     let (category, from_closure, span, region_name) =
                         self.nonlexical_regioncx.free_region_constraint_info(
-                            self.body,
-                        &self.local_names,
-                        &self.upvars,
+                            &self.body_cache,
+                            &self.local_names,
+                            &self.upvars,
                             self.mir_def_id,
                             self.infcx,
                             borrow_region_vid,
@@ -365,7 +365,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 return outmost_back_edge;
             }
 
-            let block = &self.body.basic_blocks()[location.block];
+            let block = &self.body_cache.basic_blocks()[location.block];
 
             if location.statement_index < block.statements.len() {
                 let successor = location.successor_within_block();
@@ -427,7 +427,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
 
         if loop_head.dominates(from, &self.dominators) {
-            let block = &self.body.basic_blocks()[from.block];
+            let block = &self.body_cache.basic_blocks()[from.block];
 
             if from.statement_index < block.statements.len() {
                 let successor = from.successor_within_block();
@@ -475,7 +475,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 (LaterUseKind::ClosureCapture, var_span)
             }
             UseSpans::OtherUse(span) => {
-                let block = &self.body.basic_blocks()[location.block];
+                let block = &self.body_cache.basic_blocks()[location.block];
 
                 let kind = if let Some(&Statement {
                     kind: StatementKind::FakeRead(FakeReadCause::ForLet, _),
@@ -498,7 +498,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             Operand::Copy(place) |
                             Operand::Move(place) => {
                                 if let Some(l) = place.as_local() {
-                                    let local_decl = &self.body.local_decls[l];
+                                    let local_decl = &self.body_cache.local_decls[l];
                                     if self.local_names[l].is_none() {
                                         local_decl.source_info.span
                                     } else {
@@ -528,7 +528,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
         // Start at the reserve location, find the place that we want to see cast to a trait object.
         let location = borrow.reserve_location;
-        let block = &self.body[location.block];
+        let block = &self.body_cache[location.block];
         let stmt = block.statements.get(location.statement_index);
         debug!(
             "was_captured_by_trait_object: location={:?} stmt={:?}",
@@ -558,7 +558,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         );
         while let Some(current_location) = queue.pop() {
             debug!("was_captured_by_trait: target={:?}", target);
-            let block = &self.body[current_location.block];
+            let block = &self.body_cache[current_location.block];
             // We need to check the current location to find out if it is a terminator.
             let is_terminator = current_location.statement_index == block.statements.len();
             if !is_terminator {
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs
index 1d429e3a6de..7cb5b839cee 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/nll/invalidation.rs
@@ -11,7 +11,7 @@ use crate::borrow_check::path_utils::*;
 use crate::dataflow::indexes::BorrowIndex;
 use rustc::ty::{self, TyCtxt};
 use rustc::mir::visit::Visitor;
-use rustc::mir::{BasicBlock, Location, Body, Place, Rvalue};
+use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyCache, Rvalue};
 use rustc::mir::{Statement, StatementKind};
 use rustc::mir::TerminatorKind;
 use rustc::mir::{Operand, BorrowKind};
@@ -22,7 +22,7 @@ pub(super) fn generate_invalidates<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     all_facts: &mut Option<AllFacts>,
     location_table: &LocationTable,
-    body: &Body<'tcx>,
+    body_cache: &ReadOnlyBodyCache<'_, 'tcx>,
     borrow_set: &BorrowSet<'tcx>,
 ) {
     if all_facts.is_none() {
@@ -31,17 +31,17 @@ pub(super) fn generate_invalidates<'tcx>(
     }
 
     if let Some(all_facts) = all_facts {
-        let dominators = body.dominators();
+        let dominators = body_cache.dominators();
         let mut ig = InvalidationGenerator {
             all_facts,
             borrow_set,
             param_env,
             tcx,
             location_table,
-            body,
+            body: body_cache.body(),
             dominators,
         };
-        ig.visit_body(body);
+        ig.visit_body(&body_cache);
     }
 }
 
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index 4d67b72c98c..dac5815fada 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -12,7 +12,8 @@ use crate::borrow_check::Upvar;
 use rustc::hir::def_id::DefId;
 use rustc::infer::InferCtxt;
 use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements,
-                 Local, Location, Body, LocalKind, BasicBlock, Promoted};
+                 Local, Location, Body, BodyCache, LocalKind, BasicBlock,
+                 Promoted, ReadOnlyBodyCache};
 use rustc::ty::{self, RegionKind, RegionVid};
 use rustc_index::vec::IndexVec;
 use rustc_errors::Diagnostic;
@@ -54,8 +55,8 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
     def_id: DefId,
     param_env: ty::ParamEnv<'tcx>,
-    body: &mut Body<'tcx>,
-    promoted: &mut IndexVec<Promoted, Body<'tcx>>,
+    body_cache: &mut BodyCache<&mut Body<'tcx>>,
+    promoted: &mut IndexVec<Promoted, BodyCache<&mut Body<'tcx>>>,
 ) -> UniversalRegions<'tcx> {
     debug!("replace_regions_in_mir(def_id={:?})", def_id);
 
@@ -63,10 +64,10 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
     let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
 
     // Replace all remaining regions with fresh inference variables.
-    renumber::renumber_mir(infcx, body, promoted);
+    renumber::renumber_mir(infcx, body_cache, promoted);
 
     let source = MirSource::item(def_id);
-    mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(()));
+    mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body_cache, |_, _| Ok(()));
 
     universal_regions
 }
@@ -157,7 +158,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
     def_id: DefId,
     universal_regions: UniversalRegions<'tcx>,
-    body: &Body<'tcx>,
+    body_cache: &ReadOnlyBodyCache<'_, 'tcx>,
     promoted: &IndexVec<Promoted, Body<'tcx>>,
     local_names: &IndexVec<Local, Option<Symbol>>,
     upvars: &[Upvar],
@@ -180,7 +181,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
 
     let universal_regions = Rc::new(universal_regions);
 
-    let elements = &Rc::new(RegionValueElements::new(body));
+    let elements = &Rc::new(RegionValueElements::new(body_cache));
 
     // Run the MIR type-checker.
     let MirTypeckResults {
@@ -189,7 +190,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     } = type_check::type_check(
         infcx,
         param_env,
-        body,
+        body_cache,
         promoted,
         def_id,
         &universal_regions,
@@ -205,7 +206,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
         all_facts
             .universal_region
             .extend(universal_regions.universal_regions());
-        populate_polonius_move_facts(all_facts, move_data, location_table, body);
+        populate_polonius_move_facts(all_facts, move_data, location_table, body_cache);
     }
 
     // Create the region inference context, taking ownership of the
@@ -229,7 +230,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
         &mut liveness_constraints,
         &mut all_facts,
         location_table,
-        &body,
+        body_cache,
         borrow_set,
     );
 
@@ -238,7 +239,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
         universal_regions,
         placeholder_indices,
         universal_region_relations,
-        body,
+        body_cache,
         outlives_constraints,
         member_constraints,
         closure_bounds_mapping,
@@ -253,7 +254,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
         param_env,
         &mut all_facts,
         location_table,
-        &body,
+        body_cache,
         borrow_set,
     );
 
@@ -283,21 +284,21 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
 
     // Solve the region constraints.
     let closure_region_requirements =
-        regioncx.solve(infcx, body, local_names, upvars, def_id, errors_buffer);
+        regioncx.solve(infcx, body_cache, local_names, upvars, def_id, errors_buffer);
 
     // Dump MIR results into a file, if that is enabled. This let us
     // write unit-tests, as well as helping with debugging.
     dump_mir_results(
         infcx,
         MirSource::item(def_id),
-        &body,
+        body_cache,
         &regioncx,
         &closure_region_requirements,
     );
 
     // We also have a `#[rustc_nll]` annotation that causes us to dump
     // information
-    dump_annotation(infcx, &body, def_id, &regioncx, &closure_region_requirements, errors_buffer);
+    dump_annotation(infcx, body_cache, def_id, &regioncx, &closure_region_requirements, errors_buffer);
 
     (regioncx, polonius_output, closure_region_requirements)
 }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
index 7a86536573d..5d1891c0bf6 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
@@ -1,4 +1,4 @@
-use rustc::mir::{BasicBlock, Location, Body};
+use rustc::mir::{BasicBlock, Location, Body, ReadOnlyBodyCache};
 use rustc::ty::{self, RegionVid};
 use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
 use rustc_data_structures::fx::FxHashMap;
@@ -92,7 +92,7 @@ impl RegionValueElements {
     /// Pushes all predecessors of `index` onto `stack`.
     crate fn push_predecessors(
         &self,
-        body: &Body<'_>,
+        body_cache: &ReadOnlyBodyCache<'_, '_>,
         index: PointIndex,
         stack: &mut Vec<PointIndex>,
     ) {
@@ -104,9 +104,9 @@ impl RegionValueElements {
             // If this is a basic block head, then the predecessors are
             // the terminators of other basic blocks
             stack.extend(
-                body.predecessors_for(block)
+                body_cache.predecessors_for(block)
                     .iter()
-                    .map(|&pred_bb| body.terminator_loc(pred_bb))
+                    .map(|&pred_bb| body_cache.terminator_loc(pred_bb))
                     .map(|pred_loc| self.point_from_location(pred_loc)),
             );
         } else {
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index d949c7e01aa..57e977eacba 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -1,6 +1,6 @@
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::mir::{Body, Location, PlaceElem, Promoted};
+use rustc::mir::{Body, BodyCache, Location, PlaceElem, Promoted};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc_index::vec::IndexVec;
@@ -9,11 +9,11 @@ use rustc_index::vec::IndexVec;
 /// inference variables, returning the number of variables created.
 pub fn renumber_mir<'tcx>(
     infcx: &InferCtxt<'_, 'tcx>,
-    body: &mut Body<'tcx>,
-    promoted: &mut IndexVec<Promoted, Body<'tcx>>,
+    body_cache: &mut BodyCache<&mut Body<'tcx>>,
+    promoted: &mut IndexVec<Promoted, BodyCache<&mut Body<'tcx>>>,
 ) {
     debug!("renumber_mir()");
-    debug!("renumber_mir: body.arg_count={:?}", body.arg_count);
+    debug!("renumber_mir: body.arg_count={:?}", body_cache.arg_count);
 
     let mut visitor = NLLVisitor { infcx };
 
@@ -21,7 +21,7 @@ pub fn renumber_mir<'tcx>(
         visitor.visit_body(body);
     }
 
-    visitor.visit_body(body);
+    visitor.visit_body(body_cache);
 }
 
 /// Replaces all regions appearing in `value` with fresh inference
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 4f95aa4a7b0..2de9f0e1282 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -115,7 +115,7 @@ mod relate_tys;
 pub(crate) fn type_check<'tcx>(
     infcx: &InferCtxt<'_, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    body: &Body<'tcx>,
+    body_cache: &ReadOnlyBodyCache<'_, 'tcx>,
     promoted: &IndexVec<Promoted, Body<'tcx>>,
     mir_def_id: DefId,
     universal_regions: &Rc<UniversalRegions<'tcx>>,
@@ -161,15 +161,15 @@ pub(crate) fn type_check<'tcx>(
         infcx,
         mir_def_id,
         param_env,
-        body,
+        body_cache,
         promoted,
         &region_bound_pairs,
         implicit_region_bound,
         &mut borrowck_context,
         &universal_region_relations,
         |mut cx| {
-            cx.equate_inputs_and_outputs(body, universal_regions, &normalized_inputs_and_output);
-            liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
+            cx.equate_inputs_and_outputs(body_cache, universal_regions, &normalized_inputs_and_output);
+            liveness::generate(&mut cx, body_cache, elements, flow_inits, move_data, location_table);
 
             translate_outlives_facts(cx.borrowck_context);
         },
@@ -185,7 +185,7 @@ fn type_check_internal<'a, 'tcx, R>(
     infcx: &'a InferCtxt<'a, 'tcx>,
     mir_def_id: DefId,
     param_env: ty::ParamEnv<'tcx>,
-    body: &'a Body<'tcx>,
+    body_cache: &ReadOnlyBodyCache<'a, 'tcx>,
     promoted: &'a IndexVec<Promoted, Body<'tcx>>,
     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
@@ -195,7 +195,7 @@ fn type_check_internal<'a, 'tcx, R>(
 ) -> R where {
     let mut checker = TypeChecker::new(
         infcx,
-        body,
+        body_cache,
         mir_def_id,
         param_env,
         region_bound_pairs,
@@ -204,14 +204,14 @@ fn type_check_internal<'a, 'tcx, R>(
         universal_region_relations,
     );
     let errors_reported = {
-        let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
-        verifier.visit_body(body);
+        let mut verifier = TypeVerifier::new(&mut checker, body_cache, promoted);
+        verifier.visit_body(body_cache);
         verifier.errors_reported
     };
 
     if !errors_reported {
         // if verifier failed, don't do further checks to avoid ICEs
-        checker.typeck_mir(body);
+        checker.typeck_mir(body_cache);
     }
 
     extra(&mut checker)
@@ -385,7 +385,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
         }
     }
 
-    fn visit_body(&mut self, body_cache: &BodyCache<&'_ Body<'tcx>>) {
+    fn visit_body(&mut self, body_cache: &ReadOnlyBodyCache<'_, 'tcx>) {
         self.sanitize_type(&"return type", body_cache.return_ty());
         for local_decl in &body_cache.local_decls {
             self.sanitize_type(local_decl, local_decl.ty);
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
index 57833cac9cb..aa02c0641e3 100644
--- a/src/librustc_mir/borrow_check/prefixes.rs
+++ b/src/librustc_mir/borrow_check/prefixes.rs
@@ -56,7 +56,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         Prefixes {
             next: Some(place_ref),
             kind,
-            body: self.body,
+            body: &self.body_cache,
             tcx: self.infcx.tcx,
         }
     }
diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs
index 95471afb788..430452efe42 100644
--- a/src/librustc_mir/borrow_check/used_muts.rs
+++ b/src/librustc_mir/borrow_check/used_muts.rs
@@ -32,7 +32,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 never_initialized_mut_locals: &mut never_initialized_mut_locals,
                 mbcx: self,
             };
-            visitor.visit_body(visitor.mbcx.body);
+            visitor.visit_body(&visitor.mbcx.body_cache);
         }
 
         // Take the union of the existed `used_mut` set with those variables we've found were