about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-10-25 13:12:46 +0200
committerGitHub <noreply@github.com>2019-10-25 13:12:46 +0200
commit8bb039fb83f7f18df5e1d71607981c8d4902b7b3 (patch)
treea513250d67d60597678687ad0333f9aec9503e90 /src
parent1f93be1bb3f89d6b30a3ddc39e8a462924ccd503 (diff)
parent5f5903df31ae1beea85fc49e765ed57212d5346a (diff)
downloadrust-8bb039fb83f7f18df5e1d71607981c8d4902b7b3.tar.gz
rust-8bb039fb83f7f18df5e1d71607981c8d4902b7b3.zip
Rollup merge of #65315 - spastorino:intern-place-projection, r=oli-obk
Intern place projection

This should sit on top of https://github.com/rust-lang/rust/pull/65197. After that one merged, I'm gonna rebase on top of it.

The important commits are the last three and there's a bunch of code repetition that I'm going to remove but for that I need to refactor some things that probably need to be added before this PR.

Anyway this work helps as is because we can run perf tests :).

r? @oli-obk /cc @nikomatsakis
Diffstat (limited to 'src')
-rw-r--r--src/librustc/mir/mod.rs97
-rw-r--r--src/librustc/mir/visit.rs10
-rw-r--r--src/librustc/ty/codec.rs25
-rw-r--r--src/librustc/ty/context.rs70
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs5
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs84
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs5
-rw-r--r--src/librustc_codegen_ssa/mir/statement.rs11
-rw-r--r--src/librustc_mir/borrow_check/borrow_set.rs5
-rw-r--r--src/librustc_mir/borrow_check/conflict_errors.rs319
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs13
-rw-r--r--src/librustc_mir/borrow_check/mod.rs113
-rw-r--r--src/librustc_mir/borrow_check/move_errors.rs70
-rw-r--r--src/librustc_mir/borrow_check/mutability_errors.rs13
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs32
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs156
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs6
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs34
-rw-r--r--src/librustc_mir/borrow_check/places_conflict.rs10
-rw-r--r--src/librustc_mir/borrow_check/used_muts.rs9
-rw-r--r--src/librustc_mir/build/expr/as_place.rs14
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs38
-rw-r--r--src/librustc_mir/build/expr/into.rs2
-rw-r--r--src/librustc_mir/build/matches/mod.rs6
-rw-r--r--src/librustc_mir/build/matches/simplify.rs4
-rw-r--r--src/librustc_mir/build/matches/test.rs19
-rw-r--r--src/librustc_mir/build/matches/util.rs34
-rw-r--r--src/librustc_mir/build/scope.rs71
-rw-r--r--src/librustc_mir/dataflow/impls/storage_liveness.rs6
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs6
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs2
-rw-r--r--src/librustc_mir/shim.rs25
-rw-r--r--src/librustc_mir/transform/check_consts/qualifs.rs4
-rw-r--r--src/librustc_mir/transform/check_consts/resolver.rs17
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs20
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs4
-rw-r--r--src/librustc_mir/transform/cleanup_post_borrowck.rs14
-rw-r--r--src/librustc_mir/transform/const_prop.rs41
-rw-r--r--src/librustc_mir/transform/copy_prop.rs134
-rw-r--r--src/librustc_mir/transform/deaggregator.rs1
-rw-r--r--src/librustc_mir/transform/erase_regions.rs4
-rw-r--r--src/librustc_mir/transform/generator.rs93
-rw-r--r--src/librustc_mir/transform/inline.rs51
-rw-r--r--src/librustc_mir/transform/instcombine.rs48
-rw-r--r--src/librustc_mir/transform/mod.rs6
-rw-r--r--src/librustc_mir/transform/no_landing_pads.rs20
-rw-r--r--src/librustc_mir/transform/promote_consts.rs57
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs55
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs4
-rw-r--r--src/librustc_mir/transform/remove_noop_landing_pads.rs15
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs38
-rw-r--r--src/librustc_mir/transform/simplify.rs11
-rw-r--r--src/librustc_mir/transform/uniform_array_move_out.rs136
-rw-r--r--src/librustc_mir/util/aggregate.rs9
-rw-r--r--src/librustc_mir/util/alignment.rs4
-rw-r--r--src/librustc_mir/util/def_use.rs44
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs60
57 files changed, 1147 insertions, 1057 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 08e7001681c..fb9c95724c9 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -15,8 +15,7 @@ use crate::ty::layout::VariantIdx;
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::subst::{Subst, SubstsRef};
 use crate::ty::{
-    self, AdtDef, CanonicalUserTypeAnnotations, Region, Ty, TyCtxt,
-    UserTypeAnnotationIndex,
+    self, AdtDef, CanonicalUserTypeAnnotations, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex,
 };
 
 use polonius_engine::Atom;
@@ -1712,15 +1711,17 @@ impl Debug for Statement<'_> {
 /// A path to a value; something that can be evaluated without
 /// changing or disturbing program state.
 #[derive(
-    Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
+    Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable,
 )]
 pub struct Place<'tcx> {
     pub base: PlaceBase<'tcx>,
 
     /// projection out of a place (access a field, deref a pointer, etc)
-    pub projection: Box<[PlaceElem<'tcx>]>,
+    pub projection: &'tcx List<PlaceElem<'tcx>>,
 }
 
+impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {}
+
 #[derive(
     Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
 )]
@@ -1824,6 +1825,8 @@ impl<V, T> ProjectionElem<V, T> {
 /// and the index is a local.
 pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
 
+impl<'tcx> Copy for PlaceElem<'tcx> { }
+
 // At least on 64 bit systems, `PlaceElem` should not be larger than two pointers.
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(PlaceElem<'_>, 16);
@@ -1846,50 +1849,11 @@ pub struct PlaceRef<'a, 'tcx> {
 }
 
 impl<'tcx> Place<'tcx> {
-    // FIXME change this back to a const when projection is a shared slice.
-    //
-    // pub const RETURN_PLACE: Place<'tcx> = Place {
-    //     base: PlaceBase::Local(RETURN_PLACE),
-    //     projection: &[],
-    // };
+    // FIXME change this to a const fn by also making List::empty a const fn.
     pub fn return_place() -> Place<'tcx> {
         Place {
             base: PlaceBase::Local(RETURN_PLACE),
-            projection: Box::new([]),
-        }
-    }
-
-    pub fn field(self, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
-        self.elem(ProjectionElem::Field(f, ty))
-    }
-
-    pub fn deref(self) -> Place<'tcx> {
-        self.elem(ProjectionElem::Deref)
-    }
-
-    pub fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Place<'tcx> {
-        self.elem(ProjectionElem::Downcast(
-            Some(adt_def.variants[variant_index].ident.name),
-            variant_index,
-        ))
-    }
-
-    pub fn downcast_unnamed(self, variant_index: VariantIdx) -> Place<'tcx> {
-        self.elem(ProjectionElem::Downcast(None, variant_index))
-    }
-
-    pub fn index(self, index: Local) -> Place<'tcx> {
-        self.elem(ProjectionElem::Index(index))
-    }
-
-    pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> {
-        // FIXME(spastorino): revisit this again once projection is not a Box<[T]> anymore
-        let mut projection = self.projection.into_vec();
-        projection.push(elem);
-
-        Place {
-            base: self.base,
-            projection: projection.into_boxed_slice(),
+            projection: List::empty(),
         }
     }
 
@@ -1906,15 +1870,15 @@ impl<'tcx> Place<'tcx> {
     //
     // 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 {
-            Place {
-                base: PlaceBase::Local(local),
-                projection: box [],
+        match self.as_ref() {
+            PlaceRef {
+                base: &PlaceBase::Local(local),
+                projection: &[],
             } |
-            Place {
-                base: PlaceBase::Local(local),
-                projection: box [ProjectionElem::Deref],
-            } => Some(*local),
+            PlaceRef {
+                base: &PlaceBase::Local(local),
+                projection: &[ProjectionElem::Deref],
+            } => Some(local),
             _ => None,
         }
     }
@@ -1922,10 +1886,7 @@ impl<'tcx> Place<'tcx> {
     /// If this place represents a local variable like `_X` with no
     /// projections, return `Some(_X)`.
     pub fn as_local(&self) -> Option<Local> {
-        match self {
-            Place { projection: box [], base: PlaceBase::Local(l) } => Some(*l),
-            _ => None,
-        }
+        self.as_ref().as_local()
     }
 
     pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
@@ -1940,7 +1901,7 @@ impl From<Local> for Place<'_> {
     fn from(local: Local) -> Self {
         Place {
             base: local.into(),
-            projection: Box::new([]),
+            projection: List::empty(),
         }
     }
 }
@@ -1969,6 +1930,15 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
             _ => None,
         }
     }
+
+    /// If this place represents a local variable like `_X` with no
+    /// projections, return `Some(_X)`.
+    pub fn as_local(&self) -> Option<Local> {
+        match self {
+            PlaceRef { base: PlaceBase::Local(l), projection: [] } => Some(*l),
+            _ => None,
+        }
+    }
 }
 
 impl Debug for Place<'_> {
@@ -3182,6 +3152,17 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> {
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>();
+        folder.tcx().intern_place_elems(&v)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.iter().any(|t| t.visit_with(visitor))
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         Static {
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 427540d7275..6a41b843e57 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -784,6 +784,8 @@ macro_rules! make_mir_visitor {
 
 macro_rules! visit_place_fns {
     (mut) => (
+        fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
+
         fn super_place(
             &mut self,
             place: &mut Place<'tcx>,
@@ -793,19 +795,21 @@ macro_rules! visit_place_fns {
             self.visit_place_base(&mut place.base, context, location);
 
             if let Some(new_projection) = self.process_projection(&place.projection) {
-                place.projection = new_projection;
+                place.projection = self.tcx().intern_place_elems(&new_projection);
             }
         }
 
         fn process_projection(
             &mut self,
             projection: &'a [PlaceElem<'tcx>],
-        ) -> Option<Box<[PlaceElem<'tcx>]>> {
+        ) -> Option<Vec<PlaceElem<'tcx>>> {
             let mut projection = Cow::Borrowed(projection);
 
             for i in 0..projection.len() {
                 if let Some(elem) = projection.get(i) {
                     if let Some(elem) = self.process_projection_elem(elem) {
+                        // This converts the borrowed projection into `Cow::Owned(_)` and returns a
+                        // clone of the projection so we can mutate and reintern later.
                         let vec = projection.to_mut();
                         vec[i] = elem;
                     }
@@ -814,7 +818,7 @@ macro_rules! visit_place_fns {
 
             match projection {
                 Cow::Borrowed(_) => None,
-                Cow::Owned(vec) => Some(vec.into_boxed_slice()),
+                Cow::Owned(vec) => Some(vec),
             }
         }
 
diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs
index 03cb4775bd8..d5e7ac19263 100644
--- a/src/librustc/ty/codec.rs
+++ b/src/librustc/ty/codec.rs
@@ -13,9 +13,9 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque};
 use std::hash::Hash;
 use std::intrinsics;
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{self, List, Ty, TyCtxt};
 use crate::ty::subst::SubstsRef;
-use crate::mir::interpret::Allocation;
+use crate::mir::{self, interpret::Allocation};
 use syntax_pos::Span;
 
 /// The shorthand encoding uses an enum's variant index `usize`
@@ -219,6 +219,18 @@ where
 }
 
 #[inline]
+pub fn decode_place<D>(decoder: &mut D) -> Result<mir::Place<'tcx>, D::Error>
+where
+    D: TyDecoder<'tcx>,
+{
+    let base: mir::PlaceBase<'tcx> = Decodable::decode(decoder)?;
+    let len = decoder.read_usize()?;
+    let projection: &'tcx List<mir::PlaceElem<'tcx>> =
+        decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?;
+    Ok(mir::Place { base, projection })
+}
+
+#[inline]
 pub fn decode_region<D>(decoder: &mut D) -> Result<ty::Region<'tcx>, D::Error>
 where
     D: TyDecoder<'tcx>,
@@ -413,6 +425,15 @@ macro_rules! implement_ty_decoder {
                 }
             }
 
+            impl<$($typaram),*> SpecializedDecoder<$crate::mir::Place<'tcx>>
+            for $DecoderName<$($typaram),*> {
+                fn specialized_decode(
+                    &mut self
+                ) -> Result<$crate::mir::Place<'tcx>, Self::Error> {
+                    decode_place(self)
+                }
+            }
+
             impl<$($typaram),*> SpecializedDecoder<ty::Region<'tcx>>
             for $DecoderName<$($typaram),*> {
                 fn specialized_decode(&mut self) -> Result<ty::Region<'tcx>, Self::Error> {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index f99298281fe..f958a7e357b 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 //! Type context book-keeping.
 
 use crate::arena::Arena;
@@ -21,7 +22,7 @@ use crate::middle::cstore::EncodedMetadata;
 use crate::middle::lang_items;
 use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
 use crate::middle::stability;
-use crate::mir::{Body, interpret, ProjectionKind, Promoted};
+use crate::mir::{Body, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted};
 use crate::mir::interpret::{ConstValue, Allocation, Scalar};
 use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst};
 use crate::ty::ReprOptions;
@@ -106,6 +107,7 @@ pub struct CtxtInterners<'tcx> {
     goal: InternedSet<'tcx, GoalKind<'tcx>>,
     goal_list: InternedSet<'tcx, List<Goal<'tcx>>>,
     projs: InternedSet<'tcx, List<ProjectionKind>>,
+    place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
     const_: InternedSet<'tcx, Const<'tcx>>,
 }
 
@@ -124,6 +126,7 @@ impl<'tcx> CtxtInterners<'tcx> {
             goal: Default::default(),
             goal_list: Default::default(),
             projs: Default::default(),
+            place_elems: Default::default(),
             const_: Default::default(),
         }
     }
@@ -2142,6 +2145,13 @@ impl<'tcx> Borrow<[ProjectionKind]>
     }
 }
 
