diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs
index 566601f0cae28..dc2b0e1b983dc 100644
--- a/src/librustc_mir/interpret/intrinsics/caller_location.rs
+++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs
@@ -39,7 +39,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let loc_ty = self
             .tcx
             .type_of(self.tcx.require_lang_item(PanicLocationLangItem, None))
-            .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_static.into()].iter()));
+            .subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
         let loc_layout = self.layout_of(loc_ty).unwrap();
         let location = self.allocate(loc_layout, MemoryKind::CallerLocation);
 
diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs
index 5288b6b370ddb..3d219ac2c01ec 100644
--- a/src/librustc_mir/transform/cleanup_post_borrowck.rs
+++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs
@@ -32,6 +32,7 @@ impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
         let mut delete = DeleteNonCodegenStatements { tcx };
         delete.visit_body(body);
+        body.user_type_annotations.raw.clear();
     }
 }
 
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
deleted file mode 100644
index 996b97c03b14e..0000000000000
--- a/src/librustc_mir/transform/erase_regions.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-//! This pass erases all early-bound regions from the types occurring in the MIR.
-//! We want to do this once just before codegen, so codegen does not have to take
-//! care erasing regions all over the place.
-//! N.B., we do _not_ erase regions of statements that are relevant for
-//! "types-as-contracts"-validation, namely, `AcquireValid` and `ReleaseValid`.
-
-use crate::transform::{MirPass, MirSource};
-use rustc::mir::visit::{MutVisitor, TyContext};
-use rustc::mir::*;
-use rustc::ty::subst::SubstsRef;
-use rustc::ty::{self, Ty, TyCtxt};
-
-struct EraseRegionsVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl EraseRegionsVisitor<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
-        EraseRegionsVisitor { tcx }
-    }
-}
-
-impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
-        *ty = self.tcx.erase_regions(ty);
-    }
-
-    fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) {
-        *region = self.tcx.lifetimes.re_erased;
-    }
-
-    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
-        *constant = self.tcx.erase_regions(constant);
-    }
-
-    fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) {
-        *substs = self.tcx.erase_regions(substs);
-    }
-
-    fn process_projection_elem(&mut self, elem: &PlaceElem<'tcx>) -> Option<PlaceElem<'tcx>> {
-        if let PlaceElem::Field(field, ty) = elem {
-            let new_ty = self.tcx.erase_regions(ty);
-
-            if new_ty != *ty {
-                return Some(PlaceElem::Field(*field, new_ty));
-            }
-        }
-
-        None
-    }
-}
-
-pub struct EraseRegions;
-
-impl<'tcx> MirPass<'tcx> for EraseRegions {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
-        EraseRegionsVisitor::new(tcx).visit_body(body);
-    }
-}
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index b2906739ff1b1..82c5ac689b568 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -357,18 +357,11 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
     }
 }
 
-fn make_generator_state_argument_indirect<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-    body: &mut BodyAndCache<'tcx>,
-) {
+fn make_generator_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyAndCache<'tcx>) {
     let gen_ty = body.local_decls.raw[1].ty;
 
-    let region = ty::ReFree(ty::FreeRegion { scope: def_id, bound_region: ty::BoundRegion::BrEnv });
-
-    let region = tcx.mk_region(region);
-
-    let ref_gen_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut });
+    let ref_gen_ty =
+        tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty: gen_ty, mutbl: Mutability::Mut });
 
     // Replace the by value generator argument
     body.local_decls.raw[1].ty = ref_gen_ty;
@@ -874,7 +867,6 @@ fn elaborate_generator_drops<'tcx>(
 fn create_generator_drop_shim<'tcx>(
     tcx: TyCtxt<'tcx>,
     transform: &TransformVisitor<'tcx>,
-    def_id: DefId,
     source: MirSource<'tcx>,
     gen_ty: Ty<'tcx>,
     body: &mut BodyAndCache<'tcx>,
@@ -912,7 +904,7 @@ fn create_generator_drop_shim<'tcx>(
         local_info: LocalInfo::Other,
     };
 
-    make_generator_state_argument_indirect(tcx, def_id, &mut body);
+    make_generator_state_argument_indirect(tcx, &mut body);
 
     // Change the generator argument from &mut to *mut
     body.local_decls[SELF_ARG] = LocalDecl {
@@ -1047,7 +1039,6 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
 fn create_generator_resume_function<'tcx>(
     tcx: TyCtxt<'tcx>,
     transform: TransformVisitor<'tcx>,
-    def_id: DefId,
     source: MirSource<'tcx>,
     body: &mut BodyAndCache<'tcx>,
     can_return: bool,
@@ -1112,7 +1103,7 @@ fn create_generator_resume_function<'tcx>(
 
     insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
 
-    make_generator_state_argument_indirect(tcx, def_id, body);
+    make_generator_state_argument_indirect(tcx, body);
     make_generator_state_argument_pinned(tcx, body);
 
     no_landing_pads(tcx, body);
@@ -1332,11 +1323,11 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
 
         // Create a copy of our MIR and use it to create the drop shim for the generator
         let drop_shim =
-            create_generator_drop_shim(tcx, &transform, def_id, source, gen_ty, body, drop_clean);
+            create_generator_drop_shim(tcx, &transform, source, gen_ty, body, drop_clean);
 
         body.generator_drop = Some(box drop_shim);
 
         // Create the Generator::resume function
-        create_generator_resume_function(tcx, transform, def_id, source, body, can_return);
+        create_generator_resume_function(tcx, transform, source, body, can_return);
     }
 }
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 3eb9d23a32a25..50868434baa32 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -22,7 +22,6 @@ pub mod copy_prop;
 pub mod deaggregator;
 pub mod dump_mir;
 pub mod elaborate_drops;
