From 0f0f254a9c90c4fe47897554948f82e44033f37a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 19 Mar 2020 11:40:38 +0000 Subject: [PATCH] Use erased regions in MIR --- .../interpret/intrinsics/caller_location.rs | 2 +- .../transform/cleanup_post_borrowck.rs | 1 + src/librustc_mir/transform/erase_regions.rs | 63 ------------------- src/librustc_mir/transform/generator.rs | 23 +++---- src/librustc_mir/transform/mod.rs | 8 ++- src/librustc_mir/transform/promote_consts.rs | 8 ++- src/librustc_mir_build/build/mod.rs | 27 +++++--- src/test/mir-opt/array-index-is-temporary.rs | 4 +- src/test/mir-opt/byte_slice.rs | 4 +- .../mir-opt/packed-struct-drop-aligned.rs | 4 +- src/test/mir-opt/retag.rs | 29 +++++---- 11 files changed, 63 insertions(+), 110 deletions(-) delete mode 100644 src/librustc_mir/transform/erase_regions.rs 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> { - 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 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) -> () { // ...