about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-01-11 14:46:17 +0000
committerbors <bors@rust-lang.org>2020-01-11 14:46:17 +0000
commit1389494ac145a84dba025ff65969f7ab150c3f02 (patch)
treea26ccd59b4b7ee66e7893cbf18de4b5f780e770d
parentbfd04876b93ad5c013d90bc46937e28b6ee1a3f4 (diff)
parente51eccd2eff685bda7b5d6734ff4923b706bd476 (diff)
downloadrust-1389494ac145a84dba025ff65969f7ab150c3f02.tar.gz
rust-1389494ac145a84dba025ff65969f7ab150c3f02.zip
Auto merge of #67000 - spastorino:remove-promoted-from-place, r=oli-obk
Promote references to constants instead of statics

r? @oli-obk
-rw-r--r--src/librustc/mir/interpret/queries.rs9
-rw-r--r--src/librustc/mir/mod.rs169
-rw-r--r--src/librustc/mir/tcx.rs20
-rw-r--r--src/librustc/mir/visit.rs35
-rw-r--r--src/librustc/traits/fulfill.rs1
-rw-r--r--src/librustc/traits/select.rs9
-rw-r--r--src/librustc/traits/wf.rs4
-rw-r--r--src/librustc/ty/codec.rs4
-rw-r--r--src/librustc/ty/context.rs2
-rw-r--r--src/librustc/ty/flags.rs2
-rw-r--r--src/librustc/ty/print/pretty.rs36
-rw-r--r--src/librustc/ty/relate.rs8
-rw-r--r--src/librustc/ty/structural_impls.rs6
-rw-r--r--src/librustc/ty/sty.rs13
-rw-r--r--src/librustc/ty/walk.rs3
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs4
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs19
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs62
-rw-r--r--src/librustc_codegen_ssa/mir/constant.rs16
-rw-r--r--src/librustc_codegen_ssa/mir/debuginfo.rs4
-rw-r--r--src/librustc_codegen_ssa/mir/operand.rs62
-rw-r--r--src/librustc_codegen_ssa/mir/place.rs89
-rw-r--r--src/librustc_mir/borrow_check/borrow_set.rs4
-rw-r--r--src/librustc_mir/borrow_check/constraint_generation.rs25
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs59
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/mod.rs77
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/move_errors.rs10
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs59
-rw-r--r--src/librustc_mir/borrow_check/invalidation.rs7
-rw-r--r--src/librustc_mir/borrow_check/mod.rs191
-rw-r--r--src/librustc_mir/borrow_check/nll.rs10
-rw-r--r--src/librustc_mir/borrow_check/path_utils.rs16
-rw-r--r--src/librustc_mir/borrow_check/place_ext.rs48
-rw-r--r--src/librustc_mir/borrow_check/places_conflict.rs104
-rw-r--r--src/librustc_mir/borrow_check/prefixes.rs71
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs154
-rw-r--r--src/librustc_mir/borrow_check/used_muts.rs18
-rw-r--r--src/librustc_mir/build/expr/as_place.rs20
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs16
-rw-r--r--src/librustc_mir/build/matches/mod.rs6
-rw-r--r--src/librustc_mir/build/mod.rs2
-rw-r--r--src/librustc_mir/const_eval.rs2
-rw-r--r--src/librustc_mir/const_eval/eval_queries.rs18
-rw-r--r--src/librustc_mir/dataflow/impls/borrowed_locals.rs5
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs60
-rw-r--r--src/librustc_mir/dataflow/impls/indirect_mutation.rs8
-rw-r--r--src/librustc_mir/dataflow/impls/storage_liveness.rs20
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs19
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs8
-rw-r--r--src/librustc_mir/hair/cx/expr.rs25
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs1
-rw-r--r--src/librustc_mir/interpret/eval_context.rs19
-rw-r--r--src/librustc_mir/interpret/intern.rs25
-rw-r--r--src/librustc_mir/interpret/machine.rs2
-rw-r--r--src/librustc_mir/interpret/operand.rs18
-rw-r--r--src/librustc_mir/interpret/place.rs68
-rw-r--r--src/librustc_mir/monomorphize/collector.rs41
-rw-r--r--src/librustc_mir/transform/check_consts/qualifs.rs24
-rw-r--r--src/librustc_mir/transform/check_consts/resolver.rs6
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs59
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs21
-rw-r--r--src/librustc_mir/transform/const_prop.rs40
-rw-r--r--src/librustc_mir/transform/generator.rs39
-rw-r--r--src/librustc_mir/transform/inline.rs33
-rw-r--r--src/librustc_mir/transform/instcombine.rs8
-rw-r--r--src/librustc_mir/transform/promote_consts.rs170
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs2
-rw-r--r--src/librustc_mir/transform/simplify.rs8
-rw-r--r--src/librustc_mir/transform/simplify_try.rs4
-rw-r--r--src/librustc_mir/util/alignment.rs2
-rw-r--r--src/librustc_typeck/astconv.rs6
-rw-r--r--src/librustdoc/clean/utils.rs8
-rw-r--r--src/test/codegen/consts.rs13
-rw-r--r--src/test/mir-opt/const-promotion-extern-static.rs6
-rw-r--r--src/test/mir-opt/const_prop/ref_deref.rs24
-rw-r--r--src/test/mir-opt/const_prop/ref_deref_project.rs41
-rw-r--r--src/test/mir-opt/const_prop/slice_len.rs6
-rw-r--r--src/test/mir-opt/inline/inline-retag.rs10
-rw-r--r--src/test/mir-opt/match_false_edges.rs3
-rw-r--r--src/test/ui/consts/array-literal-index-oob.rs11
-rw-r--r--src/test/ui/consts/array-literal-index-oob.stderr32
-rw-r--r--src/test/ui/consts/const-eval/conditional_array_execution.rs1
-rw-r--r--src/test/ui/consts/const-eval/conditional_array_execution.stderr6
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs4
-rw-r--r--src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr6
-rw-r--r--src/test/ui/consts/const-eval/issue-43197.rs6
-rw-r--r--src/test/ui/consts/const-eval/issue-43197.stderr20
-rw-r--r--src/test/ui/consts/const-eval/issue-44578.rs2
-rw-r--r--src/test/ui/consts/const-eval/issue-50814.rs6
-rw-r--r--src/test/ui/consts/const-eval/issue-50814.stderr2
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors.rs28
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors.stderr60
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors2.rs30
-rw-r--r--src/test/ui/consts/const-eval/promoted_errors2.stderr62
-rw-r--r--src/test/ui/consts/const-eval/ub-nonnull.stderr2
-rw-r--r--src/test/ui/consts/miri_unleashed/non_const_fn.rs4
-rw-r--r--src/test/ui/consts/miri_unleashed/non_const_fn.stderr6
-rw-r--r--src/test/ui/consts/zst_no_llvm_alloc.rs10
-rw-r--r--src/test/ui/invalid_const_promotion.rs61
-rw-r--r--src/test/ui/symbol-names/impl1.legacy.stderr4
100 files changed, 1116 insertions, 1593 deletions
diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs
index 161c9a3fcc1..ed57f81e782 100644
--- a/src/librustc/mir/interpret/queries.rs
+++ b/src/librustc/mir/interpret/queries.rs
@@ -36,11 +36,16 @@ impl<'tcx> TyCtxt<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         def_id: DefId,
         substs: SubstsRef<'tcx>,
+        promoted: Option<mir::Promoted>,
         span: Option<Span>,
     ) -> ConstEvalResult<'tcx> {
         let instance = ty::Instance::resolve(self, param_env, def_id, substs);
         if let Some(instance) = instance {
-            self.const_eval_instance(param_env, instance, span)
+            if let Some(promoted) = promoted {
+                self.const_eval_promoted(param_env, instance, promoted)
+            } else {
+                self.const_eval_instance(param_env, instance, span)
+            }
         } else {
             Err(ErrorHandled::TooGeneric)
         }
@@ -63,11 +68,11 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Evaluate a promoted constant.
     pub fn const_eval_promoted(
         self,
+        param_env: ty::ParamEnv<'tcx>,
         instance: ty::Instance<'tcx>,
         promoted: mir::Promoted,
     ) -> ConstEvalResult<'tcx> {
         let cid = GlobalId { instance, promoted: Some(promoted) };
-        let param_env = ty::ParamEnv::reveal_all();
         self.const_eval_validated(param_env.and(cid))
     }
 }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index ff64302b1e5..281cf46bdc2 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -166,6 +166,16 @@ pub struct Body<'tcx> {
 
     /// A span representing this MIR, for error reporting.
     pub span: Span,
+
+    /// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because
+    /// we'd statically know that no thing with interior mutability will ever be available to the
+    /// user without some serious unsafe code.  Now this means that our promoted is actually
+    /// &[(SOME_CELL, 42)] and the MIR using it will do the &promoted[i].1 projection because the
+    /// index may be a runtime value. Such a promoted value is illegal because it has reachable
+    /// interior mutability. This flag just makes this situation very obvious where the previous
+    /// implementation without the flag hid this situation silently.
+    /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
+    pub ignore_interior_mut_in_const_validation: bool,
 }
 
 impl<'tcx> Body<'tcx> {
@@ -202,6 +212,7 @@ impl<'tcx> Body<'tcx> {
             spread_arg: None,
             var_debug_info,
             span,
+            ignore_interior_mut_in_const_validation: false,
             control_flow_destroyed,
         }
     }
@@ -1642,9 +1653,9 @@ 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, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)]
 pub struct Place<'tcx> {
-    pub base: PlaceBase<'tcx>,
+    pub local: Local,
 
     /// projection out of a place (access a field, deref a pointer, etc)
     pub projection: &'tcx List<PlaceElem<'tcx>>,
@@ -1652,58 +1663,6 @@ pub struct Place<'tcx> {
 
 impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {}
 
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)]
-pub enum PlaceBase<'tcx> {
-    /// local variable
-    Local(Local),
-
-    /// static or static mut variable
-    Static(Box<Static<'tcx>>),
-}
-
-/// We store the normalized type to avoid requiring normalization when reading MIR
-#[derive(
-    Clone,
-    Debug,
-    PartialEq,
-    Eq,
-    PartialOrd,
-    Ord,
-    Hash,
-    RustcEncodable,
-    RustcDecodable,
-    HashStable
-)]
-pub struct Static<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub kind: StaticKind<'tcx>,
-    /// The `DefId` of the item this static was declared in. For promoted values, usually, this is
-    /// the same as the `DefId` of the `mir::Body` containing the `Place` this promoted appears in.
-    /// However, after inlining, that might no longer be the case as inlined `Place`s are copied
-    /// into the calling frame.
-    pub def_id: DefId,
-}
-
-#[derive(
-    Clone,
-    Debug,
-    PartialEq,
-    Eq,
-    PartialOrd,
-    Ord,
-    Hash,
-    HashStable,
-    RustcEncodable,
-    RustcDecodable
-)]
-pub enum StaticKind<'tcx> {
-    /// Promoted references consist of an id (`Promoted`) and the substs necessary to monomorphize
-    /// it. Usually, these substs are just the identity substs for the item. However, the inliner
-    /// will adjust these substs when it inlines a function based on the substs at the callsite.
-    Promoted(Promoted, SubstsRef<'tcx>),
-    Static,
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[derive(RustcEncodable, RustcDecodable, HashStable)]
 pub enum ProjectionElem<V, T> {
@@ -1791,14 +1750,14 @@ rustc_index::newtype_index! {
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct PlaceRef<'a, 'tcx> {
-    pub base: &'a PlaceBase<'tcx>,
+    pub local: &'a Local,
     pub projection: &'a [PlaceElem<'tcx>],
 }
 
 impl<'tcx> Place<'tcx> {
     // 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: List::empty() }
+        Place { local: RETURN_PLACE, projection: List::empty() }
     }
 
     /// Returns `true` if this `Place` contains a `Deref` projection.
@@ -1815,10 +1774,8 @@ 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.as_ref() {
-            PlaceRef { base: &PlaceBase::Local(local), projection: &[] }
-            | PlaceRef { base: &PlaceBase::Local(local), projection: &[ProjectionElem::Deref] } => {
-                Some(local)
-            }
+            PlaceRef { local, projection: &[] }
+            | PlaceRef { local, projection: &[ProjectionElem::Deref] } => Some(*local),
             _ => None,
         }
     }
@@ -1830,19 +1787,13 @@ impl<'tcx> Place<'tcx> {
     }
 
     pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
-        PlaceRef { base: &self.base, projection: &self.projection }
+        PlaceRef { local: &self.local, projection: &self.projection }
     }
 }
 
 impl From<Local> for Place<'_> {
     fn from(local: Local) -> Self {
-        Place { base: local.into(), projection: List::empty() }
-    }
-}
-
-impl From<Local> for PlaceBase<'_> {
-    fn from(local: Local) -> Self {
-        PlaceBase::Local(local)
+        Place { local, projection: List::empty() }
     }
 }
 
@@ -1853,10 +1804,8 @@ impl<'a, 'tcx> PlaceRef<'a, '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 {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] }
-            | PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] } => {
-                Some(*local)
-            }
+            PlaceRef { local, projection: [] }
+            | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(**local),
             _ => None,
         }
     }
@@ -1865,7 +1814,7 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
     /// projections, return `Some(_X)`.
     pub fn as_local(&self) -> Option<Local> {
         match self {
-            PlaceRef { base: PlaceBase::Local(l), projection: [] } => Some(*l),
+            PlaceRef { local, projection: [] } => Some(**local),
             _ => None,
         }
     }
@@ -1887,7 +1836,7 @@ impl Debug for Place<'_> {
             }
         }
 
-        write!(fmt, "{:?}", self.base)?;
+        write!(fmt, "{:?}", self.local)?;
 
         for elem in self.projection.iter() {
             match elem {
@@ -1931,22 +1880,6 @@ impl Debug for Place<'_> {
     }
 }
 
-impl Debug for PlaceBase<'_> {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        match *self {
-            PlaceBase::Local(id) => write!(fmt, "{:?}", id),
-            PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static, def_id }) => {
-                write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.def_path_str(def_id)), ty)
-            }
-            PlaceBase::Static(box self::Static {
-                ty,
-                kind: StaticKind::Promoted(promoted, _),
-                def_id: _,
-            }) => write!(fmt, "({:?}: {:?})", promoted, ty),
-        }
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Scopes
 
@@ -3007,27 +2940,11 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
 
 impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Place { base: self.base.fold_with(folder), projection: self.projection.fold_with(folder) }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.base.visit_with(visitor) || self.projection.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        match self {
-            PlaceBase::Local(local) => PlaceBase::Local(local.fold_with(folder)),
-            PlaceBase::Static(static_) => PlaceBase::Static(static_.fold_with(folder)),
-        }
+        Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match self {
-            PlaceBase::Local(local) => local.visit_with(visitor),
-            PlaceBase::Static(static_) => (**static_).visit_with(visitor),
-        }
+        self.local.visit_with(visitor) || self.projection.visit_with(visitor)
     }
 }
 
