about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2019-07-11 19:25:37 +0200
committerSantiago Pastorino <spastorino@gmail.com>2019-07-20 05:08:39 +0200
commit46f81fc53dbff924aa48e448430f8b8ade8c8d20 (patch)
tree198ee021e2dd61365602b347185267272d451e3d
parentec65db07ef4cf75d0944f43a1bc1f1bd18da6545 (diff)
downloadrust-46f81fc53dbff924aa48e448430f8b8ade8c8d20.tar.gz
rust-46f81fc53dbff924aa48e448430f8b8ade8c8d20.zip
Avoid cloning Place in report_use_of_moved_or_uninitialized and friends
-rw-r--r--src/librustc/mir/mod.rs23
-rw-r--r--src/librustc_mir/borrow_check/conflict_errors.rs71
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs92
-rw-r--r--src/librustc_mir/borrow_check/mod.rs150
-rw-r--r--src/librustc_mir/borrow_check/move_errors.rs20
-rw-r--r--src/librustc_mir/borrow_check/mutability_errors.rs13
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs2
-rw-r--r--src/librustc_mir/borrow_check/path_utils.rs2
-rw-r--r--src/librustc_mir/borrow_check/places_conflict.rs10
-rw-r--r--src/librustc_mir/borrow_check/prefixes.rs67
-rw-r--r--src/librustc_mir/dataflow/drop_flag_effects.rs2
-rw-r--r--src/librustc_mir/dataflow/impls/mod.rs6
-rw-r--r--src/librustc_mir/dataflow/mod.rs4
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs2
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs4
-rw-r--r--src/librustc_mir/transform/elaborate_drops.rs12
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs4
17 files changed, 253 insertions, 231 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index f27cc632c1f..b113f87fb86 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1826,7 +1826,7 @@ newtype_index! {
     }
 }
 
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
 pub struct PlaceRef<'a, 'tcx> {
     pub base: &'a PlaceBase<'tcx>,
     pub projection: &'a Option<Box<Projection<'tcx>>>,
@@ -1961,6 +1961,27 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
     ) -> R {
         Place::iterate_over(self.base, self.projection, op)
     }
+
+    /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
+    /// a single deref of a local.
+    //
+    // FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
+    pub fn local_or_deref_local(&self) -> Option<Local> {
+        match self {
+            PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: None,
+            } |
+            PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: Some(box Projection {
+                    base: None,
+                    elem: ProjectionElem::Deref,
+                }),
+            } => Some(*local),
+            _ => None,
+        }
+    }
 }
 
 /// A linked list of projections running up the stack; begins with the
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
index 7bd3a4729ac..ce4460e8ded 100644
--- a/src/librustc_mir/borrow_check/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/conflict_errors.rs
@@ -2,7 +2,7 @@ use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
-    LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection,
+    LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, Projection, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
 };
 use rustc::ty::{self, Ty};
@@ -48,7 +48,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         &mut self,
         location: Location,
         desired_action: InitializationRequiringAction,