-pub mod erase_regions;
 pub mod generator;
 pub mod inline;
 pub mod instcombine;
@@ -296,8 +295,6 @@ fn run_optimization_passes<'tcx>(
             &simplify::SimplifyCfg::new("elaborate-drops"),
             // No lifetime analysis based on borrowing can be done from here on out.
 
-            // From here on out, regions are gone.
-            &erase_regions::EraseRegions,
             // Optimizations begin.
             &unreachable_prop::UnreachablePropagation,
             &uninhabited_enum_branching::UninhabitedEnumBranching,
@@ -341,6 +338,9 @@ fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &BodyAndCache<'_> {
     let mut body = body.steal();
     run_optimization_passes(tcx, &mut body, def_id, None);
     body.ensure_predecessors();
+
+    debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
+
     tcx.arena.alloc(body)
 }
 
@@ -358,5 +358,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &IndexVec<Promoted, BodyAndCa
         body.ensure_predecessors();
     }
 
+    debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
+
     tcx.intern_promoted(promoted)
 }
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 1336206e18626..a27c80d91cfd0 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -913,7 +913,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                         ty,
                         val: ty::ConstKind::Unevaluated(
                             def_id,
-                            InternalSubsts::identity_for_item(tcx, def_id),
+                            InternalSubsts::for_item(tcx, def_id, |param, _| {
+                                if let ty::GenericParamDefKind::Lifetime = param.kind {
+                                    tcx.lifetimes.re_erased.into()
+                                } else {
+                                    tcx.mk_param_from_def(param)
+                                }
+                            }),
                             Some(promoted_id),
                         ),
                     }),
diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
index 821c4d68c7e8a..ac613adbcc6ca 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -6,7 +6,7 @@ use rustc::middle::lang_items;
 use rustc::middle::region;
 use rustc::mir::*;
 use rustc::ty::subst::Subst;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_attr::{self as attr, UnwindAttr};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -43,8 +43,7 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> {
             ..
         })
         | Node::TraitItem(hir::TraitItem {
-            kind:
-                hir::TraitItemKind::Fn(hir::FnSig { decl, .. }, hir::TraitFn::Provided(body_id)),
+            kind: hir::TraitItemKind::Fn(hir::FnSig { decl, .. }, hir::TraitFn::Provided(body_id)),
             ..
         }) => (*body_id, decl.output.span()),
         Node::Item(hir::Item { kind: hir::ItemKind::Static(ty, _, body_id), .. })
@@ -128,12 +127,8 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> {
                 let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() {
                     let va_list_did =
                         tcx.require_lang_item(lang_items::VaListTypeLangItem, Some(arg.span));
-                    let region = tcx.mk_region(ty::ReScope(region::Scope {
-                        id: body.value.hir_id.local_id,
-                        data: region::ScopeData::CallSite,
-                    }));
 
-                    tcx.type_of(va_list_did).subst(tcx, &[region.into()])
+                    tcx.type_of(va_list_did).subst(tcx, &[tcx.lifetimes.re_erased.into()])
                 } else {
                     fn_sig.inputs()[index]
                 };
@@ -189,6 +184,20 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> {
 
         let mut body = BodyAndCache::new(body);
         body.ensure_predecessors();
+
+        // The borrow checker will replace all the regions here with its own
+        // inference variables. There's no point having non-erased regions here.
+        // The exception is `body.user_type_annotations`, which is used unmodified
+        // by borrow checking.
+        debug_assert!(
+            !(body.local_decls.has_free_regions()
+                || body.basic_blocks().has_free_regions()
+                || body.var_debug_info.has_free_regions()
+                || body.yield_ty.has_free_regions()),
+            "Unexpected free regions in MIR: {:?}",
+            body,
+        );
+
         body
     })
 }
@@ -209,7 +218,7 @@ fn liberated_closure_env_ty(
     };
 
     let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap();
-    tcx.liberate_late_bound_regions(closure_def_id, &closure_env_ty)
+    tcx.erase_late_bound_regions(&closure_env_ty)
 }
 
 #[derive(Debug, PartialEq, Eq)]
diff --git a/src/test/mir-opt/array-index-is-temporary.rs b/src/test/mir-opt/array-index-is-temporary.rs
index 096f98bade25a..57f30acb3a643 100644
--- a/src/test/mir-opt/array-index-is-temporary.rs
+++ b/src/test/mir-opt/array-index-is-temporary.rs
@@ -15,7 +15,7 @@ fn main() {
 }
 
 // END RUST SOURCE