@@ -3042,42 +2959,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Static {
-            ty: self.ty.fold_with(folder),
-            kind: self.kind.fold_with(folder),
-            def_id: self.def_id,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        let Static { ty, kind, def_id: _ } = self;
-
-        ty.visit_with(visitor) || kind.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for StaticKind<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        match self {
-            StaticKind::Promoted(promoted, substs) => {
-                StaticKind::Promoted(promoted.fold_with(folder), substs.fold_with(folder))
-            }
-            StaticKind::Static => StaticKind::Static,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match self {
-            StaticKind::Promoted(promoted, substs) => {
-                promoted.visit_with(visitor) || substs.visit_with(visitor)
-            }
-            StaticKind::Static => false,
-        }
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         use crate::mir::Rvalue::*;
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 77f3ff47ff2..e2aac562cc4 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -114,7 +114,7 @@ impl<'tcx> PlaceTy<'tcx> {
 
 impl<'tcx> Place<'tcx> {
     pub fn ty_from<D>(
-        base: &PlaceBase<'tcx>,
+        local: &Local,
         projection: &[PlaceElem<'tcx>],
         local_decls: &D,
         tcx: TyCtxt<'tcx>,
@@ -124,26 +124,16 @@ impl<'tcx> Place<'tcx> {
     {
         projection
             .iter()
-            .fold(base.ty(local_decls), |place_ty, elem| place_ty.projection_ty(tcx, elem))
+            .fold(PlaceTy::from_ty(local_decls.local_decls()[*local].ty), |place_ty, elem| {
+                place_ty.projection_ty(tcx, elem)
+            })
     }
 
     pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
     where
         D: HasLocalDecls<'tcx>,
     {
-        Place::ty_from(&self.base, &self.projection, local_decls, tcx)
-    }
-}
-
-impl<'tcx> PlaceBase<'tcx> {
-    pub fn ty<D>(&self, local_decls: &D) -> PlaceTy<'tcx>
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        match self {
-            PlaceBase::Local(index) => PlaceTy::from_ty(local_decls.local_decls()[*index].ty),
-            PlaceBase::Static(data) => PlaceTy::from_ty(data.ty),
-        }
+        Place::ty_from(&self.local, &self.projection, local_decls, tcx)
     }
 }
 
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 9173c328006..4c5db1b07d2 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -164,10 +164,10 @@ macro_rules! make_mir_visitor {
             }
 
             fn visit_place_base(&mut self,
-                                base: & $($mutability)? PlaceBase<'tcx>,
+                                local: & $($mutability)? Local,
                                 context: PlaceContext,
                                 location: Location) {
-                self.super_place_base(base, context, location);
+                self.super_place_base(local, context, location);
             }
 
             visit_place_fns!($($mutability)?);
@@ -705,17 +705,10 @@ macro_rules! make_mir_visitor {
             }
 
             fn super_place_base(&mut self,
-                                place_base: & $($mutability)? PlaceBase<'tcx>,
+                                local: & $($mutability)? Local,
                                 context: PlaceContext,
                                 location: Location) {
-                match place_base {
-                    PlaceBase::Local(local) => {
-                        self.visit_local(local, context, location);
-                    }
-                    PlaceBase::Static(box Static { kind: _, ty, def_id: _ }) => {
-                        self.visit_ty(& $($mutability)? *ty, TyContext::Location(location));
-                    }
-                }
+                self.visit_local(local, context, location);
             }
 
             fn super_local_decl(&mut self,
@@ -848,7 +841,7 @@ macro_rules! visit_place_fns {
             context: PlaceContext,
             location: Location,
         ) {
-            self.visit_place_base(&mut place.base, context, location);
+            self.visit_place_base(&mut place.local, context, location);
 
             if let Some(new_projection) = self.process_projection(&place.projection) {
                 place.projection = self.tcx().intern_place_elems(&new_projection);
@@ -889,23 +882,23 @@ macro_rules! visit_place_fns {
     () => (
         fn visit_projection(
             &mut self,
-            base: &PlaceBase<'tcx>,
+            local: &Local,
             projection: &[PlaceElem<'tcx>],
             context: PlaceContext,
             location: Location,
         ) {
-            self.super_projection(base, projection, context, location);
+            self.super_projection(local, projection, context, location);
         }
 
         fn visit_projection_elem(
             &mut self,
-            base: &PlaceBase<'tcx>,
+            local: &Local,
             proj_base: &[PlaceElem<'tcx>],
             elem: &PlaceElem<'tcx>,
             context: PlaceContext,
             location: Location,
         ) {
-            self.super_projection_elem(base, proj_base, elem, context, location);
+            self.super_projection_elem(local, proj_base, elem, context, location);
         }
 
         fn super_place(
@@ -924,9 +917,9 @@ macro_rules! visit_place_fns {
                 };
             }
 
-            self.visit_place_base(&place.base, context, location);
+            self.visit_place_base(&place.local, context, location);
 
-            self.visit_projection(&place.base,
+            self.visit_projection(&place.local,
                                   &place.projection,
                                   context,
                                   location);
@@ -934,7 +927,7 @@ macro_rules! visit_place_fns {
 
         fn super_projection(
             &mut self,
-            base: &PlaceBase<'tcx>,
+            local: &Local,
             projection: &[PlaceElem<'tcx>],
             context: PlaceContext,
             location: Location,
@@ -942,13 +935,13 @@ macro_rules! visit_place_fns {
             let mut cursor = projection;
             while let [proj_base @ .., elem] = cursor {
                 cursor = proj_base;
-                self.visit_projection_elem(base, cursor, elem, context, location);
+                self.visit_projection_elem(local, cursor, elem, context, location);
             }
         }
 
         fn super_projection_elem(
             &mut self,
-            _base: &PlaceBase<'tcx>,
+            _local: &Local,
             _proj_base: &[PlaceElem<'tcx>],
             elem: &PlaceElem<'tcx>,
             _context: PlaceContext,
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index b0b6994945c..46ece6fc405 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -515,6 +515,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                             obligation.param_env,
                             def_id,
                             substs,
+                            None,
                             Some(obligation.cause.span),
                         ) {
                             Ok(_) => ProcessResult::Changed(vec![]),
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 8b66f4926e0..e96697cc7e0 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -802,8 +802,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             ty::Predicate::ConstEvaluatable(def_id, substs) => {
                 if !(obligation.param_env, substs).has_local_value() {
-                    match self.tcx().const_eval_resolve(obligation.param_env, def_id, substs, None)
-                    {
+                    match self.tcx().const_eval_resolve(
+                        obligation.param_env,
+                        def_id,
+                        substs,
+                        None,
+                        None,
+                    ) {
                         Ok(_) => Ok(EvaluatedToOk),
                         Err(_) => Ok(EvaluatedToErr),
                     }
diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs
index 551f8fde12b..2301395f557 100644
--- a/src/librustc/traits/wf.rs
+++ b/src/librustc/traits/wf.rs
@@ -359,7 +359,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     /// Pushes the obligations required for an array length to be WF
     /// into `self.out`.
     fn compute_array_len(&mut self, constant: ty::Const<'tcx>) {
-        if let ty::ConstKind::Unevaluated(def_id, substs) = constant.val {
+        if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val {
+            assert!(promoted.is_none());
+
             let obligations = self.nominal_obligations(def_id, substs);
             self.out.extend(obligations);
 
diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs
index 9b2714082f1..df1602b2ac4 100644
--- a/src/librustc/ty/codec.rs
+++ b/src/librustc/ty/codec.rs
@@ -226,11 +226,11 @@ 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 local: mir::Local = 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 })
+    Ok(mir::Place { local, projection })
 }
 
 #[inline]
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 1b0b5fc4d07..af079736db5 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -2434,7 +2434,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let mut projection = place.projection.to_vec();
         projection.push(elem);
 
-        Place { base: place.base, projection: self.intern_place_elems(&projection) }
+        Place { local: place.local, projection: self.intern_place_elems(&projection) }
     }
 
     pub fn intern_existential_predicates(
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index b9aa12b4665..4a4280ba7dc 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -219,7 +219,7 @@ impl FlagComputation {
     fn add_const(&mut self, c: &ty::Const<'_>) {
         self.add_ty(c.ty);
         match c.val {
-            ty::ConstKind::Unevaluated(_, substs) => {
+            ty::ConstKind::Unevaluated(_, substs, _) => {
                 self.add_substs(substs);
                 self.add_flags(TypeFlags::HAS_PROJECTION);
             }
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 16d89343596..8b1b2bb5865 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -841,23 +841,31 @@ pub trait PrettyPrinter<'tcx>:
 
         match (ct.val, &ct.ty.kind) {
             (_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
-            (ty::ConstKind::Unevaluated(did, substs), _) => match self.tcx().def_kind(did) {
-                Some(DefKind::Static) | Some(DefKind::Const) | Some(DefKind::AssocConst) => {
-                    p!(print_value_path(did, substs))
-                }
-                _ => {
-                    if did.is_local() {
-                        let span = self.tcx().def_span(did);
-                        if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
-                            p!(write("{}", snip))
-                        } else {
-                            p!(write("_: "), print(ct.ty))
+            (ty::ConstKind::Unevaluated(did, substs, promoted), _) => {
+                if let Some(promoted) = promoted {
+                    p!(print_value_path(did, substs));
+                    p!(write("::{:?}", promoted));
+                } else {
+                    match self.tcx().def_kind(did) {
+                        Some(DefKind::Static)
+                        | Some(DefKind::Const)
+                        | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
+                        _ => {
+                            if did.is_local() {
+                                let span = self.tcx().def_span(did);
+                                if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
+                                {
+                                    p!(write("{}", snip))
+                                } else {
+                                    p!(write("_: "), print(ct.ty))
+                                }
+                            } else {
+                                p!(write("_: "), print(ct.ty))
+                            }
                         }
-                    } else {
-                        p!(write("_: "), print(ct.ty))
                     }
                 }
-            },
+            }
             (ty::ConstKind::Infer(..), _) => p!(write("_: "), print(ct.ty)),
             (ty::ConstKind::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
             (ty::ConstKind::Value(value), _) => return self.pretty_print_const_value(value, ct.ty),
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 9472281b56f..3b9df72266f 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -568,12 +568,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
 
         // FIXME(const_generics): this is wrong, as it is a projection
         (
-            ty::ConstKind::Unevaluated(a_def_id, a_substs),
-            ty::ConstKind::Unevaluated(b_def_id, b_substs),
-        ) if a_def_id == b_def_id => {
+            ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
+            ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
+        ) if a_def_id == b_def_id && a_promoted == b_promoted => {
             let substs =
                 relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
-            Ok(ty::ConstKind::Unevaluated(a_def_id, &substs))
+            Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
         }
         _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
     };
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 5e24c843025..62e895af7f3 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -1037,8 +1037,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
         match *self {
             ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
             ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
-            ty::ConstKind::Unevaluated(did, substs) => {
-                ty::ConstKind::Unevaluated(did, substs.fold_with(folder))
+            ty::ConstKind::Unevaluated(did, substs, promoted) => {
+                ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted)
             }
             ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) => {
                 *self
@@ -1050,7 +1050,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
         match *self {
             ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
             ty::ConstKind::Param(p) => p.visit_with(visitor),
-            ty::ConstKind::Unevaluated(_, substs) => substs.visit_with(visitor),
+            ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor),
             ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
                 false
             }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index c89d045cebb..84236128482 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -9,6 +9,7 @@ use crate::infer::canonical::Canonical;
 use crate::middle::region;
 use crate::mir::interpret::ConstValue;
 use crate::mir::interpret::Scalar;
+use crate::mir::Promoted;
 use crate::ty::layout::VariantIdx;
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
@@ -2375,7 +2376,7 @@ impl<'tcx> Const<'tcx> {
 
     #[inline]
     pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
-        let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
+        let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| {
             let param_env_and_substs = param_env.with_reveal_all().and(substs);
 
             // Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
@@ -2387,11 +2388,11 @@ impl<'tcx> Const<'tcx> {
 
             // try to resolve e.g. associated constants to their definition on an impl, and then
             // evaluate the const.
-            tcx.const_eval_resolve(param_env, did, substs, None).ok()
+            tcx.const_eval_resolve(param_env, did, substs, promoted, None).ok()
         };
 
         match self.val {
-            ConstKind::Unevaluated(did, substs) => {
+            ConstKind::Unevaluated(did, substs, promoted) => {
                 // HACK(eddyb) when substs contain e.g. inference variables,
                 // attempt using identity substs instead, that will succeed
                 // when the expression doesn't depend on any parameters.
@@ -2401,12 +2402,12 @@ impl<'tcx> Const<'tcx> {
                     let identity_substs = InternalSubsts::identity_for_item(tcx, did);
                     // The `ParamEnv` needs to match the `identity_substs`.
                     let identity_param_env = tcx.param_env(did);
-                    match try_const_eval(did, identity_param_env, identity_substs) {
+                    match try_const_eval(did, identity_param_env, identity_substs, promoted) {
                         Some(ct) => ct.subst(tcx, substs),
                         None => self,
                     }
                 } else {
-                    try_const_eval(did, param_env, substs).unwrap_or(self)
+                    try_const_eval(did, param_env, substs, promoted).unwrap_or(self)
                 }
             }
             _ => self,
@@ -2470,7 +2471,7 @@ pub enum ConstKind<'tcx> {
 
     /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
     /// variants when the code is monomorphic enough for that.
-    Unevaluated(DefId, SubstsRef<'tcx>),
+    Unevaluated(DefId, SubstsRef<'tcx>, Option<Promoted>),
 
     /// Used to hold computed value.
     Value(ConstValue<'tcx>),
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 9e0dd8e067a..da08fbcf144 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -81,7 +81,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         | ty::Bound(..)
         | ty::Foreign(..) => {}
         ty::Array(ty, len) => {
-            if let ty::ConstKind::Unevaluated(_, substs) = len.val {
+            if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val {
+                assert!(promoted.is_none());
                 stack.extend(substs.types().rev());
             }
             stack.push(len.ty);
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 8d8e86de4d4..d1f70ad43bd 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -1286,9 +1286,9 @@ fn generator_layout_and_saved_local_names(
     let generator_layout = body.generator_layout.as_ref().unwrap();
     let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys);
 
-    let state_arg = mir::PlaceBase::Local(mir::Local::new(1));
+    let state_arg = mir::Local::new(1);
     for var in &body.var_debug_info {
-        if var.place.base != state_arg {
+        if var.place.local != state_arg {
             continue;
         }
         match var.place.projection[..] {
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index 0ceb44d019b..c3affd233f8 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -14,7 +14,6 @@ use rustc::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_span::DUMMY_SP;
 
 pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     fx: &FunctionCx<'a, 'tcx, Bx>,
@@ -129,17 +128,13 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
             };
             if is_consume {
                 let base_ty =
-                    mir::Place::ty_from(place_ref.base, proj_base, *self.fx.mir, cx.tcx());
+                    mir::Place::ty_from(place_ref.local, proj_base, *self.fx.mir, cx.tcx());
                 let base_ty = self.fx.monomorphize(&base_ty);
 
                 // ZSTs don't require any actual memory access.
                 let elem_ty = base_ty.projection_ty(cx.tcx(), elem).ty;
                 let elem_ty = self.fx.monomorphize(&elem_ty);
-                let span = if let mir::PlaceBase::Local(index) = place_ref.base {
-                    self.fx.mir.local_decls[*index].source_info.span
-                } else {
-                    DUMMY_SP
-                };
+                let span = self.fx.mir.local_decls[*place_ref.local].source_info.span;
                 if cx.spanned_layout_of(elem_ty, span).is_zst() {
                     return;
                 }
@@ -179,9 +174,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
                     // We use `NonUseContext::VarDebugInfo` for the base,
                     // which might not force the base local to memory,
                     // so we have to do it manually.
-                    if let mir::PlaceBase::Local(local) = place_ref.base {
-                        self.visit_local(&local, context, location);
-                    }
+                    self.visit_local(place_ref.local, context, location);
                 }
             }
 
@@ -192,7 +185,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
             }
 
             self.process_place(
-                &mir::PlaceRef { base: place_ref.base, projection: proj_base },
+                &mir::PlaceRef { local: place_ref.local, projection: proj_base },
                 base_context,
                 location,
             );
@@ -219,8 +212,8 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
                 };
             }
 
-            self.visit_place_base(place_ref.base, context, location);
-            self.visit_projection(place_ref.base, place_ref.projection, context, location);
+            self.visit_place_base(place_ref.local, context, location);
+            self.visit_projection(place_ref.local, place_ref.projection, context, location);
         }
     }
 }
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index a1d4c0c820b..9169010da88 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -10,8 +10,8 @@ use crate::traits::*;
 use crate::MemFlags;
 
 use rustc::middle::lang_items;
+use rustc::mir;
 use rustc::mir::interpret::PanicInfo;
-use rustc::mir::{self, PlaceBase, Static, StaticKind};
 use rustc::ty::layout::{self, FnAbiExt, HasTyCtxt, LayoutOf};
 use rustc::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_index::vec::Idx;
@@ -609,53 +609,17 @@ 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 {
-                            // 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) | mir::Operand::Move(place) => {
-                                if let mir::PlaceRef {
-                                    base:
-                                        &PlaceBase::Static(box Static {
-                                            kind: StaticKind::Promoted(promoted, substs),
-                                            ty,
-                                            def_id,
-                                        }),
-                                    projection: &[],
-                                } = place.as_ref()
-                                {
-                                    let c = bx.tcx().const_eval_promoted(
-                                        Instance::new(def_id, self.monomorphize(&substs)),
-                                        promoted,
-                                    );
-                                    let (llval, ty) = self.simd_shuffle_indices(
-                                        &bx,
-                                        terminator.source_info.span,
-                                        ty,
-                                        c,
-                                    );
-                                    return OperandRef {
-                                        val: Immediate(llval),
-                                        layout: bx.layout_of(ty),
-                                    };
-                                } else {
-                                    span_bug!(span, "shuffle indices must be constant");
-                                }
-                            }
-
-                            mir::Operand::Constant(constant) => {
-                                let c = self.eval_mir_constant(constant);
-                                let (llval, ty) = self.simd_shuffle_indices(
-                                    &bx,
-                                    constant.span,
-                                    constant.literal.ty,
-                                    c,
-                                );
-                                return OperandRef {
-                                    val: Immediate(llval),
-                                    layout: bx.layout_of(ty),
-                                };
-                            }
+                        if let mir::Operand::Constant(constant) = arg {
+                            let c = self.eval_mir_constant(constant);
+                            let (llval, ty) = self.simd_shuffle_indices(
+                                &bx,
+                                constant.span,
+                                constant.literal.ty,
+                                c,
+                            );
+                            return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty) };
+                        } else {
+                            span_bug!(span, "shuffle indices must be constant");
                         }
                     }
 
@@ -1147,7 +1111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         } else {
             self.codegen_place(
                 bx,
-                &mir::PlaceRef { base: &dest.base, projection: &dest.projection },
+                &mir::PlaceRef { local: &dest.local, projection: &dest.projection },
             )
         };
         if fn_ret.is_indirect() {
diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs
index f508ed90de4..3ce916d7812 100644
--- a/src/librustc_codegen_ssa/mir/constant.rs
+++ b/src/librustc_codegen_ssa/mir/constant.rs
@@ -20,7 +20,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // use `get_static` to get at their id.
             // FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics
             // always produce `&STATIC`. This may also simplify how const eval works with statics.
-            ty::ConstKind::Unevaluated(def_id, substs) if self.cx.tcx().is_static(def_id) => {
+            ty::ConstKind::Unevaluated(def_id, substs, None) if self.cx.tcx().is_static(def_id) => {
                 assert!(substs.is_empty(), "we don't support generic statics yet");
                 let static_ = bx.get_static(def_id);
                 // we treat operands referring to statics as if they were `&STATIC` instead
@@ -40,16 +40,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         constant: &mir::Constant<'tcx>,
     ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
         match constant.literal.val {
-            ty::ConstKind::Unevaluated(def_id, substs) => {
+            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
                 let substs = self.monomorphize(&substs);
                 self.cx
                     .tcx()
-                    .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, None)
+                    .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
                     .map_err(|err| {
-                        self.cx
-                            .tcx()
-                            .sess
-                            .span_err(constant.span, "erroneous constant encountered");
+                        if promoted.is_none() {
+                            self.cx
+                                .tcx()
+                                .sess
+                                .span_err(constant.span, "erroneous constant encountered");
+                        }
                         err
                     })
             }
diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs
index 6c17a01eb91..e0aec5d6dd5 100644
--- a/src/librustc_codegen_ssa/mir/debuginfo.rs
+++ b/src/librustc_codegen_ssa/mir/debuginfo.rs
@@ -258,9 +258,7 @@ pub fn per_local_var_debug_info(
     if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() {
         let mut per_local = IndexVec::from_elem(vec![], &body.local_decls);
         for var in &body.var_debug_info {
-            if let mir::PlaceBase::Local(local) = var.place.base {
-                per_local[local].push(var);
-            }
+            per_local[var.place.local].push(var);
         }
         Some(per_local)
     } else {
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index d5306965437..a155a6e78f7 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -373,44 +373,40 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> Option<OperandRef<'tcx, Bx::Value>> {
         debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
 
-        if let mir::PlaceBase::Local(index) = place_ref.base {
-            match self.locals[*index] {
-                LocalRef::Operand(Some(mut o)) => {
-                    // Moves out of scalar and scalar pair fields are trivial.
-                    for elem in place_ref.projection.iter() {
-                        match elem {
-                            mir::ProjectionElem::Field(ref f, _) => {
-                                o = o.extract_field(bx, f.index());
-                            }
-                            mir::ProjectionElem::Index(_)
-                            | mir::ProjectionElem::ConstantIndex { .. } => {
-                                // ZSTs don't require any actual memory access.
-                                // FIXME(eddyb) deduplicate this with the identical
-                                // checks in `codegen_consume` and `extract_field`.
-                                let elem = o.layout.field(bx.cx(), 0);
-                                if elem.is_zst() {
-                                    o = OperandRef::new_zst(bx, elem);
-                                } else {
-                                    return None;
-                                }
+        match self.locals[*place_ref.local] {
+            LocalRef::Operand(Some(mut o)) => {
+                // Moves out of scalar and scalar pair fields are trivial.
+                for elem in place_ref.projection.iter() {
+                    match elem {
+                        mir::ProjectionElem::Field(ref f, _) => {
+                            o = o.extract_field(bx, f.index());
+                        }
+                        mir::ProjectionElem::Index(_)
+                        | mir::ProjectionElem::ConstantIndex { .. } => {
+                            // ZSTs don't require any actual memory access.
+                            // FIXME(eddyb) deduplicate this with the identical
+                            // checks in `codegen_consume` and `extract_field`.
+                            let elem = o.layout.field(bx.cx(), 0);
+                            if elem.is_zst() {
+                                o = OperandRef::new_zst(bx, elem);
+                            } else {
+                                return None;
                             }
-                            _ => return None,
                         }
+                        _ => return None,
                     }
-
-                    Some(o)
-                }
-                LocalRef::Operand(None) => {
-                    bug!("use of {:?} before def", place_ref);
-                }
-                LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
-                    // watch out for locals that do not have an
-                    // alloca; they are handled somewhat differently
-                    None
                 }
+
+                Some(o)
+            }
+            LocalRef::Operand(None) => {
+                bug!("use of {:?} before def", place_ref);
+            }
+            LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
+                // watch out for locals that do not have an
+                // alloca; they are handled somewhat differently
+                None
             }
-        } else {
-            None
         }
     }
 
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 7399db1f2b9..5e03a35b8a6 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -9,7 +9,7 @@ use crate::MemFlags;
 use rustc::mir;
 use rustc::mir::tcx::PlaceTy;
 use rustc::ty::layout::{self, Align, HasTyCtxt, LayoutOf, TyLayout, VariantIdx};
-use rustc::ty::{self, Instance, Ty};
+use rustc::ty::{self, Ty};
 
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceRef<'tcx, V> {
@@ -37,15 +37,6 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         PlaceRef { llval, llextra: None, layout, align }
     }
 
-    fn new_thin_place<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
-        bx: &mut Bx,
-        llval: V,
-        layout: TyLayout<'tcx>,
-    ) -> PlaceRef<'tcx, V> {
-        assert!(!bx.cx().type_has_metadata(layout.ty));
-        PlaceRef { llval, llextra: None, layout, align: layout.align.abi }
-    }
-
     // FIXME(eddyb) pass something else for the name so no work is done
     // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`).
     pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
@@ -424,76 +415,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let tcx = self.cx.tcx();
 
         let result = match place_ref {
-            mir::PlaceRef { base: mir::PlaceBase::Local(index), projection: [] } => {
-                match self.locals[*index] {
-                    LocalRef::Place(place) => {
-                        return place;
-                    }
-                    LocalRef::UnsizedPlace(place) => {
-                        return bx.load_operand(place).deref(cx);
-                    }
-                    LocalRef::Operand(..) => {
-                        bug!("using operand local {:?} as place", place_ref);
-                    }
+            mir::PlaceRef { local, projection: [] } => match self.locals[**local] {
+                LocalRef::Place(place) => {
+                    return place;
                 }
-            }
-            mir::PlaceRef {
-                base:
-                    mir::PlaceBase::Static(box mir::Static {
-                        ty,
-                        kind: mir::StaticKind::Promoted(promoted, substs),
-                        def_id,
-                    }),
-                projection: [],
-            } => {
-                let instance = Instance::new(*def_id, self.monomorphize(substs));
-                let layout = cx.layout_of(self.monomorphize(&ty));
-                match bx.tcx().const_eval_promoted(instance, *promoted) {
-                    Ok(val) => match val.val {
-                        ty::ConstKind::Value(mir::interpret::ConstValue::ByRef {
-                            alloc,
-                            offset,
-                        }) => bx.cx().from_const_alloc(layout, alloc, offset),
-                        _ => bug!("promoteds should have an allocation: {:?}", val),
-                    },
-                    Err(_) => {
-                        // This is unreachable as long as runtime
-                        // and compile-time agree perfectly.
-                        // With floats that won't always be true,
-                        // so we generate a (safe) abort.
-                        bx.abort();
-                        // We still have to return a place but it doesn't matter,
-                        // this code is unreachable.
-                        let llval =
-                            bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout)));
-                        PlaceRef::new_sized(llval, layout)
-                    }
+                LocalRef::UnsizedPlace(place) => {
+                    return bx.load_operand(place).deref(cx);
                 }
-            }
-            mir::PlaceRef {
-                base:
-                    mir::PlaceBase::Static(box mir::Static {
-                        ty,
-                        kind: mir::StaticKind::Static,
-                        def_id,
-                    }),
-                projection: [],
-            } => {
-                // NB: The layout of a static may be unsized as is the case when working
-                // with a static that is an extern_type.
-                let layout = cx.layout_of(self.monomorphize(&ty));
-                let static_ = bx.get_static(*def_id);
-                PlaceRef::new_thin_place(bx, static_, layout)
-            }
-            mir::PlaceRef { base, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => {
+                LocalRef::Operand(..) => {
+                    bug!("using operand local {:?} as place", place_ref);
+                }
+            },
+            mir::PlaceRef { local, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => {
                 // Load the pointer from its location.
-                self.codegen_consume(bx, &mir::PlaceRef { base, projection: proj_base })
+                self.codegen_consume(bx, &mir::PlaceRef { local, projection: proj_base })
                     .deref(bx.cx())
             }
-            mir::PlaceRef { base, projection: [proj_base @ .., elem] } => {
+            mir::PlaceRef { local, projection: [proj_base @ .., elem] } => {
                 // FIXME turn this recursion into iteration
                 let cg_base =
-                    self.codegen_place(bx, &mir::PlaceRef { base, projection: proj_base });
+                    self.codegen_place(bx, &mir::PlaceRef { local, projection: proj_base });
 
                 match elem {
                     mir::ProjectionElem::Deref => bug!(),
@@ -558,7 +499,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
     pub fn monomorphized_place_ty(&self, place_ref: &mir::PlaceRef<'_, 'tcx>) -> Ty<'tcx> {
         let tcx = self.cx.tcx();
-        let place_ty = mir::Place::ty_from(place_ref.base, place_ref.projection, *self.mir, tcx);
+        let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, *self.mir, tcx);
         self.monomorphize(&place_ty.ty)
     }
 }
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index b66b2e4b1f7..f2a44986cc4 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -208,9 +208,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
 
             self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx);
 
-            if let mir::PlaceBase::Local(local) = borrowed_place.base {
-                self.local_map.entry(local).or_default().insert(idx);
-            }
+            self.local_map.entry(borrowed_place.local).or_default().insert(idx);
         }
 
         self.super_assign(assigned_place, rvalue, location)
diff --git a/src/librustc_mir/borrow_check/constraint_generation.rs b/src/librustc_mir/borrow_check/constraint_generation.rs
index 97de201faba..0f6a360c793 100644
--- a/src/librustc_mir/borrow_check/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/constraint_generation.rs
@@ -2,8 +2,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, PlaceRef, ProjectionElem,
-    Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
+    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue,
+    SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
 };
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::SubstsRef;
@@ -16,7 +16,6 @@ use crate::borrow_check::{
 
 pub(super) fn generate_constraints<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     liveness_constraints: &mut LivenessValues<RegionVid>,
     all_facts: &mut Option<AllFacts>,
     location_table: &LocationTable,
@@ -30,7 +29,6 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
         location_table,
         all_facts,
         body,
-        param_env,
     };
 
     for (bb, data) in body.basic_blocks().iter_enumerated() {
@@ -41,7 +39,6 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
 /// 'cg = the duration of the constraint generation process itself.
 struct ConstraintGeneration<'cg, 'cx, 'tcx> {
     infcx: &'cg InferCtxt<'cx, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     all_facts: &'cg mut Option<AllFacts>,
     location_table: &'cg LocationTable,
     liveness_constraints: &'cg mut LivenessValues<RegionVid>,
@@ -191,11 +188,8 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
             //   of the borrows are killed: the ones whose `borrowed_place`
             //   conflicts with the `place`.
             match place.as_ref() {
-                PlaceRef { base: &PlaceBase::Local(local), projection: &[] }
-                | PlaceRef {
-                    base: &PlaceBase::Local(local),
-                    projection: &[ProjectionElem::Deref],
-                } => {
+                PlaceRef { local, projection: &[] }
+                | PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
                     debug!(
                         "Recording `killed` facts for borrows of local={:?} at location={:?}",
                         local, location
@@ -205,16 +199,12 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
                         all_facts,
                         self.borrow_set,
                         self.location_table,
-                        &local,
+                        local,
                         location,
                     );
                 }
 
-                PlaceRef { base: &PlaceBase::Static(_), .. } => {
-                    // Ignore kills of static or static mut variables.
-                }
-
-                PlaceRef { base: &PlaceBase::Local(local), projection: &[.., _] } => {
+                PlaceRef { local, projection: &[.., _] } => {
                     // Kill conflicting borrows of the innermost local.
                     debug!(
                         "Recording `killed` facts for borrows of \
@@ -222,11 +212,10 @@ 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,
-                                self.param_env,
                                 self.body,
                                 &self.borrow_set.borrows[borrow_index].borrowed_place,
                                 place,
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index 7e251560a6c..08333ae423d 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -1,7 +1,7 @@
 use rustc::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
-    FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase,
-    PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
+    FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
+    ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
 };
 use rustc::traits::error_reporting::suggest_constraining_type_param;
 use rustc::ty::{self, Ty};
@@ -186,7 +186,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
 
             let ty =
-                Place::ty_from(used_place.base, used_place.projection, *self.body, self.infcx.tcx)
+                Place::ty_from(used_place.local, used_place.projection, *self.body, self.infcx.tcx)
                     .ty;
             let needs_note = match ty.kind {
                 ty::Closure(id, _) => {
@@ -597,15 +597,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // field access to a union. If we find that, then we will keep the place of the
                 // union being accessed and the field that was being accessed so we can check the
                 // second borrowed place for the same union and a access to a different field.
-                let Place { base, projection } = first_borrowed_place;
+                let Place { local, projection } = first_borrowed_place;
 
                 let mut cursor = projection.as_ref();
                 while let [proj_base @ .., elem] = cursor {
                     cursor = proj_base;
 
                     match elem {
-                        ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
-                            return Some((PlaceRef { base: base, projection: proj_base }, field));
+                        ProjectionElem::Field(field, _) if union_ty(local, proj_base).is_some() => {
+                            return Some((PlaceRef { local, projection: proj_base }, field));
                         }
                         _ => {}
                     }
@@ -615,21 +615,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             .and_then(|(target_base, target_field)| {
                 // With the place of a union and a field access into it, we traverse the second
                 // borrowed place and look for a access to a different field of the same union.
-                let Place { base, projection } = second_borrowed_place;
+                let Place { local, projection } = second_borrowed_place;
 
                 let mut cursor = projection.as_ref();
                 while let [proj_base @ .., elem] = cursor {
                     cursor = proj_base;
 
                     if let ProjectionElem::Field(field, _) = elem {
-                        if let Some(union_ty) = union_ty(base, proj_base) {
+                        if let Some(union_ty) = union_ty(local, proj_base) {
                             if field != target_field
-                                && base == target_base.base
+                                && local == target_base.local
                                 && proj_base == target_base.projection
                             {
                                 // FIXME when we avoid clone reuse describe_place closure
                                 let describe_base_place = self
-                                    .describe_place(PlaceRef { base: base, projection: proj_base })
+                                    .describe_place(PlaceRef { local, projection: proj_base })
                                     .unwrap_or_else(|| "_".to_owned());
 
                                 return Some((
@@ -686,15 +686,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let borrow_span = borrow_spans.var_or_use();
 
         assert!(root_place.projection.is_empty());
-        let proper_span = match root_place.base {
-            PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
-            _ => drop_span,
-        };
+        let proper_span = self.body.local_decls[*root_place.local].source_info.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 },
+            Place { local: root_place.local.clone(), projection: root_place_projection },
             borrow_span,
         )) {
             debug!(
@@ -705,18 +702,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
 
         self.access_place_error_reported.insert((
-            Place { base: root_place.base.clone(), projection: root_place_projection },
+            Place { local: root_place.local.clone(), projection: root_place_projection },
             borrow_span,
         ));
 
-        if let PlaceBase::Local(local) = borrow.borrowed_place.base {
-            if self.body.local_decls[local].is_ref_to_thread_local() {
-                let err = self
-                    .report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
-                err.buffer(&mut self.errors_buffer);
-                return;
-            }
-        };
+        let borrowed_local = borrow.borrowed_place.local;
+        if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
+            let err =
+                self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
+            err.buffer(&mut self.errors_buffer);
+            return;
+        }
 
         if let StorageDeadOrDrop::Destructor(dropped_ty) =
             self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
@@ -1142,12 +1138,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         } else {
             let root_place =
                 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
-            let local =
-                if let PlaceRef { base: PlaceBase::Local(local), projection: [] } = root_place {
-                    local
-                } else {
-                    bug!("try_report_cannot_return_reference_to_local: not a local")
-                };
+            let local = root_place.local;
             match self.body.local_kind(*local) {
                 LocalKind::ReturnPointer | LocalKind::Temp => {
                     ("temporary value".to_string(), "temporary value created here".to_string())
@@ -1514,7 +1505,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             [proj_base @ .., elem] => {
                 // FIXME(spastorino) make this iterate
                 let base_access = self.classify_drop_access_kind(PlaceRef {
-                    base: place.base,
+                    local: place.local,
                     projection: proj_base,
                 });
                 match elem {
@@ -1522,7 +1513,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         StorageDeadOrDrop::LocalStorageDead
                         | StorageDeadOrDrop::BoxedStorageDead => {
                             assert!(
-                                Place::ty_from(&place.base, proj_base, *self.body, tcx).ty.is_box(),
+                                Place::ty_from(&place.local, proj_base, *self.body, tcx)
+                                    .ty
+                                    .is_box(),
                                 "Drop of value behind a reference or raw pointer"
                             );
                             StorageDeadOrDrop::BoxedStorageDead
@@ -1530,7 +1523,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         StorageDeadOrDrop::Destructor(_) => base_access,
                     },
                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
-                        let base_ty = Place::ty_from(&place.base, proj_base, *self.body, tcx).ty;
+                        let base_ty = Place::ty_from(&place.local, proj_base, *self.body, tcx).ty;
                         match base_ty.kind {
                             ty::Adt(def, _) if def.has_dtor(tcx) => {
                                 // Report the outermost adt with a destructor
diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs
index c8a59331f31..3f3bdb9d36c 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mod.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs
@@ -2,8 +2,7 @@
 
 use rustc::mir::{
     AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
-    PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Static, StaticKind,
-    Terminator, TerminatorKind,
+    PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
 };
 use rustc::ty::layout::VariantIdx;
 use rustc::ty::print::Print;
@@ -169,42 +168,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         including_downcast: &IncludingDowncast,
     ) -> Result<(), ()> {
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+            PlaceRef { local, projection: [] } => {
                 self.append_local_to_string(*local, buf)?;
             }
-            PlaceRef {
-                base: PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }),
-                projection: [],
-            } => {
-                buf.push_str("promoted");
-            }
-            PlaceRef {
-                base: PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }),
-                projection: [],
-            } => {
-                buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
-            }
-            PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
-                if self.body.local_decls[local].is_ref_for_guard() =>
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if self.body.local_decls[*local].is_ref_for_guard() =>
             {
                 self.append_place_to_string(
-                    PlaceRef { base: &PlaceBase::Local(local), projection: &[] },
+                    PlaceRef { local: local, projection: &[] },
                     buf,
                     autoderef,
                     &including_downcast,
                 )?;
             }
-            PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
-                if self.body.local_decls[local].is_ref_to_static() =>
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if self.body.local_decls[*local].is_ref_to_static() =>
             {
-                let local_info = &self.body.local_decls[local].local_info;
+                let local_info = &self.body.local_decls[*local].local_info;
                 if let LocalInfo::StaticRef { def_id, .. } = *local_info {
                     buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
                 } else {
                     unreachable!();
                 }
             }
-            PlaceRef { base, projection: [proj_base @ .., elem] } => {
+            PlaceRef { local, projection: [proj_base @ .., elem] } => {
                 match elem {
                     ProjectionElem::Deref => {
                         let upvar_field_projection = self.is_upvar_field_projection(place);
@@ -220,29 +207,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             if autoderef {
                                 // FIXME turn this recursion into iteration
                                 self.append_place_to_string(
-                                    PlaceRef { base, projection: proj_base },
+                                    PlaceRef { local, projection: proj_base },
                                     buf,
                                     autoderef,
                                     &including_downcast,
                                 )?;
                             } else {
-                                match (proj_base, base) {
-                                    _ => {
-                                        buf.push_str(&"*");
-                                        self.append_place_to_string(
-                                            PlaceRef { base, projection: proj_base },
-                                            buf,
-                                            autoderef,
-                                            &including_downcast,
-                                        )?;
-                                    }
-                                }
+                                buf.push_str(&"*");
+                                self.append_place_to_string(
+                                    PlaceRef { local, projection: proj_base },
+                                    buf,
+                                    autoderef,
+                                    &including_downcast,
+                                )?;
                             }
                         }
                     }
                     ProjectionElem::Downcast(..) => {
                         self.append_place_to_string(
-                            PlaceRef { base, projection: proj_base },
+                            PlaceRef { local, projection: proj_base },
                             buf,
                             autoderef,
                             &including_downcast,
@@ -261,9 +244,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             buf.push_str(&name);
                         } else {
                             let field_name = self
-                                .describe_field(PlaceRef { base, projection: proj_base }, *field);
+                                .describe_field(PlaceRef { local, projection: proj_base }, *field);
                             self.append_place_to_string(
-                                PlaceRef { base, projection: proj_base },
+                                PlaceRef { local, projection: proj_base },
                                 buf,
                                 autoderef,
                                 &including_downcast,
@@ -275,7 +258,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         autoderef = true;
 
                         self.append_place_to_string(
-                            PlaceRef { base, projection: proj_base },
+                            PlaceRef { local, projection: proj_base },
                             buf,
                             autoderef,
                             &including_downcast,
@@ -292,7 +275,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         // then use another while the borrow is held, don't output indices details
                         // to avoid confusing the end-user
                         self.append_place_to_string(
-                            PlaceRef { base, projection: proj_base },
+                            PlaceRef { local, projection: proj_base },
                             buf,
                             autoderef,
                             &including_downcast,
@@ -323,20 +306,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String {
         // FIXME Place2 Make this work iteratively
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+            PlaceRef { local, projection: [] } => {
                 let local = &self.body.local_decls[*local];
                 self.describe_field_from_ty(&local.ty, field, None)
             }
-            PlaceRef { base: PlaceBase::Static(static_), projection: [] } => {
-                self.describe_field_from_ty(&static_.ty, field, None)
-            }
-            PlaceRef { base, projection: [proj_base @ .., elem] } => match elem {
+            PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
                 ProjectionElem::Deref => {
-                    self.describe_field(PlaceRef { base, projection: proj_base }, field)
+                    self.describe_field(PlaceRef { local, projection: proj_base }, field)
                 }
                 ProjectionElem::Downcast(_, variant_index) => {
                     let base_ty =
-                        Place::ty_from(place.base, place.projection, *self.body, self.infcx.tcx).ty;
+                        Place::ty_from(place.local, place.projection, *self.body, self.infcx.tcx)
+                            .ty;
                     self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
                 }
                 ProjectionElem::Field(_, field_type) => {
@@ -345,7 +326,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 ProjectionElem::Index(..)
                 | ProjectionElem::ConstantIndex { .. }
                 | ProjectionElem::Subslice { .. } => {
-                    self.describe_field(PlaceRef { base, projection: proj_base }, field)
+                    self.describe_field(PlaceRef { local, projection: proj_base }, field)
                 }
             },
         }
@@ -466,7 +447,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         // If we didn't find an overloaded deref or index, then assume it's a
         // built in deref and check the type of the base.
-        let base_ty = Place::ty_from(deref_base.base, deref_base.projection, *self.body, tcx).ty;
+        let base_ty = Place::ty_from(deref_base.local, deref_base.projection, *self.body, tcx).ty;
         if base_ty.is_unsafe_ptr() {
             BorrowedContentSource::DerefRawPointer
         } else if base_ty.is_mutable_ptr() {
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index 3f4204bc12f..eb6db7c145c 100644
--- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -243,9 +243,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             );
             (
                 match kind {
-                    IllegalMoveOriginKind::Static => {
-                        unreachable!();
-                    }
                     IllegalMoveOriginKind::BorrowedContent { target_place } => self
                         .report_cannot_move_from_borrowed_content(
                             original_path,
@@ -276,7 +273,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let description = if place.projection.len() == 1 {
             format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
         } else {
-            let base_static = PlaceRef { base: &place.base, projection: &[ProjectionElem::Deref] };
+            let base_static =
+                PlaceRef { local: &place.local, projection: &[ProjectionElem::Deref] };
 
             format!(
                 "`{:?}` as `{:?}` is a static item",
@@ -305,12 +303,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
         let deref_base = match deref_target_place.projection.as_ref() {
             &[ref proj_base @ .., ProjectionElem::Deref] => {
-                PlaceRef { base: &deref_target_place.base, projection: &proj_base }
+                PlaceRef { local: &deref_target_place.local, projection: &proj_base }
             }
             _ => bug!("deref_target_place is not a deref projection"),
         };
 
-        if let PlaceRef { base: PlaceBase::Local(local), projection: [] } = deref_base {
+        if let PlaceRef { local, projection: [] } = deref_base {
             let decl = &self.body.local_decls[*local];
             if decl.is_ref_for_guard() {
                 let mut err = self.cannot_move_out_of(
diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
index 595acec2f74..ae468e83ae2 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
@@ -1,5 +1,5 @@
 use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyAndCache};
-use rustc::mir::{Mutability, Place, PlaceBase, PlaceRef, ProjectionElem};
+use rustc::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
 use rustc_hir::Node;
@@ -42,7 +42,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
 
         match the_place_err {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+            PlaceRef { local, projection: [] } => {
                 item_msg = format!("`{}`", access_place_desc.unwrap());
                 if access_place.as_local().is_some() {
                     reason = ", as it is not declared as mutable".to_string();
@@ -53,11 +53,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
 
             PlaceRef {
-                base: _,
+                local,
                 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(&the_place_err.base, proj_base, *self.body, self.infcx.tcx).ty
+                    Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty
                 ));
 
                 item_msg = format!("`{}`", access_place_desc.unwrap());
@@ -69,21 +69,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 }
             }
 
-            PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
-                if self.body.local_decls[local].is_ref_for_guard() =>
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if self.body.local_decls[*local].is_ref_for_guard() =>
             {
                 item_msg = format!("`{}`", access_place_desc.unwrap());
                 reason = ", as it is immutable for the pattern guard".to_string();
             }
-            PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
-                if self.body.local_decls[local].is_ref_to_static() =>
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if self.body.local_decls[*local].is_ref_to_static() =>
             {
                 if access_place.projection.len() == 1 {
                     item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
                     reason = String::new();
                 } else {
                     item_msg = format!("`{}`", access_place_desc.unwrap());
-                    let local_info = &self.body.local_decls[local].local_info;
+                    let local_info = &self.body.local_decls[*local].local_info;
                     if let LocalInfo::StaticRef { def_id, .. } = *local_info {
                         let static_name = &self.infcx.tcx.item_name(def_id);
                         reason = format!(", as `{}` is an immutable static item", static_name);
@@ -92,8 +92,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     }
                 }
             }
-            PlaceRef { base: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
-                if the_place_err.base == &PlaceBase::Local(Local::new(1))
+            PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
+                if *the_place_err.local == Local::new(1)
                     && proj_base.is_empty()
                     && !self.upvars.is_empty()
                 {
@@ -101,7 +101,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
                     debug_assert!(is_closure_or_generator(
                         Place::ty_from(
-                            the_place_err.base,
+                            the_place_err.local,
                             the_place_err.projection,
                             *self.body,
                             self.infcx.tcx
@@ -116,7 +116,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     }
                 } else {
                     let source = self.borrowed_content_source(PlaceRef {
-                        base: the_place_err.base,
+                        local: the_place_err.local,
                         projection: proj_base,
                     });
                     let pointer_type = source.describe_for_immutable_place();
@@ -136,11 +136,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 }
             }
 
-            PlaceRef { base: PlaceBase::Static(_), .. }
-            | PlaceRef { base: _, projection: [.., ProjectionElem::Index(_)] }
-            | PlaceRef { base: _, projection: [.., ProjectionElem::ConstantIndex { .. }] }
-            | PlaceRef { base: _, projection: [.., ProjectionElem::Subslice { .. }] }
-            | PlaceRef { base: _, projection: [.., ProjectionElem::Downcast(..)] } => {
+            PlaceRef { local: _, projection: [.., ProjectionElem::Index(_)] }
+            | PlaceRef { local: _, projection: [.., ProjectionElem::ConstantIndex { .. }] }
+            | PlaceRef { local: _, projection: [.., ProjectionElem::Subslice { .. }] }
+            | PlaceRef { local: _, projection: [.., ProjectionElem::Downcast(..)] } => {
                 bug!("Unexpected immutable place.")
             }
         }
@@ -188,7 +187,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             // struct we've got a field access of (it must be a reference since there's a deref
             // after the field access).
             PlaceRef {
-                base,
+                local,
                 projection:
                     [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref],
             } => {
@@ -196,7 +195,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 if let Some((span, message)) = annotate_struct_field(
                     self.infcx.tcx,
-                    Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty,
+                    Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty,
                     field,
                 ) {
                     err.span_suggestion(
@@ -209,7 +208,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
 
             // Suggest removing a `&mut` from the use of a mutable reference.
-            PlaceRef { base: PlaceBase::Local(local), projection: [] }
+            PlaceRef { local, projection: [] }
                 if {
                     self.body
                         .local_decls
@@ -247,7 +246,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
             // We want to suggest users use `let mut` for local (user
             // variable) mutations...
-            PlaceRef { base: PlaceBase::Local(local), projection: [] }
+            PlaceRef { local, projection: [] }
                 if self.body.local_decls[*local].can_be_made_mutable() =>
             {
                 // ... but it doesn't make sense to suggest it on
@@ -268,11 +267,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
             // Also suggest adding mut for upvars
             PlaceRef {
-                base,
+                local,
                 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty
+                    Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty
                 ));
 
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
@@ -299,7 +298,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             // complete hack to approximate old AST-borrowck
             // diagnostic: if the span starts with a mutable borrow of
             // a local variable, then just suggest the user remove it.
-            PlaceRef { base: PlaceBase::Local(_), projection: [] }
+            PlaceRef { local: _, projection: [] }
                 if {
                     if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
                         snippet.starts_with("&mut ")
@@ -312,7 +311,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 err.span_label(span, "try removing `&mut` here");
             }
 
-            PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
                 if self.body.local_decls[*local].is_ref_for_guard() =>
             {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
@@ -326,7 +325,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             //
             // FIXME: can this case be generalized to work for an
             // arbitrary base for the projection?
-            PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
                 if self.body.local_decls[*local].is_user_variable() =>
             {
                 let local_decl = &self.body.local_decls[*local];
@@ -409,10 +408,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
 
             PlaceRef {
-                base,
+                local,
                 projection: [ProjectionElem::Deref],
                 // FIXME document what is this 1 magic number about
-            } if *base == PlaceBase::Local(Local::new(1)) && !self.upvars.is_empty() => {
+            } if *local == Local::new(1) && !self.upvars.is_empty() => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
                 err.span_help(
                     self.body.span,
@@ -420,7 +419,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 );
             }
 
-            PlaceRef { base: _, projection: [.., ProjectionElem::Deref] } => {
+            PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
 
                 match opt_source {
diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs
index f9ffa2138ba..bb56c11872a 100644
--- a/src/librustc_mir/borrow_check/invalidation.rs
+++ b/src/librustc_mir/borrow_check/invalidation.rs
@@ -3,7 +3,7 @@ use rustc::mir::TerminatorKind;
 use rustc::mir::{BasicBlock, Body, Location, Place, ReadOnlyBodyAndCache, Rvalue};
 use rustc::mir::{BorrowKind, Mutability, Operand};
 use rustc::mir::{Statement, StatementKind};
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 use rustc_data_structures::graph::dominators::Dominators;
 
 use crate::dataflow::indexes::BorrowIndex;
@@ -16,7 +16,6 @@ use crate::borrow_check::{
 
 pub(super) fn generate_invalidates<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     all_facts: &mut Option<AllFacts>,
     location_table: &LocationTable,
     body: ReadOnlyBodyAndCache<'_, 'tcx>,
@@ -33,7 +32,6 @@ pub(super) fn generate_invalidates<'tcx>(
         let mut ig = InvalidationGenerator {
             all_facts,
             borrow_set,
-            param_env,
             tcx,
             location_table,
             body: &body,
@@ -45,7 +43,6 @@ pub(super) fn generate_invalidates<'tcx>(
 
 struct InvalidationGenerator<'cx, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     all_facts: &'cx mut AllFacts,
     location_table: &'cx LocationTable,
     body: &'cx Body<'tcx>,
@@ -337,13 +334,11 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
         );
         let tcx = self.tcx;
         let body = self.body;
-        let param_env = self.param_env;
         let borrow_set = self.borrow_set.clone();
         let indices = self.borrow_set.borrows.indices();
         each_borrow_involving_path(
             self,
             tcx,
-            param_env,
             body,
             location,
             (sd, place),
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index fff6f036da0..7b0a103fd00 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -5,7 +5,7 @@ use rustc::lint::builtin::MUTABLE_BORROW_RESERVATION_CONFLICT;
 use rustc::lint::builtin::UNUSED_MUT;
 use rustc::mir::{
     read_only, Body, BodyAndCache, ClearCrossCrate, Local, Location, Mutability, Operand, Place,
-    PlaceBase, PlaceElem, PlaceRef, ReadOnlyBodyAndCache, Static, StaticKind,
+    PlaceElem, PlaceRef, ReadOnlyBodyAndCache,
 };
 use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
@@ -239,7 +239,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         def_id,
         &attributes,
         &dead_unwinds,
-        Borrows::new(tcx, &body, param_env, regioncx.clone(), &borrow_set),
+        Borrows::new(tcx, &body, regioncx.clone(), &borrow_set),
         |rs, i| DebugFormatted::new(&rs.location(i)),
     ));
     let flow_uninits = FlowAtLocation::new(do_dataflow(
@@ -275,7 +275,6 @@ fn do_mir_borrowck<'a, 'tcx>(
         infcx,
         body,
         mir_def_id: def_id,
-        param_env,
         move_data: &mdpe.move_data,
         location_table,
         movable_generator,
@@ -418,7 +417,6 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
     crate infcx: &'cx InferCtxt<'cx, 'tcx>,
     body: ReadOnlyBodyAndCache<'cx, 'tcx>,
     mir_def_id: DefId,
-    param_env: ty::ParamEnv<'tcx>,
     move_data: &'cx MoveData<'tcx>,
 
     /// Map from MIR `Location` to `LocationIndex`; created
@@ -817,7 +815,7 @@ enum InitializationRequiringAction {
 }
 
 struct RootPlace<'d, 'tcx> {
-    place_base: &'d PlaceBase<'tcx>,
+    place_local: &'d Local,
     place_projection: &'d [PlaceElem<'tcx>],
     is_local_mutation_allowed: LocalMutationIsAllowed,
 }
@@ -926,13 +924,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let tcx = self.infcx.tcx;
         let body = self.body;
         let body: &Body<'_> = &body;
-        let param_env = self.param_env;
         let location_table = self.location_table.start_index(location);
         let borrow_set = self.borrow_set.clone();
         each_borrow_involving_path(
             self,
             tcx,
-            param_env,
             body,
             location,
             (sd, place_span.0),
@@ -1255,8 +1251,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
                     this.used_mut_upvars.push(field);
                 }
-            } else if let PlaceBase::Local(local) = place.base {
-                this.used_mut.insert(local);
+            } else {
+                this.used_mut.insert(place.local);
             }
         };
 
@@ -1380,7 +1376,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         debug!("check_for_invalidation_at_exit({:?})", borrow);
         let place = &borrow.borrowed_place;
         let deref = [ProjectionElem::Deref];
-        let mut root_place = PlaceRef { base: &place.base, projection: &[] };
+        let mut root_place = PlaceRef { local: &place.local, projection: &[] };
 
         // FIXME(nll-rfc#40): do more precise destructor tracking here. For now
         // we just know that all locals are dropped at function exit (otherwise
@@ -1388,20 +1384,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         //
         // FIXME: allow thread-locals to borrow other thread locals?
 
-        let (might_be_alive, will_be_dropped) = match root_place.base {
-            PlaceBase::Static(_) => (true, false),
-            PlaceBase::Local(local) => {
-                if self.body.local_decls[*local].is_ref_to_thread_local() {
-                    // Thread-locals might be dropped after the function exits
-                    // We have to dereference the outer reference because
-                    // borrows don't conflict behind shared references.
-                    root_place.projection = &deref;
-                    (true, true)
-                } else {
-                    (false, self.locals_are_invalidated_at_exit)
-                }
-            }
-        };
+        let (might_be_alive, will_be_dropped) =
+            if self.body.local_decls[*root_place.local].is_ref_to_thread_local() {
+                // Thread-locals might be dropped after the function exits
+                // We have to dereference the outer reference because
+                // borrows don't conflict behind shared references.
+                root_place.projection = &deref;
+                (true, true)
+            } else {
+                (false, self.locals_are_invalidated_at_exit)
+            };
 
         if !will_be_dropped {
             debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
@@ -1412,7 +1404,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         if places_conflict::borrow_conflicts_with_place(
             self.infcx.tcx,
-            self.param_env,
             &self.body,
             place,
             borrow.kind,
@@ -1654,26 +1645,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // This code covers scenarios 1, 2, and 3.
 
         debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
-        match self.move_path_closest_to(place_span.0) {
-            Ok((prefix, mpi)) => {
-                if maybe_uninits.contains(mpi) {
-                    self.report_use_of_moved_or_uninitialized(
-                        location,
-                        desired_action,
-                        (prefix, place_span.0, place_span.1),
-                        mpi,
-                    );
-                }
-            }
-            Err(NoMovePathFound::ReachedStatic) => {
-                // Okay: we do not build MoveData for static variables
-            } // Only query longest prefix with a MovePath, not further
-              // ancestors; dataflow recurs on children when parents
-              // move (to support partial (re)inits).
-              //
-              // (I.e., querying parents breaks scenario 7; but may want
-              // to do such a query based on partial-init feature-gate.)
-        }
+        let (prefix, mpi) = self.move_path_closest_to(place_span.0);
+        if maybe_uninits.contains(mpi) {
+            self.report_use_of_moved_or_uninitialized(
+                location,
+                desired_action,
+                (prefix, place_span.0, place_span.1),
+                mpi,
+            );
+        } // Only query longest prefix with a MovePath, not further
+        // ancestors; dataflow recurs on children when parents
+        // move (to support partial (re)inits).
+        //
+        // (I.e., querying parents breaks scenario 7; but may want
+        // to do such a query based on partial-init feature-gate.)
     }
 
     /// Subslices correspond to multiple move paths, so we iterate through the
@@ -1746,9 +1731,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             place_span.0.projection
         {
             let place_ty =
-                Place::ty_from(place_span.0.base, base_proj, self.body(), self.infcx.tcx);
+                Place::ty_from(place_span.0.local, base_proj, self.body(), self.infcx.tcx);
             if let ty::Array(..) = place_ty.ty.kind {
-                let array_place = PlaceRef { base: place_span.0.base, projection: base_proj };
+                let array_place = PlaceRef { local: place_span.0.local, projection: base_proj };
                 self.check_if_subslice_element_is_moved(
                     location,
                     desired_action,
@@ -1797,12 +1782,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     fn move_path_closest_to(
         &mut self,
         place: PlaceRef<'_, 'tcx>,
-    ) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> {
+    ) -> (PlaceRef<'cx, 'tcx>, MovePathIndex) {
         match self.move_data.rev_lookup.find(place) {
             LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
-                Ok((self.move_data.move_paths[mpi].place.as_ref(), mpi))
+                (self.move_data.move_paths[mpi].place.as_ref(), mpi)
             }
-            LookupResult::Parent(None) => Err(NoMovePathFound::ReachedStatic),
+            LookupResult::Parent(None) => panic!("should have move path for every Local"),
         }
     }
 
@@ -1845,7 +1830,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     self.check_if_full_path_is_moved(
                         location, InitializationRequiringAction::Use,
                         (PlaceRef {
-                            base: &place.base,
+                            local: &place.local,
                             projection: proj_base,
                         }, span), flow_state);
                     // (base initialized; no need to
@@ -1863,13 +1848,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     // assigning to `P.f` requires `P` itself
                     // be already initialized
                     let tcx = self.infcx.tcx;
-                    let base_ty = Place::ty_from(&place.base, proj_base, self.body(), tcx).ty;
+                    let base_ty = Place::ty_from(&place.local, proj_base, self.body(), tcx).ty;
                     match base_ty.kind {
                         ty::Adt(def, _) if def.has_dtor(tcx) => {
                             self.check_if_path_or_subpath_is_moved(
                                 location, InitializationRequiringAction::Assignment,
                                 (PlaceRef {
-                                    base: &place.base,
+                                    local: &place.local,
                                     projection: proj_base,
                                 }, span), flow_state);
 
@@ -1882,21 +1867,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         // is allowed, remove this match arm.
                         ty::Adt(..) | ty::Tuple(..) => {
                             check_parent_of_field(self, location, PlaceRef {
-                                base: &place.base,
+                                local: &place.local,
                                 projection: proj_base,
                             }, span, flow_state);
 
-                            if let PlaceBase::Local(local) = place.base {
-                                // rust-lang/rust#21232,
-                                // #54499, #54986: during
-                                // period where we reject
-                                // partial initialization, do
-                                // not complain about
-                                // unnecessary `mut` on an
-                                // attempt to do a partial
-                                // initialization.
-                                self.used_mut.insert(local);
-                            }
+                            // rust-lang/rust#21232, #54499, #54986: during period where we reject
+                            // partial initialization, do not complain about unnecessary `mut` on
+                            // an attempt to do a partial initialization.
+                            self.used_mut.insert(place.local);
                         }
 
                         _ => {}
@@ -1974,7 +1952,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // of the union - we should error in that case.
                 let tcx = this.infcx.tcx;
                 if let ty::Adt(def, _) =
-                    Place::ty_from(base.base, base.projection, this.body(), tcx).ty.kind
+                    Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind
                 {
                     if def.is_union() {
                         if this.move_data.path_map[mpi].iter().any(|moi| {
@@ -2093,11 +2071,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // partial initialization, do not complain about mutability
         // errors except for actual mutation (as opposed to an attempt
         // to do a partial initialization).
-        let previously_initialized = if let PlaceBase::Local(local) = place.base {
-            self.is_local_ever_initialized(local, flow_state).is_some()
-        } else {
-            true
-        };
+        let previously_initialized =
+            self.is_local_ever_initialized(place.local, flow_state).is_some();
 
         // at this point, we have set up the error reporting state.
         if previously_initialized {
@@ -2126,11 +2101,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Adds the place into the used mutable variables set
     fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flows<'cx, 'tcx>) {
         match root_place {
-            RootPlace {
-                place_base: PlaceBase::Local(local),
-                place_projection: [],
-                is_local_mutation_allowed,
-            } => {
+            RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
                 // If the local may have been initialized, and it is now currently being
                 // mutated, then it is justified to be annotated with the `mut`
                 // keyword, since the mutation may be a possible reassignment.
@@ -2141,27 +2112,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 }
             }
             RootPlace {
-                place_base: _,
+                place_local: _,
                 place_projection: _,
                 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
             } => {}
             RootPlace {
-                place_base,
+                place_local,
                 place_projection: place_projection @ [.., _],
                 is_local_mutation_allowed: _,
             } => {
                 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
-                    base: &place_base,
-                    projection: &place_projection,
+                    local: place_local,
+                    projection: place_projection,
                 }) {
                     self.used_mut_upvars.push(field);
                 }
             }
-            RootPlace {
-                place_base: PlaceBase::Static(..),
-                place_projection: [],
-                is_local_mutation_allowed: _,
-            } => {}
         }
     }
 
@@ -2173,58 +2139,34 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         is_local_mutation_allowed: LocalMutationIsAllowed,
     ) -> Result<RootPlace<'d, 'tcx>, PlaceRef<'d, 'tcx>> {
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+            PlaceRef { local, projection: [] } => {
                 let local = &self.body.local_decls[*local];
                 match local.mutability {
                     Mutability::Not => match is_local_mutation_allowed {
                         LocalMutationIsAllowed::Yes => Ok(RootPlace {
-                            place_base: place.base,
+                            place_local: place.local,
                             place_projection: place.projection,
                             is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
                         }),
                         LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
-                            place_base: place.base,
+                            place_local: place.local,
                             place_projection: place.projection,
                             is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
                         }),
                         LocalMutationIsAllowed::No => Err(place),
                     },
                     Mutability::Mut => Ok(RootPlace {
-                        place_base: place.base,
+                        place_local: place.local,
                         place_projection: place.projection,
                         is_local_mutation_allowed,
                     }),
                 }
             }
-            // The rules for promotion are made by `qualify_consts`, there wouldn't even be a
-            // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
-            PlaceRef {
-                base: PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }),
-                projection: [],
-            } => Ok(RootPlace {
-                place_base: place.base,
-                place_projection: place.projection,
-                is_local_mutation_allowed,
-            }),
-            PlaceRef {
-                base: PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }),
-                projection: [],
-            } => {
-                if !self.infcx.tcx.is_mutable_static(*def_id) {
-                    Err(place)
-                } else {
-                    Ok(RootPlace {
-                        place_base: place.base,
-                        place_projection: place.projection,
-                        is_local_mutation_allowed,
-                    })
-                }
-            }
-            PlaceRef { base: _, projection: [proj_base @ .., elem] } => {
+            PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
                 match elem {
                     ProjectionElem::Deref => {
                         let base_ty =
-                            Place::ty_from(place.base, proj_base, self.body(), self.infcx.tcx).ty;
+                            Place::ty_from(place.local, proj_base, self.body(), self.infcx.tcx).ty;
 
                         // Check the kind of deref to decide
                         match base_ty.kind {
@@ -2243,7 +2185,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                         };
 
                                         self.is_mutable(
-                                            PlaceRef { base: place.base, projection: proj_base },
+                                            PlaceRef { local: place.local, projection: proj_base },
                                             mode,
                                         )
                                     }
@@ -2256,7 +2198,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     // `*mut` raw pointers are always mutable, regardless of
                                     // context. The users have to check by themselves.
                                     hir::Mutability::Mut => Ok(RootPlace {
-                                        place_base: place.base,
+                                        place_local: place.local,
                                         place_projection: place.projection,
                                         is_local_mutation_allowed,
                                     }),
@@ -2264,7 +2206,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             }
                             // `Box<T>` owns its content, so mutable if its location is mutable
                             _ if base_ty.is_box() => self.is_mutable(
-                                PlaceRef { base: place.base, projection: proj_base },
+                                PlaceRef { local: place.local, projection: proj_base },
                                 is_local_mutation_allowed,
                             ),
                             // Deref should only be for reference, pointers or boxes
@@ -2320,11 +2262,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     // }
                                     // ```
                                     let _ = self.is_mutable(
-                                        PlaceRef { base: place.base, projection: proj_base },
+                                        PlaceRef { local: place.local, projection: proj_base },
                                         is_local_mutation_allowed,
                                     )?;
                                     Ok(RootPlace {
-                                        place_base: place.base,
+                                        place_local: place.local,
                                         place_projection: place.projection,
                                         is_local_mutation_allowed,
                                     })
@@ -2332,7 +2274,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             }
                         } else {
                             self.is_mutable(
-                                PlaceRef { base: place.base, projection: proj_base },
+                                PlaceRef { local: place.local, projection: proj_base },
                                 is_local_mutation_allowed,
                             )
                         }
@@ -2358,7 +2300,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         match place_projection {
             [base @ .., ProjectionElem::Field(field, _ty)] => {
                 let tcx = self.infcx.tcx;
-                let base_ty = Place::ty_from(place_ref.base, base, self.body(), tcx).ty;
+                let base_ty = Place::ty_from(place_ref.local, base, self.body(), tcx).ty;
 
                 if (base_ty.is_closure() || base_ty.is_generator())
                     && (!by_ref || self.upvars[field.index()].by_ref)
@@ -2374,11 +2316,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum NoMovePathFound {
-    ReachedStatic,
-}
-
 /// The degree of overlap between 2 places for borrow-checking.
 enum Overlap {
     /// The places might partially overlap - in this case, we give
diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs
index a4c2299b3ea..151a2c4c19a 100644
--- a/src/librustc_mir/borrow_check/nll.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -231,7 +231,6 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
 
     constraint_generation::generate_constraints(
         infcx,
-        param_env,
         &mut liveness_constraints,
         &mut all_facts,
         location_table,
@@ -253,14 +252,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     );
 
     // Generate various additional constraints.
-    invalidation::generate_invalidates(
-        infcx.tcx,
-        param_env,
-        &mut all_facts,
-        location_table,
-        body,
-        borrow_set,
-    );
+    invalidation::generate_invalidates(infcx.tcx, &mut all_facts, location_table, body, borrow_set);
 
     // Dump facts if requested.
     let polonius_output = all_facts.and_then(|all_facts| {
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index 23b4799643a..deec6f386ff 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -3,8 +3,8 @@ use crate::borrow_check::places_conflict;
 use crate::borrow_check::AccessDepth;
 use crate::dataflow::indexes::BorrowIndex;
 use rustc::mir::BorrowKind;
-use rustc::mir::{BasicBlock, Body, Location, Place, PlaceBase};
-use rustc::ty::{self, TyCtxt};
+use rustc::mir::{BasicBlock, Body, Location, Place};
+use rustc::ty::TyCtxt;
 use rustc_data_structures::graph::dominators::Dominators;
 
 /// Returns `true` if the borrow represented by `kind` is
@@ -25,7 +25,6 @@ pub(super) enum Control {
 pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
     s: &mut S,
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     _location: Location,
     access_place: (AccessDepth, &Place<'tcx>),
@@ -48,7 +47,6 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
 
         if places_conflict::borrow_conflicts_with_place(
             tcx,
-            param_env,
             body,
             &borrowed.borrowed_place,
             borrowed.kind,
@@ -133,11 +131,7 @@ pub(super) fn is_active<'tcx>(
 /// Determines if a given borrow is borrowing local data
 /// This is called for all Yield expressions on movable generators
 pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool {
-    match place.base {
-        PlaceBase::Static(_) => false,
-
-        // Reborrow of already borrowed data is ignored
-        // Any errors will be caught on the initial borrow
-        PlaceBase::Local(_) => !place.is_indirect(),
-    }
+    // Reborrow of already borrowed data is ignored
+    // Any errors will be caught on the initial borrow
+    !place.is_indirect()
 }
diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs
index 91ab314e2b9..ac02da26615 100644
--- a/src/librustc_mir/borrow_check/place_ext.rs
+++ b/src/librustc_mir/borrow_check/place_ext.rs
@@ -1,6 +1,6 @@
 use crate::borrow_check::borrow_set::LocalsStateAtExit;
 use rustc::mir::ProjectionElem;
-use rustc::mir::{Body, Mutability, Place, PlaceBase};
+use rustc::mir::{Body, Mutability, Place};
 use rustc::ty::{self, TyCtxt};
 use rustc_hir as hir;
 
@@ -25,41 +25,35 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
         body: &Body<'tcx>,
         locals_state_at_exit: &LocalsStateAtExit,
     ) -> bool {
-        let local = match self.base {
-            // If a local variable is immutable, then we only need to track borrows to guard
-            // against two kinds of errors:
-            // * The variable being dropped while still borrowed (e.g., because the fn returns
-            //   a reference to a local variable)
-            // * The variable being moved while still borrowed
-            //
-            // In particular, the variable cannot be mutated -- the "access checks" will fail --
-            // so we don't have to worry about mutation while borrowed.
-            PlaceBase::Local(local) => match locals_state_at_exit {
-                LocalsStateAtExit::AllAreInvalidated => local,
-                LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
-                    let ignore = !has_storage_dead_or_moved.contains(local)
-                        && body.local_decls[local].mutability == Mutability::Not;
-                    debug!("ignore_borrow: local {:?} => {:?}", local, ignore);
-                    if ignore {
-                        return true;
-                    } else {
-                        local
-                    }
-                }
-            },
-            PlaceBase::Static(_) => return true,
-        };
+        // If a local variable is immutable, then we only need to track borrows to guard
+        // against two kinds of errors:
+        // * The variable being dropped while still borrowed (e.g., because the fn returns
+        //   a reference to a local variable)
+        // * The variable being moved while still borrowed
+        //
+        // In particular, the variable cannot be mutated -- the "access checks" will fail --
+        // so we don't have to worry about mutation while borrowed.
+        if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } =
+            locals_state_at_exit
+        {
+            let ignore = !has_storage_dead_or_moved.contains(self.local)
+                && body.local_decls[self.local].mutability == Mutability::Not;
+            debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore);
+            if ignore {
+                return true;
+            }
+        }
 
         for (i, elem) in self.projection.iter().enumerate() {
             let proj_base = &self.projection[..i];
 
             if *elem == ProjectionElem::Deref {
-                let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty;
+                let ty = Place::ty_from(&self.local, proj_base, body, tcx).ty;
                 match ty.kind {
                     ty::Ref(_, _, hir::Mutability::Not) if i == 0 => {
                         // For references to thread-local statics, we do need
                         // to track the borrow.
-                        if body.local_decls[local].is_ref_to_thread_local() {
+                        if body.local_decls[self.local].is_ref_to_thread_local() {
                             continue;
                         }
                         return true;
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index 64103719fe9..b95d1af11ad 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -1,9 +1,7 @@
 use crate::borrow_check::ArtificialField;
 use crate::borrow_check::Overlap;
 use crate::borrow_check::{AccessDepth, Deep, Shallow};
-use rustc::mir::{
-    Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind,
-};
+use rustc::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem};
 use rustc::ty::{self, TyCtxt};
 use rustc_hir as hir;
 use std::cmp::max;
@@ -25,7 +23,6 @@ crate enum PlaceConflictBias {
 /// dataflow).
 crate fn places_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     borrow_place: &Place<'tcx>,
     access_place: &Place<'tcx>,
@@ -33,7 +30,6 @@ crate fn places_conflict<'tcx>(
 ) -> bool {
     borrow_conflicts_with_place(
         tcx,
-        param_env,
         body,
         borrow_place,
         BorrowKind::Mut { allow_two_phase_borrow: true },
@@ -49,7 +45,6 @@ crate fn places_conflict<'tcx>(
 /// order to make the conservative choice and preserve soundness.
 pub(super) fn borrow_conflicts_with_place<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     borrow_place: &Place<'tcx>,
     borrow_kind: BorrowKind,
@@ -70,21 +65,11 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
         }
     }
 
-    place_components_conflict(
-        tcx,
-        param_env,
-        body,
-        borrow_place,
-        borrow_kind,
-        access_place,
-        access,
-        bias,
-    )
+    place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias)
 }
 
 fn place_components_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     borrow_place: &Place<'tcx>,
     borrow_kind: BorrowKind,
@@ -134,10 +119,10 @@ fn place_components_conflict<'tcx>(
     //    and either equal or disjoint.
     //  - If we did run out of access, the borrow can access a part of it.
 
-    let borrow_base = &borrow_place.base;
-    let access_base = access_place.base;
+    let borrow_local = &borrow_place.local;
+    let access_local = access_place.local;
 
-    match place_base_conflict(tcx, param_env, borrow_base, access_base) {
+    match place_base_conflict(borrow_local, access_local) {
         Overlap::Arbitrary => {
             bug!("Two base can't return Arbitrary");
         }
@@ -176,7 +161,7 @@ fn place_components_conflict<'tcx>(
         match place_projection_conflict(
             tcx,
             body,
-            borrow_base,
+            borrow_local,
             borrow_proj_base,
             borrow_c,
             access_c,
@@ -223,7 +208,7 @@ fn place_components_conflict<'tcx>(
             // access cares about.
 
             let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
-            let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty;
+            let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty;
 
             match (elem, &base_ty.kind, access) {
                 (_, _, Shallow(Some(ArtificialField::ArrayLength)))
@@ -308,68 +293,15 @@ fn place_components_conflict<'tcx>(
 // Given that the bases of `elem1` and `elem2` are always either equal
 // or disjoint (and have the same type!), return the overlap situation
 // between `elem1` and `elem2`.
-fn place_base_conflict<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    elem1: &PlaceBase<'tcx>,
-    elem2: &PlaceBase<'tcx>,
-) -> Overlap {
-    match (elem1, elem2) {
-        (PlaceBase::Local(l1), PlaceBase::Local(l2)) => {
-            if l1 == l2 {
-                // the same local - base case, equal
-                debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL");
-                Overlap::EqualOrDisjoint
-            } else {
-                // different locals - base case, disjoint
-                debug!("place_element_conflict: DISJOINT-LOCAL");
-                Overlap::Disjoint
-            }
-        }
-        (PlaceBase::Static(s1), PlaceBase::Static(s2)) => {
-            match (&s1.kind, &s2.kind) {
-                (StaticKind::Static, StaticKind::Static) => {
-                    if s1.def_id != s2.def_id {
-                        debug!("place_element_conflict: DISJOINT-STATIC");
-                        Overlap::Disjoint
-                    } else if tcx.is_mutable_static(s1.def_id) {
-                        // We ignore mutable statics - they can only be unsafe code.
-                        debug!("place_element_conflict: IGNORE-STATIC-MUT");
-                        Overlap::Disjoint
-                    } else {
-                        debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC");
-                        Overlap::EqualOrDisjoint
-                    }
-                }
-                (StaticKind::Promoted(promoted_1, _), StaticKind::Promoted(promoted_2, _)) => {
-                    if promoted_1 == promoted_2 {
-                        if let ty::Array(_, len) = s1.ty.kind {
-                            if let Some(0) = len.try_eval_usize(tcx, param_env) {
-                                // Ignore conflicts with promoted [T; 0].
-                                debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
-                                return Overlap::Disjoint;
-                            }
-                        }
-                        // the same promoted - base case, equal
-                        debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
-                        Overlap::EqualOrDisjoint
-                    } else {
-                        // different promoteds - base case, disjoint
-                        debug!("place_element_conflict: DISJOINT-PROMOTED");
-                        Overlap::Disjoint
-                    }
-                }
-                (_, _) => {
-                    debug!("place_element_conflict: DISJOINT-STATIC-PROMOTED");
-                    Overlap::Disjoint
-                }
-            }
-        }
-        (PlaceBase::Local(_), PlaceBase::Static(_))
-        | (PlaceBase::Static(_), PlaceBase::Local(_)) => {
-            debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
-            Overlap::Disjoint
-        }
+fn place_base_conflict(l1: &Local, l2: &Local) -> Overlap {
+    if l1 == l2 {
+        // the same local - base case, equal
+        debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL");
+        Overlap::EqualOrDisjoint
+    } else {
+        // different locals - base case, disjoint
+        debug!("place_element_conflict: DISJOINT-LOCAL");
+        Overlap::Disjoint
     }
 }
 
@@ -379,7 +311,7 @@ fn place_base_conflict<'tcx>(
 fn place_projection_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    pi1_base: &PlaceBase<'tcx>,
+    pi1_local: &Local,
     pi1_proj_base: &[PlaceElem<'tcx>],
     pi1_elem: &PlaceElem<'tcx>,
     pi2_elem: &PlaceElem<'tcx>,
@@ -397,7 +329,7 @@ fn place_projection_conflict<'tcx>(
                 debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
                 Overlap::EqualOrDisjoint
             } else {
-                let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty;
+                let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
                 match ty.kind {
                     ty::Adt(def, _) if def.is_union() => {
                         // Different fields of a union, we are basically stuck.
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
index 1e88f696f23..31bee460fa0 100644
--- a/src/librustc_mir/borrow_check/prefixes.rs
+++ b/src/librustc_mir/borrow_check/prefixes.rs
@@ -9,7 +9,7 @@
 
 use super::MirBorrowckCtxt;
 
-use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache};
+use rustc::mir::{Place, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache};
 use rustc::ty::{self, TyCtxt};
 use rustc_hir as hir;
 
@@ -19,7 +19,7 @@ pub trait IsPrefixOf<'cx, 'tcx> {
 
 impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
     fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
-        self.base == other.base
+        self.local == other.local
             && self.projection.len() <= other.projection.len()
             && self.projection == &other.projection[..self.projection.len()]
     }
@@ -69,39 +69,23 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
 
         'cursor: loop {
             match &cursor {
-                PlaceRef {
-                    base: PlaceBase::Local(_),
-                    projection: [],
-                }
-                | // search yielded this leaf
-                PlaceRef {
-                    base: PlaceBase::Static(_),
-                    projection: [],
-                } => {
+                PlaceRef { local: _, projection: [] } => {
                     self.next = None;
                     return Some(cursor);
                 }
-                PlaceRef {
-                    base: _,
-                    projection: [proj_base @ .., elem],
-                } => {
+                PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
                     match elem {
                         ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
                             // FIXME: add union handling
-                            self.next = Some(PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            });
+                            self.next =
+                                Some(PlaceRef { local: cursor.local, projection: proj_base });
                             return Some(cursor);
                         }
-                        ProjectionElem::Downcast(..) |
-                        ProjectionElem::Subslice { .. } |
-                        ProjectionElem::ConstantIndex { .. } |
-                        ProjectionElem::Index(_) => {
-                            cursor = PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            };
+                        ProjectionElem::Downcast(..)
+                        | ProjectionElem::Subslice { .. }
+                        | ProjectionElem::ConstantIndex { .. }
+                        | ProjectionElem::Index(_) => {
+                            cursor = PlaceRef { local: cursor.local, projection: proj_base };
                             continue 'cursor;
                         }
                         ProjectionElem::Deref => {
@@ -122,10 +106,8 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
                         PrefixSet::All => {
                             // All prefixes: just blindly enqueue the base
                             // of the projection.
-                            self.next = Some(PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            });
+                            self.next =
+                                Some(PlaceRef { local: cursor.local, projection: proj_base });
                             return Some(cursor);
                         }
                         PrefixSet::Supporting => {
@@ -138,37 +120,24 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
                     // derefs, except we stop at the deref of a shared
                     // reference.
 
-                    let ty = Place::ty_from(cursor.base, proj_base, *self.body, self.tcx).ty;
+                    let ty = Place::ty_from(cursor.local, proj_base, *self.body, self.tcx).ty;
                     match ty.kind {
-                        ty::RawPtr(_) |
-                        ty::Ref(
-                            _, /*rgn*/
-                            _, /*ty*/
-                            hir::Mutability::Not
-                            ) => {
+                        ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
                             // don't continue traversing over derefs of raw pointers or shared
                             // borrows.
                             self.next = None;
                             return Some(cursor);
                         }
 
-                        ty::Ref(
-                            _, /*rgn*/
-                            _, /*ty*/
-                            hir::Mutability::Mut,
-                            ) => {
-                            self.next = Some(PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            });
+                        ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
+                            self.next =
+                                Some(PlaceRef { local: cursor.local, projection: proj_base });
                             return Some(cursor);
                         }
 
                         ty::Adt(..) if ty.is_box() => {
-                            self.next = Some(PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            });
+                            self.next =
+                                Some(PlaceRef { local: cursor.local, projection: proj_base });
                             return Some(cursor);
                         }
 
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index b1df198406d..947bbef4379 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -310,17 +310,54 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                 );
             }
         } else {
-            if let ty::ConstKind::Unevaluated(def_id, substs) = constant.literal.val {
-                if let Err(terr) = self.cx.fully_perform_op(
-                    location.to_locations(),
-                    ConstraintCategory::Boring,
-                    self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
-                        constant.literal.ty,
-                        def_id,
-                        UserSubsts { substs, user_self_ty: None },
-                    )),
-                ) {
-                    span_mirbug!(self, constant, "bad constant type {:?} ({:?})", constant, terr);
+            if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val {
+                if let Some(promoted) = promoted {
+                    let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
+                                     promoted: &ReadOnlyBodyAndCache<'_, 'tcx>,
+                                     ty,
+                                     san_ty| {
+                        if let Err(terr) = verifier.cx.eq_types(
+                            san_ty,
+                            ty,
+                            location.to_locations(),
+                            ConstraintCategory::Boring,
+                        ) {
+                            span_mirbug!(
+                                verifier,
+                                promoted,
+                                "bad promoted type ({:?}: {:?}): {:?}",
+                                ty,
+                                san_ty,
+                                terr
+                            );
+                        };
+                    };
+
+                    if !self.errors_reported {
+                        let promoted_body = self.promoted[promoted];
+                        self.sanitize_promoted(promoted_body, location);
+
+                        let promoted_ty = promoted_body.return_ty();
+                        check_err(self, &promoted_body, ty, promoted_ty);
+                    }
+                } else {
+                    if let Err(terr) = self.cx.fully_perform_op(
+                        location.to_locations(),
+                        ConstraintCategory::Boring,
+                        self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
+                            constant.literal.ty,
+                            def_id,
+                            UserSubsts { substs, user_self_ty: None },
+                        )),
+                    ) {
+                        span_mirbug!(
+                            self,
+                            constant,
+                            "bad constant type {:?} ({:?})",
+                            constant,
+                            terr
+                        );
+                    }
                 }
             }
             if let ty::FnDef(def_id, substs) = constant.literal.ty.kind {
@@ -428,83 +465,32 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
     ) -> PlaceTy<'tcx> {
         debug!("sanitize_place: {:?}", place);
 
-        let mut place_ty = match &place.base {
-            PlaceBase::Local(index) => PlaceTy::from_ty(self.body.local_decls[*index].ty),
-            PlaceBase::Static(box Static { kind, ty, def_id }) => {
-                let san_ty = self.sanitize_type(place, ty);
-                let check_err =
-                    |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, place: &Place<'tcx>, ty, san_ty| {
-                        if let Err(terr) = verifier.cx.eq_types(
-                            san_ty,
-                            ty,
-                            location.to_locations(),
-                            ConstraintCategory::Boring,
-                        ) {
-                            span_mirbug!(
-                                verifier,
-                                place,
-                                "bad promoted type ({:?}: {:?}): {:?}",
-                                ty,
-                                san_ty,
-                                terr
-                            );
-                        };
-                    };
-                match kind {
-                    StaticKind::Promoted(promoted, _) => {
-                        if !self.errors_reported {
-                            let promoted_body_cache = self.promoted[*promoted];
-                            self.sanitize_promoted(promoted_body_cache, location);
-
-                            let promoted_ty = promoted_body_cache.return_ty();
-                            check_err(self, place, promoted_ty, san_ty);
-                        }
-                    }
-                    StaticKind::Static => {
-                        let ty = self.tcx().type_of(*def_id);
-                        let ty = self.cx.normalize(ty, location);
-
-                        check_err(self, place, ty, san_ty);
-                    }
-                }
-                PlaceTy::from_ty(san_ty)
-            }
-        };
+        let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
 
         if place.projection.is_empty() {
             if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
-                let is_promoted = match place.as_ref() {
-                    PlaceRef {
-                        base: &PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }),
-                        projection: &[],
-                    } => true,
-                    _ => false,
+                let tcx = self.tcx();
+                let trait_ref = ty::TraitRef {
+                    def_id: tcx.lang_items().copy_trait().unwrap(),
+                    substs: tcx.mk_substs_trait(place_ty.ty, &[]),
                 };
 
-                if !is_promoted {
-                    let tcx = self.tcx();
-                    let trait_ref = ty::TraitRef {
-                        def_id: tcx.lang_items().copy_trait().unwrap(),
-                        substs: tcx.mk_substs_trait(place_ty.ty, &[]),
-                    };
-
-                    // To have a `Copy` operand, the type `T` of the
-                    // value must be `Copy`. Note that we prove that `T: Copy`,
-                    // rather than using the `is_copy_modulo_regions`
-                    // test. This is important because
-                    // `is_copy_modulo_regions` ignores the resulting region
-                    // obligations and assumes they pass. This can result in
-                    // bounds from `Copy` impls being unsoundly ignored (e.g.,
-                    // #29149). Note that we decide to use `Copy` before knowing
-                    // whether the bounds fully apply: in effect, the rule is
-                    // that if a value of some type could implement `Copy`, then
-                    // it must.
-                    self.cx.prove_trait_ref(
-                        trait_ref,
-                        location.to_locations(),
-                        ConstraintCategory::CopyBound,
-                    );
-                }
+                // To have a `Copy` operand, the type `T` of the
+                // value must be `Copy`. Note that we prove that `T: Copy`,
+                // rather than using the `is_copy_modulo_regions`
+                // test. This is important because
+                // `is_copy_modulo_regions` ignores the resulting region
+                // obligations and assumes they pass. This can result in
+                // bounds from `Copy` impls being unsoundly ignored (e.g.,
+                // #29149). Note that we decide to use `Copy` before knowing
+                // whether the bounds fully apply: in effect, the rule is
+                // that if a value of some type could implement `Copy`, then
+                // it must.
+                self.cx.prove_trait_ref(
+                    trait_ref,
+                    location.to_locations(),
+                    ConstraintCategory::CopyBound,
+                );
             }
         }
 
@@ -2401,7 +2387,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             match elem {
                 ProjectionElem::Deref => {
                     let tcx = self.infcx.tcx;
-                    let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty;
+                    let base_ty = Place::ty_from(&borrowed_place.local, proj_base, body, tcx).ty;
 
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
                     match base_ty.kind {
diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs
index 608a2436bf3..5e4eebb771f 100644
--- a/src/librustc_mir/borrow_check/used_muts.rs
+++ b/src/librustc_mir/borrow_check/used_muts.rs
@@ -1,5 +1,5 @@
 use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind};
+use rustc::mir::{Local, Location, Place, Statement, StatementKind, TerminatorKind};
 
 use rustc_data_structures::fx::FxHashSet;
 
@@ -57,9 +57,7 @@ impl GatherUsedMutsVisitor<'_, '_, '_> {
         // be those that were never initialized - we will consider those as being used as
         // they will either have been removed by unreachable code optimizations; or linted
         // as unused variables.
-        if let PlaceBase::Local(local) = into.base {
-            let _ = self.never_initialized_mut_locals.remove(&local);
-        }
+        self.never_initialized_mut_locals.remove(&into.local);
     }
 }
 
@@ -80,13 +78,11 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
     fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location) {
         match &statement.kind {
             StatementKind::Assign(box (into, _)) => {
-                if let PlaceBase::Local(local) = into.base {
-                    debug!(
-                        "visit_statement: statement={:?} local={:?} \
-                         never_initialized_mut_locals={:?}",
-                        statement, local, self.never_initialized_mut_locals
-                    );
-                }
+                debug!(
+                    "visit_statement: statement={:?} local={:?} \
+                    never_initialized_mut_locals={:?}",
+                    statement, into.local, self.never_initialized_mut_locals
+                );
                 self.remove_never_initialized_mut_locals(into);
             }
             _ => {}
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 29eac5e4b3f..eb2e87f4a2d 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -20,13 +20,13 @@ use rustc_index::vec::Idx;
 /// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
 #[derive(Clone)]
 struct PlaceBuilder<'tcx> {
-    base: PlaceBase<'tcx>,
+    local: Local,
     projection: Vec<PlaceElem<'tcx>>,
 }
 
 impl PlaceBuilder<'tcx> {
     fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
-        Place { base: self.base, projection: tcx.intern_place_elems(&self.projection) }
+        Place { local: self.local, projection: tcx.intern_place_elems(&self.projection) }
     }
 
     fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
@@ -49,13 +49,7 @@ impl PlaceBuilder<'tcx> {
 
 impl From<Local> for PlaceBuilder<'tcx> {
     fn from(local: Local) -> Self {
-        Self { base: local.into(), projection: Vec::new() }
-    }
-}
-
-impl From<PlaceBase<'tcx>> for PlaceBuilder<'tcx> {
-    fn from(base: PlaceBase<'tcx>) -> Self {
-        Self { base, projection: Vec::new() }
+        Self { local, projection: Vec::new() }
     }
 }
 
@@ -370,7 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ) {
         let tcx = self.hir.tcx();
         let place_ty =
-            Place::ty_from(&base_place.base, &base_place.projection, &self.local_decls, tcx);
+            Place::ty_from(&base_place.local, &base_place.projection, &self.local_decls, tcx);
         if let ty::Slice(_) = place_ty.ty.kind {
             // We need to create fake borrows to ensure that the bounds
             // check that we just did stays valid. Since we can't assign to
@@ -380,7 +374,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 match elem {
                     ProjectionElem::Deref => {
                         let fake_borrow_deref_ty = Place::ty_from(
-                            &base_place.base,
+                            &base_place.local,
                             &base_place.projection[..idx],
                             &self.local_decls,
                             tcx,
@@ -398,14 +392,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             Rvalue::Ref(
                                 tcx.lifetimes.re_erased,
                                 BorrowKind::Shallow,
-                                Place { base: base_place.base.clone(), projection },
+                                Place { local: base_place.local.clone(), projection },
                             ),
                         );
                         fake_borrow_temps.push(fake_borrow_temp);
                     }
                     ProjectionElem::Index(_) => {
                         let index_ty = Place::ty_from(
-                            &base_place.base,
+                            &base_place.local,
                             &base_place.projection[..idx],
                             &self.local_decls,
                             tcx,
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 34b0cbf3b25..6f7b7258b5a 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -393,26 +393,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let arg_place = unpack!(block = this.as_place(block, arg));
 
         let mutability = match arg_place.as_ref() {
-            PlaceRef { base: &PlaceBase::Local(local), projection: &[] } => {
-                this.local_decls[local].mutability
-            }
-            PlaceRef { base: &PlaceBase::Local(local), projection: &[ProjectionElem::Deref] } => {
+            PlaceRef { local, projection: &[] } => this.local_decls[*local].mutability,
+            PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
                 debug_assert!(
-                    this.local_decls[local].is_ref_for_guard(),
+                    this.local_decls[*local].is_ref_for_guard(),
                     "Unexpected capture place",
                 );
-                this.local_decls[local].mutability
+                this.local_decls[*local].mutability
             }
             PlaceRef {
-                ref base,
+                ref local,
                 projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             }
             | PlaceRef {
-                ref base,
+                ref local,
                 projection:
                     &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref],
             } => {
-                let place = PlaceRef { base, projection: proj_base };
+                let place = PlaceRef { local, projection: proj_base };
 
                 // Not projected from the implicit `self` in a closure.
                 debug_assert!(
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 7eea90befb0..1dcd29d9232 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -890,7 +890,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let proj_base = &source.projection[..i];
 
                     fake_borrows.insert(Place {
-                        base: source.base.clone(),
+                        local: source.local.clone(),
                         projection: self.hir.tcx().intern_place_elems(proj_base),
                     });
                 }
@@ -1241,7 +1241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // Insert a shallow borrow after a deref. For other
                     // projections the borrow of prefix_cursor will
                     // conflict with any mutation of base.
-                    all_fake_borrows.push(PlaceRef { base: &place.base, projection: proj_base });
+                    all_fake_borrows.push(PlaceRef { local: &place.local, projection: proj_base });
                 }
             }
 
@@ -1258,7 +1258,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             .into_iter()
             .map(|matched_place_ref| {
                 let matched_place = Place {
-                    base: matched_place_ref.base.clone(),
+                    local: matched_place_ref.local.clone(),
                     projection: tcx.intern_place_elems(matched_place_ref.projection),
                 };
                 let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index d6d22db9ff2..d4813d8ab68 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -834,7 +834,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             span: tcx_hir.span(var_id),
                         },
                         place: Place {
-                            base: closure_env_arg.into(),
+                            local: closure_env_arg.into(),
                             projection: tcx.intern_place_elems(&projs),
                         },
                     });
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 7b2ce7f9ac7..eb89553b770 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -52,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>(
 
     let loc_ty = tcx.caller_location_ty();
     let loc_place = ecx.alloc_caller_location(file, line, col);
-    intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
+    intern_const_alloc_recursive(&mut ecx, None, loc_place, false).unwrap();
     let loc_const = ty::Const {
         ty: loc_ty,
         val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())),
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index 53f3b539bda..d260a6808d1 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -56,7 +56,12 @@ fn eval_body_using_ecx<'mir, 'tcx>(
     ecx.run()?;
 
     // Intern the result
-    intern_const_alloc_recursive(ecx, tcx.static_mutability(cid.instance.def_id()), ret)?;
+    intern_const_alloc_recursive(
+        ecx,
+        tcx.static_mutability(cid.instance.def_id()),
+        ret,
+        body.ignore_interior_mut_in_const_validation,
+    )?;
 
     debug!("eval_body_using_ecx done: {:?}", *ret);
     Ok(ret)
@@ -171,9 +176,14 @@ fn validate_and_turn_into_const<'tcx>(
     let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static);
     let val = (|| {
         let mplace = ecx.raw_const_to_mplace(constant)?;
-        let mut ref_tracking = RefTracking::new(mplace);
-        while let Some((mplace, path)) = ref_tracking.todo.pop() {
-            ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
+
+        // FIXME do not validate promoteds until a decision on
+        // https://github.com/rust-lang/rust/issues/67465 is made
+        if cid.promoted.is_none() {
+            let mut ref_tracking = RefTracking::new(mplace);
+            while let Some((mplace, path)) = ref_tracking.todo.pop() {
+                ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
+            }
         }
         // Now that we validated, turn this into a proper constant.
         // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides
diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
index 65976908f59..63834d0ecda 100644
--- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs
+++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
@@ -86,10 +86,7 @@ struct BorrowedLocalsVisitor<'gk> {
 }
 
 fn find_local(place: &Place<'_>) -> Option<Local> {
-    match place.base {
-        PlaceBase::Local(local) if !place.is_indirect() => Some(local),
-        _ => None,
-    }
+    if !place.is_indirect() { Some(place.local) } else { None }
 }
 
 impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> {
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 8d51cb23912..f94ee67f2be 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -1,6 +1,6 @@
-use rustc::mir::{self, Body, Location, Place, PlaceBase};
+use rustc::mir::{self, Body, Location, Place};
 use rustc::ty::RegionVid;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
@@ -30,7 +30,6 @@ rustc_index::newtype_index! {
 pub struct Borrows<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
 
     borrow_set: Rc<BorrowSet<'tcx>>,
     borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
@@ -134,7 +133,6 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
     crate fn new(
         tcx: TyCtxt<'tcx>,
         body: &'a Body<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
         nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
         borrow_set: &Rc<BorrowSet<'tcx>>,
     ) -> Self {
@@ -156,7 +154,6 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
         Borrows {
             tcx,
             body,
-            param_env,
             borrow_set: borrow_set.clone(),
             borrows_out_of_scope_at_location,
             _nonlexical_regioncx: nonlexical_regioncx,
@@ -198,37 +195,34 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
     fn kill_borrows_on_place(&self, trans: &mut GenKillSet<BorrowIndex>, place: &Place<'tcx>) {
         debug!("kill_borrows_on_place: place={:?}", place);
 
-        if let PlaceBase::Local(local) = place.base {
-            let other_borrows_of_local =
-                self.borrow_set.local_map.get(&local).into_iter().flat_map(|bs| bs.into_iter());
+        let other_borrows_of_local =
+            self.borrow_set.local_map.get(&place.local).into_iter().flat_map(|bs| bs.into_iter());
 
-            // If the borrowed place is a local with no projections, all other borrows of this
-            // local must conflict. This is purely an optimization so we don't have to call
-            // `places_conflict` for every borrow.
-            if place.projection.is_empty() {
-                if !self.body.local_decls[local].is_ref_to_static() {
-                    trans.kill_all(other_borrows_of_local);
-                }
-                return;
+        // If the borrowed place is a local with no projections, all other borrows of this
+        // local must conflict. This is purely an optimization so we don't have to call
+        // `places_conflict` for every borrow.
+        if place.projection.is_empty() {
+            if !self.body.local_decls[place.local].is_ref_to_static() {
+                trans.kill_all(other_borrows_of_local);
             }
-
-            // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
-            // pair of array indices are unequal, so that when `places_conflict` returns true, we
-            // will be assured that two places being compared definitely denotes the same sets of
-            // locations.
-            let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| {
-                places_conflict(
-                    self.tcx,
-                    self.param_env,
-                    self.body,
-                    &self.borrow_set.borrows[i].borrowed_place,
-                    place,
-                    PlaceConflictBias::NoOverlap,
-                )
-            });
-
-            trans.kill_all(definitely_conflicting_borrows);
+            return;
         }
+
+        // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
+        // pair of array indices are unequal, so that when `places_conflict` returns true, we
+        // will be assured that two places being compared definitely denotes the same sets of
+        // locations.
+        let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| {
+            places_conflict(
+                self.tcx,
+                self.body,
+                &self.borrow_set.borrows[i].borrowed_place,
+                place,
+                PlaceConflictBias::NoOverlap,
+            )
+        });
+
+        trans.kill_all(definitely_conflicting_borrows);
     }
 }
 
diff --git a/src/librustc_mir/dataflow/impls/indirect_mutation.rs b/src/librustc_mir/dataflow/impls/indirect_mutation.rs
index 38401b42b48..85bf342c8a3 100644
--- a/src/librustc_mir/dataflow/impls/indirect_mutation.rs
+++ b/src/librustc_mir/dataflow/impls/indirect_mutation.rs
@@ -111,12 +111,8 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
         if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
             if self.borrow_allows_mutation(kind, borrowed_place) {
-                match borrowed_place.base {
-                    mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect() => {
-                        self.trans.gen(borrowed_local)
-                    }
-
-                    _ => (),
+                if !borrowed_place.is_indirect() {
+                    self.trans.gen(borrowed_place.local);
                 }
             }
         }
diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs
index 17f71e83cfd..6a48d1e9803 100644
--- a/src/librustc_mir/dataflow/impls/storage_liveness.rs
+++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs
@@ -116,15 +116,11 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
             StatementKind::StorageDead(l) => sets.kill(l),
             StatementKind::Assign(box (ref place, _))
             | StatementKind::SetDiscriminant { box ref place, .. } => {
-                if let PlaceBase::Local(local) = place.base {
-                    sets.gen(local);
-                }
+                sets.gen(place.local);
             }
             StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => {
-                for p in &**outputs {
-                    if let PlaceBase::Local(local) = p.base {
-                        sets.gen(local);
-                    }
+                for place in &**outputs {
+                    sets.gen(place.local);
                 }
             }
             _ => (),
@@ -140,10 +136,8 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
     fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
         self.check_for_borrow(sets, loc);
 
-        if let TerminatorKind::Call {
-            destination: Some((Place { base: PlaceBase::Local(local), .. }, _)),
-            ..
-        } = self.body[loc.block].terminator().kind
+        if let TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. } =
+            self.body[loc.block].terminator().kind
         {
             sets.gen(local);
         }
@@ -171,9 +165,7 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
         _dest_bb: mir::BasicBlock,
         dest_place: &mir::Place<'tcx>,
     ) {
-        if let PlaceBase::Local(local) = dest_place.base {
-            in_out.insert(local);
-        }
+        in_out.insert(dest_place.local);
     }
 }
 
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index c05f7f8959d..271bcce6ca5 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -96,12 +96,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     /// Maybe we should have separate "borrowck" and "moveck" modes.
     fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
         debug!("lookup({:?})", place);
-        let mut base = match place.base {
-            PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local],
-            PlaceBase::Static(..) => {
-                return Err(MoveError::cannot_move_out_of(self.loc, Static));
-            }
-        };
+        let mut base = self.builder.data.rev_lookup.locals[place.local];
 
         // The move path index of the first union that we find. Once this is
         // some we stop creating child move paths, since moves from unions
@@ -114,7 +109,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             let proj_base = &place.projection[..i];
             let body = self.builder.body;
             let tcx = self.builder.tcx;
-            let place_ty = Place::ty_from(&place.base, proj_base, body, tcx).ty;
+            let place_ty = Place::ty_from(&place.local, proj_base, body, tcx).ty;
             match place_ty.kind {
                 ty::Ref(..) | ty::RawPtr(..) => {
                     let proj = &place.projection[..i + 1];
@@ -122,7 +117,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                         self.loc,
                         BorrowedContent {
                             target_place: Place {
-                                base: place.base.clone(),
+                                local: place.local,
                                 projection: tcx.intern_place_elems(proj),
                             },
                         },
@@ -163,7 +158,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
 
             if union_path.is_none() {
                 base = self.add_move_path(base, elem, |tcx| Place {
-                    base: place.base.clone(),
+                    local: place.local.clone(),
                     projection: tcx.intern_place_elems(&place.projection[..i + 1]),
                 });
             }
@@ -436,7 +431,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             // `ConstIndex` patterns. This is done to ensure that all move paths
             // are disjoint, which is expected by drop elaboration.
             let base_place = Place {
-                base: place.base.clone(),
+                local: place.local.clone(),
                 projection: self.builder.tcx.intern_place_elems(base),
             };
             let base_path = match self.move_path_for(&base_place) {
@@ -497,10 +492,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
         // of the union so it is marked as initialized again.
         if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
             if let ty::Adt(def, _) =
-                Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.kind
+                Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx).ty.kind
             {
                 if def.is_union() {
-                    place = PlaceRef { base: place.base, projection: proj_base }
+                    place = PlaceRef { local: place.local, projection: proj_base }
                 }
             }
         }
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index e5cddaf6c66..a46465ab493 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -246,10 +246,7 @@ impl MovePathLookup {
     // unknown place, but will rather return the nearest available
     // parent.
     pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult {
-        let mut result = match place.base {
-            PlaceBase::Local(local) => self.locals[*local],
-            PlaceBase::Static(..) => return LookupResult::Parent(None),
-        };
+        let mut result = self.locals[*place.local];
 
         for elem in place.projection.iter() {
             if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
@@ -281,9 +278,6 @@ pub struct IllegalMoveOrigin<'tcx> {
 
 #[derive(Debug)]
 pub(crate) enum IllegalMoveOriginKind<'tcx> {
-    /// Illegal move due to attempt to move from `static` variable.
-    Static,
-
     /// Illegal move due to attempt to move from behind a reference.
     BorrowedContent {
         /// The place the reference refers to: if erroneous code was trying to
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 8fd8143ee37..471e09fc03b 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -411,15 +411,18 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             let def_id = cx.tcx.hir().local_def_id(count.hir_id);
             let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
             let span = cx.tcx.def_span(def_id);
-            let count = match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, Some(span)) {
-                Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env),
-                Err(ErrorHandled::Reported) => 0,
-                Err(ErrorHandled::TooGeneric) => {
-                    let span = cx.tcx.def_span(def_id);
-                    cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters");
-                    0
-                }
-            };
+            let count =
+                match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, None, Some(span)) {
+                    Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env),
+                    Err(ErrorHandled::Reported) => 0,
+                    Err(ErrorHandled::TooGeneric) => {
+                        let span = cx.tcx.def_span(def_id);
+                        cx.tcx
+                            .sess
+                            .span_err(span, "array lengths can't depend on generic parameters");
+                        0
+                    }
+                };
 
             ExprKind::Repeat { value: v.to_ref(), count }
         }
@@ -523,7 +526,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
                             let lhs = mk_const(cx.tcx().mk_const(ty::Const {
-                                val: ty::ConstKind::Unevaluated(did, substs),
+                                val: ty::ConstKind::Unevaluated(did, substs, None),
                                 ty: var_ty,
                             }));
                             let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
@@ -719,7 +722,7 @@ fn convert_path_expr<'a, 'tcx>(
             debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
             ExprKind::Literal {
                 literal: cx.tcx.mk_const(ty::Const {
-                    val: ty::ConstKind::Unevaluated(def_id, substs),
+                    val: ty::ConstKind::Unevaluated(def_id, substs, None),
                     ty: cx.tables().node_type(expr.hir_id),
                 }),
                 user_ty,
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 2598ce2391f..c7e26c6ea4f 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -775,6 +775,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     self.param_env.with_reveal_all(),
                     def_id,
                     substs,
+                    None,
                     Some(span),
                 ) {
                     Ok(value) => {
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 864f4f9487c..206d3d15673 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -757,13 +757,22 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &self,
         gid: GlobalId<'tcx>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        let val = if self.tcx.is_static(gid.instance.def_id()) {
-            self.tcx.const_eval_poly(gid.instance.def_id())?
-        } else if let Some(promoted) = gid.promoted {
-            self.tcx.const_eval_promoted(gid.instance, promoted)?
+        // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
+        // and thus don't care about the parameter environment. While we could just use
+        // `self.param_env`, that would mean we invoke the query to evaluate the static
+        // with different parameter environments, thus causing the static to be evaluated
+        // multiple times.
+        let param_env = if self.tcx.is_static(gid.instance.def_id()) {
+            ty::ParamEnv::reveal_all()
         } else {
-            self.tcx.const_eval_instance(self.param_env, gid.instance, Some(self.tcx.span))?
+            self.param_env
         };
+        let val = if let Some(promoted) = gid.promoted {
+            self.tcx.const_eval_promoted(param_env, gid.instance, promoted)?
+        } else {
+            self.tcx.const_eval_instance(param_env, gid.instance, Some(self.tcx.span))?
+        };
+
         // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a
         // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not
         // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index 9b3a2fa36f7..220761ce28d 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -41,6 +41,11 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> {
     /// despite the nested mutable reference!
     /// The field gets updated when an `UnsafeCell` is encountered.
     mutability: Mutability,
+
+    /// This flag is to avoid triggering UnsafeCells are not allowed behind references in constants
+    /// for promoteds.
+    /// It's a copy of `mir::Body`'s ignore_interior_mut_in_const_validation field
+    ignore_interior_mut_in_const_validation: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
@@ -164,14 +169,16 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
                 // References we encounter inside here are interned as pointing to mutable
                 // allocations.
                 let old = std::mem::replace(&mut self.mutability, Mutability::Mut);
-                assert_ne!(
-                    self.mode,
-                    InternMode::Const,
-                    "UnsafeCells are not allowed behind references in constants. This should have \
-                    been prevented statically by const qualification. If this were allowed one \
-                    would be able to change a constant at one use site and other use sites could \
-                    observe that mutation.",
-                );
+                if !self.ignore_interior_mut_in_const_validation {
+                    assert_ne!(
+                        self.mode,
+                        InternMode::Const,
+                        "UnsafeCells are not allowed behind references in constants. This should \
+                        have been prevented statically by const qualification. If this were \
+                        allowed one would be able to change a constant at one use site and other \
+                        use sites could observe that mutation.",
+                    );
+                }
                 let walked = self.walk_aggregate(mplace, fields);
                 self.mutability = old;
                 return walked;
@@ -266,6 +273,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
     // The `mutability` of the place, ignoring the type.
     place_mut: Option<hir::Mutability>,
     ret: MPlaceTy<'tcx>,
+    ignore_interior_mut_in_const_validation: bool,
 ) -> InterpResult<'tcx> {
     let tcx = ecx.tcx;
     let (base_mutability, base_intern_mode) = match place_mut {
@@ -302,6 +310,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
             mode,
             leftover_allocations,
             mutability,
+            ignore_interior_mut_in_const_validation,
         }
         .visit_value(mplace);
         if let Err(error) = interned {
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 6d15827536c..3309e9b9b62 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -212,7 +212,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         frame.locals[local].access()
     }
 
-    /// Called before a `StaticKind::Static` value is accessed.
+    /// Called before a `Static` value is accessed.
     fn before_access_static(
         _memory_extra: &Self::MemoryExtra,
         _allocation: &Allocation,
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index ddd9776e893..b37eff3f406 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -462,19 +462,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         place: &mir::Place<'tcx>,
         layout: Option<TyLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        use rustc::mir::PlaceBase;
-
-        let base_op = match &place.base {
-            PlaceBase::Local(mir::RETURN_PLACE) => throw_unsup!(ReadFromReturnPointer),
-            PlaceBase::Local(local) => {
+        let base_op = match place.local {
+            mir::RETURN_PLACE => throw_unsup!(ReadFromReturnPointer),
+            local => {
                 // Do not use the layout passed in as argument if the base we are looking at
                 // here is not the entire place.
-                // FIXME use place_projection.is_empty() when is available
                 let layout = if place.projection.is_empty() { layout } else { None };
 
-                self.access_local(self.frame(), *local, layout)?
+                self.access_local(self.frame(), local, layout)?
             }
-            PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
         };
 
         let op = place
@@ -532,7 +528,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Early-return cases.
         let val_val = match val.val {
             ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
-            ty::ConstKind::Unevaluated(def_id, substs) => {
+            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
                 let instance = self.resolve(def_id, substs)?;
                 // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
                 // The reason we use `const_eval_raw` everywhere else is to prevent cycles during
@@ -540,9 +536,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // potentially requiring the current static to be evaluated again. This is not a
                 // problem here, because we are building an operand which means an actual read is
                 // happening.
-                // FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of
-                // `StaticKind` once and for all.
-                return self.const_eval(GlobalId { instance, promoted: None });
+                return Ok(OpTy::from(self.const_eval(GlobalId { instance, promoted })?));
             }
             ty::ConstKind::Infer(..)
             | ty::ConstKind::Bound(..)
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 890627a5454..8888e3fd463 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -10,14 +10,13 @@ use rustc::mir::interpret::truncate;
 use rustc::ty::layout::{
     self, Align, HasDataLayout, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx,
 };
-use rustc::ty::TypeFoldable;
 use rustc::ty::{self, Ty};
 use rustc_macros::HashStable;
 
 use super::{
-    AllocId, AllocMap, Allocation, AllocationExtra, GlobalId, ImmTy, Immediate, InterpCx,
-    InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, PointerArithmetic,
-    RawConst, Scalar, ScalarMaybeUndef,
+    AllocId, AllocMap, Allocation, AllocationExtra, ImmTy, Immediate, InterpCx, InterpResult,
+    LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, PointerArithmetic, RawConst, Scalar,
+    ScalarMaybeUndef,
 };
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
@@ -619,64 +618,14 @@ where
         })
     }
 
-    /// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
-    /// `eval_place` and `eval_place_to_op`.
-    pub(super) fn eval_static_to_mplace(
-        &self,
-        place_static: &mir::Static<'tcx>,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
-        use rustc::mir::StaticKind;
-
-        Ok(match place_static.kind {
-            StaticKind::Promoted(promoted, promoted_substs) => {
-                let substs = self.subst_from_frame_and_normalize_erasing_regions(promoted_substs);
-                let instance = ty::Instance::new(place_static.def_id, substs);
-
-                // Even after getting `substs` from the frame, this instance may still be
-                // polymorphic because `ConstProp` will try to promote polymorphic MIR.
-                if instance.needs_subst() {
-                    throw_inval!(TooGeneric);
-                }
-
-                self.const_eval_raw(GlobalId { instance, promoted: Some(promoted) })?
-            }
-
-            StaticKind::Static => {
-                let ty = place_static.ty;
-                assert!(!ty.needs_subst());
-                let layout = self.layout_of(ty)?;
-                // Just create a lazy reference, so we can support recursive statics.
-                // tcx takes care of assigning every static one and only one unique AllocId.
-                // When the data here is ever actually used, memory will notice,
-                // and it knows how to deal with alloc_id that are present in the
-                // global table but not in its local memory: It calls back into tcx through
-                // a query, triggering the CTFE machinery to actually turn this lazy reference
-                // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
-                // this InterpCx uses another Machine (e.g., in miri).  This is what we
-                // want!  This way, computing statics works consistently between codegen
-                // and miri: They use the same query to eventually obtain a `ty::Const`
-                // and use that for further computation.
-                //
-                // Notice that statics have *two* AllocIds: the lazy one, and the resolved
-                // one.  Here we make sure that the interpreted program never sees the
-                // resolved ID.  Also see the doc comment of `Memory::get_static_alloc`.
-                let alloc_id = self.tcx.alloc_map.lock().create_static_alloc(place_static.def_id);
-                let ptr = self.tag_static_base_pointer(Pointer::from(alloc_id));
-                MPlaceTy::from_aligned_ptr(ptr, layout)
-            }
-        })
-    }
-
     /// Computes a place. You should only use this if you intend to write into this
     /// place; for reading, a more efficient alternative is `eval_place_for_read`.
     pub fn eval_place(
         &mut self,
         place: &mir::Place<'tcx>,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
-        use rustc::mir::PlaceBase;
-
-        let mut place_ty = match &place.base {
-            PlaceBase::Local(mir::RETURN_PLACE) => {
+        let mut place_ty = match place.local {
+            mir::RETURN_PLACE => {
                 // `return_place` has the *caller* layout, but we want to use our
                 // `layout to verify our assumption. The caller will validate
                 // their layout on return.
@@ -697,12 +646,11 @@ where
                     ))?,
                 }
             }
-            PlaceBase::Local(local) => PlaceTy {
+            local => PlaceTy {
                 // This works even for dead/uninitialized locals; we check further when writing
-                place: Place::Local { frame: self.cur_frame(), local: *local },
-                layout: self.layout_of_local(self.frame(), *local, None)?,
+                place: Place::Local { frame: self.cur_frame(), local: local },
+                layout: self.layout_of_local(self.frame(), local, None)?,
             },
-            PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
         };
 
         for elem in place.projection.iter() {
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 511a5fbc617..f5f00c93435 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -182,11 +182,11 @@ use rustc::mir::interpret::{AllocId, ConstValue};
 use rustc::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
 use rustc::mir::mono::{InstantiationMode, MonoItem};
 use rustc::mir::visit::Visitor as MirVisitor;
-use rustc::mir::{self, Location, PlaceBase, Static, StaticKind};
+use rustc::mir::{self, Local, Location};
 use rustc::session::config::EntryFnType;
 use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast};
 use rustc::ty::print::obsolete::DefPathBasedNames;
-use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
+use rustc::ty::subst::{InternalSubsts, SubstsRef};
 use rustc::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
@@ -642,39 +642,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
 
     fn visit_place_base(
         &mut self,
-        place_base: &mir::PlaceBase<'tcx>,
+        _place_local: &Local,
         _context: mir::visit::PlaceContext,
-        location: Location,
+        _location: Location,
     ) {
-        match place_base {
-            PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
-                debug!("visiting static {:?} @ {:?}", def_id, location);
-
-                let tcx = self.tcx;
-                let instance = Instance::mono(tcx, *def_id);
-                if should_monomorphize_locally(tcx, &instance) {
-                    self.output.push(MonoItem::Static(*def_id));
-                }
-            }
-            PlaceBase::Static(box Static {
-                kind: StaticKind::Promoted(promoted, substs),
-                def_id,
-                ..
-            }) => {
-                let instance = Instance::new(*def_id, substs.subst(self.tcx, self.param_substs));
-                match self.tcx.const_eval_promoted(instance, *promoted) {
-                    Ok(val) => collect_const(self.tcx, val, substs, self.output),
-                    Err(ErrorHandled::Reported) => {}
-                    Err(ErrorHandled::TooGeneric) => {
-                        let span = self.tcx.promoted_mir(*def_id)[*promoted].span;
-                        span_bug!(span, "collection encountered polymorphic constant")
-                    }
-                }
-            }
-            PlaceBase::Local(_) => {
-                // Locals have no relevance for collector.
-            }
-        }
     }
 }
 
@@ -1249,8 +1220,8 @@ fn collect_const<'tcx>(
                 collect_miri(tcx, id, output);
             }
         }
-        ty::ConstKind::Unevaluated(def_id, substs) => {
-            match tcx.const_eval_resolve(param_env, def_id, substs, None) {
+        ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
+            match tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) {
                 Ok(val) => collect_const(tcx, val, param_substs, output),
                 Err(ErrorHandled::Reported) => {}
                 Err(ErrorHandled::TooGeneric) => {
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index 0799cc2374a..577736f9bd1 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -38,12 +38,15 @@ pub trait Qualif {
         place: PlaceRef<'_, 'tcx>,
     ) -> bool {
         if let [proj_base @ .., elem] = place.projection {
-            let base_qualif =
-                Self::in_place(cx, per_local, PlaceRef { base: place.base, projection: proj_base });
+            let base_qualif = Self::in_place(
+                cx,
+                per_local,
+                PlaceRef { local: place.local, projection: proj_base },
+            );
             let qualif = base_qualif
                 && Self::in_any_value_of_ty(
                     cx,
-                    Place::ty_from(place.base, proj_base, *cx.body, cx.tcx)
+                    Place::ty_from(place.local, proj_base, *cx.body, cx.tcx)
                         .projection_ty(cx.tcx, elem)
                         .ty,
                 );
@@ -75,11 +78,8 @@ pub trait Qualif {
         place: PlaceRef<'_, 'tcx>,
     ) -> bool {
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => per_local(*local),
-            PlaceRef { base: PlaceBase::Static(_), projection: [] } => {
-                bug!("qualifying already promoted MIR")
-            }
-            PlaceRef { base: _, projection: [.., _] } => Self::in_projection(cx, per_local, place),
+            PlaceRef { local, projection: [] } => per_local(*local),
+            PlaceRef { local: _, projection: [.., _] } => Self::in_projection(cx, per_local, place),
         }
     }
 
@@ -102,7 +102,9 @@ pub trait Qualif {
                     // Note: this uses `constant.literal.ty` which is a reference or pointer to the
                     // type of the actual `static` item.
                     Self::in_any_value_of_ty(cx, constant.literal.ty)
-                } else if let ty::ConstKind::Unevaluated(def_id, _) = constant.literal.val {
+                } else if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val
+                {
+                    assert!(promoted.is_none());
                     // Don't peek inside trait associated constants.
                     if cx.tcx.trait_of_item(def_id).is_some() {
                         Self::in_any_value_of_ty(cx, constant.literal.ty)
@@ -147,12 +149,12 @@ pub trait Qualif {
             Rvalue::Ref(_, _, ref place) | Rvalue::AddressOf(_, ref place) => {
                 // Special-case reborrows to be more like a copy of the reference.
                 if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
-                    let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
+                    let base_ty = Place::ty_from(&place.local, proj_base, *cx.body, cx.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind {
                         return Self::in_place(
                             cx,
                             per_local,
-                            PlaceRef { base: &place.base, projection: proj_base },
+                            PlaceRef { local: &place.local, projection: proj_base },
                         );
                     }
                 }
diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs
index 207683054f9..c445568dd2a 100644
--- a/src/librustc_mir/transform/check_consts/resolver.rs
+++ b/src/librustc_mir/transform/check_consts/resolver.rs
@@ -47,15 +47,15 @@ where
         debug_assert!(!place.is_indirect());
 
         match (value, place.as_ref()) {
-            (true, mir::PlaceRef { base: &mir::PlaceBase::Local(local), .. }) => {
-                self.qualifs_per_local.insert(local);
+            (true, mir::PlaceRef { 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::PlaceRef { base: &mir::PlaceBase::Local(_local), projection: &[] }) => {
+            (false, mir::PlaceRef { local: _, projection: &[] }) => {
                 // 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 b8183972476..10a4b7d92b7 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -304,8 +304,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                             PlaceContext::MutatingUse(MutatingUseContext::Borrow)
                         }
                     };
-                    self.visit_place_base(&place.base, ctx, location);
-                    self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+                    self.visit_place_base(&place.local, ctx, location);
+                    self.visit_projection(&place.local, reborrowed_proj, ctx, location);
                     return;
                 }
             }
@@ -317,8 +317,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                         }
                         Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
                     };
-                    self.visit_place_base(&place.base, ctx, location);
-                    self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+                    self.visit_place_base(&place.local, ctx, location);
+                    self.visit_projection(&place.local, reborrowed_proj, ctx, location);
                     return;
                 }
             }
@@ -369,15 +369,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
 
             Rvalue::AddressOf(Mutability::Mut, _) => self.check_op(ops::MutAddressOf),
 
-            // At the moment, `PlaceBase::Static` is only used for promoted MIR.
-            Rvalue::Ref(_, BorrowKind::Shared, ref place)
-            | Rvalue::Ref(_, BorrowKind::Shallow, ref place)
-            | Rvalue::AddressOf(Mutability::Not, ref place)
-                if matches!(place.base, PlaceBase::Static(_)) =>
-            {
-                bug!("Saw a promoted during const-checking, which must run before promotion")
-            }
-
             Rvalue::Ref(_, BorrowKind::Shared, ref place)
             | Rvalue::Ref(_, BorrowKind::Shallow, ref place) => {
                 self.check_immutable_borrow_like(location, place)
@@ -421,26 +412,14 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
         }
     }
 
-    fn visit_place_base(
-        &mut self,
-        place_base: &PlaceBase<'tcx>,
-        context: PlaceContext,
-        location: Location,
-    ) {
+    fn visit_place_base(&mut self, place_local: &Local, context: PlaceContext, location: Location) {
         trace!(
-            "visit_place_base: place_base={:?} context={:?} location={:?}",
-            place_base,
+            "visit_place_base: place_local={:?} context={:?} location={:?}",
+            place_local,
             context,
             location,
         );
-        self.super_place_base(place_base, context, location);
-
-        match place_base {
-            PlaceBase::Local(_) => {}
-            PlaceBase::Static(_) => {
-                bug!("Promotion must be run after const validation");
-            }
-        }
+        self.super_place_base(place_local, context, location);
     }
 
     fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
@@ -453,30 +432,30 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
     }
     fn visit_projection_elem(
         &mut self,
-        place_base: &PlaceBase<'tcx>,
+        place_local: &Local,
         proj_base: &[PlaceElem<'tcx>],
         elem: &PlaceElem<'tcx>,
         context: PlaceContext,
         location: Location,
     ) {
         trace!(
-            "visit_projection_elem: place_base={:?} proj_base={:?} elem={:?} \
+            "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \
             context={:?} location={:?}",
-            place_base,
+            place_local,
             proj_base,
             elem,
             context,
             location,
         );
 
-        self.super_projection_elem(place_base, proj_base, elem, context, location);
+        self.super_projection_elem(place_local, proj_base, elem, context, location);
 
         match elem {
             ProjectionElem::Deref => {
-                let base_ty = Place::ty_from(place_base, proj_base, *self.body, self.tcx).ty;
+                let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty;
                 if let ty::RawPtr(_) = base_ty.kind {
                     if proj_base.is_empty() {
-                        if let (PlaceBase::Local(local), []) = (place_base, proj_base) {
+                        if let (local, []) = (place_local, proj_base) {
                             let decl = &self.body.local_decls[*local];
                             if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
                                 let span = decl.source_info.span;
@@ -497,7 +476,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Field(..)
             | ProjectionElem::Index(_) => {
-                let base_ty = Place::ty_from(place_base, proj_base, *self.body, self.tcx).ty;
+                let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty;
                 match base_ty.ty_adt_def() {
                     Some(def) if def.is_union() => {
                         self.check_op(ops::UnionAccess);
@@ -681,17 +660,15 @@ fn place_as_reborrow(
 
         // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
         // that points to the allocation for the static. Don't treat these as reborrows.
-        if let PlaceBase::Local(local) = place.base {
-            if body.local_decls[local].is_ref_to_static() {
-                return None;
-            }
+        if body.local_decls[place.local].is_ref_to_static() {
+            return None;
         }
 
         // Ensure the type being derefed is a reference and not a raw pointer.
         //
         // This is sufficient to prevent an access to a `static mut` from being marked as a
         // reborrow, even if the check above were to disappear.
-        let inner_ty = Place::ty_from(&place.base, inner, body, tcx).ty;
+        let inner_ty = Place::ty_from(&place.local, inner, body, tcx).ty;
         match inner_ty.kind {
             ty::Ref(..) => Some(inner),
             _ => None,
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 02c54803842..934b262c2f9 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -190,18 +190,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
     }
 
     fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
-        match place.base {
-            PlaceBase::Local(..) => {
-                // Locals are safe.
-            }
-            PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
-                bug!("unsafety checking should happen before promotion");
-            }
-            PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
-                bug!("StaticKind::Static should not exist");
-            }
-        }
-
         for (i, elem) in place.projection.iter().enumerate() {
             let proj_base = &place.projection[..i];
 
@@ -229,7 +217,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 }
             }
             let is_borrow_of_interior_mut = context.is_borrow()
-                && !Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty.is_freeze(
+                && !Place::ty_from(&place.local, proj_base, self.body, self.tcx).ty.is_freeze(
                     self.tcx,
                     self.param_env,
                     self.source_info.span,
@@ -244,7 +232,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use());
             }
             let old_source_info = self.source_info;
-            if let (PlaceBase::Local(local), []) = (&place.base, proj_base) {
+            if let (local, []) = (&place.local, proj_base) {
                 let decl = &self.body.local_decls[*local];
                 if decl.internal {
                     // Internal locals are used in the `move_val_init` desugaring.
@@ -272,7 +260,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                     }
                 }
             }
-            let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
+            let base_ty = Place::ty_from(&place.local, proj_base, self.body, self.tcx).ty;
             match base_ty.kind {
                 ty::RawPtr(..) => self.require_unsafe(
                     "dereference of raw pointer",
@@ -426,7 +414,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
             match elem {
                 ProjectionElem::Field(..) => {
                     let ty =
-                        Place::ty_from(&place.base, proj_base, &self.body.local_decls, self.tcx).ty;
+                        Place::ty_from(&place.local, proj_base, &self.body.local_decls, self.tcx)
+                            .ty;
                     match ty.kind {
                         ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
                             (Bound::Unbounded, Bound::Unbounded) => {}
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index d5d56b36cf4..1d5a643484a 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -10,15 +10,15 @@ use rustc::mir::visit::{
 };
 use rustc::mir::{
     read_only, AggregateKind, BasicBlock, BinOp, Body, BodyAndCache, ClearCrossCrate, Constant,
-    Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, ReadOnlyBodyAndCache, Rvalue,
+    Local, LocalDecl, LocalKind, Location, Operand, Place, ReadOnlyBodyAndCache, Rvalue,
     SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
     UnOp, RETURN_PLACE,
 };
 use rustc::ty::layout::{
     HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
 };
-use rustc::ty::subst::InternalSubsts;
-use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::subst::{InternalSubsts, Subst};
+use rustc::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -33,7 +33,6 @@ use crate::interpret::{
     LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
     ScalarMaybeUndef, StackPopCleanup,
 };
-use crate::rustc::ty::subst::Subst;
 use crate::transform::{MirPass, MirSource};
 
 /// The maximum number of bytes that we'll allocate space for a return value.
@@ -432,12 +431,25 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         source_info: SourceInfo,
     ) -> Option<Const<'tcx>> {
         self.ecx.tcx.span = c.span;
+
+        // FIXME we need to revisit this for #67176
+        if c.needs_subst() {
+            return None;
+        }
+
         match self.ecx.eval_const_to_op(c.literal, None) {
             Ok(op) => Some(op),
             Err(error) => {
                 let err = error_to_const_error(&self.ecx, error);
-                match self.lint_root(source_info) {
-                    Some(lint_root) if c.literal.needs_subst() => {
+                if let Some(lint_root) = self.lint_root(source_info) {
+                    let lint_only = match c.literal.val {
+                        // Promoteds must lint and not error as the user didn't ask for them
+                        ConstKind::Unevaluated(_, _, Some(_)) => true,
+                        // Out of backwards compatibility we cannot report hard errors in unused
+                        // generic functions using associated constants of the generic parameters.
+                        _ => c.literal.needs_subst(),
+                    };
+                    if lint_only {
                         // Out of backwards compatibility we cannot report hard errors in unused
                         // generic functions using associated constants of the generic parameters.
                         err.report_as_lint(
@@ -446,10 +458,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                             lint_root,
                             Some(c.span),
                         );
-                    }
-                    _ => {
+                    } else {
                         err.report_as_error(self.ecx.tcx, "erroneous constant used");
                     }
+                } else {
+                    err.report_as_error(self.ecx.tcx, "erroneous constant used");
                 }
                 None
             }
@@ -552,6 +565,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             return None;
         }
 
+        // FIXME we need to revisit this for #67176
+        if rvalue.needs_subst() {
+            return None;
+        }
+
         let overflow_check = self.tcx.sess.overflow_checks();
 
         // Perform any special handling for specific Rvalue types.
@@ -708,7 +726,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             )) => l.is_bits() && r.is_bits(),
             interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
                 let mplace = op.assert_mem_place(&self.ecx);
-                intern_const_alloc_recursive(&mut self.ecx, None, mplace)
+                intern_const_alloc_recursive(&mut self.ecx, None, mplace, false)
                     .expect("failed to intern alloc");
                 true
             }
@@ -866,9 +884,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                         // doesn't use the invalid value
                         match cond {
                             Operand::Move(ref place) | Operand::Copy(ref place) => {
-                                if let PlaceBase::Local(local) = place.base {
-                                    self.remove_const(local);
-                                }
+                                self.remove_const(place.local);
                             }
                             Operand::Constant(_) => {}
                         }
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 96fb992e53b..825ac4a28d8 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -112,17 +112,17 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> {
     }
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        if place.base == PlaceBase::Local(self_arg()) {
+        if place.local == self_arg() {
             replace_base(
                 place,
                 Place {
-                    base: PlaceBase::Local(self_arg()),
+                    local: self_arg(),
                     projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Deref]),
                 },
                 self.tcx,
             );
         } else {
-            self.visit_place_base(&mut place.base, context, location);
+            self.visit_place_base(&mut place.local, context, location);
 
             for elem in place.projection.iter() {
                 if let PlaceElem::Index(local) = elem {
@@ -148,11 +148,11 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
     }
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        if place.base == PlaceBase::Local(self_arg()) {
+        if place.local == self_arg() {
             replace_base(
                 place,
                 Place {
-                    base: PlaceBase::Local(self_arg()),
+                    local: self_arg(),
                     projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Field(
                         Field::new(0),
                         self.ref_gen_ty,
@@ -161,7 +161,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
                 self.tcx,
             );
         } else {
-            self.visit_place_base(&mut place.base, context, location);
+            self.visit_place_base(&mut place.local, context, location);
 
             for elem in place.projection.iter() {
                 if let PlaceElem::Index(local) = elem {
@@ -173,7 +173,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
 }
 
 fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) {
-    place.base = new_base.base;
+    place.local = new_base.local;
 
     let mut new_projection = new_base.projection.to_vec();
     new_projection.append(&mut place.projection.to_vec());
@@ -236,7 +236,7 @@ impl TransformVisitor<'tcx> {
         let mut projection = base.projection.to_vec();
         projection.push(ProjectionElem::Field(Field::new(idx), ty));
 
-        Place { base: base.base, projection: self.tcx.intern_place_elems(&projection) }
+        Place { local: base.local, projection: self.tcx.intern_place_elems(&projection) }
     }
 
     // Create a statement which changes the discriminant
@@ -275,20 +275,15 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
         assert_eq!(self.remap.get(local), None);
     }
 
-    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        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), self.tcx);
-            }
-        } else {
-            self.visit_place_base(&mut place.base, context, location);
-
-            for elem in place.projection.iter() {
-                if let PlaceElem::Index(local) = elem {
-                    assert_ne!(*local, self_arg());
-                }
-            }
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        _context: PlaceContext,
+        _location: Location,
+    ) {
+        // Replace an Local in the remap with a generator struct access
+        if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) {
+            replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
         }
     }
 
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 3c5d2c9f310..2dd00fe2fee 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -430,12 +430,7 @@ impl Inliner<'tcx> {
                         }
                     }
 
-                    match place.base {
-                        // Static variables need a borrow because the callee
-                        // might modify the same static.
-                        PlaceBase::Static(_) => true,
-                        _ => false,
-                    }
+                    false
                 }
 
                 let dest = if dest_needs_borrow(&destination.0) {
@@ -647,10 +642,7 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
 
     fn make_integrate_local(&self, local: &Local) -> Local {
         if *local == RETURN_PLACE {
-            match self.destination.base {
-                PlaceBase::Local(l) => return l,
-                PlaceBase::Static(ref s) => bug!("Return place is {:?}, not local", s),
-            }
+            return self.destination.local;
         }
 
         let idx = local.index() - 1;
@@ -672,19 +664,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
     }
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        match &mut place.base {
-            PlaceBase::Static(_) => {}
-            PlaceBase::Local(l) => {
-                // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
-                let dest_proj_len = self.destination.projection.len();
-                if *l == RETURN_PLACE && dest_proj_len > 0 {
-                    let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
-                    projs.extend(self.destination.projection);
-                    projs.extend(place.projection);
-
-                    place.projection = self.tcx.intern_place_elems(&*projs);
-                }
-            }
+        // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
+        let dest_proj_len = self.destination.projection.len();
+        if place.local == RETURN_PLACE && dest_proj_len > 0 {
+            let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
+            projs.extend(self.destination.projection);
+            projs.extend(place.projection);
+
+            place.projection = self.tcx.intern_place_elems(&*projs);
         }
         // Handles integrating any locals that occur in the base
         // or projections
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index a2f3fcea756..69eedb1ae18 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -3,7 +3,7 @@
 use crate::transform::{MirPass, MirSource};
 use rustc::mir::visit::{MutVisitor, Visitor};
 use rustc::mir::{
-    read_only, Body, BodyAndCache, Constant, Local, Location, Operand, Place, PlaceBase, PlaceRef,
+    read_only, Body, BodyAndCache, Constant, Local, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue,
 };
 use rustc::ty::{self, TyCtxt};
@@ -55,7 +55,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
 
                         Place {
                             // Replace with dummy
-                            base: mem::replace(&mut place.base, PlaceBase::Local(Local::new(0))),
+                            local: mem::replace(&mut place.local, Local::new(0)),
                             projection: self.tcx().intern_place_elems(proj_l),
                         }
                     } else {
@@ -92,10 +92,10 @@ 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) = rvalue {
-            if let PlaceRef { base, projection: &[ref proj_base @ .., ProjectionElem::Deref] } =
+            if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } =
                 place.as_ref()
             {
-                if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
+                if Place::ty_from(local, proj_base, self.body, self.tcx).ty.is_region_ptr() {
                     self.optimizations.and_stars.insert(location);
                 }
             }
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 00a39905c02..f058ac834ef 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -27,7 +27,7 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_target::spec::abi::Abi;
 
 use std::cell::Cell;
-use std::{iter, mem, usize};
+use std::{cmp, iter, mem, usize};
 
 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item};
@@ -39,7 +39,7 @@ use crate::transform::{MirPass, MirSource};
 /// errors when promotion of `#[rustc_args_required_const]` arguments fails.
 ///
 /// After this pass is run, `promoted_fragments` will hold the MIR body corresponding to each
-/// newly created `StaticKind::Promoted`.
+/// newly created `Constant`.
 #[derive(Default)]
 pub struct PromoteTemps<'tcx> {
     pub promoted_fragments: Cell<IndexVec<Promoted, BodyAndCache<'tcx>>>,
@@ -308,18 +308,14 @@ impl<'tcx> Validator<'_, 'tcx> {
 
                         // We can only promote interior borrows of promotable temps (non-temps
                         // don't get promoted anyway).
-                        let base = match place.base {
-                            PlaceBase::Local(local) => local,
-                            _ => return Err(Unpromotable),
-                        };
-                        self.validate_local(base)?;
+                        self.validate_local(place.local)?;
 
                         if place.projection.contains(&ProjectionElem::Deref) {
                             return Err(Unpromotable);
                         }
 
                         let mut has_mut_interior =
-                            self.qualif_local::<qualifs::HasMutInterior>(base);
+                            self.qualif_local::<qualifs::HasMutInterior>(place.local);
                         // HACK(eddyb) this should compute the same thing as
                         // `<HasMutInterior as Qualif>::in_projection` from
                         // `check_consts::qualifs` but without recursion.
@@ -333,7 +329,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                                 // FIXME(eddyb) this is probably excessive, with
                                 // the exception of `union` member accesses.
                                 let ty =
-                                    Place::ty_from(&place.base, proj_base, *self.body, self.tcx)
+                                    Place::ty_from(&place.local, proj_base, *self.body, self.tcx)
                                         .projection_ty(self.tcx, elem)
                                         .ty;
                                 if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
@@ -349,7 +345,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                         if has_mut_interior {
                             return Err(Unpromotable);
                         }
-                        if self.qualif_local::<qualifs::NeedsDrop>(base) {
+                        if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
                             return Err(Unpromotable);
                         }
 
@@ -479,13 +475,8 @@ impl<'tcx> Validator<'_, 'tcx> {
 
     fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable> {
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
-                self.validate_local(*local)
-            }
-            PlaceRef { base: PlaceBase::Static(_), projection: [] } => {
-                bug!("qualifying already promoted MIR")
-            }
-            PlaceRef { base: _, projection: [proj_base @ .., elem] } => {
+            PlaceRef { local, projection: [] } => self.validate_local(*local),
+            PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
                 match *elem {
                     ProjectionElem::Deref | ProjectionElem::Downcast(..) => {
                         return Err(Unpromotable);
@@ -500,7 +491,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                     ProjectionElem::Field(..) => {
                         if self.const_kind.is_none() {
                             let base_ty =
-                                Place::ty_from(place.base, proj_base, *self.body, self.tcx).ty;
+                                Place::ty_from(place.local, proj_base, *self.body, self.tcx).ty;
                             if let Some(def) = base_ty.ty_adt_def() {
                                 // No promotion of union field accesses.
                                 if def.is_union() {
@@ -511,7 +502,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                     }
                 }
 
-                self.validate_place(PlaceRef { base: place.base, projection: proj_base })
+                self.validate_place(PlaceRef { local: place.local, projection: proj_base })
             }
         }
     }
@@ -598,10 +589,12 @@ impl<'tcx> Validator<'_, 'tcx> {
                 // Raw reborrows can come from reference to pointer coercions,
                 // so are allowed.
                 if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
-                    let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty;
+                    let base_ty = Place::ty_from(&place.local, proj_base, *self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind {
-                        return self
-                            .validate_place(PlaceRef { base: &place.base, projection: proj_base });
+                        return self.validate_place(PlaceRef {
+                            local: &place.local,
+                            projection: proj_base,
+                        });
                     }
                 }
                 Err(Unpromotable)
@@ -635,9 +628,9 @@ impl<'tcx> Validator<'_, 'tcx> {
                 // Special-case reborrows to be more like a copy of the reference.
                 let mut place = place.as_ref();
                 if let [proj_base @ .., ProjectionElem::Deref] = &place.projection {
-                    let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty;
+                    let base_ty = Place::ty_from(&place.local, proj_base, *self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind {
-                        place = PlaceRef { base: &place.base, projection: proj_base };
+                        place = PlaceRef { local: &place.local, projection: proj_base };
                     }
                 }
 
@@ -646,17 +639,15 @@ impl<'tcx> Validator<'_, 'tcx> {
                 // HACK(eddyb) this should compute the same thing as
                 // `<HasMutInterior as Qualif>::in_projection` from
                 // `check_consts::qualifs` but without recursion.
-                let mut has_mut_interior = match place.base {
-                    PlaceBase::Local(local) => self.qualif_local::<qualifs::HasMutInterior>(*local),
-                    PlaceBase::Static(_) => false,
-                };
+                let mut has_mut_interior =
+                    self.qualif_local::<qualifs::HasMutInterior>(*place.local);
                 if has_mut_interior {
                     let mut place_projection = place.projection;
                     // FIXME(eddyb) use a forward loop instead of a reverse one.
                     while let [proj_base @ .., elem] = place_projection {
                         // FIXME(eddyb) this is probably excessive, with
                         // the exception of `union` member accesses.
-                        let ty = Place::ty_from(place.base, proj_base, *self.body, self.tcx)
+                        let ty = Place::ty_from(place.local, proj_base, *self.body, self.tcx)
                             .projection_ty(self.tcx, elem)
                             .ty;
                         if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
@@ -761,6 +752,7 @@ struct Promoter<'a, 'tcx> {
     source: &'a mut BodyAndCache<'tcx>,
     promoted: BodyAndCache<'tcx>,
     temps: &'a mut IndexVec<Local, TempState>,
+    extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>,
 
     /// If true, all nested temps are also kept in the
     /// source MIR, not moved to the promoted MIR.
@@ -903,39 +895,76 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         candidate: Candidate,
         next_promoted_id: usize,
     ) -> Option<BodyAndCache<'tcx>> {
-        let mut operand = {
+        let mut rvalue = {
             let promoted = &mut self.promoted;
             let promoted_id = Promoted::new(next_promoted_id);
             let tcx = self.tcx;
-            let mut promoted_place = |ty, span| {
+            let mut promoted_operand = |ty, span| {
                 promoted.span = span;
                 promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span);
-                Place {
-                    base: PlaceBase::Static(box Static {
-                        kind: StaticKind::Promoted(
-                            promoted_id,
+
+                Operand::Constant(Box::new(Constant {
+                    span,
+                    user_ty: None,
+                    literal: tcx.mk_const(ty::Const {
+                        ty,
+                        val: ty::ConstKind::Unevaluated(
+                            def_id,
                             InternalSubsts::identity_for_item(tcx, def_id),
+                            Some(promoted_id),
                         ),
-                        ty,
-                        def_id,
                     }),
-                    projection: List::empty(),
-                }
+                }))
             };
             let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
             match candidate {
                 Candidate::Ref(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref mut place))) => {
+                        StatementKind::Assign(box (
+                            _,
+                            Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
+                        )) => {
                             // Use the underlying local for this (necessarily interior) borrow.
-                            let ty = place.base.ty(local_decls).ty;
+                            let ty = local_decls.local_decls()[place.local].ty;
                             let span = statement.source_info.span;
 
-                            Operand::Move(Place {
-                                base: mem::replace(&mut place.base, promoted_place(ty, span).base),
-                                projection: List::empty(),
-                            })
+                            let ref_ty = tcx.mk_ref(
+                                tcx.lifetimes.re_erased,
+                                ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
+                            );
+
+                            *region = tcx.lifetimes.re_erased;
+
+                            let mut projection = vec![PlaceElem::Deref];
+                            projection.extend(place.projection);
+                            place.projection = tcx.intern_place_elems(&projection);
+
+                            // Create a temp to hold the promoted reference.
+                            // This is because `*r` requires `r` to be a local,
+                            // otherwise we would use the `promoted` directly.
+                            let mut promoted_ref = LocalDecl::new_temp(ref_ty, span);
+                            promoted_ref.source_info = statement.source_info;
+                            let promoted_ref = local_decls.push(promoted_ref);
+                            assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
+
+                            let promoted_ref_statement = Statement {
+                                source_info: statement.source_info,
+                                kind: StatementKind::Assign(Box::new((
+                                    Place::from(promoted_ref),
+                                    Rvalue::Use(promoted_operand(ref_ty, span)),
+                                ))),
+                            };
+                            self.extra_statements.push((loc, promoted_ref_statement));
+
+                            Rvalue::Ref(
+                                tcx.lifetimes.re_erased,
+                                borrow_kind,
+                                Place {
+                                    local: mem::replace(&mut place.local, promoted_ref),
+                                    projection: List::empty(),
+                                },
+                            )
                         }
                         _ => bug!(),
                     }
@@ -946,7 +975,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                         StatementKind::Assign(box (_, Rvalue::Repeat(ref mut operand, _))) => {
                             let ty = operand.ty(local_decls, self.tcx);
                             let span = statement.source_info.span;
-                            mem::replace(operand, Operand::Copy(promoted_place(ty, span)))
+
+                            Rvalue::Use(mem::replace(operand, promoted_operand(ty, span)))
                         }
                         _ => bug!(),
                     }
@@ -957,8 +987,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                         TerminatorKind::Call { ref mut args, .. } => {
                             let ty = args[index].ty(local_decls, self.tcx);
                             let span = terminator.source_info.span;
-                            let operand = Operand::Copy(promoted_place(ty, span));
-                            mem::replace(&mut args[index], operand)
+
+                            Rvalue::Use(mem::replace(&mut args[index], promoted_operand(ty, span)))
                         }
                         // We expected a `TerminatorKind::Call` for which we'd like to promote an
                         // argument. `qualify_consts` saw a `TerminatorKind::Call` here, but
@@ -975,13 +1005,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         };
 
         assert_eq!(self.new_block(), START_BLOCK);
-        self.visit_operand(
-            &mut operand,
+        self.visit_rvalue(
+            &mut rvalue,
             Location { block: BasicBlock::new(0), statement_index: usize::MAX },
         );
 
         let span = self.promoted.span;
-        self.assign(RETURN_PLACE, Rvalue::Use(operand), span);
+        self.assign(RETURN_PLACE, rvalue, span);
         Some(self.promoted)
     }
 }
@@ -1020,6 +1050,7 @@ pub fn promote_candidates<'tcx>(
 
     let mut promotions = IndexVec::new();
 
+    let mut extra_statements = vec![];
     for candidate in candidates.into_iter().rev() {
         match candidate {
             Candidate::Repeat(Location { block, statement_index })
@@ -1043,23 +1074,27 @@ pub fn promote_candidates<'tcx>(
         let initial_locals =
             iter::once(LocalDecl::new_return_place(tcx.types.never, body.span)).collect();
 
+        let mut promoted = Body::new(
+            IndexVec::new(),
+            // FIXME: maybe try to filter this to avoid blowing up
+            // memory usage?
+            body.source_scopes.clone(),
+            initial_locals,
+            IndexVec::new(),
+            0,
+            vec![],
+            body.span,
+            vec![],
+            body.generator_kind,
+        );
+        promoted.ignore_interior_mut_in_const_validation = true;
+
         let promoter = Promoter {
-            promoted: BodyAndCache::new(Body::new(
-                IndexVec::new(),
-                // FIXME: maybe try to filter this to avoid blowing up
-                // memory usage?
-                body.source_scopes.clone(),
-                initial_locals,
-                IndexVec::new(),
-                0,
-                vec![],
-                body.span,
-                vec![],
-                body.generator_kind,
-            )),
+            promoted: BodyAndCache::new(promoted),
             tcx,
             source: body,
             temps: &mut temps,
+            extra_statements: &mut extra_statements,
             keep_original: false,
         };
 
@@ -1069,6 +1104,13 @@ pub fn promote_candidates<'tcx>(
         }
     }
 
+    // Insert each of `extra_statements` before its indicated location, which
+    // has to be done in reverse location order, to not invalidate the rest.
+    extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc));
+    for (loc, statement) in extra_statements {
+        body[loc.block].statements.insert(loc.statement_index, statement);
+    }
+
     // Eliminate assignments to, and drops of promoted temps.
     let promoted = |index: Local| temps[index] == TempState::PromotedOut;
     for block in body.basic_blocks_mut() {
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index c2c1625001d..70345567408 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -261,7 +261,7 @@ fn check_place(
             ProjectionElem::Downcast(_symbol, _variant_index) => {}
 
             ProjectionElem::Field(..) => {
-                let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty;
+                let base_ty = Place::ty_from(&place.local, &proj_base, body, tcx).ty;
                 if let Some(def) = base_ty.ty_adt_def() {
                     // No union field accesses in `const fn`
                     if def.is_union() {
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index fb7f4fac4dc..ddf8d73e548 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -388,13 +388,7 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
         // Remove unnecessary StorageLive and StorageDead annotations.
         data.statements.retain(|stmt| match &stmt.kind {
             StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => self.map[*l].is_some(),
-            StatementKind::Assign(box (place, _)) => {
-                if let PlaceBase::Local(local) = place.base {
-                    self.map[local].is_some()
-                } else {
-                    true
-                }
-            }
+            StatementKind::Assign(box (place, _)) => self.map[place.local].is_some(),
             _ => true,
         });
         self.super_basic_block_data(block, data);
diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs
index 3b8871f86b2..e733b0a5b59 100644
--- a/src/librustc_mir/transform/simplify_try.rs
+++ b/src/librustc_mir/transform/simplify_try.rs
@@ -137,9 +137,9 @@ struct VarField<'tcx> {
 fn match_variant_field_place<'tcx>(place: &Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
     match place.as_ref() {
         PlaceRef {
-            base: &PlaceBase::Local(local),
+            local,
             projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)],
-        } => Some((local, VarField { field, field_ty: ty, var_idx })),
+        } => Some((*local, VarField { field, field_ty: ty, var_idx })),
         _ => None,
     }
 }
diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs
index 70d6aaf70eb..e17c7a80f1a 100644
--- a/src/librustc_mir/util/alignment.rs
+++ b/src/librustc_mir/util/alignment.rs
@@ -46,7 +46,7 @@ where
             // encountered a Deref, which is ABI-aligned
             ProjectionElem::Deref => break,
             ProjectionElem::Field(..) => {
-                let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty;
+                let ty = Place::ty_from(&place.local, proj_base, local_decls, tcx).ty;
                 match ty.kind {
                     ty::Adt(def, _) if def.repr.packed() => return true,
                     _ => {}
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index c15bcd81443..dae394b8f4b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -2700,7 +2700,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let def_id = tcx.hir().local_def_id(ast_const.hir_id);
 
         let mut const_ = ty::Const {
-            val: ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id)),
+            val: ty::ConstKind::Unevaluated(
+                def_id,
+                InternalSubsts::identity_for_item(tcx, def_id),
+                None,
+            ),
             ty,
         };
 
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 874cb9b8a5c..8058536d60b 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -460,12 +460,16 @@ pub fn name_from_pat(p: &hir::Pat) -> String {
 
 pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
     match n.val {
-        ty::ConstKind::Unevaluated(def_id, _) => {
-            if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
+        ty::ConstKind::Unevaluated(def_id, _, promoted) => {
+            let mut s = if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
                 print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
             } else {
                 inline::print_inlined_const(cx, def_id)
+            };
+            if let Some(promoted) = promoted {
+                s.push_str(&format!("::{:?}", promoted))
             }
+            s
         }
         _ => {
             let mut s = n.to_string();
diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs
index 7d65ad1435e..a89ecdfd3a9 100644
--- a/src/test/codegen/consts.rs
+++ b/src/test/codegen/consts.rs
@@ -14,10 +14,9 @@
 
 // This checks the constants from {low,high}_align_const, they share the same
 // constant, but the alignment differs, so the higher one should be used
-// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}}, align 4
+// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @2, i32 0, i32 0, i32 0), {{.*}},
 
 #[derive(Copy, Clone)]
-
 // repr(i16) is required for the {low,high}_align_const test
 #[repr(i16)]
 pub enum E<A, B> {
@@ -31,7 +30,7 @@ pub static STATIC: E<i16, i32> = E::A(0);
 // CHECK-LABEL: @static_enum_const
 #[no_mangle]
 pub fn static_enum_const() -> E<i16, i32> {
-   STATIC
+    STATIC
 }
 
 // CHECK-LABEL: @inline_enum_const
@@ -43,15 +42,15 @@ pub fn inline_enum_const() -> E<i8, i16> {
 // CHECK-LABEL: @low_align_const
 #[no_mangle]
 pub fn low_align_const() -> E<i16, [i16; 3]> {
-// Check that low_align_const and high_align_const use the same constant
-// CHECK: i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
+    // Check that low_align_const and high_align_const use the same constant
+    // CHECK: load %"E<i16, [i16; 3]>"*, %"E<i16, [i16; 3]>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, [i16; 3]>"**),
     *&E::A(0)
 }
 
 // CHECK-LABEL: @high_align_const
 #[no_mangle]
 pub fn high_align_const() -> E<i16, i32> {
-// Check that low_align_const and high_align_const use the same constant
-// CHECK: i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
+    // Check that low_align_const and high_align_const use the same constant
+    // CHECK: load %"E<i16, i32>"*, %"E<i16, i32>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, i32>"**),
     *&E::A(0)
 }
diff --git a/src/test/mir-opt/const-promotion-extern-static.rs b/src/test/mir-opt/const-promotion-extern-static.rs
index d611ec22c38..3abc90e42e8 100644
--- a/src/test/mir-opt/const-promotion-extern-static.rs
+++ b/src/test/mir-opt/const-promotion-extern-static.rs
@@ -48,7 +48,8 @@ fn main() {}
 // START rustc.BAR.PromoteTemps.after.mir
 // bb0: {
 // ...
-//     _2 = &(promoted[0]: [&'static i32; 1]);
+//     _6 = const BAR::promoted[0];
+//     _2 = &(*_6);
 //     _1 = move _2 as &[&'static i32] (Pointer(Unsize));
 //     _0 = const core::slice::<impl [&'static i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1];
 // }
@@ -60,7 +61,8 @@ fn main() {}
 // START rustc.FOO.PromoteTemps.after.mir
 // bb0: {
 // ...
-//     _2 = &(promoted[0]: [&'static i32; 1]);
+//     _6 = const FOO::promoted[0];
+//     _2 = &(*_6);
 //     _1 = move _2 as &[&'static i32] (Pointer(Unsize));
 //     _0 = const core::slice::<impl [&'static i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1];
 // }
diff --git a/src/test/mir-opt/const_prop/ref_deref.rs b/src/test/mir-opt/const_prop/ref_deref.rs
index d45ffdc8775..8b48296a5d9 100644
--- a/src/test/mir-opt/const_prop/ref_deref.rs
+++ b/src/test/mir-opt/const_prop/ref_deref.rs
@@ -3,10 +3,29 @@ fn main() {
 }
 
 // END RUST SOURCE
+// START rustc.main.PromoteTemps.before.mir
+// bb0: {
+//     ...
+//     _3 = const 4i32;
+//     _2 = &_3;
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.PromoteTemps.before.mir
+// START rustc.main.PromoteTemps.after.mir
+// bb0: {
+//     ...
+//     _4 = const main::promoted[0];
+//     _2 = &(*_4);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.PromoteTemps.after.mir
 // START rustc.main.ConstProp.before.mir
 // bb0: {
 //     ...
-//     _2 = &(promoted[0]: i32);
+//     _4 = const main::promoted[0];
+//     _2 = _4;
 //     _1 = (*_2);
 //     ...
 //}
@@ -14,7 +33,8 @@ fn main() {
 // START rustc.main.ConstProp.after.mir
 // bb0: {
 //     ...
-//     _2 = &(promoted[0]: i32);
+//     _4 = const main::promoted[0];
+//     _2 = _4;
 //     _1 = const 4i32;
 //     ...
 // }
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.rs b/src/test/mir-opt/const_prop/ref_deref_project.rs
new file mode 100644
index 00000000000..5808a8be176
--- /dev/null
+++ b/src/test/mir-opt/const_prop/ref_deref_project.rs
@@ -0,0 +1,41 @@
+fn main() {
+    *(&(4, 5).1);
+}
+
+// END RUST SOURCE
+// START rustc.main.PromoteTemps.before.mir
+// bb0: {
+//     ...
+//     _3 = (const 4i32, const 5i32);
+//     _2 = &(_3.1: i32);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.PromoteTemps.before.mir
+// START rustc.main.PromoteTemps.after.mir
+// bb0: {
+//     ...
+//     _4 = const main::promoted[0];
+//     _2 = &((*_4).1: i32);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.PromoteTemps.after.mir
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+//     ...
+//     _4 = const main::promoted[0];
+//     _2 = &((*_4).1: i32);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+//     ...
+//     _4 = const main::promoted[0];
+//     _2 = &((*_4).1: i32);
+//     _1 = const 5i32;
+//     ...
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs
index d6ff76b34b9..43813e43d36 100644
--- a/src/test/mir-opt/const_prop/slice_len.rs
+++ b/src/test/mir-opt/const_prop/slice_len.rs
@@ -6,7 +6,8 @@ fn main() {
 // START rustc.main.ConstProp.before.mir
 //  bb0: {
 //      ...
-//      _4 = &(promoted[0]: [u32; 3]);
+//      _9 = const main::promoted[0];
+//      _4 = _9;
 //      _3 = _4;
 //      _2 = move _3 as &[u32] (Pointer(Unsize));
 //      ...
@@ -24,7 +25,8 @@ fn main() {
 // START rustc.main.ConstProp.after.mir
 //  bb0: {
 //      ...
-//      _4 = &(promoted[0]: [u32; 3]);
+//      _9 = const main::promoted[0];
+//      _4 = _9;
 //      _3 = _4;
 //      _2 = move _3 as &[u32] (Pointer(Unsize));
 //      ...
diff --git a/src/test/mir-opt/inline/inline-retag.rs b/src/test/mir-opt/inline/inline-retag.rs
index 6cdbcfdb0ad..7b78fc339f2 100644
--- a/src/test/mir-opt/inline/inline-retag.rs
+++ b/src/test/mir-opt/inline/inline-retag.rs
@@ -25,11 +25,11 @@ fn foo(x: &i32, y: &i32) -> bool {
 //         ...
 //         Retag(_3);
 //         Retag(_6);
-//         StorageLive(_9);
-//         _9 = (*_3);
-//         StorageLive(_10);
-//         _10 = (*_6);
-//         _0 = Eq(move _9, move _10);
+//         StorageLive(_11);
+//         _11 = (*_3);
+//         StorageLive(_12);
+//         _12 = (*_6);
+//         _0 = Eq(move _11, move _12);
 //         ...
 //         return;
 //     }
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index 648856b5523..2c20c35e4a4 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -65,7 +65,8 @@ fn main() {
 //  }
 //  bb6: { // binding1 and guard
 //      StorageLive(_6);
-//      _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
+//      _11 = const full_tested_match::promoted[0];
+//      _6 = &(((*_11) as Some).0: i32);
 //      _4 = &shallow _2;
 //      StorageLive(_7);
 //      _7 = const guard() -> [return: bb7, unwind: bb1];
diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs
index 1de6bafd293..64aeb46894d 100644
--- a/src/test/ui/consts/array-literal-index-oob.rs
+++ b/src/test/ui/consts/array-literal-index-oob.rs
@@ -1,7 +1,10 @@
-// build-fail
+// build-pass
+
+#![warn(const_err)]
 
 fn main() {
-    &{[1, 2, 3][4]};
-    //~^ ERROR index out of bounds
-    //~| ERROR reaching this expression at runtime will panic or abort
+    &{ [1, 2, 3][4] };
+    //~^ WARN index out of bounds
+    //~| WARN reaching this expression at runtime will panic or abort
+    //~| WARN erroneous constant used [const_err]
 }
diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr
index f3ef16659dd..50ad8e83e90 100644
--- a/src/test/ui/consts/array-literal-index-oob.stderr
+++ b/src/test/ui/consts/array-literal-index-oob.stderr
@@ -1,18 +1,26 @@
-error: index out of bounds: the len is 3 but the index is 4
-  --> $DIR/array-literal-index-oob.rs:4:7
+warning: index out of bounds: the len is 3 but the index is 4
+  --> $DIR/array-literal-index-oob.rs:6:8
    |
-LL |     &{[1, 2, 3][4]};
-   |       ^^^^^^^^^^^^
+LL |     &{ [1, 2, 3][4] };
+   |        ^^^^^^^^^^^^
    |
-   = note: `#[deny(const_err)]` on by default
+note: lint level defined here
+  --> $DIR/array-literal-index-oob.rs:3:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
-  --> $DIR/array-literal-index-oob.rs:4:7
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/array-literal-index-oob.rs:6:8
    |
-LL |     &{[1, 2, 3][4]};
-   |     --^^^^^^^^^^^^-
-   |       |
-   |       indexing out of bounds: the len is 3 but the index is 4
+LL |     &{ [1, 2, 3][4] };
+   |     ---^^^^^^^^^^^^--
+   |        |
+   |        indexing out of bounds: the len is 3 but the index is 4
 
-error: aborting due to 2 previous errors
+warning: erroneous constant used
+  --> $DIR/array-literal-index-oob.rs:6:5
+   |
+LL |     &{ [1, 2, 3][4] };
+   |     ^^^^^^^^^^^^^^^^^ referenced constant has errors
 
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.rs b/src/test/ui/consts/const-eval/conditional_array_execution.rs
index 96f67c92a5e..2058d2e2184 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.rs
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.rs
@@ -10,4 +10,5 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
 fn main() {
     println!("{}", FOO);
     //~^ ERROR
+    //~| WARN erroneous constant used [const_err]
 }
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
index ec18f8f011d..b5f5f84cf38 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
@@ -18,6 +18,12 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{}", FOO);
    |                    ^^^ referenced constant has errors
 
+warning: erroneous constant used
+  --> $DIR/conditional_array_execution.rs:11:20
+   |
+LL |     println!("{}", FOO);
+   |                    ^^^ referenced constant has errors
+
 error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
index a5f04d088b6..81f53826d81 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
@@ -4,7 +4,9 @@
 #![feature(const_fn)]
 #![allow(const_err)]
 
-fn double(x: usize) -> usize { x * 2 }
+fn double(x: usize) -> usize {
+    x * 2
+}
 const X: fn(usize) -> usize = double;
 
 const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
index 19f37fa0079..f99505c3090 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
@@ -1,11 +1,11 @@
 warning: skipping const checks
-  --> $DIR/const_fn_ptr_fail2.rs:11:5
+  --> $DIR/const_fn_ptr_fail2.rs:13:5
    |
 LL |     x(y)
    |     ^^^^
 
 error[E0080]: evaluation of constant expression failed
-  --> $DIR/const_fn_ptr_fail2.rs:18:5
+  --> $DIR/const_fn_ptr_fail2.rs:20:5
    |
 LL |     assert_eq!(Y, 4);
    |     ^^^^^^^^^^^-^^^^^
@@ -15,7 +15,7 @@ LL |     assert_eq!(Y, 4);
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error[E0080]: evaluation of constant expression failed
-  --> $DIR/const_fn_ptr_fail2.rs:20:5
+  --> $DIR/const_fn_ptr_fail2.rs:22:5
    |
 LL |     assert_eq!(Z, 4);
    |     ^^^^^^^^^^^-^^^^^
diff --git a/src/test/ui/consts/const-eval/issue-43197.rs b/src/test/ui/consts/const-eval/issue-43197.rs
index 849c81ad449..9109307632b 100644
--- a/src/test/ui/consts/const-eval/issue-43197.rs
+++ b/src/test/ui/consts/const-eval/issue-43197.rs
@@ -7,11 +7,13 @@ const fn foo(x: u32) -> u32 {
 }
 
 fn main() {
-    const X: u32 = 0-1;
+    const X: u32 = 0 - 1;
     //~^ WARN any use of this value will cause
-    const Y: u32 = foo(0-1);
+    const Y: u32 = foo(0 - 1);
     //~^ WARN any use of this value will cause
     println!("{} {}", X, Y);
     //~^ ERROR evaluation of constant expression failed
     //~| ERROR evaluation of constant expression failed
+    //~| WARN erroneous constant used [const_err]
+    //~| WARN erroneous constant used [const_err]
 }
diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr
index a1b3a05ed41..23b54d954c6 100644
--- a/src/test/ui/consts/const-eval/issue-43197.stderr
+++ b/src/test/ui/consts/const-eval/issue-43197.stderr
@@ -1,8 +1,8 @@
 warning: any use of this value will cause an error
   --> $DIR/issue-43197.rs:10:20
    |
-LL |     const X: u32 = 0-1;
-   |     ---------------^^^-
+LL |     const X: u32 = 0 - 1;
+   |     ---------------^^^^^-
    |                    |
    |                    attempt to subtract with overflow
    |
@@ -15,8 +15,8 @@ LL | #![warn(const_err)]
 warning: any use of this value will cause an error
   --> $DIR/issue-43197.rs:12:24
    |
-LL |     const Y: u32 = foo(0-1);
-   |     -------------------^^^--
+LL |     const Y: u32 = foo(0 - 1);
+   |     -------------------^^^^^--
    |                        |
    |                        attempt to subtract with overflow
 
@@ -26,12 +26,24 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{} {}", X, Y);
    |                       ^ referenced constant has errors
 
+warning: erroneous constant used
+  --> $DIR/issue-43197.rs:14:23
+   |
+LL |     println!("{} {}", X, Y);
+   |                       ^ referenced constant has errors
+
 error[E0080]: evaluation of constant expression failed
   --> $DIR/issue-43197.rs:14:26
    |
 LL |     println!("{} {}", X, Y);
    |                          ^ referenced constant has errors
 
+warning: erroneous constant used
+  --> $DIR/issue-43197.rs:14:26
+   |
+LL |     println!("{} {}", X, Y);
+   |                          ^ referenced constant has errors
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-44578.rs b/src/test/ui/consts/const-eval/issue-44578.rs
index 7da9256bb39..f9194709dc0 100644
--- a/src/test/ui/consts/const-eval/issue-44578.rs
+++ b/src/test/ui/consts/const-eval/issue-44578.rs
@@ -25,5 +25,5 @@ impl Foo for u16 {
 
 fn main() {
     println!("{}", <Bar<u16, u8> as Foo>::AMT);
-    //~^ ERROR E0080
+    //~^ ERROR evaluation of constant expression failed [E0080]
 }
diff --git a/src/test/ui/consts/const-eval/issue-50814.rs b/src/test/ui/consts/const-eval/issue-50814.rs
index e589126a942..5c3635e4650 100644
--- a/src/test/ui/consts/const-eval/issue-50814.rs
+++ b/src/test/ui/consts/const-eval/issue-50814.rs
@@ -12,11 +12,13 @@ impl Unsigned for U8 {
 struct Sum<A,B>(A,B);
 
 impl<A: Unsigned, B: Unsigned> Unsigned for Sum<A,B> {
-    const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will cause an error
+    const MAX: u8 = A::MAX + B::MAX;
+    //~^ ERROR any use of this value will cause an error [const_err]
 }
 
 fn foo<T>(_: T) -> &'static u8 {
-    &Sum::<U8,U8>::MAX //~ ERROR E0080
+    &Sum::<U8,U8>::MAX
+    //~^ ERROR E0080
 }
 
 fn main() {
diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr
index f8b017e4b53..2e5167a99a2 100644
--- a/src/test/ui/consts/const-eval/issue-50814.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814.stderr
@@ -9,7 +9,7 @@ LL |     const MAX: u8 = A::MAX + B::MAX;
    = note: `#[deny(const_err)]` on by default
 
 error[E0080]: evaluation of constant expression failed
-  --> $DIR/issue-50814.rs:19:5
+  --> $DIR/issue-50814.rs:20:5
    |
 LL |     &Sum::<U8,U8>::MAX
    |     ^-----------------
diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs
index 2eed8ca7d32..fee232185d2 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors.rs
@@ -1,20 +1,22 @@
-// build-fail
+// build-pass
 // compile-flags: -O
 
-#![deny(const_err)]
+#![warn(const_err)]
 
 fn main() {
     println!("{}", 0u32 - 1);
     let _x = 0u32 - 1;
-    //~^ ERROR const_err
-    println!("{}", 1/(1-1));
-    //~^ ERROR attempt to divide by zero [const_err]
-    //~| ERROR const_err
-    let _x = 1/(1-1);
-    //~^ ERROR const_err
-    println!("{}", 1/(false as u32));
-    //~^ ERROR attempt to divide by zero [const_err]
-    //~| ERROR const_err
-    let _x = 1/(false as u32);
-    //~^ ERROR const_err
+    //~^ WARN const_err
+    println!("{}", 1 / (1 - 1));
+    //~^ WARN attempt to divide by zero [const_err]
+    //~| WARN const_err
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (1 - 1);
+    //~^ WARN const_err
+    println!("{}", 1 / (false as u32));
+    //~^ WARN attempt to divide by zero [const_err]
+    //~| WARN const_err
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (false as u32);
+    //~^ WARN const_err
 }
diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr
index 8f17ef05f23..4de22fdf4ab 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.stderr
@@ -1,4 +1,4 @@
-error: this expression will panic at runtime
+warning: this expression will panic at runtime
   --> $DIR/promoted_errors.rs:8:14
    |
 LL |     let _x = 0u32 - 1;
@@ -7,44 +7,54 @@ LL |     let _x = 0u32 - 1;
 note: lint level defined here
   --> $DIR/promoted_errors.rs:4:9
    |
-LL | #![deny(const_err)]
+LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
-error: attempt to divide by zero
+warning: attempt to divide by zero
   --> $DIR/promoted_errors.rs:10:20
    |
-LL |     println!("{}", 1/(1-1));
-   |                    ^^^^^^^
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
+warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors.rs:10:20
    |
-LL |     println!("{}", 1/(1-1));
-   |                    ^^^^^^^ dividing by zero
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ dividing by zero
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:13:14
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:10:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ referenced constant has errors
+
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors.rs:14:14
    |
-LL |     let _x = 1/(1-1);
-   |              ^^^^^^^
+LL |     let _x = 1 / (1 - 1);
+   |              ^^^^^^^^^^^
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:15:20
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors.rs:16:20
    |
-LL |     println!("{}", 1/(false as u32));
-   |                    ^^^^^^^^^^^^^^^^
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors.rs:15:20
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors.rs:16:20
    |
-LL |     println!("{}", 1/(false as u32));
-   |                    ^^^^^^^^^^^^^^^^ dividing by zero
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ dividing by zero
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:18:14
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:16:20
    |
-LL |     let _x = 1/(false as u32);
-   |              ^^^^^^^^^^^^^^^^
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ referenced constant has errors
 
-error: aborting due to 7 previous errors
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors.rs:20:14
+   |
+LL |     let _x = 1 / (false as u32);
+   |              ^^^^^^^^^^^^^^^^^^
 
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs
index ae680b4f107..41a989d91c5 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors2.rs
@@ -1,21 +1,23 @@
-// build-fail
+// build-pass
 // compile-flags: -C overflow-checks=on -O
 
-#![deny(const_err)]
+#![warn(const_err)]
 
 fn main() {
     println!("{}", 0u32 - 1);
-    //~^ ERROR attempt to subtract with overflow
+    //~^ WARN attempt to subtract with overflow
     let _x = 0u32 - 1;
-    //~^ ERROR attempt to subtract with overflow
-    println!("{}", 1/(1-1));
-    //~^ ERROR attempt to divide by zero [const_err]
-    //~| ERROR const_err
-    let _x = 1/(1-1);
-    //~^ ERROR const_err
-    println!("{}", 1/(false as u32));
-    //~^ ERROR attempt to divide by zero [const_err]
-    //~| ERROR const_err
-    let _x = 1/(false as u32);
-    //~^ ERROR const_err
+    //~^ WARN attempt to subtract with overflow
+    println!("{}", 1 / (1 - 1));
+    //~^ WARN attempt to divide by zero [const_err]
+    //~| WARN const_err
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (1 - 1);
+    //~^ WARN const_err
+    println!("{}", 1 / (false as u32));
+    //~^ WARN attempt to divide by zero [const_err]
+    //~| WARN const_err
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (false as u32);
+    //~^ WARN const_err
 }
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr
index 60a3cba6e1f..4f7ba8bf385 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr
@@ -1,4 +1,4 @@
-error: attempt to subtract with overflow
+warning: attempt to subtract with overflow
   --> $DIR/promoted_errors2.rs:7:20
    |
 LL |     println!("{}", 0u32 - 1);
@@ -7,50 +7,60 @@ LL |     println!("{}", 0u32 - 1);
 note: lint level defined here
   --> $DIR/promoted_errors2.rs:4:9
    |
-LL | #![deny(const_err)]
+LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
-error: attempt to subtract with overflow
+warning: attempt to subtract with overflow
   --> $DIR/promoted_errors2.rs:9:14
    |
 LL |     let _x = 0u32 - 1;
    |              ^^^^^^^^
 
-error: attempt to divide by zero
+warning: attempt to divide by zero
   --> $DIR/promoted_errors2.rs:11:20
    |
-LL |     println!("{}", 1/(1-1));
-   |                    ^^^^^^^
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
+warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors2.rs:11:20
    |
-LL |     println!("{}", 1/(1-1));
-   |                    ^^^^^^^ dividing by zero
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ dividing by zero
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:14:14
+warning: erroneous constant used
+  --> $DIR/promoted_errors2.rs:11:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ referenced constant has errors
+
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors2.rs:15:14
    |
-LL |     let _x = 1/(1-1);
-   |              ^^^^^^^
+LL |     let _x = 1 / (1 - 1);
+   |              ^^^^^^^^^^^
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:16:20
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors2.rs:17:20
    |
-LL |     println!("{}", 1/(false as u32));
-   |                    ^^^^^^^^^^^^^^^^
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors2.rs:16:20
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors2.rs:17:20
    |
-LL |     println!("{}", 1/(false as u32));
-   |                    ^^^^^^^^^^^^^^^^ dividing by zero
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ dividing by zero
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:19:14
+warning: erroneous constant used
+  --> $DIR/promoted_errors2.rs:17:20
    |
-LL |     let _x = 1/(false as u32);
-   |              ^^^^^^^^^^^^^^^^
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ referenced constant has errors
 
-error: aborting due to 8 previous errors
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors2.rs:21:14
+   |
+LL |     let _x = 1 / (false as u32);
+   |              ^^^^^^^^^^^^^^^^^^
 
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr
index 80d80a98675..ea9fffa883e 100644
--- a/src/test/ui/consts/const-eval/ub-nonnull.stderr
+++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr
@@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
 LL | |     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
 LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
 LL | |     let out_of_bounds_ptr = &ptr[255];
-   | |                             ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 6 which has size 1
+   | |                             ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 9 which has size 1
 LL | |     mem::transmute(out_of_bounds_ptr)
 LL | | } };
    | |____-
diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.rs b/src/test/ui/consts/miri_unleashed/non_const_fn.rs
index 32a713ebaa4..cfb57d21cee 100644
--- a/src/test/ui/consts/miri_unleashed/non_const_fn.rs
+++ b/src/test/ui/consts/miri_unleashed/non_const_fn.rs
@@ -11,5 +11,7 @@ const C: () = foo(); //~ WARN: skipping const checks
 //~^ WARN any use of this value will cause an error
 
 fn main() {
-    println!("{:?}", C); //~ ERROR: evaluation of constant expression failed
+    println!("{:?}", C);
+    //~^ ERROR: evaluation of constant expression failed
+    //~| WARN: erroneous constant used [const_err]
 }
diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
index 75f532a81bd..6a7df858feb 100644
--- a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
+++ b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
@@ -24,6 +24,12 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{:?}", C);
    |                      ^ referenced constant has errors
 
+warning: erroneous constant used
+  --> $DIR/non_const_fn.rs:14:22
+   |
+LL |     println!("{:?}", C);
+   |                      ^ referenced constant has errors
+
 error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/zst_no_llvm_alloc.rs b/src/test/ui/consts/zst_no_llvm_alloc.rs
index 5d779355400..2a41f708c2b 100644
--- a/src/test/ui/consts/zst_no_llvm_alloc.rs
+++ b/src/test/ui/consts/zst_no_llvm_alloc.rs
@@ -7,13 +7,15 @@ static FOO: Foo = Foo;
 
 fn main() {
     let x: &'static () = &();
-    assert_eq!(x as *const () as usize, 1);
+    assert_ne!(x as *const () as usize, 1);
     let x: &'static Foo = &Foo;
-    assert_eq!(x as *const Foo as usize, 4);
+    assert_ne!(x as *const Foo as usize, 4);
 
     // statics must have a unique address
     assert_ne!(&FOO as *const Foo as usize, 4);
 
-    assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
-    assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
+    // FIXME this two tests should be assert_eq!
+    // this stopped working since we are promoting to constants instead of statics
+    assert_ne!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
+    assert_ne!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
 }
diff --git a/src/test/ui/invalid_const_promotion.rs b/src/test/ui/invalid_const_promotion.rs
deleted file mode 100644
index 5d7664cefb3..00000000000
--- a/src/test/ui/invalid_const_promotion.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// run-pass
-
-#![allow(unused_mut)]
-// ignore-wasm32
-// ignore-emscripten
-// ignore-sgx no processes
-
-// compile-flags: -C debug_assertions=yes
-
-#![stable(feature = "rustc", since = "1.0.0")]
-#![feature(const_fn, rustc_private, staged_api, rustc_attrs)]
-#![allow(const_err)]
-
-extern crate libc;
-
-use std::env;
-use std::process::{Command, Stdio};
-
-// this will panic in debug mode and overflow in release mode
-//
-// NB we give bar an unused argument because otherwise memoization
-// of the const fn kicks in, causing a different code path in the
-// compiler to be executed (see PR #66294).
-#[stable(feature = "rustc", since = "1.0.0")]
-#[rustc_const_stable(feature = "rustc", since = "1.0.0")]
-#[rustc_promotable]
-const fn bar(_: bool) -> usize { 0 - 1 }
-
-fn foo() {
-    let _: &'static _ = &bar(true);
-}
-
-#[cfg(unix)]
-fn check_status(status: std::process::ExitStatus)
-{
-    use std::os::unix::process::ExitStatusExt;
-
-    assert!(status.signal() == Some(libc::SIGILL)
-            || status.signal() == Some(libc::SIGTRAP)
-            || status.signal() == Some(libc::SIGABRT));
-}
-
-#[cfg(not(unix))]
-fn check_status(status: std::process::ExitStatus)
-{
-    assert!(!status.success());
-}
-
-fn main() {
-    let args: Vec<String> = env::args().collect();
-    if args.len() > 1 && args[1] == "test" {
-        foo();
-        return;
-    }
-
-    let mut p = Command::new(&args[0])
-        .stdout(Stdio::piped())
-        .stdin(Stdio::piped())
-        .arg("test").output().unwrap();
-    check_status(p.status);
-}
diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr
index 53ab2f9878f..affb5537b18 100644
--- a/src/test/ui/symbol-names/impl1.legacy.stderr
+++ b/src/test/ui/symbol-names/impl1.legacy.stderr
@@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz)
 LL |         #[rustc_def_path]
    |         ^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h92c563325b7ff21aE)
+error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17hf07584432cd4d8beE)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h92c563325b7ff21a)
+error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::hf07584432cd4d8be)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]