about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2018-09-23 10:43:14 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2018-09-24 23:33:13 +0100
commitf71f733d482d892b5bff021b3955435e7b3eee25 (patch)
tree163045eabfcf8451464b38fef4495c6ae3ef1a3b /src
parent1a6ed0271e7cc8864e6030d945b92aaa850e4afe (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/lib.rs2
-rw-r--r--src/librustc_mir/transform/cleanup_post_borrowck.rs62
-rw-r--r--src/librustc_mir/transform/mod.rs5
-rw-r--r--src/test/mir-opt/remove_fake_borrows.rs122
4 files changed, 188 insertions, 3 deletions
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 4546e0bf253..a2d70bc05c1 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 9edb1a1f76a..aaba7ab8418 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<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);
+    }
+}
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 19fb35be9d4..d18836999dc 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 00000000000..8411fba02e9
--- /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: &'<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