-// START rustc.main.EraseRegions.after.mir
+// START rustc.main.SimplifyCfg-elaborate-drops.after.mir
 //     bb0: {
 //         ...
 //         _4 = &mut _2;
@@ -38,4 +38,4 @@ fn main() {
 //         ...
 //         return;
 //     }
-// END rustc.main.EraseRegions.after.mir
+// END rustc.main.SimplifyCfg-elaborate-drops.after.mir
diff --git a/src/test/mir-opt/byte_slice.rs b/src/test/mir-opt/byte_slice.rs
index 7edfa3e1124db..0fb685c3c4e6d 100644
--- a/src/test/mir-opt/byte_slice.rs
+++ b/src/test/mir-opt/byte_slice.rs
@@ -6,10 +6,10 @@ fn main() {
 }
 
 // END RUST SOURCE
-// START rustc.main.EraseRegions.after.mir
+// START rustc.main.SimplifyCfg-elaborate-drops.after.mir
 // ...
 // _1 = const b"foo";
 // ...
 // _2 = [const 5u8, const 120u8];
 // ...
-// END rustc.main.EraseRegions.after.mir
+// END rustc.main.SimplifyCfg-elaborate-drops.after.mir
diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs
index 113f81c441f7c..39b9006017958 100644
--- a/src/test/mir-opt/packed-struct-drop-aligned.rs
+++ b/src/test/mir-opt/packed-struct-drop-aligned.rs
@@ -15,7 +15,7 @@ impl Drop for Droppy {
 }
 
 // END RUST SOURCE
-// START rustc.main.EraseRegions.before.mir
+// START rustc.main.SimplifyCfg-elaborate-drops.after.mir
 // fn main() -> () {
 //     let mut _0: ();
 //     let mut _1: Packed;
@@ -56,4 +56,4 @@ impl Drop for Droppy {
 //         drop(_1) -> [return: bb2, unwind: bb1];
 //     }
 // }
-// END rustc.main.EraseRegions.before.mir
+// END rustc.main.SimplifyCfg-elaborate-drops.after.mir
diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs
index 1c88a9e4d5a32..e917441200b8a 100644
--- a/src/test/mir-opt/retag.rs
+++ b/src/test/mir-opt/retag.rs
@@ -8,8 +8,12 @@ struct Test(i32);
 
 impl Test {
     // Make sure we run the pass on a method, not just on bare functions.
-    fn foo<'x>(&self, x: &'x mut i32) -> &'x mut i32 { x }
-    fn foo_shr<'x>(&self, x: &'x i32) -> &'x i32 { x }
+    fn foo<'x>(&self, x: &'x mut i32) -> &'x mut i32 {
+        x
+    }
+    fn foo_shr<'x>(&self, x: &'x i32) -> &'x i32 {
+        x
+    }
 }
 
 impl Drop for Test {
@@ -27,7 +31,10 @@ fn main() {
     }
 
     // Also test closures
-    let c: fn(&i32) -> &i32 = |x: &i32| -> &i32 { let _y = x; x };
+    let c: fn(&i32) -> &i32 = |x: &i32| -> &i32 {
+        let _y = x;
+        x
+    };
     let _w = c(&x);
 
     // need to call `foo_shr` or it doesn't even get generated
@@ -38,7 +45,7 @@ fn main() {
 }
 
 // END RUST SOURCE
-// START rustc.{{impl}}-foo.EraseRegions.after.mir
+// START rustc.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir
 //     bb0: {
 //         Retag([fn entry] _1);
 //         Retag([fn entry] _2);
@@ -48,8 +55,8 @@ fn main() {
 //         ...
 //         return;
 //     }
-// END rustc.{{impl}}-foo.EraseRegions.after.mir
-// START rustc.{{impl}}-foo_shr.EraseRegions.after.mir
+// END rustc.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir
+// START rustc.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir
 //     bb0: {
 //         Retag([fn entry] _1);
 //         Retag([fn entry] _2);
@@ -59,8 +66,8 @@ fn main() {
 //         ...
 //         return;
 //     }
-// END rustc.{{impl}}-foo_shr.EraseRegions.after.mir
-// START rustc.main.EraseRegions.after.mir
+// END rustc.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir
+// START rustc.main.SimplifyCfg-elaborate-drops.after.mir
 // fn main() -> () {
 //     ...
 //     bb0: {
@@ -96,8 +103,8 @@ fn main() {
 //
 //     ...
 // }
-// END rustc.main.EraseRegions.after.mir
-// START rustc.main-{{closure}}.EraseRegions.after.mir
+// END rustc.main.SimplifyCfg-elaborate-drops.after.mir
+// START rustc.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir
 // fn main::{{closure}}#0(_1: &[closure@main::{{closure}}#0], _2: &i32) -> &i32 {
 //     ...
 //     bb0: {
@@ -112,7 +119,7 @@ fn main() {
 //         return;
 //     }
 // }
-// END rustc.main-{{closure}}.EraseRegions.after.mir
+// END rustc.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir
 // START rustc.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
 // fn  std::intrinsics::drop_in_place(_1: *mut Test) -> () {
 //     ...