+impl<'tcx> Borrow<[PlaceElem<'tcx>]>
+    for Interned<'tcx, List<PlaceElem<'tcx>>> {
+    fn borrow(&self) -> &[PlaceElem<'tcx>] {
+        &self.0[..]
+    }
+}
+
 impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
     fn borrow(&self) -> &RegionKind {
         &self.0
@@ -2242,7 +2252,8 @@ slice_interners!(
     predicates: _intern_predicates(Predicate<'tcx>),
     clauses: _intern_clauses(Clause<'tcx>),
     goal_list: _intern_goals(Goal<'tcx>),
-    projs: _intern_projs(ProjectionKind)
+    projs: _intern_projs(ProjectionKind),
+    place_elems: _intern_place_elems(PlaceElem<'tcx>)
 );
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -2584,6 +2595,48 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_ty(Opaque(def_id, substs))
     }
 
+    pub fn mk_place_field(self, place: Place<'tcx>, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
+        self.mk_place_elem(place, PlaceElem::Field(f, ty))
+    }
+
+    pub fn mk_place_deref(self, place: Place<'tcx>) -> Place<'tcx> {
+        self.mk_place_elem(place, PlaceElem::Deref)
+    }
+
+    pub fn mk_place_downcast(
+        self,
+        place: Place<'tcx>,
+        adt_def: &'tcx AdtDef,
+        variant_index: VariantIdx,
+    ) -> Place<'tcx> {
+        self.mk_place_elem(
+            place,
+            PlaceElem::Downcast(Some(adt_def.variants[variant_index].ident.name), variant_index),
+        )
+    }
+
+    pub fn mk_place_downcast_unnamed(
+        self,
+        place: Place<'tcx>,
+        variant_index: VariantIdx,
+    ) -> Place<'tcx> {
+        self.mk_place_elem(place, PlaceElem::Downcast(None, variant_index))
+    }
+
+    pub fn mk_place_index(self, place: Place<'tcx>, index: Local) -> Place<'tcx> {
+        self.mk_place_elem(place, PlaceElem::Index(index))
+    }
+
+    /// This method copies `Place`'s projection, add an element and reintern it. Should not be used
+    /// to build a full `Place` it's just a convenient way to grab a projection and modify it in
+    /// flight.
+    pub fn mk_place_elem(self, place: Place<'tcx>, elem: PlaceElem<'tcx>) -> Place<'tcx> {
+        let mut projection = place.projection.to_vec();
+        projection.push(elem);
+
+        Place { base: place.base, projection: self.intern_place_elems(&projection) }
+    }
+
     pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'tcx>])
         -> &'tcx List<ExistentialPredicate<'tcx>> {
         assert!(!eps.is_empty());
@@ -2628,6 +2681,14 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    pub fn intern_place_elems(self, ts: &[PlaceElem<'tcx>]) -> &'tcx List<PlaceElem<'tcx>> {
+        if ts.len() == 0 {
+            List::empty()
+        } else {
+            self._intern_place_elems(ts)
+        }
+    }
+
     pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'tcx> {
         if ts.len() == 0 {
             List::empty()
@@ -2690,6 +2751,11 @@ impl<'tcx> TyCtxt<'tcx> {
         iter.intern_with(|xs| self.intern_substs(xs))
     }
 
+    pub fn mk_place_elems<I: InternAs<[PlaceElem<'tcx>],
+                          &'tcx List<PlaceElem<'tcx>>>>(self, iter: I) -> I::Output {
+        iter.intern_with(|xs| self.intern_place_elems(xs))
+    }
+
     pub fn mk_substs_trait(self,
                      self_ty: Ty<'tcx>,
                      rest: &[GenericArg<'tcx>])
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index ea1cf926fcc..604deffcf94 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -191,10 +191,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
                     location: Location) {
         debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
 
-        if let mir::Place {
-            base: mir::PlaceBase::Local(index),
-            projection: box [],
-        } = *place {
+        if let Some(index) = place.as_local() {
             self.assign(index, location);
             let decl_span = self.fx.mir.local_decls[index].source_info.span;
             if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index dc77d025c00..28441cae26e 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -2,7 +2,7 @@ use rustc_index::vec::Idx;
 use rustc::middle::lang_items;
 use rustc::ty::{self, Ty, TypeFoldable, Instance};
 use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
-use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
+use rustc::mir::{self, PlaceBase, Static, StaticKind};
 use rustc::mir::interpret::PanicInfo;
 use rustc_target::abi::call::{ArgType, FnType, PassMode};
 use rustc_target::spec::abi::Abi;
@@ -630,53 +630,43 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 // checked by const-qualification, which also
                 // promotes any complex rvalues to constants.
                 if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
-                    match *arg {
+                    match arg {
                         // The shuffle array argument is usually not an explicit constant,
                         // but specified directly in the code. This means it gets promoted
                         // and we can then extract the value by evaluating the promoted.
-                        mir::Operand::Copy(
-                            Place {
-                                base: PlaceBase::Static(box Static {
-                                    kind: StaticKind::Promoted(promoted, _),
+                        mir::Operand::Copy(place) | mir::Operand::Move(place) => {
+                            if let mir::PlaceRef {
+                                base:
+                                    &PlaceBase::Static(box Static {
+                                        kind: StaticKind::Promoted(promoted, _),
+                                        ty,
+                                        def_id: _,
+                                    }),
+                                projection: &[],
+                            } = place.as_ref()
+                            {
+                                let param_env = ty::ParamEnv::reveal_all();
+                                let cid = mir::interpret::GlobalId {
+                                    instance: self.instance,
+                                    promoted: Some(promoted),
+                                };
+                                let c = bx.tcx().const_eval(param_env.and(cid));
+                                let (llval, ty) = self.simd_shuffle_indices(
+                                    &bx,
+                                    terminator.source_info.span,
                                     ty,
-                                    def_id: _,
-                                }),
-                                projection: box [],
+                                    c,
+                                );
+                                return OperandRef {
+                                    val: Immediate(llval),
+                                    layout: bx.layout_of(ty),
+                                };
+                            } else {
+                                span_bug!(span, "shuffle indices must be constant");
                             }
-                        ) |
-                        mir::Operand::Move(
-                            Place {
-                                base: PlaceBase::Static(box Static {
-                                    kind: StaticKind::Promoted(promoted, _),
-                                    ty,
-                                    def_id: _,
-                                }),
-                                projection: box [],
-                            }
-                        ) => {
-                            let param_env = ty::ParamEnv::reveal_all();
-                            let cid = mir::interpret::GlobalId {
-                                instance: self.instance,
-                                promoted: Some(promoted),
-                            };
-                            let c = bx.tcx().const_eval(param_env.and(cid));
-                            let (llval, ty) = self.simd_shuffle_indices(
-                                &bx,
-                                terminator.source_info.span,
-                                ty,
-                                c,
-                            );
-                            return OperandRef {
-                                val: Immediate(llval),
-                                layout: bx.layout_of(ty),
-                            };
-
-                        }
-                        mir::Operand::Copy(_) |
-                        mir::Operand::Move(_) => {
-                            span_bug!(span, "shuffle indices must be constant");
                         }
-                        mir::Operand::Constant(ref constant) => {
+
+                        mir::Operand::Constant(constant) => {
                             let c = self.eval_mir_constant(constant);
                             let (llval, ty) = self.simd_shuffle_indices(
                                 &bx,
@@ -1117,10 +1107,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         if fn_ret.is_ignore() {
             return ReturnDest::Nothing;
         }
-        let dest = if let mir::Place {
-            base: mir::PlaceBase::Local(index),
-            projection: box [],
-        } = *dest {
+        let dest = if let Some(index) = dest.as_local() {
             match self.locals[index] {
                 LocalRef::Place(dest) => dest,
                 LocalRef::UnsizedPlace(_) => bug!("return type must be sized"),
@@ -1178,10 +1165,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         src: &mir::Operand<'tcx>,
         dst: &mir::Place<'tcx>
     ) {
-        if let mir::Place {
-            base: mir::PlaceBase::Local(index),
-            projection: box [],
-        } = *dst {
+        if let Some(index) = dst.as_local() {
             match self.locals[index] {
                 LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
                 LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 7e662ea37db..1608f222bc6 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -530,10 +530,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> Bx::Value {
         // ZST are passed as operands and require special handling
         // because codegen_place() panics if Local is operand.
-        if let mir::Place {
-            base: mir::PlaceBase::Local(index),
-            projection: box [],
-        } = *place {
+        if let Some(index) = place.as_local() {
             if let LocalRef::Operand(Some(op)) = self.locals[index] {
                 if let ty::Array(_, n) = op.layout.ty.kind {
                     let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs
index dab7dfc0417..43d5c2570b7 100644
--- a/src/librustc_codegen_ssa/mir/statement.rs
+++ b/src/librustc_codegen_ssa/mir/statement.rs
@@ -17,11 +17,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         self.set_debug_loc(&mut bx, statement.source_info);
         match statement.kind {
             mir::StatementKind::Assign(box(ref place, ref rvalue)) => {
-                if let mir::Place {
-                    base: mir::PlaceBase::Local(index),
-                    projection: box [],
-                } = place {
-                    match self.locals[*index] {
+                if let Some(index) = place.as_local() {
+                    match self.locals[index] {
                         LocalRef::Place(cg_dest) => {
                             self.codegen_rvalue(bx, cg_dest, rvalue)
                         }
@@ -30,7 +27,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         }
                         LocalRef::Operand(None) => {
                             let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
-                            if let Some(name) = self.mir.local_decls[*index].name {
+                            if let Some(name) = self.mir.local_decls[index].name {
                                 match operand.val {
                                     OperandValue::Ref(x, ..) |
                                     OperandValue::Immediate(x) => {
@@ -44,7 +41,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                     }
                                 }
                             }
-                            self.locals[*index] = LocalRef::Operand(Some(operand));
+                            self.locals[index] = LocalRef::Operand(Some(operand));
                             bx
                         }
                         LocalRef::Operand(Some(op)) => {
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index 7dd1db3b7bd..98641031c17 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -315,10 +315,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
         //    TEMP = &foo
         //
         // so extract `temp`.
-        let temp = if let &mir::Place {
-            base: mir::PlaceBase::Local(temp),
-            projection: box [],
-        } = assigned_place {
+        let temp = if let Some(temp) = assigned_place.as_local() {
             temp
         } else {
             span_bug!(
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
index 4c469a82ac3..36db68a3372 100644
--- a/src/librustc_mir/borrow_check/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/conflict_errors.rs
@@ -239,11 +239,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         );
                     }
                 }
-                let span = if let Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [],
-                } = place {
-                    let decl = &self.body.local_decls[*local];
+                let span = if let Some(local) = place.as_local() {
+                    let decl = &self.body.local_decls[local];
                     Some(decl.source_info.span)
                 } else {
                     None
@@ -611,7 +608,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     projection,
                 } = first_borrowed_place;
 
-                let mut cursor = &**projection;
+                let mut cursor = projection.as_ref();
                 while let [proj_base @ .., elem] = cursor {
                     cursor = proj_base;
 
@@ -635,7 +632,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     projection,
                 } = second_borrowed_place;
 
-                let mut cursor = &**projection;
+                let mut cursor = projection.as_ref();
                 while let [proj_base @ .., elem] = cursor {
                     cursor = proj_base;
 
@@ -710,10 +707,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             _ => drop_span,
         };
 
+        let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
+
         if self.access_place_error_reported
             .contains(&(Place {
                 base: root_place.base.clone(),
-                projection: root_place.projection.to_vec().into_boxed_slice(),
+                projection: root_place_projection,
             }, borrow_span))
         {
             debug!(
@@ -726,7 +725,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         self.access_place_error_reported
             .insert((Place {
                 base: root_place.base.clone(),
-                projection: root_place.projection.to_vec().into_boxed_slice(),
+                projection: root_place_projection,
             }, borrow_span));
 
         if let StorageDeadOrDrop::Destructor(dropped_ty) =
@@ -1124,26 +1123,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         };
 
         let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
-            let local_kind = match borrow.borrowed_place {
-                Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [],
-                } => {
-                    match self.body.local_kind(local) {
-                        LocalKind::ReturnPointer
-                        | LocalKind::Temp => bug!("temporary or return pointer with a name"),
-                        LocalKind::Var => "local variable ",
-                        LocalKind::Arg
-                        if !self.upvars.is_empty()
-                            && local == Local::new(1) => {
-                            "variable captured by `move` "
-                        }
-                        LocalKind::Arg => {
-                            "function parameter "
-                        }
+            let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
+                match self.body.local_kind(local) {
+                    LocalKind::ReturnPointer
+                    | LocalKind::Temp => bug!("temporary or return pointer with a name"),
+                    LocalKind::Var => "local variable ",
+                    LocalKind::Arg
+                    if !self.upvars.is_empty()
+                        && local == Local::new(1) => {
+                        "variable captured by `move` "
+                    }
+                    LocalKind::Arg => {
+                        "function parameter "
                     }
                 }
-                _ => "local data ",
+            } else {
+                "local data "
             };
             (
                 format!("{}`{}`", local_kind, place_desc),
@@ -1480,10 +1475,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         assigned_span: Span,
         err_place: &Place<'tcx>,
     ) {
-        let (from_arg, local_decl) = if let Place {
-            base: PlaceBase::Local(local),
-            projection: box [],
-        } = *err_place {
+        let (from_arg, local_decl) = if let Some(local) = err_place.as_local() {
             if let LocalKind::Arg = self.body.local_kind(local) {
                 (true, Some(&self.body.local_decls[local]))
             } else {
@@ -1643,11 +1635,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 reservation
             );
             // Check that the initial assignment of the reserve location is into a temporary.
-            let mut target = *match reservation {
-                Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [],
-                } if self.body.local_kind(*local) == LocalKind::Temp => local,
+            let mut target = match reservation.as_local() {
+                Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
                 _ => return None,
             };
 
@@ -1659,127 +1648,122 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
                     target, stmt
                 );
-                if let StatementKind::Assign(
-                    box(
-                        Place {
-                            base: PlaceBase::Local(assigned_to),
-                            projection: box [],
-                        },
-                        rvalue
-                    )
-                ) = &stmt.kind {
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: assigned_to={:?} \
-                         rvalue={:?}",
-                        assigned_to, rvalue
-                    );
-                    // Check if our `target` was captured by a closure.
-                    if let Rvalue::Aggregate(
-                        box AggregateKind::Closure(def_id, substs),
-                        operands,
-                    ) = rvalue
-                    {
-                        for operand in operands {
-                            let assigned_from = match operand {
-                                Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                if let StatementKind::Assign(box(place, rvalue)) = &stmt.kind {
+                    if let Some(assigned_to) = place.as_local() {
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: assigned_to={:?} \
+                             rvalue={:?}",
+                            assigned_to, rvalue
+                        );
+                        // Check if our `target` was captured by a closure.
+                        if let Rvalue::Aggregate(
+                            box AggregateKind::Closure(def_id, substs),
+                            operands,
+                        ) = rvalue
+                        {
+                            for operand in operands {
+                                let assigned_from = match operand {
+                                    Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                                        assigned_from
+                                    }
+                                    _ => continue,
+                                };
+                                debug!(
+                                    "annotate_argument_and_return_for_borrow: assigned_from={:?}",
                                     assigned_from
-                                }
-                                _ => continue,
-                            };
-                            debug!(
-                                "annotate_argument_and_return_for_borrow: assigned_from={:?}",
-                                assigned_from
-                            );
+                                );
 
-                            // Find the local from the operand.
-                            let assigned_from_local = match assigned_from.local_or_deref_local() {
-                                Some(local) => local,
-                                None => continue,
-                            };
+                                // Find the local from the operand.
+                                let assigned_from_local = match assigned_from.local_or_deref_local()
+                                {
+                                    Some(local) => local,
+                                    None => continue,
+                                };
 
-                            if assigned_from_local != target {
-                                continue;
-                            }
-
-                            // If a closure captured our `target` and then assigned
-                            // into a place then we should annotate the closure in
-                            // case it ends up being assigned into the return place.
-                            annotated_closure = self.annotate_fn_sig(
-                                *def_id,
-                                self.infcx.closure_sig(*def_id, *substs),
-                            );
-                            debug!(
-                                "annotate_argument_and_return_for_borrow: \
-                                 annotated_closure={:?} assigned_from_local={:?} \
-                                 assigned_to={:?}",
-                                annotated_closure, assigned_from_local, assigned_to
-                            );
+                                if assigned_from_local != target {
+                                    continue;
+                                }
 
-                            if *assigned_to == mir::RETURN_PLACE {
-                                // If it was assigned directly into the return place, then
-                                // return now.
-                                return annotated_closure;
-                            } else {
-                                // Otherwise, update the target.
-                                target = *assigned_to;
+                                // If a closure captured our `target` and then assigned
+                                // into a place then we should annotate the closure in
+                                // case it ends up being assigned into the return place.
+                                annotated_closure = self.annotate_fn_sig(
+                                    *def_id,
+                                    self.infcx.closure_sig(*def_id, *substs),
+                                );
+                                debug!(
+                                    "annotate_argument_and_return_for_borrow: \
+                                     annotated_closure={:?} assigned_from_local={:?} \
+                                     assigned_to={:?}",
+                                    annotated_closure, assigned_from_local, assigned_to
+                                );
+
+                                if assigned_to == mir::RETURN_PLACE {
+                                    // If it was assigned directly into the return place, then
+                                    // return now.
+                                    return annotated_closure;
+                                } else {
+                                    // Otherwise, update the target.
+                                    target = assigned_to;
+                                }
                             }
-                        }
 
-                        // If none of our closure's operands matched, then skip to the next
-                        // statement.
-                        continue;
-                    }
+                            // If none of our closure's operands matched, then skip to the next
+                            // statement.
+                            continue;
+                        }
 
-                    // Otherwise, look at other types of assignment.
-                    let assigned_from = match rvalue {
-                        Rvalue::Ref(_, _, assigned_from) => assigned_from,
-                        Rvalue::Use(operand) => match operand {
-                            Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                                assigned_from
-                            }
+                        // Otherwise, look at other types of assignment.
+                        let assigned_from = match rvalue {
+                            Rvalue::Ref(_, _, assigned_from) => assigned_from,
+                            Rvalue::Use(operand) => match operand {
+                                Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                                    assigned_from
+                                }
+                                _ => continue,
+                            },
                             _ => continue,
-                        },
-                        _ => continue,
-                    };
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: \
-                         assigned_from={:?}",
-                        assigned_from,
-                    );
+                        };
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: \
+                             assigned_from={:?}",
+                            assigned_from,
+                        );
 
-                    // Find the local from the rvalue.
-                    let assigned_from_local = match assigned_from.local_or_deref_local() {
-                        Some(local) => local,
-                        None => continue,
-                    };
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: \
-                         assigned_from_local={:?}",
-                        assigned_from_local,
-                    );
+                        // Find the local from the rvalue.
+                        let assigned_from_local = match assigned_from.local_or_deref_local() {
+                            Some(local) => local,
+                            None => continue,
+                        };
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: \
+                             assigned_from_local={:?}",
+                            assigned_from_local,
+                        );
 
-                    // Check if our local matches the target - if so, we've assigned our
-                    // borrow to a new place.
-                    if assigned_from_local != target {
-                        continue;
-                    }
+                        // Check if our local matches the target - if so, we've assigned our
+                        // borrow to a new place.
+                        if assigned_from_local != target {
+                            continue;
+                        }
 
-                    // If we assigned our `target` into a new place, then we should
-                    // check if it was the return place.
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: \
-                         assigned_from_local={:?} assigned_to={:?}",
-                        assigned_from_local, assigned_to
-                    );
-                    if *assigned_to == mir::RETURN_PLACE {
-                        // If it was then return the annotated closure if there was one,
-                        // else, annotate this function.
-                        return annotated_closure.or_else(fallback);
-                    }
+                        // If we assigned our `target` into a new place, then we should
+                        // check if it was the return place.
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: \
+                             assigned_from_local={:?} assigned_to={:?}",
+                            assigned_from_local, assigned_to
+                        );
+                        if assigned_to == mir::RETURN_PLACE {
+                            // If it was then return the annotated closure if there was one,
+                            // else, annotate this function.
+                            return annotated_closure.or_else(fallback);
+                        }
 
-                    // If we didn't assign into the return place, then we just update
-                    // the target.
-                    target = *assigned_to;
+                        // If we didn't assign into the return place, then we just update
+                        // the target.
+                        target = assigned_to;
+                    }
                 }
             }
 
@@ -1790,38 +1774,37 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 target, terminator
             );
             if let TerminatorKind::Call {
-                destination: Some((Place {
-                    base: PlaceBase::Local(assigned_to),
-                    projection: box [],
-                }, _)),
+                destination: Some((place, _)),
                 args,
                 ..
             } = &terminator.kind
             {
-                debug!(
-                    "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
-                    assigned_to, args
-                );
-                for operand in args {
-                    let assigned_from = match operand {
-                        Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                            assigned_from
-                        }
-                        _ => continue,
-                    };
+                if let Some(assigned_to) = place.as_local() {
                     debug!(
-                        "annotate_argument_and_return_for_borrow: assigned_from={:?}",
-                        assigned_from,
+                        "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
+                        assigned_to, args
                     );
-
-                    if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
+                    for operand in args {
+                        let assigned_from = match operand {
+                            Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                                assigned_from
+                            }
+                            _ => continue,
+                        };
                         debug!(
-                            "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
-                            assigned_from_local,
+                            "annotate_argument_and_return_for_borrow: assigned_from={:?}",
+                            assigned_from,
                         );
 
-                        if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
-                            return annotated_closure.or_else(fallback);
+                        if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
+                            debug!(
+                                "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
+                                assigned_from_local,
+                            );
+
+                            if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
+                                return annotated_closure.or_else(fallback);
+                            }
                         }
                     }
                 }
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 5e0727d5157..4036e9db33b 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -838,12 +838,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             .get(location.statement_index)
         {
             Some(&Statement {
-                kind: StatementKind::Assign(box(Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [],
-                }, _)),
+                kind: StatementKind::Assign(box(ref place, _)),
                 ..
-            }) => local,
+            }) => {
+                if let Some(local) = place.as_local() {
+                    local
+                } else {
+                    return OtherUse(use_span);
+                }
+            }
             _ => return OtherUse(use_span),
         };
 
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 75d4b56fdb7..c3369e87215 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1133,15 +1133,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // Special case: you can assign a immutable local variable
         // (e.g., `x = ...`) so long as it has never been initialized
         // before (at this point in the flow).
-        if let Place {
-            base: PlaceBase::Local(local),
-            projection: box [],
-        } = place_span.0 {
-            if let Mutability::Not = self.body.local_decls[*local].mutability {
+        if let Some(local) = place_span.0.as_local() {
+            if let Mutability::Not = self.body.local_decls[local].mutability {
                 // check for reassignments to immutable local variables
                 self.check_if_reassignment_to_immutable_state(
                     location,
-                    *local,
+                    local,
                     place_span,
                     flow_state,
                 );
@@ -1288,60 +1285,58 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // captures of a closure are copied/moved directly
         // when generating MIR.
         match *operand {
-            Operand::Move(Place {
-                base: PlaceBase::Local(local),
-                projection: box [],
-            }) |
-            Operand::Copy(Place {
-                base: PlaceBase::Local(local),
-                projection: box [],
-            }) if self.body.local_decls[local].is_user_variable.is_none() => {
-                if self.body.local_decls[local].ty.is_mutable_ptr() {
-                    // The variable will be marked as mutable by the borrow.
-                    return;
-                }
-                // This is an edge case where we have a `move` closure
-                // inside a non-move closure, and the inner closure
-                // contains a mutation:
-                //
-                // let mut i = 0;
-                // || { move || { i += 1; }; };
-                //
-                // In this case our usual strategy of assuming that the
-                // variable will be captured by mutable reference is
-                // wrong, since `i` can be copied into the inner
-                // closure from a shared reference.
-                //
-                // As such we have to search for the local that this
-                // capture comes from and mark it as being used as mut.
-
-                let temp_mpi = self.move_data.rev_lookup.find_local(local);
-                let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
-                    &self.move_data.inits[init_index]
-                } else {
-                    bug!("temporary should be initialized exactly once")
-                };
-
-                let loc = match init.location {
-                    InitLocation::Statement(stmt) => stmt,
-                    _ => bug!("temporary initialized in arguments"),
-                };
-
-                let bbd = &self.body[loc.block];
-                let stmt = &bbd.statements[loc.statement_index];
-                debug!("temporary assigned in: stmt={:?}", stmt);
-
-                if let StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref source))) = stmt.kind {
-                    propagate_closure_used_mut_place(self, source);
-                } else {
-                    bug!("closures should only capture user variables \
-                        or references to user variables");
+            Operand::Move(ref place) | Operand::Copy(ref place) => {
+                match place.as_local() {
+                    Some(local) if self.body.local_decls[local].is_user_variable.is_none() => {
+                        if self.body.local_decls[local].ty.is_mutable_ptr() {
+                            // The variable will be marked as mutable by the borrow.
+                            return;
+                        }
+                        // This is an edge case where we have a `move` closure
+                        // inside a non-move closure, and the inner closure
+                        // contains a mutation:
+                        //
+                        // let mut i = 0;
+                        // || { move || { i += 1; }; };
+                        //
+                        // In this case our usual strategy of assuming that the
+                        // variable will be captured by mutable reference is
+                        // wrong, since `i` can be copied into the inner
+                        // closure from a shared reference.
+                        //
+                        // As such we have to search for the local that this
+                        // capture comes from and mark it as being used as mut.
+
+                        let temp_mpi = self.move_data.rev_lookup.find_local(local);
+                        let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
+                            &self.move_data.inits[init_index]
+                        } else {
+                            bug!("temporary should be initialized exactly once")
+                        };
+
+                        let loc = match init.location {
+                            InitLocation::Statement(stmt) => stmt,
+                            _ => bug!("temporary initialized in arguments"),
+                        };
+
+                        let bbd = &self.body[loc.block];
+                        let stmt = &bbd.statements[loc.statement_index];
+                        debug!("temporary assigned in: stmt={:?}", stmt);
+
+                        if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref source))) =
+                            stmt.kind
+                        {
+                            propagate_closure_used_mut_place(self, source);
+                        } else {
+                            bug!(
+                                "closures should only capture user variables \
+                                 or references to user variables"
+                            );
+                        }
+                    }
+                    _ => propagate_closure_used_mut_place(self, place),
                 }
             }
-            Operand::Move(ref place)
-            | Operand::Copy(ref place) => {
-                propagate_closure_used_mut_place(self, place);
-            }
             Operand::Constant(..) => {}
         }
     }
@@ -1702,7 +1697,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         debug!("check_if_assigned_path_is_moved place: {:?}", place);
 
         // None case => assigning to `x` does not require `x` be initialized.
-        let mut cursor = &*place.projection;
+        let mut cursor = &*place.projection.as_ref();
         while let [proj_base @ .., elem] = cursor {
             cursor = proj_base;
 
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs
index 431361fa5a8..d9e958d9450 100644
--- a/src/librustc_mir/borrow_check/move_errors.rs
+++ b/src/librustc_mir/borrow_check/move_errors.rs
@@ -89,45 +89,41 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 // If that ever stops being the case, then the ever initialized
                 // flow could be used.
                 if let Some(StatementKind::Assign(
-                    box(
-                        Place {
-                            base: PlaceBase::Local(local),
-                            projection: box [],
-                        },
-                        Rvalue::Use(Operand::Move(move_from))
-                    )
+                    box(place, Rvalue::Use(Operand::Move(move_from)))
                 )) = self.body.basic_blocks()[location.block]
                     .statements
                     .get(location.statement_index)
                     .map(|stmt| &stmt.kind)
                 {
-                    let local_decl = &self.body.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)
-                    //       ^^^^                match_span is the span of *x.y
-                    //
-                    // opt_match_place is None for let [mut] x = ... statements,
-                    // whether or not the right-hand side is a place expression
-                    if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                        opt_match_place: Some((ref opt_match_place, match_span)),
-                        binding_mode: _,
-                        opt_ty_info: _,
-                        pat_span: _,
-                    }))) = local_decl.is_user_variable
-                    {
-                        let stmt_source_info = self.body.source_info(location);
-                        self.append_binding_error(
-                            grouped_errors,
-                            kind,
-                            original_path,
-                            move_from,
-                            *local,
-                            opt_match_place,
-                            match_span,
-                            stmt_source_info.span,
-                        );
-                        return;
+                    if let Some(local) = place.as_local() {
+                        let local_decl = &self.body.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)
+                        //       ^^^^                match_span is the span of *x.y
+                        //
+                        // opt_match_place is None for let [mut] x = ... statements,
+                        // whether or not the right-hand side is a place expression
+                        if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                            opt_match_place: Some((ref opt_match_place, match_span)),
+                            binding_mode: _,
+                            opt_ty_info: _,
+                            pat_span: _,
+                        }))) = local_decl.is_user_variable
+                        {
+                            let stmt_source_info = self.body.source_info(location);
+                            self.append_binding_error(
+                                grouped_errors,
+                                kind,
+                                original_path,
+                                move_from,
+                                local,
+                                opt_match_place,
+                                match_span,
+                                stmt_source_info.span,
+                            );
+                            return;
+                        }
                     }
                 }
 
@@ -307,11 +303,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let upvar_field = self.prefixes(move_place.as_ref(), PrefixSet::All)
             .find_map(|p| self.is_upvar_field_projection(p));
 
-        let deref_base = match &deref_target_place.projection {
-            box [proj_base @ .., ProjectionElem::Deref] => {
+        let deref_base = match deref_target_place.projection.as_ref() {
+            &[ref proj_base @ .., ProjectionElem::Deref] => {
                 PlaceRef {
                     base: &deref_target_place.base,
-                    projection: proj_base,
+                    projection: &proj_base,
                 }
             }
             _ => bug!("deref_target_place is not a deref projection"),
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs
index 8ab4020394f..68b33331a1f 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/mutability_errors.rs
@@ -49,10 +49,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 projection: [],
             } => {
                 item_msg = format!("`{}`", access_place_desc.unwrap());
-                if let Place {
-                    base: PlaceBase::Local(_),
-                    projection: box [],
-                } = access_place {
+                if access_place.as_local().is_some() {
                     reason = ", as it is not declared as mutable".to_string();
                 } else {
                     let name = self.body.local_decls[*local]
@@ -153,10 +150,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     }),
                 projection: [],
             } => {
-                if let Place {
-                    base: PlaceBase::Static(_),
-                    projection: box [],
-                } = access_place {
+                if let PlaceRef {
+                    base: &PlaceBase::Static(_),
+                    projection: &[],
+                } = access_place.as_ref() {
                     item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
                     reason = String::new();
                 } else {
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index b105664399a..cae303039a1 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -8,8 +8,8 @@ use rustc::infer::InferCtxt;
 use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
 use rustc::mir::{
-    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, ProjectionElem, Rvalue,
-    SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
+    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, PlaceRef, ProjectionElem,
+    Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
 };
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, RegionVid, Ty};
@@ -211,14 +211,14 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
             // - if it's a deeper projection, we have to filter which
             //   of the borrows are killed: the ones whose `borrowed_place`
             //   conflicts with the `place`.
-            match place {
-                Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [],
+            match place.as_ref() {
+                PlaceRef {
+                    base: &PlaceBase::Local(local),
+                    projection: &[],
                 } |
-                Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [ProjectionElem::Deref],
+                PlaceRef {
+                    base: &PlaceBase::Local(local),
+                    projection: &[ProjectionElem::Deref],
                 } => {
                     debug!(
                         "Recording `killed` facts for borrows of local={:?} at location={:?}",
@@ -229,21 +229,21 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
                         all_facts,
                         self.borrow_set,
                         self.location_table,
-                        local,
+                        &local,
                         location,
                     );
                 }
 
-                Place {
-                    base: PlaceBase::Static(_),
+                PlaceRef {
+                    base: &PlaceBase::Static(_),
                     ..
                 } => {
                     // Ignore kills of static or static mut variables.
                 }
 
-                Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [.., _],
+                PlaceRef {
+                    base: &PlaceBase::Local(local),
+                    projection: &[.., _],
                 } => {
                     // Kill conflicting borrows of the innermost local.
                     debug!(
@@ -252,7 +252,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
                         local, location
                     );
 
-                    if let Some(borrow_indices) = self.borrow_set.local_map.get(local) {
+                    if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
                         for &borrow_index in borrow_indices {
                             let places_conflict = places_conflict::places_conflict(
                                 self.infcx.tcx,
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 59b2796db7a..26bead3047d 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -6,8 +6,8 @@ use crate::borrow_check::nll::region_infer::{Cause, RegionName};
 use crate::borrow_check::nll::ConstraintDescription;
 use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
 use rustc::mir::{
-    CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, PlaceBase,
-    Rvalue, Statement, StatementKind, TerminatorKind,
+    CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue,
+    Statement, StatementKind, TerminatorKind,
 };
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::adjustment::{PointerCast};
@@ -273,12 +273,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let mut should_note_order = false;
                 if body.local_decls[local].name.is_some() {
                     if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place {
-                        if let Place {
-                            base: PlaceBase::Local(borrowed_local),
-                            projection: box [],
-                        } = place {
-                             if body.local_decls[*borrowed_local].name.is_some()
-                                && local != *borrowed_local
+                        if let Some(borrowed_local) = place.as_local() {
+                             if body.local_decls[borrowed_local].name.is_some()
+                                && local != borrowed_local
                             {
                                 should_note_order = true;
                             }
@@ -494,22 +491,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         // Just point to the function, to reduce the chance of overlapping spans.
                         let function_span = match func {
                             Operand::Constant(c) => c.span,
-                            Operand::Copy(Place {
-                                base: PlaceBase::Local(l),
-                                projection: box [],
-                            }) |
-                            Operand::Move(Place {
-                                base: PlaceBase::Local(l),
-                                projection: box [],
-                            }) => {
-                                let local_decl = &self.body.local_decls[*l];
-                                if local_decl.name.is_none() {
-                                    local_decl.source_info.span
+                            Operand::Copy(place) |
+                            Operand::Move(place) => {
+                                if let Some(l) = place.as_local() {
+                                    let local_decl = &self.body.local_decls[l];
+                                    if local_decl.name.is_none() {
+                                        local_decl.source_info.span
+                                    } else {
+                                        span
+                                    }
                                 } else {
                                     span
                                 }
                             }
-                            _ => span,
                         };
                         return (LaterUseKind::Call, function_span);
                     } else {
@@ -542,14 +536,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // it which simplifies the termination logic.
         let mut queue = vec![location];
         let mut target = if let Some(&Statement {
-            kind: StatementKind::Assign(box(Place {
-                base: PlaceBase::Local(local),
-                projection: box [],
-            }, _)),
+            kind: StatementKind::Assign(box(ref place, _)),
             ..
-        }) = stmt
-        {
-            local
+        }) = stmt {
+            if let Some(local) = place.as_local() {
+                local
+            } else {
+                return false;
+            }
         } else {
             return false;
         };
@@ -582,17 +576,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         // If we see a use, we should check whether it is our data, and if so
                         // update the place that we're looking for to that new place.
                         Rvalue::Use(operand) => match operand {
-                            Operand::Copy(Place {
-                                base: PlaceBase::Local(from),
-                                projection: box [],
-                            })
-                            | Operand::Move(Place {
-                                base: PlaceBase::Local(from),
-                                projection: box [],
-                            })
-                                if *from == target =>
-                            {
-                                target = into;
+                            Operand::Copy(place)
+                            | Operand::Move(place) => {
+                                if let Some(from) = place.as_local() {
+                                    if from == target {
+                                        target = into;
+                                    }
+                                }
                             }
                             _ => {}
                         },
@@ -601,28 +591,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         Rvalue::Cast(
                             CastKind::Pointer(PointerCast::Unsize), operand, ty
                         ) => match operand {
-                            Operand::Copy(Place {
-                                base: PlaceBase::Local(from),
-                                projection: box [],
-                            })
-                            | Operand::Move(Place {
-                                base: PlaceBase::Local(from),
-                                projection: box [],
-                            })
-                                if *from == target =>
-                            {
-                                debug!("was_captured_by_trait_object: ty={:?}", ty);
-                                // Check the type for a trait object.
-                                return match ty.kind {
-                                    // `&dyn Trait`
-                                    ty::Ref(_, ty, _) if ty.is_trait() => true,
-                                    // `Box<dyn Trait>`
-                                    _ if ty.is_box() && ty.boxed_ty().is_trait() => true,
-                                    // `dyn Trait`
-                                    _ if ty.is_trait() => true,
-                                    // Anything else.
-                                    _ => false,
-                                };
+                            Operand::Copy(place)
+                            | Operand::Move(place) => {
+                                if let Some(from) = place.as_local() {
+                                    if from == target {
+                                        debug!("was_captured_by_trait_object: ty={:?}", ty);
+                                        // Check the type for a trait object.
+                                        return match ty.kind {
+                                            // `&dyn Trait`
+                                            ty::Ref(_, ty, _) if ty.is_trait() => true,
+                                            // `Box<dyn Trait>`
+                                            _ if ty.is_box() && ty.boxed_ty().is_trait() => true,
+                                            // `dyn Trait`
+                                            _ if ty.is_trait() => true,
+                                            // Anything else.
+                                            _ => false,
+                                        };
+                                    }
+                                }
+                                return false;
                             }
                             _ => return false,
                         },
@@ -638,34 +625,33 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 debug!("was_captured_by_trait_object: terminator={:?}", terminator);
 
                 if let TerminatorKind::Call {
-                    destination: Some((Place {
-                        base: PlaceBase::Local(dest),
-                        projection: box [],
-                    }, block)),
+                    destination: Some((place, block)),
                     args,
                     ..
-                } = &terminator.kind
-                {
-                    debug!(
-                        "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
-                        target, dest, args
-                    );
-                    // Check if one of the arguments to this function is the target place.
-                    let found_target = args.iter().any(|arg| {
-                        if let Operand::Move(Place {
-                            base: PlaceBase::Local(potential),
-                            projection: box [],
-                        }) = arg {
-                            *potential == target
-                        } else {
-                            false
-                        }
-                    });
+                } = &terminator.kind {
+                    if let Some(dest) = place.as_local() {
+                        debug!(
+                            "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
+                            target, dest, args
+                        );
+                        // Check if one of the arguments to this function is the target place.
+                        let found_target = args.iter().any(|arg| {
+                            if let Operand::Move(place) = arg {
+                                if let Some(potential) = place.as_local() {
+                                    potential == target
+                                } else {
+                                    false
+                                }
+                            } else {
+                                false
+                            }
+                        });
 
-                    // If it is, follow this to the next block and update the target.
-                    if found_target {
-                        target = *dest;
-                        queue.push(block.start_location());
+                        // If it is, follow this to the next block and update the target.
+                        if found_target {
+                            target = dest;
+                            queue.push(block.start_location());
+                        }
                     }
                 }
             }
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index 9ecd6f83775..d949c7e01aa 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -1,5 +1,5 @@
 use rustc::ty::subst::SubstsRef;
-use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::mir::{Body, Location, PlaceElem, Promoted};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
@@ -54,6 +54,10 @@ impl<'a, 'tcx> NLLVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
         debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);
 
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 ed639e8eee7..b5560fe6751 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -480,13 +480,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
 
         if place.projection.is_empty() {
             if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
-                let is_promoted = match place {
-                    Place {
-                        base: PlaceBase::Static(box Static {
+                let is_promoted = match place.as_ref() {
+                    PlaceRef {
+                        base: &PlaceBase::Static(box Static {
                             kind: StaticKind::Promoted(..),
                             ..
                         }),
-                        projection: box [],
+                        projection: &[],
                     } => true,
                     _ => false,
                 };
@@ -1366,11 +1366,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // they are not caused by the user, but rather artifacts
                 // of lowering. Assignments to other sorts of places *are* interesting
                 // though.
-                let category = match *place {
-                    Place {
-                        base: PlaceBase::Local(RETURN_PLACE),
-                        projection: box [],
-                    } => if let BorrowCheckContext {
+                let category = match place.as_local() {
+                    Some(RETURN_PLACE) => if let BorrowCheckContext {
                         universal_regions:
                             UniversalRegions {
                                 defining_ty: DefiningTy::Const(def_id, _),
@@ -1386,10 +1383,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     } else {
                         ConstraintCategory::Return
                     },
-                    Place {
-                        base: PlaceBase::Local(l),
-                        projection: box [],
-                    } if !body.local_decls[l].is_user_variable.is_some() => {
+                    Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
                         ConstraintCategory::Boring
                     }
                     _ => ConstraintCategory::Assignment,
@@ -1675,11 +1669,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             Some((ref dest, _target_block)) => {
                 let dest_ty = dest.ty(body, tcx).ty;
                 let dest_ty = self.normalize(dest_ty, term_location);
-                let category = match *dest {
-                    Place {
-                        base: PlaceBase::Local(RETURN_PLACE),
-                        projection: box [],
-                    } => {
+                let category = match dest.as_local() {
+                    Some(RETURN_PLACE) => {
                         if let BorrowCheckContext {
                             universal_regions:
                                 UniversalRegions {
@@ -1698,10 +1689,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             ConstraintCategory::Return
                         }
                     }
-                    Place {
-                        base: PlaceBase::Local(l),
-                        projection: box [],
-                    } if !body.local_decls[l].is_user_variable.is_some() => {
+                    Some(l) if !body.local_decls[l].is_user_variable.is_some() => {
                         ConstraintCategory::Boring
                     }
                     _ => ConstraintCategory::Assignment,
@@ -2432,7 +2420,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             location, borrow_region, borrowed_place
         );
 
-        let mut cursor = &*borrowed_place.projection;
+        let mut cursor = borrowed_place.projection.as_ref();
         while let [proj_base @ .., elem] = cursor {
             cursor = proj_base;
 
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index 9dd3e119c21..264e4807af0 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -64,14 +64,8 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
 
     // This Local/Local case is handled by the more general code below, but
     // it's so common that it's a speed win to check for it first.
-    if let Place {
-        base: PlaceBase::Local(l1),
-        projection: box [],
-    } = borrow_place {
-        if let PlaceRef {
-            base: PlaceBase::Local(l2),
-            projection: [],
-        } = access_place {
+    if let Some(l1) = borrow_place.as_local() {
+        if let Some(l2) = access_place.as_local() {
             return l1 == l2;
         }
     }
diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs
index 695080dfe23..95471afb788 100644
--- a/src/librustc_mir/borrow_check/used_muts.rs
+++ b/src/librustc_mir/borrow_check/used_muts.rs
@@ -1,7 +1,5 @@
 use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::mir::{
-    Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind
-};
+use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind};
 
 use rustc_data_structures::fx::FxHashSet;
 
@@ -118,10 +116,7 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
                     "assignment of {:?} to {:?}, adding {:?} to used mutable set",
                     path.place, local, path.place
                 );
-                if let Place {
-                    base: PlaceBase::Local(user_local),
-                    projection: box [],
-                } = path.place {
+                if let Some(user_local) = path.place.as_local() {
                     self.mbcx.used_mut.insert(user_local);
                 }
             }
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 60fe37e26e9..8d2bef39bed 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -6,7 +6,7 @@ use crate::build::{BlockAnd, BlockAndExtension, Builder};
 use crate::hair::*;
 use rustc::mir::interpret::{PanicInfo::BoundsCheck};
 use rustc::mir::*;
-use rustc::ty::{CanonicalUserTypeAnnotation, Ty, Variance};
+use rustc::ty::{CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
 
 use rustc_index::vec::Idx;
 
@@ -23,10 +23,10 @@ struct PlaceBuilder<'tcx> {
 }
 
 impl PlaceBuilder<'tcx> {
-    fn into_place(self) -> Place<'tcx> {
+    fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
         Place {
             base: self.base,
-            projection: self.projection.into_boxed_slice(),
+            projection: tcx.intern_place_elems(&self.projection),
         }
     }
 
@@ -73,7 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let place_builder = unpack!(block = self.as_place_builder(block, expr));
-        block.and(place_builder.into_place())
+        block.and(place_builder.into_place(self.hir.tcx()))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -96,7 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         M: Mirror<'tcx, Output = Expr<'tcx>>,
     {
         let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
-        block.and(place_builder.into_place())
+        block.and(place_builder.into_place(self.hir.tcx()))
     }
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -165,7 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     Mutability::Not,
                 ));
 
-                let slice = place_builder.clone().into_place();
+                let slice = place_builder.clone().into_place(this.hir.tcx());
                 // bounds check:
                 let (len, lt) = (
                     this.temp(usize_ty.clone(), expr_span),
@@ -225,7 +225,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         }
                     );
 
-                    let place = place_builder.clone().into_place();
+                    let place = place_builder.clone().into_place(this.hir.tcx());
                     this.cfg.push(
                         block,
                         Statement {
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 87d95a75153..4f1ac8e51dc 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -139,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // initialize the box contents:
                 unpack!(
                     block = this.into(
-                        &Place::from(result).deref(),
+                        &this.hir.tcx().mk_place_deref(Place::from(result)),
                         block, value
                     )
                 );
@@ -296,8 +296,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         .zip(field_types.into_iter())
                         .map(|(n, ty)| match fields_map.get(&n) {
                             Some(v) => v.clone(),
-                            None => this.consume_by_copy_or_move(base.clone().field(n, ty)),
-                        }).collect()
+                            None => this.consume_by_copy_or_move(this.hir.tcx().mk_place_field(
+                                base.clone(),
+                                n,
+                                ty,
+                            )),
+                        })
+                        .collect()
                 } else {
                     field_names
                         .iter()
@@ -397,8 +402,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let val_fld = Field::new(0);
             let of_fld = Field::new(1);
 
-            let val = result_value.clone().field(val_fld, ty);
-            let of = result_value.field(of_fld, bool_ty);
+            let tcx = self.hir.tcx();
+            let val = tcx.mk_place_field(result_value.clone(), val_fld, ty);
+            let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
 
             let err = PanicInfo::Overflow(op);
 
@@ -496,14 +502,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let arg_place = unpack!(block = this.as_place(block, arg));
 
-        let mutability = match arg_place {
-            Place {
-                base: PlaceBase::Local(local),
-                projection: box [],
+        let mutability = match arg_place.as_ref() {
+            PlaceRef {
+                base: &PlaceBase::Local(local),
+                projection: &[],
             } => this.local_decls[local].mutability,
-            Place {
-                base: PlaceBase::Local(local),
-                projection: box [ProjectionElem::Deref],
+            PlaceRef {
+                base: &PlaceBase::Local(local),
+                projection: &[ProjectionElem::Deref],
             } => {
                 debug_assert!(
                     this.local_decls[local].is_ref_for_guard(),
@@ -511,13 +517,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 );
                 this.local_decls[local].mutability
             }
-            Place {
+            PlaceRef {
                 ref base,
-                projection: box [ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
+                projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             }
-            | Place {
+            | PlaceRef {
                 ref base,
-                projection: box [
+                projection: &[
                     ref proj_base @ ..,
                     ProjectionElem::Field(upvar_index, _),
                     ProjectionElem::Deref
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 8a6bc5a2a76..e7388b92054 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -235,7 +235,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     });
                     let ptr_temp = Place::from(ptr_temp);
                     let block = unpack!(this.into(&ptr_temp, block, ptr));
-                    this.into(&ptr_temp.deref(), block, val)
+                    this.into(&this.hir.tcx().mk_place_deref(ptr_temp), block, val)
                 } else {
                     let args: Vec<_> = args
                         .into_iter()
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 2e451fc88d9..667b37bbd80 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -948,7 +948,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     fake_borrows.insert(Place {
                         base: source.base.clone(),
-                        projection: proj_base.to_vec().into_boxed_slice(),
+                        projection: self.hir.tcx().intern_place_elems(proj_base),
                     });
                 }
             }
@@ -1293,7 +1293,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // Insert a Shallow borrow of the prefixes of any fake borrows.
         for place in fake_borrows
         {
-            let mut cursor = &*place.projection;
+            let mut cursor = place.projection.as_ref();
             while let [proj_base @ .., elem] = cursor {
                 cursor = proj_base;
 
@@ -1488,7 +1488,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     BorrowKind::Shallow,
                     Place {
                         base: place.base.clone(),
-                        projection: place.projection.to_vec().into_boxed_slice(),
+                        projection: tcx.intern_place_elems(place.projection),
                     },
                 );
                 self.cfg.push_assign(
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index 3826e5e3ba5..9b7bccca2dd 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -166,7 +166,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     }
                 });
                 if irrefutable {
-                    let place = match_pair.place.downcast(adt_def, variant_index);
+                    let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index);
                     candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
                     Ok(())
                 } else {
@@ -191,7 +191,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             PatKind::Deref { ref subpattern } => {
-                let place = match_pair.place.deref();
+                let place = tcx.mk_place_deref(match_pair.place);
                 candidate.match_pairs.push(MatchPair::new(place, subpattern));
                 Ok(())
             }
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index a04c989e6e0..5c2f72c0a06 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -743,22 +743,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         candidate: &mut Candidate<'pat, 'tcx>,
     ) {
         let match_pair = candidate.match_pairs.remove(match_pair_index);
+        let tcx = self.hir.tcx();
 
         // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
         // we want to create a set of derived match-patterns like
         // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
         let elem = ProjectionElem::Downcast(
             Some(adt_def.variants[variant_index].ident.name), variant_index);
-        let downcast_place = match_pair.place.elem(elem); // `(x as Variant)`
-        let consequent_match_pairs =
-            subpatterns.iter()
-                       .map(|subpattern| {
-                           // e.g., `(x as Variant).0`
-                           let place = downcast_place.clone().field(subpattern.field,
-                                                                      subpattern.pattern.ty);
-                           // e.g., `(x as Variant).0 @ P1`
-                           MatchPair::new(place, &subpattern.pattern)
-                       });
+        let downcast_place = tcx.mk_place_elem(match_pair.place, elem); // `(x as Variant)`
+        let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
+            // e.g., `(x as Variant).0`
+            let place =
+                tcx.mk_place_field(downcast_place.clone(), subpattern.field, subpattern.pattern.ty);
+            // e.g., `(x as Variant).0 @ P1`
+            MatchPair::new(place, &subpattern.pattern)
+        });
 
         candidate.match_pairs.extend(consequent_match_pairs);
     }
diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs
index 83fb924af63..917535f31dc 100644
--- a/src/librustc_mir/build/matches/util.rs
+++ b/src/librustc_mir/build/matches/util.rs
@@ -6,17 +6,22 @@ use std::u32;
 use std::convert::TryInto;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    pub fn field_match_pairs<'pat>(&mut self,
-                                   place: Place<'tcx>,
-                                   subpatterns: &'pat [FieldPat<'tcx>])
-                                   -> Vec<MatchPair<'pat, 'tcx>> {
-        subpatterns.iter()
-                   .map(|fieldpat| {
-                       let place = place.clone().field(fieldpat.field,
-                                                       fieldpat.pattern.ty);
-                       MatchPair::new(place, &fieldpat.pattern)
-                   })
-                   .collect()
+    pub fn field_match_pairs<'pat>(
+        &mut self,
+        place: Place<'tcx>,
+        subpatterns: &'pat [FieldPat<'tcx>],
+    ) -> Vec<MatchPair<'pat, 'tcx>> {
+        subpatterns
+            .iter()
+            .map(|fieldpat| {
+                let place = self.hir.tcx().mk_place_field(
+                    place.clone(),
+                    fieldpat.field,
+                    fieldpat.pattern.ty,
+                );
+                MatchPair::new(place, &fieldpat.pattern)
+            })
+            .collect()
     }
 
     pub fn prefix_slice_suffix<'pat>(&mut self,
@@ -27,6 +32,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                      suffix: &'pat [Pat<'tcx>]) {
         let min_length = prefix.len() + suffix.len();
         let min_length = min_length.try_into().unwrap();
+        let tcx = self.hir.tcx();
 
         match_pairs.extend(
             prefix.iter()
@@ -37,13 +43,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                           min_length,
                           from_end: false,
                       };
-                      let place = place.clone().elem(elem);
+                      let place = tcx.mk_place_elem(place.clone(), elem);
                       MatchPair::new(place, subpattern)
                   })
         );
 
         if let Some(subslice_pat) = opt_slice {
-            let subslice = place.clone().elem(ProjectionElem::Subslice {
+            let subslice = tcx.mk_place_elem(place.clone(),ProjectionElem::Subslice {
                 from: prefix.len() as u32,
                 to: suffix.len() as u32
             });
@@ -60,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                           min_length,
                           from_end: true,
                       };
-                      let place = place.clone().elem(elem);
+                      let place = tcx.mk_place_elem(place.clone(), elem);
                       MatchPair::new(place, subpattern)
                   })
         );
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index a749b4263ea..1b3d8641f20 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -926,46 +926,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // If constants and statics, we don't generate StorageLive for this
             // temporary, so don't try to generate StorageDead for it either.
             _ if self.local_scope().is_none() => (),
-            Operand::Copy(Place {
-                base: PlaceBase::Local(cond_temp),
-                projection: box [],
-            })
-            | Operand::Move(Place {
-                base: PlaceBase::Local(cond_temp),
-                projection: box [],
-            }) => {
-                // Manually drop the condition on both branches.
-                let top_scope = self.scopes.scopes.last_mut().unwrap();
-                let top_drop_data = top_scope.drops.pop().unwrap();
-
-                match top_drop_data.kind {
-                    DropKind::Value { .. } => {
-                        bug!("Drop scheduled on top of condition variable")
-                    }
-                    DropKind::Storage => {
-                        let source_info = top_scope.source_info(top_drop_data.span);
-                        let local = top_drop_data.local;
-                        assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
-                        self.cfg.push(
-                            true_block,
-                            Statement {
-                                source_info,
-                                kind: StatementKind::StorageDead(local)
-                            },
-                        );
-                        self.cfg.push(
-                            false_block,
-                            Statement {
-                                source_info,
-                                kind: StatementKind::StorageDead(local)
-                            },
-                        );
+            Operand::Copy(place)
+            | Operand::Move(place) => {
+                if let Some(cond_temp) = place.as_local() {
+                    // Manually drop the condition on both branches.
+                    let top_scope = self.scopes.scopes.last_mut().unwrap();
+                    let top_drop_data = top_scope.drops.pop().unwrap();
+
+                    match top_drop_data.kind {
+                        DropKind::Value { .. } => {
+                            bug!("Drop scheduled on top of condition variable")
+                        }
+                        DropKind::Storage => {
+                            let source_info = top_scope.source_info(top_drop_data.span);
+                            let local = top_drop_data.local;
+                            assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
+                            self.cfg.push(
+                                true_block,
+                                Statement {
+                                    source_info,
+                                    kind: StatementKind::StorageDead(local)
+                                },
+                            );
+                            self.cfg.push(
+                                false_block,
+                                Statement {
+                                    source_info,
+                                    kind: StatementKind::StorageDead(local)
+                                },
+                            );
+                        }
                     }
-                }
 
-                top_scope.invalidate_cache(true, self.is_generator, true);
+                    top_scope.invalidate_cache(true, self.is_generator, true);
+                } else {
+                    bug!("Expected as_local_operand to produce a temporary");
+                }
             }
-            _ => bug!("Expected as_local_operand to produce a temporary"),
         }
 
         (true_block, false_block)
diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs
index c1695ba66d0..1b81032bfe6 100644
--- a/src/librustc_mir/dataflow/impls/storage_liveness.rs
+++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs
@@ -157,10 +157,12 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
         // Since `propagate_call_unwind` doesn't exist, we have to kill the
         // destination here, and then gen it again in `propagate_call_return`.
         if let TerminatorKind::Call {
-            destination: Some((Place { base: PlaceBase::Local(local), projection: box [] }, _)),
+            destination: Some((ref place, _)),
             ..
         } = self.body[loc.block].terminator().kind {
-            sets.kill(local);
+            if let Some(local) = place.as_local() {
+                sets.kill(local);
+            }
         }
         self.check_for_move(sets, loc);
     }
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 53b18e4364b..52016d4c936 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -114,7 +114,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                         BorrowedContent {
                             target_place: Place {
                                 base: place.base.clone(),
-                                projection: proj.to_vec().into_boxed_slice(),
+                                projection: tcx.intern_place_elems(proj),
                             },
                         },
                     ));
@@ -172,7 +172,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                             Some(base),
                             Place {
                                 base: place.base.clone(),
-                                projection: proj.to_vec().into_boxed_slice(),
+                                projection: tcx.intern_place_elems(proj),
                             },
                         );
                         ent.insert(path);
@@ -274,7 +274,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                     // Box starts out uninitialized - need to create a separate
                     // move-path for the interior so it will be separate from
                     // the exterior.
-                    self.create_move_path(&place.clone().deref());
+                    self.create_move_path(&self.builder.tcx.mk_place_deref(place.clone()));
                     self.gather_init(place.as_ref(), InitKind::Shallow);
                 } else {
                     self.gather_init(place.as_ref(), InitKind::Deep);
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index f5a03316d80..b599f479944 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -327,7 +327,7 @@ impl<'tcx> MoveData<'tcx> {
     pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
         loop {
             let path = &self.move_paths[mpi];
-            if let Place { base: PlaceBase::Local(l), projection: box [] } = path.place {
+            if let Some(l) = path.place.as_local() {
                 return Some(l);
             }
             if let Some(parent) = path.parent {
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index f532a18072f..177639956f7 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -117,7 +117,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
 
     run_passes(tcx, &mut result, instance, None, MirPhase::Const, &[
         &add_moves_for_packed_drops::AddMovesForPackedDrops,
-        &no_landing_pads::NoLandingPads,
+        &no_landing_pads::NoLandingPads::new(tcx),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &simplify::SimplifyCfg::new("make_shim"),
         &add_call_guards::CriticalCallEdges,
@@ -231,7 +231,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
                 tcx,
                 param_env
             };
-            let dropee = dropee_ptr.deref();
+            let dropee = tcx.mk_place_deref(dropee_ptr);
             let resume_block = elaborator.patch.resume_block();
             elaborate_drops::elaborate_drop(
                 &mut elaborator,
@@ -312,7 +312,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
     let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
 
     let dest = Place::return_place();
-    let src = Place::from(Local::new(1+0)).deref();
+    let src = tcx.mk_place_deref(Place::from(Local::new(1+0)));
 
     match self_ty.kind {
         _ if is_copy => builder.copy_shim(),
@@ -415,7 +415,7 @@ impl CloneShimBuilder<'tcx> {
     }
 
     fn copy_shim(&mut self) {
-        let rcvr = Place::from(Local::new(1+0)).deref();
+        let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1+0)));
         let ret_statement = self.make_statement(
             StatementKind::Assign(
                 box(
@@ -561,8 +561,8 @@ impl CloneShimBuilder<'tcx> {
         // BB #2
         // `dest[i] = Clone::clone(src[beg])`;
         // Goto #3 if ok, #5 if unwinding happens.
-        let dest_field = dest.clone().index(beg);
-        let src_field = src.index(beg);
+        let dest_field = self.tcx.mk_place_index(dest.clone(), beg);
+        let src_field = self.tcx.mk_place_index(src, beg);
         self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3),
                              BasicBlock::new(5));
 
@@ -616,7 +616,7 @@ impl CloneShimBuilder<'tcx> {
         // BB #7 (cleanup)
         // `drop(dest[beg])`;
         self.block(vec![], TerminatorKind::Drop {
-            location: dest.index(beg),
+            location: self.tcx.mk_place_index(dest, beg),
             target: BasicBlock::new(8),
             unwind: None,
         }, true);
@@ -648,9 +648,9 @@ impl CloneShimBuilder<'tcx> {
         let mut previous_field = None;
         for (i, ity) in tys.enumerate() {
             let field = Field::new(i);
-            let src_field = src.clone().field(field, ity);
+            let src_field = self.tcx.mk_place_field(src.clone(), field, ity);
 
-            let dest_field = dest.clone().field(field, ity);
+            let dest_field = self.tcx.mk_place_field(dest.clone(), field, ity);
 
             // #(2i + 1) is the cleanup block for the previous clone operation
             let cleanup_block = self.block_index_offset(1);
@@ -721,14 +721,14 @@ fn build_call_shim<'tcx>(
 
     let rcvr = match rcvr_adjustment {
         Adjustment::Identity => Operand::Move(rcvr_l),
-        Adjustment::Deref => Operand::Copy(rcvr_l.deref()),
+        Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_l)),
         Adjustment::DerefMove => {
             // fn(Self, ...) -> fn(*mut Self, ...)
             let arg_ty = local_decls[rcvr_arg].ty;
             debug_assert!(tcx.generics_of(def_id).has_self && arg_ty == tcx.types.self_param);
             local_decls[rcvr_arg].ty = tcx.mk_mut_ptr(arg_ty);
 
-            Operand::Move(rcvr_l.deref())
+            Operand::Move(tcx.mk_place_deref(rcvr_l))
         }
         Adjustment::RefMut => {
             // let rcvr = &mut rcvr;
@@ -772,7 +772,7 @@ fn build_call_shim<'tcx>(
     if let Some(untuple_args) = untuple_args {
         args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
             let arg_place = Place::from(Local::new(1+1));
-            Operand::Move(arg_place.field(Field::new(i), *ity))
+            Operand::Move(tcx.mk_place_field(arg_place, Field::new(i), *ity))
         }));
     } else {
         args.extend((1..sig.inputs().len()).map(|i| {
@@ -901,6 +901,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> {
             )),
         AggregateKind::Adt(adt_def, variant_index, substs, None, None),
         source_info,
+        tcx,
     ).collect();
 
     let start_block = BasicBlockData {
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index 40007eb3c4a..c8605e22e10 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -164,8 +164,8 @@ pub trait Qualif {
 
             Rvalue::Ref(_, _, ref place) => {
                 // Special-case reborrows to be more like a copy of the reference.
-                if let box [proj_base @ .., elem] = &place.projection {
-                    if ProjectionElem::Deref == *elem {
+                if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
+                    if ProjectionElem::Deref == elem {
                         let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
                         if let ty::Ref(..) = base_ty.kind {
                             return Self::in_place(cx, per_local, PlaceRef {
diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs
index 4fa4eba4c23..fc9290d6380 100644
--- a/src/librustc_mir/transform/check_consts/resolver.rs
+++ b/src/librustc_mir/transform/check_consts/resolver.rs
@@ -56,16 +56,16 @@ where
     fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
         debug_assert!(!place.is_indirect());
 
-        match (value, place) {
-            (true, mir::Place { base: mir::PlaceBase::Local(local), .. }) => {
-                self.qualifs_per_local.insert(*local);
+        match (value, place.as_ref()) {
+            (true, mir::PlaceRef { base: &mir::PlaceBase::Local(local), .. }) => {
+                self.qualifs_per_local.insert(local);
             }
 
             // For now, we do not clear the qualif if a local is overwritten in full by
             // an unqualified rvalue (e.g. `y = 5`). This is to be consistent
             // with aggregates where we overwrite all fields with assignments, which would not
             // get this feature.
-            (false, mir::Place { base: mir::PlaceBase::Local(_local), projection: box [] }) => {
+            (false, mir::PlaceRef { base: &mir::PlaceBase::Local(_local), projection: &[] }) => {
                 // self.qualifs_per_local.remove(*local);
             }
 
@@ -101,11 +101,10 @@ where
 
         // If a local with no projections is moved from (e.g. `x` in `y = x`), record that
         // it no longer needs to be dropped.
-        if let mir::Operand::Move(mir::Place {
-            base: mir::PlaceBase::Local(local),
-            projection: box [],
-        }) = *operand {
-            self.qualifs_per_local.remove(local);
+        if let mir::Operand::Move(place) = operand {
+            if let Some(local) = place.as_local() {
+                self.qualifs_per_local.remove(local);
+            }
         }
     }
 
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 87cd39b02cd..76a73adf038 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -244,8 +244,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
         if let Rvalue::Ref(_, kind, ref place) = *rvalue {
             // Special-case reborrows to be more like a copy of a reference.
             let mut reborrow_place = None;
-            if let box [proj_base @ .., elem] = &place.projection {
-                if *elem == ProjectionElem::Deref {
+            if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
+                if elem == ProjectionElem::Deref {
                     let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind {
                         reborrow_place = Some(proj_base);
@@ -376,12 +376,15 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
             );
 
             if rvalue_has_mut_interior {
-                let is_derived_from_illegal_borrow = match *borrowed_place {
+                let is_derived_from_illegal_borrow = match borrowed_place.as_local() {
                     // If an unprojected local was borrowed and its value was the result of an
                     // illegal borrow, suppress this error and mark the result of this borrow as
                     // illegal as well.
-                    Place { base: PlaceBase::Local(borrowed_local), projection: box [] }
-                        if self.derived_from_illegal_borrow.contains(borrowed_local) => true,
+                    Some(borrowed_local)
+                        if self.derived_from_illegal_borrow.contains(borrowed_local) =>
+                    {
+                        true
+                    }
 
                     // Otherwise proceed normally: check the legality of a mutable borrow in this
                     // context.
@@ -394,7 +397,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                 // FIXME: should we also clear `derived_from_illegal_borrow` when a local is
                 // assigned a new value?
                 if is_derived_from_illegal_borrow {
-                    if let Place { base: PlaceBase::Local(dest), projection: box [] } = *dest {
+                    if let Some(dest) = dest.as_local() {
                         self.derived_from_illegal_borrow.insert(dest);
                     }
                 }
@@ -571,10 +574,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                     return;
                 }
 
-                let needs_drop = if let Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [],
-                } = *dropped_place {
+                let needs_drop = if let Some(local) = dropped_place.as_local() {
                     // Use the span where the local was declared as the span of the drop error.
                     err_span = self.body.local_decls[local].source_info.span;
                     self.qualifs.needs_drop.contains(local)
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 3ff36e01275..d9b983ab790 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -406,8 +406,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
         place: &Place<'tcx>,
         is_mut_use: bool,
     ) {
-        let mut cursor = &*place.projection;
-        while let [proj_base @ .., elem] = cursor {
+        let mut cursor = place.projection.as_ref();
+        while let &[ref proj_base @ .., elem] = cursor {
             cursor = proj_base;
 
             match elem {
diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs
index ea173279aa0..4fd4fe45cd4 100644
--- a/src/librustc_mir/transform/cleanup_post_borrowck.rs
+++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs
@@ -24,16 +24,22 @@ use crate::transform::{MirPass, MirSource};
 
 pub struct CleanupNonCodegenStatements;
 
-pub struct DeleteNonCodegenStatements;
+pub struct DeleteNonCodegenStatements<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
 
 impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        let mut delete = DeleteNonCodegenStatements;
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+        let mut delete = DeleteNonCodegenStatements { tcx };
         delete.visit_body(body);
     }
 }
 
-impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements {
+impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_statement(&mut self,
                        statement: &mut Statement<'tcx>,
                        location: Location) {
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 108c6c9786b..13097a21561 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -7,10 +7,9 @@ use std::cell::Cell;
 use rustc::hir::def::DefKind;
 use rustc::hir::def_id::DefId;
 use rustc::mir::{
-    AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue,
-    Local, UnOp, StatementKind, Statement, LocalKind,
-    TerminatorKind, Terminator,  ClearCrossCrate, SourceInfo, BinOp,
-    SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
+    AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, Local, UnOp,
+    StatementKind, Statement, LocalKind, TerminatorKind, Terminator,  ClearCrossCrate, SourceInfo,
+    BinOp, SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
 };
 use rustc::mir::visit::{
     Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
@@ -525,18 +524,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             // (e.g. for CTFE) it can never happen. But here in const_prop
             // unknown data is uninitialized, so if e.g. a function argument is unsized
             // and has a reference taken, we get an ICE.
-            Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => {
-                trace!("checking Ref({:?})", place);
-                let alive =
-                    if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value {
-                        true
-                    } else {
-                        false
-                    };
+            Rvalue::Ref(_, _, place_ref) => {
+                trace!("checking Ref({:?})", place_ref);
 
-                if !alive {
-                    trace!("skipping Ref({:?}) to uninitialized local", place);
-                    return None;
+                if let Some(local) = place_ref.as_local() {
+                    let alive =
+                        if let LocalValue::Live(_) = self.ecx.frame().locals[local].value {
+                            true
+                        } else {
+                            false
+                        };
+
+                    if !alive {
+                        trace!("skipping Ref({:?}) to uninitialized local", place);
+                        return None;
+                    }
                 }
             }
 
@@ -685,6 +687,10 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
 }
 
 impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_constant(
         &mut self,
         constant: &mut Constant<'tcx>,
@@ -706,10 +712,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                 .ty(&self.local_decls, self.tcx)
                 .ty;
             if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
-                if let Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [],
-                } = *place {
+                if let Some(local) = place.as_local() {
                     let source = statement.source_info;
                     if let Some(()) = self.const_prop(rval, place_layout, source, place) {
                         if self.can_const_prop[local] {
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index 28f97f41b50..4c26feac4af 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -19,9 +19,7 @@
 //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
 //! future.
 
-use rustc::mir::{
-    Constant, Local, LocalKind, Location, Place, PlaceBase, Body, Operand, Rvalue, StatementKind
-};
+use rustc::mir::{Constant, Local, LocalKind, Location, Place, Body, Operand, Rvalue, StatementKind};
 use rustc::mir::visit::MutVisitor;
 use rustc::ty::TyCtxt;
 use crate::transform::{MirPass, MirSource};
@@ -92,28 +90,32 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
                     };
 
                     // That use of the source must be an assignment.
-                    match statement.kind {
-                        StatementKind::Assign(
-                            box(
-                                Place {
-                                    base: PlaceBase::Local(local),
-                                    projection: box [],
-                                },
-                                Rvalue::Use(ref operand)
-                            )
-                        ) if local == dest_local => {
-                            let maybe_action = match *operand {
-                                Operand::Copy(ref src_place) |
-                                Operand::Move(ref src_place) => {
-                                    Action::local_copy(&body, &def_use_analysis, src_place)
-                                }
-                                Operand::Constant(ref src_constant) => {
-                                    Action::constant(src_constant)
+                    match &statement.kind {
+                        StatementKind::Assign(box(place, Rvalue::Use(operand))) => {
+                            if let Some(local) = place.as_local() {
+                                if local == dest_local {
+                                    let maybe_action = match operand {
+                                        Operand::Copy(ref src_place) |
+                                        Operand::Move(ref src_place) => {
+                                            Action::local_copy(&body, &def_use_analysis, src_place)
+                                        }
+                                        Operand::Constant(ref src_constant) => {
+                                            Action::constant(src_constant)
+                                        }
+                                    };
+                                    match maybe_action {
+                                        Some(this_action) => action = this_action,
+                                        None => continue,
+                                    }
+                                } else {
+                                    debug!("  Can't copy-propagate local: source use is not an \
+                                    assignment");
+                                    continue
                                 }
-                            };
-                            match maybe_action {
-                                Some(this_action) => action = this_action,
-                                None => continue,
+                            } else {
+                                debug!("  Can't copy-propagate local: source use is not an \
+                                    assignment");
+                                continue
                             }
                         }
                         _ => {
@@ -124,7 +126,8 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
                     }
                 }
 
-                changed = action.perform(body, &def_use_analysis, dest_local, location) || changed;
+                changed =
+                    action.perform(body, &def_use_analysis, dest_local, location, tcx) || changed;
                 // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of
                 // regenerating the chains.
                 break
@@ -148,31 +151,20 @@ fn eliminate_self_assignments(
         for def in dest_use_info.defs_not_including_drop() {
             let location = def.location;
             if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
-                match stmt.kind {
-                    StatementKind::Assign(
-                        box(
-                            Place {
-                                base: PlaceBase::Local(local),
-                                projection: box [],
-                            },
-                            Rvalue::Use(Operand::Copy(Place {
-                                base: PlaceBase::Local(src_local),
-                                projection: box [],
-                            })),
-                        )
-                    ) |
-                    StatementKind::Assign(
-                        box(
-                            Place {
-                                base: PlaceBase::Local(local),
-                                projection: box [],
-                            },
-                            Rvalue::Use(Operand::Move(Place {
-                                base: PlaceBase::Local(src_local),
-                                projection: box [],
-                            })),
-                        )
-                    ) if local == dest_local && dest_local == src_local => {}
+                match &stmt.kind {
+                    StatementKind::Assign(box (place, Rvalue::Use(Operand::Copy(src_place))))
+                    | StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(src_place)))) => {
+                        if let (Some(local), Some(src_local)) =
+                            (place.as_local(), src_place.as_local())
+                        {
+                            if local == dest_local && dest_local == src_local {
+                            } else {
+                                continue;
+                            }
+                        } else {
+                            continue;
+                        }
+                    }
                     _ => {
                         continue;
                     }
@@ -198,10 +190,7 @@ impl<'tcx> Action<'tcx> {
     fn local_copy(body: &Body<'tcx>, def_use_analysis: &DefUseAnalysis, src_place: &Place<'tcx>)
                   -> Option<Action<'tcx>> {
         // The source must be a local.
-        let src_local = if let Place {
-            base: PlaceBase::Local(local),
-            projection: box [],
-        } = *src_place {
+        let src_local = if let Some(local) = src_place.as_local() {
             local
         } else {
             debug!("  Can't copy-propagate local: source is not a local");
@@ -256,7 +245,8 @@ impl<'tcx> Action<'tcx> {
                body: &mut Body<'tcx>,
                def_use_analysis: &DefUseAnalysis,
                dest_local: Local,
-               location: Location)
+               location: Location,
+               tcx: TyCtxt<'tcx>)
                -> bool {
         match self {
             Action::PropagateLocalCopy(src_local) => {
@@ -280,7 +270,7 @@ impl<'tcx> Action<'tcx> {
                 }
 
                 // Replace all uses of the destination local with the source local.
-                def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local);
+                def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local, tcx);
 
                 // Finally, zap the now-useless assignment instruction.
                 debug!("  Deleting assignment");
@@ -304,7 +294,8 @@ impl<'tcx> Action<'tcx> {
 
                 // Replace all uses of the destination local with the constant.
                 let mut visitor = ConstantPropagationVisitor::new(dest_local,
-                                                                  src_constant);
+                                                                  src_constant,
+                                                                  tcx);
                 for dest_place_use in &dest_local_info.defs_and_uses {
                     visitor.visit_location(body, dest_place_use.location)
                 }
@@ -336,33 +327,42 @@ impl<'tcx> Action<'tcx> {
 struct ConstantPropagationVisitor<'tcx> {
     dest_local: Local,
     constant: Constant<'tcx>,
+    tcx: TyCtxt<'tcx>,
     uses_replaced: usize,
 }
 
 impl<'tcx> ConstantPropagationVisitor<'tcx> {
-    fn new(dest_local: Local, constant: Constant<'tcx>)
+    fn new(dest_local: Local, constant: Constant<'tcx>, tcx: TyCtxt<'tcx>)
            -> ConstantPropagationVisitor<'tcx> {
         ConstantPropagationVisitor {
             dest_local,
             constant,
+            tcx,
             uses_replaced: 0,
         }
     }
 }
 
 impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
         self.super_operand(operand, location);
 
-        match *operand {
-            Operand::Copy(Place {
-                base: PlaceBase::Local(local),
-                projection: box [],
-            }) |
-            Operand::Move(Place {
-                base: PlaceBase::Local(local),
-                projection: box [],
-            }) if local == self.dest_local => {}
+        match operand {
+            Operand::Copy(place) |
+            Operand::Move(place) => {
+                if let Some(local) = place.as_local() {
+                    if local == self.dest_local {
+                    } else {
+                        return;
+                    }
+                } else {
+                    return;
+                }
+            }
             _ => return,
         }
 
diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index c1224be6324..cdde9e12edc 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -45,6 +45,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
                     }),
                     *kind,
                     source_info,
+                    tcx,
                 ))
             });
         }
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 439cae2093a..b30e2de4ca0 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -23,6 +23,10 @@ impl EraseRegionsVisitor<'tcx> {
 }
 
 impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
         *ty = self.tcx.erase_regions(ty);
     }
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 6533e3c5ba8..911901be36b 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -74,12 +74,17 @@ use crate::util::liveness;
 
 pub struct StateTransform;
 
-struct RenameLocalVisitor {
+struct RenameLocalVisitor<'tcx> {
     from: Local,
     to: Local,
+    tcx: TyCtxt<'tcx>,
 }
 
-impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
+impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_local(&mut self,
                    local: &mut Local,
                    _: PlaceContext,
@@ -102,9 +107,15 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
     }
 }
 
-struct DerefArgVisitor;
+struct DerefArgVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
 
-impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
     fn visit_local(&mut self,
                    local: &mut Local,
                    _: PlaceContext,
@@ -119,8 +130,8 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
         if place.base == PlaceBase::Local(self_arg()) {
             replace_base(place, Place {
                 base: PlaceBase::Local(self_arg()),
-                projection: Box::new([ProjectionElem::Deref]),
-            });
+                projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Deref]),
+            }, self.tcx);
         } else {
             self.visit_place_base(&mut place.base, context, location);
 
@@ -135,9 +146,14 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
 
 struct PinArgVisitor<'tcx> {
     ref_gen_ty: Ty<'tcx>,
+    tcx: TyCtxt<'tcx>,
 }
 
 impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_local(&mut self,
                    local: &mut Local,
                    _: PlaceContext,
@@ -145,15 +161,19 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
         assert_ne!(*local, self_arg());
     }
 
-    fn visit_place(&mut self,
-                    place: &mut Place<'tcx>,
-                    context: PlaceContext,
-                    location: Location) {
+    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
         if place.base == PlaceBase::Local(self_arg()) {
-            replace_base(place, Place {
-                base: PlaceBase::Local(self_arg()),
-                projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
-            });
+            replace_base(
+                place,
+                Place {
+                    base: PlaceBase::Local(self_arg()),
+                    projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Field(
+                            Field::new(0),
+                            self.ref_gen_ty,
+                    )]),
+                },
+                self.tcx,
+            );
         } else {
             self.visit_place_base(&mut place.base, context, location);
 
@@ -166,13 +186,13 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
     }
 }
 
-fn replace_base(place: &mut Place<'tcx>, new_base: Place<'tcx>) {
+fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) {
     place.base = new_base.base;
 
     let mut new_projection = new_base.projection.to_vec();
     new_projection.append(&mut place.projection.to_vec());
 
-    place.projection = new_projection.into_boxed_slice();
+    place.projection = tcx.intern_place_elems(&new_projection);
 }
 
 fn self_arg() -> Local {
@@ -226,13 +246,13 @@ impl TransformVisitor<'tcx> {
     // Create a Place referencing a generator struct field
     fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
         let self_place = Place::from(self_arg());
-        let base = self_place.downcast_unnamed(variant_index);
+        let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index);
         let mut projection = base.projection.to_vec();
         projection.push(ProjectionElem::Field(Field::new(idx), ty));
 
         Place {
             base: base.base,
-            projection: projection.into_boxed_slice(),
+            projection: self.tcx.intern_place_elems(&projection),
         }
     }
 
@@ -264,6 +284,10 @@ impl TransformVisitor<'tcx> {
 }
 
 impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_local(&mut self,
                    local: &mut Local,
                    _: PlaceContext,
@@ -280,7 +304,7 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
         if let PlaceBase::Local(l) = place.base {
             // Replace an Local in the remap with a generator struct access
             if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) {
-                replace_base(place, self.make_field(variant_index, idx, ty));
+                replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
             }
         } else {
             self.visit_place_base(&mut place.base, context, location);
@@ -375,7 +399,7 @@ fn make_generator_state_argument_indirect<'tcx>(
     body.local_decls.raw[1].ty = ref_gen_ty;
 
     // Add a deref to accesses of the generator state
-    DerefArgVisitor.visit_body(body);
+    DerefArgVisitor { tcx }.visit_body(body);
 }
 
 fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -390,12 +414,13 @@ fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
     body.local_decls.raw[1].ty = pin_ref_gen_ty;
 
     // Add the Pin field access to accesses of the generator state
-    PinArgVisitor { ref_gen_ty }.visit_body(body);
+    PinArgVisitor { ref_gen_ty, tcx }.visit_body(body);
 }
 
 fn replace_result_variable<'tcx>(
     ret_ty: Ty<'tcx>,
     body: &mut Body<'tcx>,
+    tcx: TyCtxt<'tcx>,
 ) -> Local {
     let source_info = source_info(body);
     let new_ret = LocalDecl {
@@ -416,6 +441,7 @@ fn replace_result_variable<'tcx>(
     RenameLocalVisitor {
         from: RETURN_PLACE,
         to: new_ret_local,
+        tcx,
     }.visit_body(body);
 
     new_ret_local
@@ -864,17 +890,24 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
 
     for (block, block_data) in body.basic_blocks().iter_enumerated() {
         let (target, unwind, source_info) = match block_data.terminator() {
-            &Terminator {
+            Terminator {
                 source_info,
                 kind: TerminatorKind::Drop {
-                    location: Place {
-                        base: PlaceBase::Local(local),
-                        projection: box [],
-                    },
+                    location,
                     target,
                     unwind
                 }
-            } if local == gen => (target, unwind, source_info),
+            } => {
+                if let Some(local) = location.as_local() {
+                    if local == gen {
+                        (target, unwind, source_info)
+                    } else {
+                        continue;
+                    }
+                } else {
+                    continue;
+                }
+            }
             _ => continue,
         };
         let unwind = if block_data.is_cleanup {
@@ -884,10 +917,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
         };
         elaborate_drop(
             &mut elaborator,
-            source_info,
+            *source_info,
             &Place::from(gen),
             (),
-            target,
+            *target,
             unwind,
             block,
         );
@@ -1175,7 +1208,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
 
         // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
         // RETURN_PLACE then is a fresh unused local with type ret_ty.
-        let new_ret_local = replace_result_variable(ret_ty, body);
+        let new_ret_local = replace_result_variable(ret_ty, body, tcx);
 
         // Extract locals which are live across suspension point into `layout`
         // `remap` gives a mapping from local indices onto generator struct indices
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 0cbdcedff47..5a34e3f471f 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -461,7 +461,7 @@ impl Inliner<'tcx> {
                     };
                     caller_body[callsite.bb]
                         .statements.push(stmt);
-                    tmp.deref()
+                    self.tcx.mk_place_deref(tmp)
                 } else {
                     destination.0
                 };
@@ -481,6 +481,7 @@ impl Inliner<'tcx> {
                     return_block,
                     cleanup_block: cleanup,
                     in_cleanup_block: false,
+                    tcx: self.tcx,
                 };
 
 
@@ -559,7 +560,8 @@ impl Inliner<'tcx> {
             let tuple_tmp_args =
                 tuple_tys.iter().enumerate().map(|(i, ty)| {
                     // This is e.g., `tuple_tmp.0` in our example above.
-                    let tuple_field = Operand::Move(tuple.clone().field(
+                    let tuple_field = Operand::Move(tcx.mk_place_field(
+                        tuple.clone(),
                         Field::new(i),
                         ty.expect_ty(),
                     ));
@@ -587,13 +589,12 @@ impl Inliner<'tcx> {
         // FIXME: Analysis of the usage of the arguments to avoid
         // unnecessary temporaries.
 
-        if let Operand::Move(Place {
-            base: PlaceBase::Local(local),
-            projection: box [],
-        }) = arg {
-            if caller_body.local_kind(local) == LocalKind::Temp {
-                // Reuse the operand if it's a temporary already
-                return local;
+        if let Operand::Move(place) = &arg {
+            if let Some(local) = place.as_local() {
+                if caller_body.local_kind(local) == LocalKind::Temp {
+                    // Reuse the operand if it's a temporary already
+                    return local;
+                }
             }
         }
 
@@ -639,6 +640,7 @@ struct Integrator<'a, 'tcx> {
     return_block: BasicBlock,
     cleanup_block: Option<BasicBlock>,
     in_cleanup_block: bool,
+    tcx: TyCtxt<'tcx>,
 }
 
 impl<'a, 'tcx> Integrator<'a, 'tcx> {
@@ -650,14 +652,9 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
 
     fn make_integrate_local(&self, local: &Local) -> Local {
         if *local == RETURN_PLACE {
-            match self.destination {
-                Place {
-                    base: PlaceBase::Local(l),
-                    projection: box [],
-                } => {
-                    return l;
-                },
-                ref place => bug!("Return place is {:?}, not local", place)
+            match self.destination.as_local() {
+                Some(l) => return l,
+                ref place => bug!("Return place is {:?}, not local", place),
             }
         }
 
@@ -671,6 +668,10 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_local(
         &mut self,
         local: &mut Local,
@@ -686,17 +687,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
         context: PlaceContext,
         location: Location,
     ) {
-        match place {
-            Place {
-                base: PlaceBase::Local(RETURN_PLACE),
-                projection: box [],
-            } => {
-                // Return pointer; update the place itself
-                *place = self.destination.clone();
-            },
-            _ => {
-                self.super_place(place, context, location);
-            }
+        if let Some(RETURN_PLACE) = place.as_local() {
+            // Return pointer; update the place itself
+            *place = self.destination.clone();
+        } else {
+            self.super_place(place, context, location);
         }
     }
 
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index bb98d63b1ee..a567ed668bf 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -1,7 +1,8 @@
 //! Performs various peephole optimizations.
 
-use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, ProjectionElem, Rvalue,
-    Local};
+use rustc::mir::{
+    Constant, Location, Place, PlaceBase, PlaceRef, Body, Operand, ProjectionElem, Rvalue, Local
+};
 use rustc::mir::visit::{MutVisitor, Visitor};
 use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
@@ -28,32 +29,33 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
         };
 
         // Then carry out those optimizations.
-        MutVisitor::visit_body(&mut InstCombineVisitor { optimizations }, body);
+        MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body);
     }
 }
 
 pub struct InstCombineVisitor<'tcx> {
     optimizations: OptimizationList<'tcx>,
+    tcx: TyCtxt<'tcx>,
 }
 
 impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
         if self.optimizations.and_stars.remove(&location) {
             debug!("replacing `&*`: {:?}", rvalue);
-            let new_place = match *rvalue {
-                Rvalue::Ref(_, _, Place {
-                    ref mut base,
-                    projection: ref mut projection @ box [.., _],
-                }) => {
-                    if let box [proj_l @ .., proj_r] = projection {
-                        let place = Place {
-                            // Replace with dummy
-                            base: mem::replace(base, PlaceBase::Local(Local::new(0))),
-                            projection: proj_l.to_vec().into_boxed_slice(),
-                        };
-                        *projection = vec![proj_r.clone()].into_boxed_slice();
+            let new_place = match rvalue {
+                Rvalue::Ref(_, _, place) => {
+                    if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() {
+                        place.projection = self.tcx().intern_place_elems(&vec![proj_r.clone()]);
 
-                        place
+                        Place {
+                            // Replace with dummy
+                            base: mem::replace(&mut place.base, PlaceBase::Local(Local::new(0))),
+                            projection: self.tcx().intern_place_elems(proj_l),
+                        }
                     } else {
                         unreachable!();
                     }
@@ -91,12 +93,14 @@ impl OptimizationFinder<'b, 'tcx> {
 
 impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
-        if let Rvalue::Ref(_, _, Place {
-            base,
-            projection: box [proj_base @ .., ProjectionElem::Deref],
-        }) = rvalue {
-            if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
-                self.optimizations.and_stars.insert(location);
+        if let Rvalue::Ref(_, _, place) = rvalue {
+            if let PlaceRef {
+                base,
+                projection: &[ref proj_base @ .., ProjectionElem::Deref],
+            } = place.as_ref() {
+                if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
+                    self.optimizations.and_stars.insert(location);
+                }
             }
         }
 
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 7e06729c2c7..dbe6c784592 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -228,7 +228,7 @@ fn run_optimization_passes<'tcx>(
 ) {
     run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[
         // Remove all things only needed by analysis
-        &no_landing_pads::NoLandingPads,
+        &no_landing_pads::NoLandingPads::new(tcx),
         &simplify_branches::SimplifyBranches::new("initial"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &cleanup_post_borrowck::CleanupNonCodegenStatements,
@@ -238,7 +238,7 @@ fn run_optimization_passes<'tcx>(
         // These next passes must be executed together
         &add_call_guards::CriticalCallEdges,
         &elaborate_drops::ElaborateDrops,
-        &no_landing_pads::NoLandingPads,
+        &no_landing_pads::NoLandingPads::new(tcx),
         // AddMovesForPackedDrops needs to run after drop
         // elaboration.
         &add_moves_for_packed_drops::AddMovesForPackedDrops,
@@ -257,7 +257,7 @@ fn run_optimization_passes<'tcx>(
 
 
         // Optimizations begin.
-        &uniform_array_move_out::RestoreSubsliceArrayMoveOut,
+        &uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
         &inline::Inline,
 
         // Lowering generator control-flow and variables
diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs
index 762bb5d4483..fbd14d9ef61 100644
--- a/src/librustc_mir/transform/no_landing_pads.rs
+++ b/src/librustc_mir/transform/no_landing_pads.rs
@@ -6,9 +6,17 @@ use rustc::mir::*;
 use rustc::mir::visit::MutVisitor;
 use crate::transform::{MirPass, MirSource};
 
-pub struct NoLandingPads;
+pub struct NoLandingPads<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> NoLandingPads<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+        NoLandingPads { tcx }
+    }
+}
 
-impl<'tcx> MirPass<'tcx> for NoLandingPads {
+impl<'tcx> MirPass<'tcx> for NoLandingPads<'tcx> {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
         no_landing_pads(tcx, body)
     }
@@ -16,11 +24,15 @@ impl<'tcx> MirPass<'tcx> for NoLandingPads {
 
 pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     if tcx.sess.no_landing_pads() {
-        NoLandingPads.visit_body(body);
+        NoLandingPads::new(tcx).visit_body(body);
     }
 }
 
-impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
+impl<'tcx> MutVisitor<'tcx> for NoLandingPads<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_terminator_kind(&mut self,
                         kind: &mut TerminatorKind<'tcx>,
                         location: Location) {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index ad1785417cd..7a9c489fa79 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -17,7 +17,7 @@ use rustc::mir::*;
 use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor};
 use rustc::mir::traversal::ReversePostorder;
 use rustc::ty::subst::InternalSubsts;
-use rustc::ty::TyCtxt;
+use rustc::ty::{List, TyCtxt};
 use syntax_pos::Span;
 
 use rustc_index::vec::{IndexVec, Idx};
@@ -321,7 +321,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                         ty,
                         def_id,
                     }),
-                    projection: box [],
+                    projection: List::empty(),
                 }
             };
             let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
@@ -339,7 +339,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                                     &mut place.base,
                                     promoted_place(ty, span).base,
                                 ),
-                                projection: box [],
+                                projection: List::empty(),
                             })
                         }
                         _ => bug!()
@@ -396,6 +396,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
 
 /// Replaces all temporaries with their promoted counterparts.
 impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_local(&mut self,
                    local: &mut Local,
                    _: PlaceContext,
@@ -434,14 +438,13 @@ pub fn promote_candidates<'tcx>(
         match candidate {
             Candidate::Repeat(Location { block, statement_index }) |
             Candidate::Ref(Location { block, statement_index }) => {
-                match body[block].statements[statement_index].kind {
-                    StatementKind::Assign(box(Place {
-                        base: PlaceBase::Local(local),
-                        projection: box [],
-                    }, _)) => {
-                        if temps[local] == TempState::PromotedOut {
-                            // Already promoted.
-                            continue;
+                match &body[block].statements[statement_index].kind {
+                    StatementKind::Assign(box(place, _)) => {
+                        if let Some(local) = place.as_local() {
+                            if temps[local] == TempState::PromotedOut {
+                                // Already promoted.
+                                continue;
+                            }
                         }
                     }
                     _ => {}
@@ -487,28 +490,30 @@ pub fn promote_candidates<'tcx>(
     let promoted = |index: Local| temps[index] == TempState::PromotedOut;
     for block in body.basic_blocks_mut() {
         block.statements.retain(|statement| {
-            match statement.kind {
-                StatementKind::Assign(box(Place {
-                    base: PlaceBase::Local(index),
-                    projection: box [],
-                }, _)) |
+            match &statement.kind {
+                StatementKind::Assign(box(place, _)) => {
+                    if let Some(index) = place.as_local() {
+                        !promoted(index)
+                    } else {
+                        true
+                    }
+                }
                 StatementKind::StorageLive(index) |
                 StatementKind::StorageDead(index) => {
-                    !promoted(index)
+                    !promoted(*index)
                 }
                 _ => true
             }
         });
         let terminator = block.terminator_mut();
-        match terminator.kind {
-            TerminatorKind::Drop { location: Place {
-                base: PlaceBase::Local(index),
-                projection: box [],
-            }, target, .. } => {
-                if promoted(index) {
-                    terminator.kind = TerminatorKind::Goto {
-                        target,
-                    };
+        match &terminator.kind {
+            TerminatorKind::Drop { location: place, target, .. } => {
+                if let Some(index) = place.as_local() {
+                    if promoted(index) {
+                        terminator.kind = TerminatorKind::Goto {
+                            target: *target,
+                        };
+                    }
                 }
             }
             _ => {}
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index da1abb9747c..6aba91f4162 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -292,8 +292,8 @@ trait Qualif {
 
             Rvalue::Ref(_, _, ref place) => {
                 // Special-case reborrows to be more like a copy of the reference.
-                if let box [proj_base @ .., elem] = &place.projection {
-                    if ProjectionElem::Deref == *elem {
+                if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
+                    if ProjectionElem::Deref == elem {
                         let base_ty = Place::ty_from(&place.base, proj_base, cx.body, cx.tcx).ty;
                         if let ty::Ref(..) = base_ty.kind {
                             return Self::in_place(cx, PlaceRef {
@@ -1041,26 +1041,24 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
             match *candidate {
                 Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
                     if let StatementKind::Assign(box(_, Rvalue::Repeat(
-                        Operand::Move(Place {
-                            base: PlaceBase::Local(index),
-                            projection: box [],
-                        }),
+                        Operand::Move(place),
                         _
-                    ))) = self.body[bb].statements[stmt_idx].kind {
-                        promoted_temps.insert(index);
+                    ))) = &self.body[bb].statements[stmt_idx].kind {
+                        if let Some(index) = place.as_local() {
+                            promoted_temps.insert(index);
+                        }
                     }
                 }
                 Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
                     if let StatementKind::Assign(
                         box(
                             _,
-                            Rvalue::Ref(_, _, Place {
-                                base: PlaceBase::Local(index),
-                                projection: box [],
-                            })
+                            Rvalue::Ref(_, _, place)
                         )
-                    ) = self.body[bb].statements[stmt_idx].kind {
-                        promoted_temps.insert(index);
+                    ) = &self.body[bb].statements[stmt_idx].kind {
+                        if let Some(index) = place.as_local() {
+                            promoted_temps.insert(index);
+                        }
                     }
                 }
                 Candidate::Argument { .. } => {}
@@ -1237,10 +1235,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
         match *operand {
             Operand::Move(ref place) => {
                 // Mark the consumed locals to indicate later drops are noops.
-                if let Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [],
-                } = *place {
+                if let Some(local) = place.as_local() {
                     self.cx.per_local[NeedsDrop].remove(local);
                 }
             }
@@ -1256,8 +1251,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
         if let Rvalue::Ref(_, kind, ref place) = *rvalue {
             // Special-case reborrows.
             let mut reborrow_place = None;
-            if let box [proj_base @ .., elem] = &place.projection {
-                if *elem == ProjectionElem::Deref {
+            if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
+                if elem == ProjectionElem::Deref {
                     let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind {
                         reborrow_place = Some(proj_base);
@@ -1568,10 +1563,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                 unleash_miri!(self);
                 // HACK(eddyb): emulate a bit of dataflow analysis,
                 // conservatively, that drop elaboration will do.
-                let needs_drop = if let Place {
-                    base: PlaceBase::Local(local),
-                    projection: box [],
-                } = *place {
+                let needs_drop = if let Some(local) = place.as_local() {
                     if NeedsDrop::in_local(self, local) {
                         Some(self.body.local_decls[local].source_info.span)
                     } else {
@@ -1817,16 +1809,17 @@ fn remove_drop_and_storage_dead_on_promoted_locals(
             }
         });
         let terminator = block.terminator_mut();
-        match terminator.kind {
+        match &terminator.kind {
             TerminatorKind::Drop {
-                location: Place {
-                    base: PlaceBase::Local(index),
-                    projection: box [],
-                },
+                location,
                 target,
                 ..
-            } if promoted_temps.contains(index) => {
-                terminator.kind = TerminatorKind::Goto { target };
+            } => {
+                if let Some(index) = location.as_local() {
+                    if promoted_temps.contains(index) {
+                        terminator.kind = TerminatorKind::Goto { target: *target };
+                    }
+                }
             }
             _ => {}
         }
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 7b6255defd1..c4e44091bc9 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -259,8 +259,8 @@ fn check_place(
     def_id: DefId,
     body: &Body<'tcx>
 ) -> McfResult {
-    let mut cursor = &*place.projection;
-    while let [proj_base @ .., elem] = cursor {
+    let mut cursor = place.projection.as_ref();
+    while let &[ref proj_base @ .., elem] = cursor {
         cursor = proj_base;
         match elem {
             ProjectionElem::Downcast(..) => {
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
index e1994c5f639..130393e2c4c 100644
--- a/src/librustc_mir/transform/remove_noop_landing_pads.rs
+++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs
@@ -32,7 +32,7 @@ impl RemoveNoopLandingPads {
         nop_landing_pads: &BitSet<BasicBlock>,
     ) -> bool {
         for stmt in &body[bb].statements {
-            match stmt.kind {
+            match &stmt.kind {
                 StatementKind::FakeRead(..) |
                 StatementKind::StorageLive(_) |
                 StatementKind::StorageDead(_) |
@@ -41,12 +41,13 @@ impl RemoveNoopLandingPads {
                     // These are all nops in a landing pad
                 }
 
-                StatementKind::Assign(box(Place {
-                    base: PlaceBase::Local(_),
-                    projection: box [],
-                }, Rvalue::Use(_))) => {
-                    // Writing to a local (e.g., a drop flag) does not
-                    // turn a landing pad to a non-nop
+                StatementKind::Assign(box(place, Rvalue::Use(_))) => {
+                    if place.as_local().is_some() {
+                        // Writing to a local (e.g., a drop flag) does not
+                        // turn a landing pad to a non-nop
+                    } else {
+                        return false;
+                    }
                 }
 
                 StatementKind::Assign { .. } |
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 6edd28a4259..aada7641df6 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -155,8 +155,8 @@ fn value_assigned_to_local<'a, 'tcx>(
     local: Local,
 ) -> Option<&'a mir::Rvalue<'tcx>> {
     if let mir::StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
-        if let mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } = place {
-            if local == *l {
+        if let Some(l) = place.as_local() {
+            if local == l {
                 return Some(&*rvalue);
             }
         }
@@ -192,7 +192,7 @@ impl PeekCall {
         tcx: TyCtxt<'tcx>,
         terminator: &mir::Terminator<'tcx>,
     ) -> Option<Self> {
-        use mir::{Operand, Place, PlaceBase};
+        use mir::Operand;
 
         let span = terminator.source_info.span;
         if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
@@ -207,14 +207,23 @@ impl PeekCall {
 
                 assert_eq!(args.len(), 1);
                 let kind = PeekCallKind::from_arg_ty(substs.type_at(0));
-                let arg = match args[0] {
-                    | Operand::Copy(Place { base: PlaceBase::Local(local), projection: box [] })
-                    | Operand::Move(Place { base: PlaceBase::Local(local), projection: box [] })
-                    => local,
-
+                let arg = match &args[0] {
+                    Operand::Copy(place) | Operand::Move(place) => {
+                        if let Some(local) = place.as_local() {
+                            local
+                        } else {
+                            tcx.sess.diagnostic().span_err(
+                                span,
+                                "dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
+                            );
+                            return None;
+                        }
+                    }
                     _ => {
                         tcx.sess.diagnostic().span_err(
-                            span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
+                            span,
+                            "dataflow::sanity_check cannot feed a non-temp to rustc_peek.",
+                        );
                         return None;
                     }
                 };
@@ -277,12 +286,11 @@ impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> {
         call: PeekCall,
     ) {
         warn!("peek_at: place={:?}", place);
-        let local = match place {
-            mir::Place { base: mir::PlaceBase::Local(l), projection: box [] } => *l,
-            _ => {
-                tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
-                return;
-            }
+        let local = if let Some(l) = place.as_local() {
+            l
+        } else {
+            tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
+            return;
         };
 
         if !flow_state.contains(local) {
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index e41b4678dbd..1b90ea78c64 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -319,7 +319,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
 
         let map = make_local_map(&mut body.local_decls, locals);
         // Update references to all vars and tmps now
-        LocalUpdater { map }.visit_body(body);
+        LocalUpdater { map, tcx }.visit_body(body);
         body.local_decls.shrink_to_fit();
     }
 }
@@ -374,11 +374,16 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
     }
 }
 
-struct LocalUpdater {
+struct LocalUpdater<'tcx> {
     map: IndexVec<Local, Option<Local>>,
+    tcx: TyCtxt<'tcx>,
 }
 
-impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
+impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
         // Remove unnecessary StorageLive and StorageDead annotations.
         data.statements.retain(|stmt| {
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
index efa39d91205..e4c2f7d389b 100644
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ b/src/librustc_mir/transform/uniform_array_move_out.rs
@@ -61,7 +61,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
                     rvalue: &Rvalue<'tcx>,
                     location: Location) {
         if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
-            if let box [proj_base @ .., elem] = &src_place.projection {
+            if let &[ref proj_base @ .., elem] = src_place.projection.as_ref() {
                 if let ProjectionElem::ConstantIndex{offset: _,
                                                      min_length: _,
                                                      from_end: false} = elem {
@@ -116,16 +116,13 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
                             min_length: size,
                             from_end: false,
                         });
-                        self.patch.add_assign(location,
-                                              Place::from(temp),
-                                              Rvalue::Use(
-                                                  Operand::Move(
-                                                      Place {
-                                                          base: base.clone(),
-                                                          projection: projection.into_boxed_slice(),
-                                                      }
-                                                  )
-                                              )
+                        self.patch.add_assign(
+                            location,
+                            Place::from(temp),
+                            Rvalue::Use(Operand::Move(Place {
+                                base: base.clone(),
+                                projection: self.tcx.intern_place_elems(&projection),
+                            })),
                         );
                         temp
                     }).collect();
@@ -153,16 +150,13 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
                         min_length: size,
                         from_end: false,
                     });
-                    self.patch.add_assign(location,
-                                          dst_place.clone(),
-                                          Rvalue::Use(
-                                              Operand::Move(
-                                                  Place {
-                                                      base: base.clone(),
-                                                      projection: projection.into_boxed_slice(),
-                                                  }
-                                              )
-                                          )
+                    self.patch.add_assign(
+                        location,
+                        dst_place.clone(),
+                        Rvalue::Use(Operand::Move(Place {
+                            base: base.clone(),
+                            projection: self.tcx.intern_place_elems(&projection),
+                        })),
                     );
                 }
                 _ => {}
@@ -185,9 +179,11 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
 //
 // replaced by _10 = move _2[:-1];
 
-pub struct RestoreSubsliceArrayMoveOut;
+pub struct RestoreSubsliceArrayMoveOut<'tcx> {
+    tcx: TyCtxt<'tcx>
+}
 
-impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
+impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
         let mut patch = MirPatch::new(body);
         let param_env = tcx.param_env(src.def_id());
@@ -203,18 +199,17 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
                 if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
                     if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
                         let items : Vec<_> = items.iter().map(|item| {
-                            if let Operand::Move(Place {
-                                base: PlaceBase::Local(local),
-                                projection: box [],
-                            }) = item {
-                                let local_use = &visitor.locals_use[*local];
-                                let opt_index_and_place =
-                                    Self::try_get_item_source(local_use, body);
-                                // each local should be used twice:
-                                //  in assign and in aggregate statements
-                                if local_use.use_count == 2 && opt_index_and_place.is_some() {
-                                    let (index, src_place) = opt_index_and_place.unwrap();
-                                    return Some((local_use, index, src_place));
+                            if let Operand::Move(place) = item {
+                                if let Some(local) = place.as_local() {
+                                    let local_use = &visitor.locals_use[local];
+                                    let opt_index_and_place =
+                                        Self::try_get_item_source(local_use, body);
+                                    // each local should be used twice:
+                                    //  in assign and in aggregate statements
+                                    if local_use.use_count == 2 && opt_index_and_place.is_some() {
+                                        let (index, src_place) = opt_index_and_place.unwrap();
+                                        return Some((local_use, index, src_place));
+                                    }
                                 }
                             }
                             None
@@ -230,7 +225,9 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
                                 None
                             }
                         });
-                        Self::check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
+                        let restore_subslice = RestoreSubsliceArrayMoveOut { tcx };
+                        restore_subslice
+                            .check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
                     }
                 }
             }
@@ -239,15 +236,20 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut {
     }
 }
 
-impl RestoreSubsliceArrayMoveOut {
+impl RestoreSubsliceArrayMoveOut<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+        RestoreSubsliceArrayMoveOut { tcx }
+    }
+
     // Checks that source has size, all locals are inited from same source place and
     // indices is an integer interval. If all checks pass do the replacent.
     // items are Vec<Option<LocalUse, index in source array, source place for init local>>
-    fn check_and_patch<'tcx>(candidate: Location,
-                             items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>],
-                             opt_size: Option<u64>,
-                             patch: &mut MirPatch<'tcx>,
-                             dst_place: &Place<'tcx>) {
+    fn check_and_patch(&self,
+                       candidate: Location,
+                       items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>],
+                       opt_size: Option<u64>,
+                       patch: &mut MirPatch<'tcx>,
+                       dst_place: &Place<'tcx>) {
         let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
 
         if opt_size.is_some() && items.iter().all(
@@ -280,46 +282,40 @@ impl RestoreSubsliceArrayMoveOut {
                 dst_place.clone(),
                 Rvalue::Use(Operand::Move(Place {
                     base: src_place.base.clone(),
-                    projection: projection.into_boxed_slice(),
+                    projection: self.tcx.intern_place_elems(&projection),
                 })),
             );
         }
     }
 
-    fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse,
-                                     body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> {
+    fn try_get_item_source<'a>(local_use: &LocalUse,
+                               body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> {
         if let Some(location) = local_use.first_use {
             let block = &body[location.block];
             if block.statements.len() > location.statement_index {
                 let statement = &block.statements[location.statement_index];
                 if let StatementKind::Assign(
-                    box(
-                        Place {
-                            base: PlaceBase::Local(_),
-                            projection: box [],
-                        },
-                        Rvalue::Use(Operand::Move(Place {
-                            base: _,
-                            projection: box [.., ProjectionElem::ConstantIndex {
-                                offset, min_length: _, from_end: false
-                            }],
-                        })),
-                    )
+                    box(place, Rvalue::Use(Operand::Move(src_place)))
                 ) = &statement.kind {
-                    // FIXME remove once we can use slices patterns
-                    if let StatementKind::Assign(
-                        box(
-                            _,
-                            Rvalue::Use(Operand::Move(Place {
+                    if let (Some(_), PlaceRef {
+                        base: _,
+                        projection: &[.., ProjectionElem::ConstantIndex {
+                            offset, min_length: _, from_end: false
+                        }],
+                    }) = (place.as_local(), src_place.as_ref()) {
+                        if let StatementKind::Assign(
+                            box(_, Rvalue::Use(Operand::Move(place)))
+                        ) = &statement.kind {
+                            if let PlaceRef {
                                 base,
-                                projection: box [proj_base @ .., _],
-                            })),
-                        )
-                    ) = &statement.kind {
-                        return Some((*offset, PlaceRef {
-                            base,
-                            projection: proj_base,
-                        }))
+                                projection: &[ref proj_base @ .., _],
+                            } = place.as_ref() {
+                                return Some((offset, PlaceRef {
+                                    base,
+                                    projection: proj_base,
+                                }))
+                            }
+                        }
                     }
                 }
             }
diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs
index c0f92185745..e6c3e4384d7 100644
--- a/src/librustc_mir/util/aggregate.rs
+++ b/src/librustc_mir/util/aggregate.rs
@@ -1,5 +1,5 @@
 use rustc::mir::*;
-use rustc::ty::Ty;
+use rustc::ty::{Ty, TyCtxt};
 use rustc::ty::layout::VariantIdx;
 use rustc_index::vec::Idx;
 
@@ -17,6 +17,7 @@ pub fn expand_aggregate<'tcx>(
     operands: impl Iterator<Item=(Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
     kind: AggregateKind<'tcx>,
     source_info: SourceInfo,
+    tcx: TyCtxt<'tcx>,
 ) -> impl Iterator<Item=Statement<'tcx>> + TrustedLen {
     let mut set_discriminant = None;
     let active_field_index = match kind {
@@ -29,7 +30,7 @@ pub fn expand_aggregate<'tcx>(
                     },
                     source_info,
                 });
-                lhs = lhs.downcast(adt_def, variant_index);
+                lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index);
             }
             active_field_index
         }
@@ -58,7 +59,7 @@ pub fn expand_aggregate<'tcx>(
             // FIXME(eddyb) `offset` should be u64.
             let offset = i as u32;
             assert_eq!(offset as usize, i);
-            lhs.clone().elem(ProjectionElem::ConstantIndex {
+            tcx.mk_place_elem(lhs.clone(), ProjectionElem::ConstantIndex {
                 offset,
                 // FIXME(eddyb) `min_length` doesn't appear to be used.
                 min_length: offset + 1,
@@ -66,7 +67,7 @@ pub fn expand_aggregate<'tcx>(
             })
         } else {
             let field = Field::new(active_field_index.unwrap_or(i));
-            lhs.clone().field(field, ty)
+            tcx.mk_place_field(lhs.clone(), field, ty)
         };
         Statement {
             source_info,
diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs
index 1bad85ec42d..f949fcf0745 100644
--- a/src/librustc_mir/util/alignment.rs
+++ b/src/librustc_mir/util/alignment.rs
@@ -38,8 +38,8 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
 where
     L: HasLocalDecls<'tcx>,
 {
-    let mut cursor = &*place.projection;
-    while let [proj_base @ .., elem] = cursor {
+    let mut cursor = place.projection.as_ref();
+    while let &[ref proj_base @ .., elem] = cursor {
         cursor = proj_base;
 
         match elem {
diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs
index cdd07ad4b8f..725ec84ca62 100644
--- a/src/librustc_mir/util/def_use.rs
+++ b/src/librustc_mir/util/def_use.rs
@@ -2,6 +2,7 @@
 
 use rustc::mir::{Body, Local, Location, PlaceElem};
 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
+use rustc::ty::TyCtxt;
 use rustc_index::vec::IndexVec;
 use std::mem;
 
@@ -47,20 +48,26 @@ impl DefUseAnalysis {
         &self.info[local]
     }
 
-    fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) {
+    fn mutate_defs_and_uses(
+        &self,
+        local: Local,
+        body: &mut Body<'tcx>,
+        new_local: Local,
+        tcx: TyCtxt<'tcx>,
+    ) {
         for place_use in &self.info[local].defs_and_uses {
-            MutateUseVisitor::new(local,
-                                  new_local,
-                                  body).visit_location(body, place_use.location)
+            MutateUseVisitor::new(local, new_local, body, tcx)
+                .visit_location(body, place_use.location)
         }
     }
 
     // FIXME(pcwalton): this should update the def-use chains.
     pub fn replace_all_defs_and_uses_with(&self,
                                           local: Local,
-                                          body: &mut Body<'_>,
-                                          new_local: Local) {
-        self.mutate_defs_and_uses(local, body, new_local)
+                                          body: &mut Body<'tcx>,
+                                          new_local: Local,
+                                          tcx: TyCtxt<'tcx>) {
+        self.mutate_defs_and_uses(local, body, new_local, tcx)
     }
 }
 
@@ -114,21 +121,28 @@ impl Info {
     }
 }
 
-struct MutateUseVisitor {
+struct MutateUseVisitor<'tcx> {
     query: Local,
     new_local: Local,
+    tcx: TyCtxt<'tcx>,
 }
 
-impl MutateUseVisitor {
-    fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor {
-        MutateUseVisitor {
-            query,
-            new_local,
-        }
+impl MutateUseVisitor<'tcx> {
+    fn new(
+        query: Local,
+        new_local: Local,
+        _: &Body<'tcx>,
+        tcx: TyCtxt<'tcx>,
+    ) -> MutateUseVisitor<'tcx> {
+        MutateUseVisitor { query, new_local, tcx }
     }
 }
 
-impl MutVisitor<'_> for MutateUseVisitor {
+impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
     fn visit_local(&mut self,
                     local: &mut Local,
                     _context: PlaceContext,
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index f7ba6f1ec69..a1846a1fb5e 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -200,13 +200,14 @@ where
         variant.fields.iter().enumerate().map(|(i, f)| {
             let field = Field::new(i);
             let subpath = self.elaborator.field_subpath(variant_path, field);
+            let tcx = self.tcx();
 
             assert_eq!(self.elaborator.param_env().reveal, Reveal::All);
-            let field_ty = self.tcx().normalize_erasing_regions(
+            let field_ty = tcx.normalize_erasing_regions(
                 self.elaborator.param_env(),
-                f.ty(self.tcx(), substs),
+                f.ty(tcx, substs),
             );
-            (base_place.clone().field(field, field_ty), subpath)
+            (tcx.mk_place_field(base_place.clone(), field, field_ty), subpath)
         }).collect()
     }
 
@@ -323,7 +324,7 @@ where
         debug!("open_drop_for_tuple({:?}, {:?})", self, tys);
 
         let fields = tys.iter().enumerate().map(|(i, &ty)| {
-            (self.place.clone().field(Field::new(i), ty),
+            (self.tcx().mk_place_field(self.place.clone(), Field::new(i), ty),
              self.elaborator.field_subpath(self.path, Field::new(i)))
         }).collect();
 
@@ -334,7 +335,7 @@ where
     fn open_drop_for_box(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock {
         debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs);
 
-        let interior = self.place.clone().deref();
+        let interior = self.tcx().mk_place_deref(self.place.clone());
         let interior_path = self.elaborator.deref_subpath(self.path);
 
         let succ = self.succ; // FIXME(#43234)
@@ -406,14 +407,19 @@ where
         };
 
         let mut have_otherwise = false;
+        let tcx = self.tcx();
 
-        for (variant_index, discr) in adt.discriminants(self.tcx()) {
+        for (variant_index, discr) in adt.discriminants(tcx) {
             let subpath = self.elaborator.downcast_subpath(
                 self.path, variant_index);
             if let Some(variant_path) = subpath {
-                let base_place = self.place.clone().elem(
-                    ProjectionElem::Downcast(Some(adt.variants[variant_index].ident.name),
-                                             variant_index));
+                let base_place = tcx.mk_place_elem(
+                    self.place.clone(),
+                    ProjectionElem::Downcast(
+                        Some(adt.variants[variant_index].ident.name),
+                        variant_index,
+                    ),
+                );
                 let fields = self.move_paths_for_fields(
                     &base_place,
                     variant_path,
@@ -586,7 +592,7 @@ where
                 BorrowKind::Mut { allow_two_phase_borrow: false },
                 Place {
                     base: PlaceBase::Local(cur),
-                    projection: Box::new([ProjectionElem::Deref]),
+                    projection: tcx.intern_place_elems(&vec![ProjectionElem::Deref]),
                 }
              ),
              Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
@@ -594,7 +600,7 @@ where
             (Rvalue::Ref(
                  tcx.lifetimes.re_erased,
                  BorrowKind::Mut { allow_two_phase_borrow: false },
-                 self.place.clone().index(cur)),
+                 tcx.mk_place_index(self.place.clone(), cur)),
              Rvalue::BinaryOp(BinOp::Add, move_(&Place::from(cur)), one))
         };
 
@@ -627,7 +633,7 @@ where
         let loop_block = self.elaborator.patch().new_block(loop_block);
 
         self.elaborator.patch().patch_terminator(drop_block, TerminatorKind::Drop {
-            location: ptr.clone().deref(),
+            location: tcx.mk_place_deref(ptr.clone()),
             target: loop_block,
             unwind: unwind.into_option()
         });
@@ -644,18 +650,27 @@ where
         //     ptr_based_loop
         // }
 
+        let tcx = self.tcx();
+
         if let Some(size) = opt_size {
             let size: u32 = size.try_into().unwrap_or_else(|_| {
                 bug!("move out check isn't implemented for array sizes bigger than u32::MAX");
             });
-            let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size).map(|i| {
-                (self.place.clone().elem(ProjectionElem::ConstantIndex{
-                    offset: i,
-                    min_length: size,
-                    from_end: false
-                }),
-                 self.elaborator.array_subpath(self.path, i, size))
-            }).collect();
+            let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size)
+                .map(|i| {
+                    (
+                        tcx.mk_place_elem(
+                            self.place.clone(),
+                            ProjectionElem::ConstantIndex {
+                                offset: i,
+                                min_length: size,
+                                from_end: false,
+                            },
+                        ),
+                        self.elaborator.array_subpath(self.path, i, size),
+                    )
+                })
+                .collect();
 
             if fields.iter().any(|(_,path)| path.is_some()) {
                 let (succ, unwind) = self.drop_ladder_bottom();
@@ -664,7 +679,6 @@ where
         }
 
         let move_ = |place: &Place<'tcx>| Operand::Move(place.clone());
-        let tcx = self.tcx();
         let elem_size = &Place::from(self.new_temp(tcx.types.usize));
         let len = &Place::from(self.new_temp(tcx.types.usize));
 
@@ -900,8 +914,8 @@ where
         );
         let args = adt.variants[VariantIdx::new(0)].fields.iter().enumerate().map(|(i, f)| {
             let field = Field::new(i);
-            let field_ty = f.ty(self.tcx(), substs);
-            Operand::Move(self.place.clone().field(field, field_ty))
+            let field_ty = f.ty(tcx, substs);
+            Operand::Move(tcx.mk_place_field(self.place.clone(), field, field_ty))
         }).collect();
 
         let call = TerminatorKind::Call {