diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 4546e0bf253c3..a2d70bc05c1d4 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,7 +14,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ -#![cfg_attr(not(stage0), feature(nll))] +#![feature(nll)] #![feature(in_band_lifetimes)] #![feature(impl_header_lifetime_elision)] #![feature(slice_patterns)] diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 9edb1a1f76a6d..aaba7ab8418f5 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -33,7 +33,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc::middle::region; -use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind}; +use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place}; +use rustc::mir::{Rvalue, Statement, StatementKind}; use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; use rustc::ty::{Ty, RegionKind, TyCtxt}; use transform::{MirPass, MirSource}; @@ -135,3 +136,62 @@ impl<'tcx> MutVisitor<'tcx> for DeleteAscribeUserType { self.super_statement(block, statement, location); } } + +pub struct CleanFakeReadsAndBorrows; + +pub struct DeleteAndRecordFakeReads { + fake_borrow_temporaries: FxHashSet, +} + +pub struct DeleteFakeBorrows { + fake_borrow_temporaries: FxHashSet, +} + +// Removes any FakeReads from the MIR +impl MirPass for CleanFakeReadsAndBorrows { + fn run_pass<'a, 'tcx>(&self, + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _source: MirSource, + mir: &mut Mir<'tcx>) { + let mut delete_reads = DeleteAndRecordFakeReads { + fake_borrow_temporaries: FxHashSet(), + }; + delete_reads.visit_mir(mir); + let mut delete_borrows = DeleteFakeBorrows { + fake_borrow_temporaries: delete_reads.fake_borrow_temporaries, + }; + delete_borrows.visit_mir(mir); + } +} + +impl<'tcx> MutVisitor<'tcx> for DeleteAndRecordFakeReads { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + if let StatementKind::FakeRead(cause, ref place) = statement.kind { + if let FakeReadCause::ForMatchGuard = cause { + match *place { + Place::Local(local) => self.fake_borrow_temporaries.insert(local), + _ => bug!("Fake match guard read of non-local: {:?}", place), + }; + } + statement.make_nop(); + } + self.super_statement(block, statement, location); + } +} + +impl<'tcx> MutVisitor<'tcx> for DeleteFakeBorrows { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + if let StatementKind::Assign(Place::Local(local), _) = statement.kind { + if self.fake_borrow_temporaries.contains(&local) { + statement.make_nop(); + } + } + self.super_statement(block, statement, location); + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 19fb35be9d4e0..d18836999dccf 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -237,9 +237,12 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx no_landing_pads::NoLandingPads, simplify_branches::SimplifyBranches::new("initial"), remove_noop_landing_pads::RemoveNoopLandingPads, - simplify::SimplifyCfg::new("early-opt"), // Remove all `AscribeUserType` statements. cleanup_post_borrowck::CleanAscribeUserType, + // Remove all `FakeRead` statements and the borrows that are only + // used for checking matches + cleanup_post_borrowck::CleanFakeReadsAndBorrows, + simplify::SimplifyCfg::new("early-opt"), // These next passes must be executed together add_call_guards::CriticalCallEdges, diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs new file mode 100644 index 0000000000000..8411fba02e977 --- /dev/null +++ b/src/test/mir-opt/remove_fake_borrows.rs @@ -0,0 +1,122 @@ +// Test that the fake borrows for matches are removed after borrow checking. + +// ignore-wasm32-bare + +#![feature(nll)] + +fn match_guard(x: Option<&&i32>) -> i32 { + match x { + Some(0) if true => 0, + _ => 1, + } +} + +fn main() { + match_guard(None); +} + +// END RUST SOURCE + +// START rustc.match_guard.CleanFakeReadsAndBorrows.before.mir +// bb0: { +// FakeRead(ForMatchedPlace, _1); +// _2 = discriminant(_1); +// _3 = &shallow _1; +// _4 = &shallow ((_1 as Some).0: &' &' i32); +// _5 = &shallow (*((_1 as Some).0: &' &' i32)); +// _6 = &shallow (*(*((_1 as Some).0: &' &' i32))); +// switchInt(move _2) -> [1isize: bb6, otherwise: bb4]; +// } +// bb1: { +// _0 = const 0i32; +// goto -> bb9; +// } +// bb2: { +// _0 = const 1i32; +// goto -> bb9; +// } +// bb3: { +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForMatchGuard, _5); +// FakeRead(ForMatchGuard, _6); +// goto -> bb7; +// } +// bb4: { +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForMatchGuard, _5); +// FakeRead(ForMatchGuard, _6); +// goto -> bb2; +// } +// bb5: { +// unreachable; +// } +// bb6: { +// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb4]; +// } +// bb7: { +// goto -> bb1; +// } +// bb8: { +// goto -> bb4; +// } +// bb9: { +// return; +// } +// bb10: { +// resume; +// } +// END rustc.match_guard.CleanFakeReadsAndBorrows.before.mir + +// START rustc.match_guard.CleanFakeReadsAndBorrows.after.mir +// bb0: { +// nop; +// _2 = discriminant(_1); +// nop; +// nop; +// nop; +// nop; +// switchInt(move _2) -> [1isize: bb6, otherwise: bb4]; +// } +// bb1: { +// _0 = const 0i32; +// goto -> bb9; +// } +// bb2: { +// _0 = const 1i32; +// goto -> bb9; +// } +// bb3: { +// nop; +// nop; +// nop; +// nop; +// goto -> bb7; +// } +// bb4: { +// nop; +// nop; +// nop; +// nop; +// goto -> bb2; +// } +// bb5: { +// unreachable; +// } +// bb6: { +// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb4]; +// } +// bb7: { +// goto -> bb1; +// } +// bb8: { +// goto -> bb4; +// } +// bb9: { +// return; +// } +// bb10: { +// resume; +// } +// END rustc.match_guard.CleanFakeReadsAndBorrows.after.mir