Add a MIR transform to remove fake reads
As we are now creating borrows of places that may not be valid for borrow checking matches, these have to be removed to avoid generating broken code.
This commit is contained in:
parent
1a6ed0271e
commit
f71f733d48
@ -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)]
|
||||
|
@ -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<Local>,
|
||||
}
|
||||
|
||||
pub struct DeleteFakeBorrows {
|
||||
fake_borrow_temporaries: FxHashSet<Local>,
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
122
src/test/mir-opt/remove_fake_borrows.rs
Normal file
122
src/test/mir-opt/remove_fake_borrows.rs
Normal file
@ -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: &'<empty> &'<empty> i32);
|
||||
// _5 = &shallow (*((_1 as Some).0: &'<empty> &'<empty> i32));
|
||||
// _6 = &shallow (*(*((_1 as Some).0: &'<empty> &'<empty> 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: &'<empty> &'<empty> 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: &'<empty> &'<empty> i32)))) -> [0i32: bb3, otherwise: bb4];
|
||||
// }
|
||||
// bb7: {
|
||||
// goto -> bb1;
|
||||
// }
|
||||
// bb8: {
|
||||
// goto -> bb4;
|
||||
// }
|
||||
// bb9: {
|
||||
// return;
|
||||
// }
|
||||
// bb10: {
|
||||
// resume;
|
||||
// }
|
||||
// END rustc.match_guard.CleanFakeReadsAndBorrows.after.mir
|
Loading…
x
Reference in New Issue
Block a user