-        (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
+        (moved_place, used_place, span): (PlaceRef<'cx, 'tcx>, PlaceRef<'cx, 'tcx>, Span),
         mpi: MovePathIndex,
     ) {
         debug!(
@@ -73,14 +73,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         if move_out_indices.is_empty() {
             let root_place = self
-                .prefixes(&used_place.base, &used_place.projection, PrefixSet::All)
+                .prefixes(used_place, PrefixSet::All)
                 .last()
                 .unwrap();
 
-            if self.uninitialized_error_reported.contains(&Place {
-                base: root_place.0.clone(),
-                projection: root_place.1.clone(),
-            }) {
+            if self.uninitialized_error_reported.contains(&root_place) {
                 debug!(
                     "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
                     root_place
@@ -88,10 +85,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 return;
             }
 
-            self.uninitialized_error_reported.insert(Place {
-                base: root_place.0.clone(),
-                projection: root_place.1.clone(),
-            });
+            self.uninitialized_error_reported.insert(root_place);
 
             let item_msg = match self.describe_place_with_options(used_place,
                                                                   IncludingDowncast(true)) {
@@ -114,8 +108,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             err.buffer(&mut self.errors_buffer);
         } else {
             if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
-                if self.prefixes(&reported_place.base, &reported_place.projection, PrefixSet::All)
-                    .any(|p| *p.0 == used_place.base && *p.1 == used_place.projection)
+                if self.prefixes(*reported_place, PrefixSet::All)
+                    .any(|p| p == used_place)
                 {
                     debug!(
                         "report_use_of_moved_or_uninitialized place: error suppressed \
@@ -132,7 +126,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 span,
                 desired_action.as_noun(),
                 msg,
-                self.describe_place_with_options(&moved_place, IncludingDowncast(true)),
+                self.describe_place_with_options(moved_place, IncludingDowncast(true)),
             );
 
             self.add_moved_or_invoked_closure_note(
@@ -145,13 +139,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             let is_partial_move = move_site_vec.iter().any(|move_site| {
                 let move_out = self.move_data.moves[(*move_site).moi];
                 let moved_place = &self.move_data.move_paths[move_out.path].place;
-                used_place != moved_place && used_place.is_prefix_of(moved_place)
+                used_place != moved_place.as_place_ref()
+                    && used_place.is_prefix_of(moved_place.as_place_ref())
             });
             for move_site in &move_site_vec {
                 let move_out = self.move_data.moves[(*move_site).moi];
                 let moved_place = &self.move_data.move_paths[move_out.path].place;
 
-                let move_spans = self.move_spans(moved_place, move_out.source);
+                let move_spans = self.move_spans(moved_place.as_place_ref(), move_out.source);
                 let move_span = move_spans.args_or_use();
 
                 let move_msg = if move_spans.for_closure() {
@@ -209,7 +204,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 );
             }
 
-            let ty = used_place.ty(self.body, self.infcx.tcx).ty;
+            let ty =
+                Place::ty_from(used_place.base, used_place.projection, self.body, self.infcx.tcx)
+                    .ty;
             let needs_note = match ty.sty {
                 ty::Closure(id, _) => {
                     let tables = self.infcx.tcx.typeck_tables_of(id);
@@ -225,7 +222,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let place = &self.move_data.move_paths[mpi].place;
 
                 let ty = place.ty(self.body, self.infcx.tcx).ty;
-                let opt_name = self.describe_place_with_options(place, IncludingDowncast(true));
+                let opt_name =
+                    self.describe_place_with_options(place.as_place_ref(), IncludingDowncast(true));
                 let note_msg = match opt_name {
                     Some(ref name) => format!("`{}`", name),
                     None => "value".to_owned(),
@@ -259,7 +257,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
 
             if let Some((_, mut old_err)) = self.move_error_reported
-                .insert(move_out_indices, (used_place.clone(), err))
+                .insert(move_out_indices, (used_place, err))
             {
                 // Cancel the old error so it doesn't ICE.
                 old_err.cancel();
@@ -289,7 +287,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let borrow_spans = self.retrieve_borrow_spans(borrow);
         let borrow_span = borrow_spans.args_or_use();
 
-        let move_spans = self.move_spans(place, location);
+        let move_spans = self.move_spans(place.as_place_ref(), location);
         let span = move_spans.args_or_use();
 
         let mut err = self.cannot_move_when_borrowed(
@@ -328,7 +326,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         // Conflicting borrows are reported separately, so only check for move
         // captures.
-        let use_spans = self.move_spans(place, location);
+        let use_spans = self.move_spans(place.as_place_ref(), location);
         let span = use_spans.var_or_use();
 
         let mut err = self.cannot_use_when_mutably_borrowed(
@@ -698,25 +696,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         );
 
         let drop_span = place_span.1;
-        let root_place = self.prefixes(&borrow.borrowed_place.base,
-                                       &borrow.borrowed_place.projection,
-                                       PrefixSet::All)
+        let root_place = self.prefixes(borrow.borrowed_place.as_place_ref(), PrefixSet::All)
             .last()
             .unwrap();
 
         let borrow_spans = self.retrieve_borrow_spans(borrow);
         let borrow_span = borrow_spans.var_or_use();
 
-        assert!(root_place.1.is_none());
-        let proper_span = match root_place.0 {
+        assert!(root_place.projection.is_none());
+        let proper_span = match root_place.base {
             PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
             _ => drop_span,
         };
 
         if self.access_place_error_reported
             .contains(&(Place {
-                base: root_place.0.clone(),
-                projection: root_place.1.clone(),
+                base: root_place.base.clone(),
+                projection: root_place.projection.clone(),
             }, borrow_span))
         {
             debug!(
@@ -728,8 +724,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         self.access_place_error_reported
             .insert((Place {
-                base: root_place.0.clone(),
-                projection: root_place.1.clone(),
+                base: root_place.base.clone(),
+                projection: root_place.projection.clone(),
             }, borrow_span));
 
         if let StorageDeadOrDrop::Destructor(dropped_ty) =
@@ -739,7 +735,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             // we're not in the uninteresting case where `B` is a
             // prefix of `D`), then report this as a more interesting
             // destructor conflict.
-            if !borrow.borrowed_place.is_prefix_of(place_span.0) {
+            if !borrow.borrowed_place.as_place_ref().is_prefix_of(place_span.0.as_place_ref()) {
                 self.report_borrow_conflicts_with_destructor(
                     location, borrow, place_span, kind, dropped_ty,
                 );
@@ -753,10 +749,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
 
         let err = match (place_desc, explanation) {
-            (Some(_), _) if self.is_place_thread_local(&Place {
-                base: root_place.0.clone(),
-                projection: root_place.1.clone(),
-            }) => {
+            (Some(_), _) if self.is_place_thread_local(root_place) => {
                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
             }
             // If the outlives constraint comes from inside the closure,
@@ -1133,12 +1126,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 format!("`{}` is borrowed here", place_desc),
             )
         } else {
-            let root_place = self.prefixes(&borrow.borrowed_place.base,
-                                           &borrow.borrowed_place.projection,
+            let root_place = self.prefixes(borrow.borrowed_place.as_place_ref(),
                                            PrefixSet::All)
                 .last()
                 .unwrap();
-            let local = if let (PlaceBase::Local(local), None) = root_place {
+            let local = if let PlaceRef {
+                base: PlaceBase::Local(local),
+                projection: None,
+            } = root_place {
                 local
             } else {
                 bug!("try_report_cannot_return_reference_to_local: not a local")
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 54f041865a1..aa772e64aa2 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -3,8 +3,8 @@ use rustc::hir::def::Namespace;
 use rustc::hir::def_id::DefId;
 use rustc::mir::{
     AggregateKind, Constant, Field, Local, LocalKind, Location, Operand,
-    Place, PlaceBase, ProjectionElem, Rvalue, Statement, StatementKind, Static,
-    StaticKind, Terminator, TerminatorKind,
+    Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
+    Static, StaticKind, Terminator, TerminatorKind,
 };
 use rustc::ty::{self, DefIdTree, Ty, TyCtxt};
 use rustc::ty::layout::VariantIdx;
@@ -34,7 +34,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     pub(super) fn add_moved_or_invoked_closure_note(
         &self,
         location: Location,
-        place: &Place<'tcx>,
+        place: PlaceRef<'cx, 'tcx>,
         diag: &mut DiagnosticBuilder<'_>,
     ) {
         debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
@@ -122,7 +122,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// End-user visible description of `place` if one can be found. If the
     /// place is a temporary for instance, None will be returned.
     pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
-        self.describe_place_with_options(place, IncludingDowncast(false))
+        self.describe_place_with_options(place.as_place_ref(), IncludingDowncast(false))
     }
 
     /// End-user visible description of `place` if one can be found. If the
@@ -131,7 +131,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// `Downcast` and `IncludingDowncast` is true
     pub(super) fn describe_place_with_options(
         &self,
-        place: &Place<'tcx>,
+        place: PlaceRef<'cx, 'tcx>,
         including_downcast: IncludingDowncast,
     ) -> Option<String> {
         let mut buf = String::new();
@@ -144,19 +144,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Appends end-user visible description of `place` to `buf`.
     fn append_place_to_string(
         &self,
-        place: &Place<'tcx>,
+        place: PlaceRef<'cx, 'tcx>,
         buf: &mut String,
         mut autoderef: bool,
         including_downcast: &IncludingDowncast,
     ) -> Result<(), ()> {
-        match *place {
-            Place {
+        match place {
+            PlaceRef {
                 base: PlaceBase::Local(local),
                 projection: None,
             } => {
-                self.append_local_to_string(local, buf)?;
+                self.append_local_to_string(*local, buf)?;
             }
-            Place {
+            PlaceRef {
                 base:
                     PlaceBase::Static(box Static {
                         kind: StaticKind::Promoted(_),
@@ -166,7 +166,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             } => {
                 buf.push_str("promoted");
             }
-            Place {
+            PlaceRef {
                 base:
                     PlaceBase::Static(box Static {
                         kind: StaticKind::Static(def_id),
@@ -174,9 +174,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     }),
                 projection: None,
             } => {
-                buf.push_str(&self.infcx.tcx.item_name(def_id).to_string());
+                buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
             }
-            Place {
+            PlaceRef {
                 ref base,
                 projection: Some(ref proj),
             } => {
@@ -196,9 +196,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             if autoderef {
                                 // FIXME turn this recursion into iteration
                                 self.append_place_to_string(
-                                    &Place {
-                                        base: base.clone(),
-                                        projection: proj.base.clone(),
+                                    PlaceRef {
+                                        base: &base,
+                                        projection: &proj.base,
                                     },
                                     buf,
                                     autoderef,
@@ -209,9 +209,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     (None, PlaceBase::Local(local)) => {
                                         if self.body.local_decls[*local].is_ref_for_guard() {
                                             self.append_place_to_string(
-                                                &Place {
-                                                    base: base.clone(),
-                                                    projection: proj.base.clone(),
+                                                PlaceRef {
+                                                    base: &base,
+                                                    projection: &proj.base,
                                                 },
                                                 buf,
                                                 autoderef,
@@ -221,9 +221,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                             // FIXME deduplicate this and the _ => body below
                                             buf.push_str(&"*");
                                             self.append_place_to_string(
-                                                &Place {
-                                                    base: base.clone(),
-                                                    projection: proj.base.clone(),
+                                                PlaceRef {
+                                                    base: &base,
+                                                    projection: &proj.base,
                                                 },
                                                 buf,
                                                 autoderef,
@@ -235,9 +235,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     _ => {
                                         buf.push_str(&"*");
                                         self.append_place_to_string(
-                                            &Place {
-                                                base: base.clone(),
-                                                projection: proj.base.clone(),
+                                            PlaceRef {
+                                                base: &base,
+                                                projection: &proj.base,
                                             },
                                             buf,
                                             autoderef,
@@ -250,9 +250,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     }
                     ProjectionElem::Downcast(..) => {
                         self.append_place_to_string(
-                            &Place {
-                                base: base.clone(),
-                                projection: proj.base.clone(),
+                            PlaceRef {
+                                base: &base,
+                                projection: &proj.base,
                             },
                             buf,
                             autoderef,
@@ -273,13 +273,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             buf.push_str(&name);
                         } else {
                             let field_name = self.describe_field(&Place {
-                                base: base.clone(),
+                                base: (*base).clone(),
                                 projection: proj.base.clone(),
                             }, field);
                             self.append_place_to_string(
-                                &Place {
-                                    base: base.clone(),
-                                    projection: proj.base.clone(),
+                                PlaceRef {
+                                    base: &base,
+                                    projection: &proj.base,
                                 },
                                 buf,
                                 autoderef,
@@ -292,9 +292,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         autoderef = true;
 
                         self.append_place_to_string(
-                            &Place {
-                                base: base.clone(),
-                                projection: proj.base.clone(),
+                            PlaceRef {
+                                base: &base,
+                                projection: &proj.base,
                             },
                             buf,
                             autoderef,
@@ -312,9 +312,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         // then use another while the borrow is held, don't output indices details
                         // to avoid confusing the end-user
                         self.append_place_to_string(
-                            &Place {
-                                base: base.clone(),
-                                projection: proj.base.clone(),
+                            PlaceRef {
+                                base: &base,
+                                projection: &proj.base,
                             },
                             buf,
                             autoderef,
@@ -436,14 +436,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     /// Checks if a place is a thread-local static.
-    pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
-        if let Place {
+    pub fn is_place_thread_local(&self, place_ref: PlaceRef<'cx, 'tcx>) -> bool {
+        if let PlaceRef {
             base: PlaceBase::Static(box Static {
                 kind: StaticKind::Static(def_id),
                 ..
             }),
             projection: None,
-        } = place {
+        } = place_ref {
             let attrs = self.infcx.tcx.get_attrs(*def_id);
             let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
 
@@ -487,7 +487,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // Look up the provided place and work out the move path index for it,
         // we'll use this to check whether it was originally from an overloaded
         // operator.
-        match self.move_data.rev_lookup.find(deref_base) {
+        match self.move_data.rev_lookup.find(deref_base.as_place_ref()) {
             LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
                 debug!("borrowed_content_source: mpi={:?}", mpi);
 
@@ -775,7 +775,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Finds the spans associated to a move or copy of move_place at location.
     pub(super) fn move_spans(
         &self,
-        moved_place: &Place<'tcx>, // Could also be an upvar.
+        moved_place: PlaceRef<'cx, 'tcx>, // Could also be an upvar.
         location: Location,
     ) -> UseSpans {
         use self::UseSpans::*;
@@ -854,7 +854,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     def_id, is_generator, places
                 );
                 if let Some((args_span, var_span)) = self.closure_span(
-                    *def_id, &Place::from(target), places
+                    *def_id, Place::from(target).as_place_ref(), places
                 ) {
                     return ClosureUse {
                         is_generator,
@@ -878,7 +878,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn closure_span(
         &self,
         def_id: DefId,
-        target_place: &Place<'tcx>,
+        target_place: PlaceRef<'cx, 'tcx>,
         places: &Vec<Operand<'tcx>>,
     ) -> Option<(Span, Span)> {
         debug!(
@@ -894,7 +894,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) {
                 match place {
                     Operand::Copy(place) |
-                    Operand::Move(place) if target_place == place => {
+                    Operand::Move(place) if target_place == place.as_place_ref() => {
                         debug!("closure_span: found captured local {:?}", place);
                         return Some((*args_span, upvar.span));
                     },
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index bebdd68cb05..b159bf4dd04 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -10,9 +10,8 @@ use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
 use rustc::middle::borrowck::SignalledError;
 use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc::mir::{
-    ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, Static,
-
-    StaticKind
+    ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef,
+    Static, StaticKind
 };
 use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind};
 use rustc::mir::{Terminator, TerminatorKind};
@@ -474,10 +473,10 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
     /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
     /// when errors in the map are being re-added to the error buffer so that errors with the
     /// same primary span come out in a consistent order.
-    move_error_reported: BTreeMap<Vec<MoveOutIndex>, (Place<'tcx>, DiagnosticBuilder<'cx>)>,
+    move_error_reported: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'cx, 'tcx>, DiagnosticBuilder<'cx>)>,
     /// This field keeps track of errors reported in the checking of uninitialized variables,
     /// so that we don't report seemingly duplicate errors.
-    uninitialized_error_reported: FxHashSet<Place<'tcx>>,
+    uninitialized_error_reported: FxHashSet<PlaceRef<'cx, 'tcx>>,
     /// Errors to be reported buffer
     errors_buffer: Vec<Diagnostic>,
     /// This field keeps track of all the local variables that are declared mut and are mutated.
@@ -520,7 +519,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
     fn visit_statement_entry(
         &mut self,
         location: Location,
-        stmt: &Statement<'tcx>,
+        stmt: &'cx Statement<'tcx>,
         flow_state: &Self::FlowState,
     ) {
         debug!(
@@ -561,7 +560,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
                 self.check_if_path_or_subpath_is_moved(
                     location,
                     InitializationRequiringAction::Use,
-                    (place, span),
+                    (place.as_place_ref(), span),
                     flow_state,
                 );
             }
@@ -592,7 +591,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
                         self.check_if_path_or_subpath_is_moved(
                             location,
                             InitializationRequiringAction::Use,
-                            (output, o.span),
+                            (output.as_place_ref(), o.span),
                             flow_state,
                         );
                     } else {
@@ -631,7 +630,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx
     fn visit_terminator_entry(
         &mut self,
         location: Location,
-        term: &Terminator<'tcx>,
+        term: &'cx Terminator<'tcx>,
         flow_state: &Self::FlowState,
     ) {
         let loc = location;
@@ -1144,7 +1143,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn mutate_place(
         &mut self,
         location: Location,
-        place_span: (&Place<'tcx>, Span),
+        place_span: (&'cx Place<'tcx>, Span),
         kind: AccessDepth,
         mode: MutateMode,
         flow_state: &Flows<'cx, 'tcx>,
@@ -1155,7 +1154,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 self.check_if_path_or_subpath_is_moved(
                     location,
                     InitializationRequiringAction::Update,
-                    place_span,
+                    (place_span.0.as_place_ref(), place_span.1),
                     flow_state,
                 );
             }
@@ -1196,7 +1195,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn consume_rvalue(
         &mut self,
         location: Location,
-        (rvalue, span): (&Rvalue<'tcx>, Span),
+        (rvalue, span): (&'cx Rvalue<'tcx>, Span),
         flow_state: &Flows<'cx, 'tcx>,
     ) {
         match *rvalue {
@@ -1233,7 +1232,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 self.check_if_path_or_subpath_is_moved(
                     location,
                     action,
-                    (place, span),
+                    (place.as_place_ref(), span),
                     flow_state,
                 );
             }
@@ -1261,7 +1260,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 self.check_if_path_or_subpath_is_moved(
                     location,
                     InitializationRequiringAction::Use,
-                    (place, span),
+                    (place.as_place_ref(), span),
                     flow_state,
                 );
             }
@@ -1310,7 +1309,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
         let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| {
             if place.projection.is_some() {
-                if let Some(field) = this.is_upvar_field_projection(place) {
+                if let Some(field) = this.is_upvar_field_projection(place.as_place_ref()) {
                     this.used_mut_upvars.push(field);
                 }
             } else if let PlaceBase::Local(local) = place.base {
@@ -1383,7 +1382,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn consume_operand(
         &mut self,
         location: Location,
-        (operand, span): (&Operand<'tcx>, Span),
+        (operand, span): (&'cx Operand<'tcx>, Span),
         flow_state: &Flows<'cx, 'tcx>,
     ) {
         match *operand {
@@ -1402,7 +1401,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 self.check_if_path_or_subpath_is_moved(
                     location,
                     InitializationRequiringAction::Use,
-                    (place, span),
+                    (place.as_place_ref(), span),
                     flow_state,
                 );
             }
@@ -1420,7 +1419,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 self.check_if_path_or_subpath_is_moved(
                     location,
                     InitializationRequiringAction::Use,
-                    (place, span),
+                    (place.as_place_ref(), span),
                     flow_state,
                 );
             }
@@ -1438,8 +1437,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     ) {
         debug!("check_for_invalidation_at_exit({:?})", borrow);
         let place = &borrow.borrowed_place;
-        let root_place =
-            self.prefixes(&place.base, &place.projection, PrefixSet::All).last().unwrap();
+        let root_place = self.prefixes(place.as_place_ref(), PrefixSet::All).last().unwrap();
 
         // FIXME(nll-rfc#40): do more precise destructor tracking here. For now
         // we just know that all locals are dropped at function exit (otherwise
@@ -1447,8 +1445,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         //
         // FIXME: allow thread-locals to borrow other thread locals?
 
-        assert!(root_place.1.is_none());
-        let (might_be_alive, will_be_dropped) = match root_place.0 {
+        assert!(root_place.projection.is_none());
+        let (might_be_alive, will_be_dropped) = match root_place.base {
             PlaceBase::Static(box Static {
                 kind: StaticKind::Promoted(_),
                 ..
@@ -1461,10 +1459,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }) => {
                 // Thread-locals might be dropped after the function exits, but
                 // "true" statics will never be.
-                (true, self.is_place_thread_local(&Place {
-                    base: root_place.0.clone(),
-                    projection: root_place.1.clone(),
-                }))
+                (true, self.is_place_thread_local(root_place))
             }
             PlaceBase::Local(_) => {
                 // Locals are always dropped at function exit, and if they
@@ -1488,10 +1483,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             self.body,
             place,
             borrow.kind,
-            &Place {
-                base: root_place.0.clone(),
-                projection: root_place.1.clone(),
-            },
+            root_place,
             sd,
             places_conflict::PlaceConflictBias::Overlap,
         ) {
@@ -1579,7 +1571,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         &mut self,
         location: Location,
         desired_action: InitializationRequiringAction,
-        place_span: (&Place<'tcx>, Span),
+        place_span: (PlaceRef<'cx, 'tcx>, Span),
         flow_state: &Flows<'cx, 'tcx>,
     ) {
         let maybe_uninits = &flow_state.uninits;
@@ -1626,7 +1618,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     self.report_use_of_moved_or_uninitialized(
                         location,
                         desired_action,
-                        (&prefix, place_span.0, place_span.1),
+                        (prefix, place_span.0, place_span.1),
                         mpi,
                     );
                     return; // don't bother finding other problems.
@@ -1647,7 +1639,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         &mut self,
         location: Location,
         desired_action: InitializationRequiringAction,
-        place_span: (&Place<'tcx>, Span),
+        place_span: (PlaceRef<'cx, 'tcx>, Span),
         flow_state: &Flows<'cx, 'tcx>,
     ) {
         let maybe_uninits = &flow_state.uninits;
@@ -1704,22 +1696,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// static variable, as we do not track those in the MoveData.
     fn move_path_closest_to(
         &mut self,
-        place: &Place<'tcx>,
-    ) -> Result<(Place<'tcx>, MovePathIndex), NoMovePathFound> {
-        let mut last_prefix = &place.base;
-
-        for prefix in self.prefixes(&place.base, &place.projection, PrefixSet::All) {
-            if let Some(mpi) = self.move_path_for_place(&Place {
-                base: prefix.0.clone(),
-                projection: prefix.1.clone(),
-            }) {
-                return Ok((Place {
-                    base: prefix.0.clone(),
-                    projection: prefix.1.clone(),
-                }, mpi));
+        place: PlaceRef<'cx, 'tcx>,
+    ) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> {
+        let mut last_prefix = place.base;
+
+        for prefix in self.prefixes(place, PrefixSet::All) {
+            if let Some(mpi) = self.move_path_for_place(prefix) {
+                return Ok((prefix, mpi));
             }
 
-            last_prefix = prefix.0;
+            last_prefix = prefix.base;
         }
 
         match last_prefix {
@@ -1728,7 +1714,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
-    fn move_path_for_place(&mut self, place: &Place<'tcx>) -> Option<MovePathIndex> {
+    fn move_path_for_place(&mut self, place: PlaceRef<'cx, 'tcx>) -> Option<MovePathIndex> {
         // If returns None, then there is no move path corresponding
         // to a direct owner of `place` (which means there is nothing
         // that borrowck tracks for its analysis).
@@ -1742,7 +1728,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn check_if_assigned_path_is_moved(
         &mut self,
         location: Location,
-        (place, span): (&Place<'tcx>, Span),
+        (place, span): (&'cx Place<'tcx>, Span),
         flow_state: &Flows<'cx, 'tcx>,
     ) {
         debug!("check_if_assigned_path_is_moved place: {:?}", place);
@@ -1766,9 +1752,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 ProjectionElem::Deref => {
                     self.check_if_full_path_is_moved(
                         location, InitializationRequiringAction::Use,
-                        (&Place {
-                            base: place.base.clone(),
-                            projection: base.clone(),
+                        (PlaceRef {
+                            base: &place.base,
+                            projection: base,
                         }, span), flow_state);
                     // (base initialized; no need to
                     // recur further)
@@ -1790,9 +1776,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         ty::Adt(def, _) if def.has_dtor(tcx) => {
                             self.check_if_path_or_subpath_is_moved(
                                 location, InitializationRequiringAction::Assignment,
-                                (&Place {
-                                    base: place.base.clone(),
-                                    projection: base.clone(),
+                                (PlaceRef {
+                                    base: &place.base,
+                                    projection: base,
                                 }, span), flow_state);
 
                             // (base initialized; no need to
@@ -1803,9 +1789,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         // Once `let s; s.x = V; read(s.x);`,
                         // is allowed, remove this match arm.
                         ty::Adt(..) | ty::Tuple(..) => {
-                            check_parent_of_field(self, location, &Place {
-                                base: place.base.clone(),
-                                projection: base.clone(),
+                            check_parent_of_field(self, location, PlaceRef {
+                                base: &place.base,
+                                projection: base,
                             }, span, flow_state);
 
                             if let PlaceBase::Local(local) = place.base {
@@ -1832,7 +1818,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         fn check_parent_of_field<'cx, 'tcx>(
             this: &mut MirBorrowckCtxt<'cx, 'tcx>,
             location: Location,
-            base: &Place<'tcx>,
+            base: PlaceRef<'cx, 'tcx>,
             span: Span,
             flow_state: &Flows<'cx, 'tcx>,
         ) {
@@ -1872,11 +1858,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             // Find the shortest uninitialized prefix you can reach
             // without going over a Deref.
             let mut shortest_uninit_seen = None;
-            for prefix in this.prefixes(&base.base, &base.projection, PrefixSet::Shallow) {
-                let mpi = match this.move_path_for_place(&Place {
-                    base: prefix.0.clone(),
-                    projection: prefix.1.clone(),
-                }) {
+            for prefix in this.prefixes(base, PrefixSet::Shallow) {
+                let mpi = match this.move_path_for_place(prefix) {
                     Some(mpi) => mpi, None => continue,
                 };
 
@@ -1896,7 +1879,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // no move out from an earlier location) then this is an attempt at initialization
                 // of the union - we should error in that case.
                 let tcx = this.infcx.tcx;
-                if let ty::Adt(def, _) = base.ty(this.body, tcx).ty.sty {
+                if let ty::Adt(def, _) =
+                    Place::ty_from(base.base, base.projection, this.body, tcx).ty.sty
+                {
                     if def.is_union() {
                         if this.move_data.path_map[mpi].iter().any(|moi| {
                             this.move_data.moves[*moi].source.is_predecessor_of(
@@ -1911,10 +1896,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 this.report_use_of_moved_or_uninitialized(
                     location,
                     InitializationRequiringAction::PartialAssignment,
-                    (&Place {
-                        base: prefix.0.clone(),
-                        projection: prefix.1.clone(),
-                    }, base, span),
+                    (prefix, base, span),
                     mpi,
                 );
             }
@@ -2103,12 +2085,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             } => {}
             RootPlace {
                 place_base,
-                place_projection: Some(proj),
+                place_projection: place_projection @ Some(_),
                 is_local_mutation_allowed: _,
             } => {
-                if let Some(field) = self.is_upvar_field_projection(&Place {
-                    base: place_base.clone(),
-                    projection: Some(proj.clone()),
+                if let Some(field) = self.is_upvar_field_projection(PlaceRef {
+                    base: &place_base,
+                    projection: &place_projection,
                 }) {
                     self.used_mut_upvars.push(field);
                 }
@@ -2193,9 +2175,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     // Mutably borrowed data is mutable, but only if we have a
                                     // unique path to the `&mut`
                                     hir::MutMutable => {
-                                        let mode = match self.is_upvar_field_projection(&Place {
-                                            base: place_base.clone(),
-                                            projection: place_projection.clone(),
+                                        let mode = match self.is_upvar_field_projection(PlaceRef {
+                                            base: &place_base,
+                                            projection: &place_projection,
                                         }) {
                                             Some(field)
                                                 if self.upvars[field.index()].by_ref =>
@@ -2239,9 +2221,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     | ProjectionElem::ConstantIndex { .. }
                     | ProjectionElem::Subslice { .. }
                     | ProjectionElem::Downcast(..) => {
-                        let upvar_field_projection = self.is_upvar_field_projection(&Place {
-                            base: place_base.clone(),
-                            projection: place_projection.clone(),
+                        let upvar_field_projection = self.is_upvar_field_projection(PlaceRef {
+                            base: &place_base,
+                            projection: &place_projection,
                         });
                         if let Some(field) = upvar_field_projection {
                             let upvar = &self.upvars[field.index()];
@@ -2306,15 +2288,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// then returns the index of the field being projected. Note that this closure will always
     /// be `self` in the current MIR, because that is the only time we directly access the fields
     /// of a closure type.
-    pub fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option<Field> {
-        let mut place_projection = place.projection.clone();
+    pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Option<Field> {
+        let mut place_projection = place_ref.projection;
         let mut by_ref = false;
 
         if let Some(box Projection {
             base,
             elem: ProjectionElem::Deref,
         }) = place_projection {
-            place_projection = base;
+            place_projection = &base;
             by_ref = true;
         }
 
@@ -2324,11 +2306,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 elem: ProjectionElem::Field(field, _ty),
             }) => {
                 let tcx = self.infcx.tcx;
-                let base_ty = Place::ty_from(&place.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) {
-                    Some(field)
+                    Some(*field)
                 } else {
                     None
                 }
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs
index b58d0e62a99..d933932309e 100644
--- a/src/librustc_mir/borrow_check/move_errors.rs
+++ b/src/librustc_mir/borrow_check/move_errors.rs
@@ -131,7 +131,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     }
                 }
 
-                let move_spans = self.move_spans(&original_path, location);
+                let move_spans = self.move_spans(original_path.as_place_ref(), location);
                 grouped_errors.push(GroupedMoveError::OtherIllegalMove {
                     use_spans: move_spans,
                     original_path,
@@ -160,7 +160,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let from_simple_let = match_place.is_none();
         let match_place = match_place.as_ref().unwrap_or(move_from);
 
-        match self.move_data.rev_lookup.find(match_place) {
+        match self.move_data.rev_lookup.find(match_place.as_place_ref()) {
             // Error with the match place
             LookupResult::Parent(_) => {
                 for ge in &mut *grouped_errors {
@@ -192,7 +192,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
             // Error with the pattern
             LookupResult::Exact(_) => {
-                let mpi = match self.move_data.rev_lookup.find(move_from) {
+                let mpi = match self.move_data.rev_lookup.find(move_from.as_place_ref()) {
                     LookupResult::Parent(Some(mpi)) => mpi,
                     // move_from should be a projection from match_place.
                     _ => unreachable!("Probably not unreachable..."),
@@ -242,7 +242,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 };
             debug!("report: original_path={:?} span={:?}, kind={:?} \
                    original_path.is_upvar_field_projection={:?}", original_path, span, kind,
-                   self.is_upvar_field_projection(original_path));
+                   self.is_upvar_field_projection(original_path.as_place_ref()));
             (
                 match kind {
                     IllegalMoveOriginKind::Static => {
@@ -308,11 +308,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         // 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 upvar_field = self.prefixes(&move_place.base, &move_place.projection, PrefixSet::All)
-            .find_map(|p| self.is_upvar_field_projection(&Place {
-                base: p.0.clone(),
-                projection: p.1.clone(),
-            }));
+        let upvar_field = self.prefixes(move_place.as_place_ref(), PrefixSet::All)
+            .find_map(|p| self.is_upvar_field_projection(p));
 
         let deref_base = match deref_target_place.projection {
             Some(box Projection { ref base, elem: ProjectionElem::Deref }) => Place {
@@ -368,7 +365,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 let place_name = self.describe_place(move_place).unwrap();
 
-                let place_description = if self.is_upvar_field_projection(move_place).is_some() {
+                let place_description = if self
+                    .is_upvar_field_projection(move_place.as_place_ref())
+                    .is_some()
+                {
                     format!("`{}`, a {}", place_name, capture_description)
                 } else {
                     format!(
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
index bc6c1c93a30..adde4ac85c8 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/mutability_errors.rs
@@ -75,7 +75,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 ));
 
                 item_msg = format!("`{}`", access_place_desc.unwrap());
-                if self.is_upvar_field_projection(access_place).is_some() {
+                if self.is_upvar_field_projection(access_place.as_place_ref()).is_some() {
                     reason = ", as it is not declared as mutable".to_string();
                 } else {
                     let name = self.upvars[upvar_index.index()].name;
@@ -100,11 +100,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         the_place_err.ty(self.body, self.infcx.tcx).ty
                     ));
 
-                    reason = if self.is_upvar_field_projection(access_place).is_some() {
-                        ", as it is a captured variable in a `Fn` closure".to_string()
-                    } else {
-                        ", as `Fn` closures cannot mutate their captured variables".to_string()
-                    }
+                    reason =
+                        if self.is_upvar_field_projection(access_place.as_place_ref()).is_some() {
+                            ", as it is a captured variable in a `Fn` closure".to_string()
+                        } else {
+                            ", as `Fn` closures cannot mutate their captured variables".to_string()
+                        }
                 } else if {
                     if let (PlaceBase::Local(local), None) = (&the_place_err.base, base) {
                         self.body.local_decls[*local].is_ref_for_guard()
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 d4ae15467be..6885baf8223 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -252,7 +252,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             Some(Cause::LiveVar(local, location)) => {
                 let span = body.source_info(location).span;
                 let spans = self
-                    .move_spans(&Place::from(local), location)
+                    .move_spans(Place::from(local).as_place_ref(), location)
                     .or_else(|| self.borrow_spans(span, location));
 
                 let borrow_location = location;
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index 538ac6881d9..75065816df0 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -50,7 +50,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
             body,
             &borrowed.borrowed_place,
             borrowed.kind,
-            place,
+            place.as_place_ref(),
             access,
             places_conflict::PlaceConflictBias::Overlap,
         ) {
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index 8f7695b40e8..348214f97f2 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -3,8 +3,8 @@ use crate::borrow_check::Overlap;
 use crate::borrow_check::{Deep, Shallow, AccessDepth};
 use rustc::hir;
 use rustc::mir::{
-    BorrowKind, Body, Place, PlaceBase, Projection, ProjectionElem, ProjectionsIter,
-    StaticKind
+    Body, BorrowKind, Place, PlaceBase, PlaceRef, Projection, ProjectionElem, ProjectionsIter,
+    StaticKind,
 };
 use rustc::ty::{self, TyCtxt};
 use std::cmp::max;
@@ -36,7 +36,7 @@ crate fn places_conflict<'tcx>(
         body,
         borrow_place,
         BorrowKind::Mut { allow_two_phase_borrow: true },
-        access_place,
+        access_place.as_place_ref(),
         AccessDepth::Deep,
         bias,
     )
@@ -51,7 +51,7 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
     body: &Body<'tcx>,
     borrow_place: &Place<'tcx>,
     borrow_kind: BorrowKind,
-    access_place: &Place<'tcx>,
+    access_place: PlaceRef<'_, 'tcx>,
     access: AccessDepth,
     bias: PlaceConflictBias,
 ) -> bool {
@@ -66,7 +66,7 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
         base: PlaceBase::Local(l1),
         projection: None,
     } = borrow_place {
-        if let Place {
+        if let PlaceRef {
             base: PlaceBase::Local(l2),
             projection: None,
         } = access_place {
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
index 38be4ae4644..ecafd4eb115 100644
--- a/src/librustc_mir/borrow_check/prefixes.rs
+++ b/src/librustc_mir/borrow_check/prefixes.rs
@@ -11,17 +11,17 @@ use super::MirBorrowckCtxt;
 
 use rustc::hir;
 use rustc::ty::{self, TyCtxt};
-use rustc::mir::{Body, Place, PlaceBase, Projection, ProjectionElem};
+use rustc::mir::{Body, Place, PlaceBase, PlaceRef, ProjectionElem};
 
-pub trait IsPrefixOf<'tcx> {
-    fn is_prefix_of(&self, other: &Place<'tcx>) -> bool;
+pub trait IsPrefixOf<'cx, 'tcx> {
+    fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool;
 }
 
-impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
-    fn is_prefix_of(&self, other: &Place<'tcx>) -> bool {
-        let mut cursor = &other.projection;
+impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
+    fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
+        let mut cursor = other.projection;
         loop {
-            if self.projection == *cursor {
+            if self.projection == cursor {
                 return self.base == other.base;
             }
 
@@ -37,7 +37,7 @@ pub(super) struct Prefixes<'cx, 'tcx> {
     body: &'cx Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     kind: PrefixSet,
-    next: Option<(&'cx PlaceBase<'tcx>, &'cx Option<Box<Projection<'tcx>>>)>,
+    next: Option<(PlaceRef<'cx, 'tcx>)>,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -58,12 +58,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// terminating the iteration early based on `kind`.
     pub(super) fn prefixes(
         &self,
-        place_base: &'cx PlaceBase<'tcx>,
-        place_projection: &'cx Option<Box<Projection<'tcx>>>,
+        place_ref: PlaceRef<'cx, 'tcx>,
         kind: PrefixSet,
     ) -> Prefixes<'cx, 'tcx> {
         Prefixes {
-            next: Some((place_base, place_projection)),
+            next: Some(place_ref),
             kind,
             body: self.body,
             tcx: self.infcx.tcx,
@@ -72,7 +71,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 }
 
 impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
-    type Item = (&'cx PlaceBase<'tcx>, &'cx Option<Box<Projection<'tcx>>>);
+    type Item = PlaceRef<'cx, 'tcx>;
     fn next(&mut self) -> Option<Self::Item> {
         let mut cursor = self.next?;
 
@@ -82,27 +81,42 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
         // downcasts here, but may return a base of a downcast).
 
         'cursor: loop {
-            let proj = match cursor {
-                (&PlaceBase::Local(_), &None)
+            let proj = match &cursor {
+                PlaceRef {
+                    base: PlaceBase::Local(_),
+                    projection: None,
+                }
                 | // search yielded this leaf
-                (&PlaceBase::Static(_), &None) => {
+                PlaceRef {
+                    base: PlaceBase::Static(_),
+                    projection: None,
+                } => {
                     self.next = None;
                     return Some(cursor);
                 }
-                (_, &Some(ref proj))  => proj,
+                PlaceRef {
+                    base: _,
+                    projection: Some(proj),
+                } => proj,
             };
 
             match proj.elem {
                 ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
                     // FIXME: add union handling
-                    self.next = Some((cursor.0, &proj.base));
+                    self.next = Some(PlaceRef {
+                        base: cursor.base,
+                        projection: &proj.base,
+                    });
                     return Some(cursor);
                 }
                 ProjectionElem::Downcast(..) |
                 ProjectionElem::Subslice { .. } |
                 ProjectionElem::ConstantIndex { .. } |
                 ProjectionElem::Index(_) => {
-                    cursor = (cursor.0, &proj.base);
+                    cursor = PlaceRef {
+                        base: cursor.base,
+                        projection: &proj.base,
+                    };
                     continue 'cursor;
                 }
                 ProjectionElem::Deref => {
@@ -123,7 +137,10 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
                 PrefixSet::All => {
                     // all prefixes: just blindly enqueue the base
                     // of the projection
-                    self.next = Some((cursor.0, &proj.base));
+                    self.next = Some(PlaceRef {
+                        base: cursor.base,
+                        projection: &proj.base,
+                    });
                     return Some(cursor);
                 }
                 PrefixSet::Supporting => {
@@ -136,7 +153,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
             // derefs, except we stop at the deref of a shared
             // reference.
 
-            let ty = Place::ty_from(cursor.0, &proj.base, self.body, self.tcx).ty;
+            let ty = Place::ty_from(cursor.base, &proj.base, self.body, self.tcx).ty;
             match ty.sty {
                 ty::RawPtr(_) |
                 ty::Ref(
@@ -154,12 +171,18 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
                     _, /*ty*/
                     hir::MutMutable,
                     ) => {
-                    self.next = Some((cursor.0, &proj.base));
+                    self.next = Some(PlaceRef {
+                        base: cursor.base,
+                        projection: &proj.base,
+                    });
                     return Some(cursor);
                 }
 
                 ty::Adt(..) if ty.is_box() => {
-                    self.next = Some((cursor.0, &proj.base));
+                    self.next = Some(PlaceRef {
+                        base: cursor.base,
+                        projection: &proj.base,
+                    });
                     return Some(cursor);
                 }
 
diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs
index 51a0a10b33d..b6dd544d395 100644
--- a/src/librustc_mir/dataflow/drop_flag_effects.rs
+++ b/src/librustc_mir/dataflow/drop_flag_effects.rs
@@ -171,7 +171,7 @@ pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>(
     let move_data = &ctxt.move_data;
     for arg in body.args_iter() {
         let place = mir::Place::from(arg);
-        let lookup_result = move_data.rev_lookup.find(&place);
+        let lookup_result = move_data.rev_lookup.find(place.as_place_ref());
         on_lookup_result_bits(tcx, body, move_data,
                               lookup_result,
                               |mpi| callback(mpi, DropFlagState::Present));
diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs
index 065cfe8a4e8..ade732bbb75 100644
--- a/src/librustc_mir/dataflow/impls/mod.rs
+++ b/src/librustc_mir/dataflow/impls/mod.rs
@@ -309,7 +309,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeInitializedPlaces<'a, 'tcx> {
         // when a call returns successfully, that means we need to set
         // the bits for that dest_place to 1 (initialized).
         on_lookup_result_bits(self.tcx, self.body, self.move_data(),
-                              self.move_data().rev_lookup.find(dest_place),
+                              self.move_data().rev_lookup.find(dest_place.as_place_ref()),
                               |mpi| { in_out.insert(mpi); });
     }
 }
@@ -367,7 +367,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> {
         // when a call returns successfully, that means we need to set
         // the bits for that dest_place to 0 (initialized).
         on_lookup_result_bits(self.tcx, self.body, self.move_data(),
-                              self.move_data().rev_lookup.find(dest_place),
+                              self.move_data().rev_lookup.find(dest_place.as_place_ref()),
                               |mpi| { in_out.remove(mpi); });
     }
 }
@@ -423,7 +423,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
         // when a call returns successfully, that means we need to set
         // the bits for that dest_place to 1 (initialized).
         on_lookup_result_bits(self.tcx, self.body, self.move_data(),
-                              self.move_data().rev_lookup.find(dest_place),
+                              self.move_data().rev_lookup.find(dest_place.as_place_ref()),
                               |mpi| { in_out.insert(mpi); });
     }
 }
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index f05dfad3257..3bdd3e3da04 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -314,12 +314,12 @@ pub(crate) trait DataflowResultsConsumer<'a, 'tcx: 'a> {
 
     fn visit_statement_entry(&mut self,
                              _loc: Location,
-                             _stmt: &Statement<'tcx>,
+                             _stmt: &'a Statement<'tcx>,
                              _flow_state: &Self::FlowState) {}
 
     fn visit_terminator_entry(&mut self,
                               _loc: Location,
-                              _term: &Terminator<'tcx>,
+                              _term: &'a Terminator<'tcx>,
                               _flow_state: &Self::FlowState) {}
 
     // Main entry point: this drives the processing of results.
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 8eff8b74e4f..93e8fd69361 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -454,7 +454,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             _ => place.clone()
         };
 
-        if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(&place) {
+        if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place.as_place_ref()) {
             let init = self.builder.data.inits.push(Init {
                 location: InitLocation::Statement(self.loc),
                 path,
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index b30750850b5..5c2255882b2 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -240,8 +240,8 @@ impl MovePathLookup {
     // alternative will *not* create a MovePath on the fly for an
     // unknown place, but will rather return the nearest available
     // parent.
-    pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
-        place.iterate(|place_base, place_projection| {
+    pub fn find(&self, place_ref: PlaceRef<'cx, 'tcx>) -> LookupResult {
+        place_ref.iterate(|place_base, place_projection| {
             let mut result = match place_base {
                 PlaceBase::Local(local) => self.locals[*local],
                 PlaceBase::Static(..) => return LookupResult::Parent(None),
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index ad19b974d7d..0748321f605 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -105,7 +105,7 @@ fn find_dead_unwinds<'tcx>(
             init_data.apply_location(tcx, body, env, loc);
         }
 
-        let path = match env.move_data.rev_lookup.find(location) {
+        let path = match env.move_data.rev_lookup.find(location.as_place_ref()) {
             LookupResult::Exact(e) => e,
             LookupResult::Parent(..) => {
                 debug!("find_dead_unwinds: has parent; skipping");
@@ -360,7 +360,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 statement_index: data.statements.len()
             });
 
-            let path = self.move_data().rev_lookup.find(location);
+            let path = self.move_data().rev_lookup.find(location.as_place_ref());
             debug!("collect_drop_flags: {:?}, place {:?} ({:?})",
                    bb, location, path);
 
@@ -399,7 +399,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             match terminator.kind {
                 TerminatorKind::Drop { ref location, target, unwind } => {
                     let init_data = self.initialization_data_at(loc);
-                    match self.move_data().rev_lookup.find(location) {
+                    match self.move_data().rev_lookup.find(location.as_place_ref()) {
                         LookupResult::Exact(path) => {
                             elaborate_drop(
                                 &mut Elaborator {
@@ -488,7 +488,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             is_cleanup: false,
         });
 
-        match self.move_data().rev_lookup.find(location) {
+        match self.move_data().rev_lookup.find(location.as_place_ref()) {
             LookupResult::Exact(path) => {
                 debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
                 let init_data = self.initialization_data_at(loc);
@@ -558,7 +558,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 assert!(!self.patch.is_patched(bb));
 
                 let loc = Location { block: tgt, statement_index: 0 };
-                let path = self.move_data().rev_lookup.find(place);
+                let path = self.move_data().rev_lookup.find(place.as_place_ref());
                 on_lookup_result_bits(
                     self.tcx, self.body, self.move_data(), path,
                     |child| self.set_drop_flag(loc, child, DropFlagState::Present)
@@ -632,7 +632,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 assert!(!self.patch.is_patched(bb));
 
                 let loc = Location { block: bb, statement_index: data.statements.len() };
-                let path = self.move_data().rev_lookup.find(place);
+                let path = self.move_data().rev_lookup.find(place.as_place_ref());
                 on_lookup_result_bits(
                     self.tcx, self.body, self.move_data(), path,
                     |child| self.set_drop_flag(loc, child, DropFlagState::Present)
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 6def9dc2b5e..1fd865c42fc 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -168,7 +168,7 @@ fn each_block<'tcx, O>(
         if place == peek_arg_place {
             if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_place) = **rvalue {
                 // Okay, our search is over.
-                match move_data.rev_lookup.find(peeking_at_place) {
+                match move_data.rev_lookup.find(peeking_at_place.as_place_ref()) {
                     LookupResult::Exact(peek_mpi) => {
                         let bit_state = on_entry.contains(peek_mpi);
                         debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
@@ -192,7 +192,7 @@ fn each_block<'tcx, O>(
             }
         }
 
-        let lhs_mpi = move_data.rev_lookup.find(place);
+        let lhs_mpi = move_data.rev_lookup.find(place.as_place_ref());
 
         debug!("rustc_peek: computing effect on place: {:?} ({:?}) in stmt: {:?}",
                place, lhs_mpi, stmt);