Skip to content

Commit f71f733

Browse files
committed
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.
1 parent 1a6ed02 commit f71f733

File tree

4 files changed

+188
-3
lines changed

4 files changed

+188
-3
lines changed

src/librustc_mir/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
1414
1515
*/
1616

17-
#![cfg_attr(not(stage0), feature(nll))]
17+
#![feature(nll)]
1818
#![feature(in_band_lifetimes)]
1919
#![feature(impl_header_lifetime_elision)]
2020
#![feature(slice_patterns)]

src/librustc_mir/transform/cleanup_post_borrowck.rs

+61-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
use rustc_data_structures::fx::FxHashSet;
3434

3535
use rustc::middle::region;
36-
use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind};
36+
use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place};
37+
use rustc::mir::{Rvalue, Statement, StatementKind};
3738
use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
3839
use rustc::ty::{Ty, RegionKind, TyCtxt};
3940
use transform::{MirPass, MirSource};
@@ -135,3 +136,62 @@ impl<'tcx> MutVisitor<'tcx> for DeleteAscribeUserType {
135136
self.super_statement(block, statement, location);
136137
}
137138
}
139+
140+
pub struct CleanFakeReadsAndBorrows;
141+
142+
pub struct DeleteAndRecordFakeReads {
143+
fake_borrow_temporaries: FxHashSet<Local>,
144+
}
145+
146+
pub struct DeleteFakeBorrows {
147+
fake_borrow_temporaries: FxHashSet<Local>,
148+
}
149+
150+
// Removes any FakeReads from the MIR
151+
impl MirPass for CleanFakeReadsAndBorrows {
152+
fn run_pass<'a, 'tcx>(&self,
153+
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
154+
_source: MirSource,
155+
mir: &mut Mir<'tcx>) {
156+
let mut delete_reads = DeleteAndRecordFakeReads {
157+
fake_borrow_temporaries: FxHashSet(),
158+
};
159+
delete_reads.visit_mir(mir);
160+
let mut delete_borrows = DeleteFakeBorrows {
161+
fake_borrow_temporaries: delete_reads.fake_borrow_temporaries,
162+
};
163+
delete_borrows.visit_mir(mir);
164+
}
165+
}
166+
167+
impl<'tcx> MutVisitor<'tcx> for DeleteAndRecordFakeReads {
168+
fn visit_statement(&mut self,
169+
block: BasicBlock,
170+
statement: &mut Statement<'tcx>,
171+
location: Location) {
172+
if let StatementKind::FakeRead(cause, ref place) = statement.kind {
173+
if let FakeReadCause::ForMatchGuard = cause {
174+
match *place {
175+
Place::Local(local) => self.fake_borrow_temporaries.insert(local),
176+
_ => bug!("Fake match guard read of non-local: {:?}", place),
177+
};
178+
}
179+
statement.make_nop();
180+
}
181+
self.super_statement(block, statement, location);
182+
}
183+
}
184+
185+
impl<'tcx> MutVisitor<'tcx> for DeleteFakeBorrows {
186+
fn visit_statement(&mut self,
187+
block: BasicBlock,
188+
statement: &mut Statement<'tcx>,
189+
location: Location) {
190+
if let StatementKind::Assign(Place::Local(local), _) = statement.kind {
191+
if self.fake_borrow_temporaries.contains(&local) {
192+
statement.make_nop();
193+
}
194+
}
195+
self.super_statement(block, statement, location);
196+
}
197+
}

src/librustc_mir/transform/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,12 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
237237
no_landing_pads::NoLandingPads,
238238
simplify_branches::SimplifyBranches::new("initial"),
239239
remove_noop_landing_pads::RemoveNoopLandingPads,
240-
simplify::SimplifyCfg::new("early-opt"),
241240
// Remove all `AscribeUserType` statements.
242241
cleanup_post_borrowck::CleanAscribeUserType,
242+
// Remove all `FakeRead` statements and the borrows that are only
243+
// used for checking matches
244+
cleanup_post_borrowck::CleanFakeReadsAndBorrows,
245+
simplify::SimplifyCfg::new("early-opt"),
243246

244247
// These next passes must be executed together
245248
add_call_guards::CriticalCallEdges,
+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Test that the fake borrows for matches are removed after borrow checking.
2+
3+
// ignore-wasm32-bare
4+
5+
#![feature(nll)]
6+
7+
fn match_guard(x: Option<&&i32>) -> i32 {
8+
match x {
9+
Some(0) if true => 0,
10+
_ => 1,
11+
}
12+
}
13+
14+
fn main() {
15+
match_guard(None);
16+
}
17+
18+
// END RUST SOURCE
19+
20+
// START rustc.match_guard.CleanFakeReadsAndBorrows.before.mir
21+
// bb0: {
22+
// FakeRead(ForMatchedPlace, _1);
23+
// _2 = discriminant(_1);
24+
// _3 = &shallow _1;
25+
// _4 = &shallow ((_1 as Some).0: &'<empty> &'<empty> i32);
26+
// _5 = &shallow (*((_1 as Some).0: &'<empty> &'<empty> i32));
27+
// _6 = &shallow (*(*((_1 as Some).0: &'<empty> &'<empty> i32)));
28+
// switchInt(move _2) -> [1isize: bb6, otherwise: bb4];
29+
// }
30+
// bb1: {
31+
// _0 = const 0i32;
32+
// goto -> bb9;
33+
// }
34+
// bb2: {
35+
// _0 = const 1i32;
36+
// goto -> bb9;
37+
// }
38+
// bb3: {
39+
// FakeRead(ForMatchGuard, _3);
40+
// FakeRead(ForMatchGuard, _4);
41+
// FakeRead(ForMatchGuard, _5);
42+
// FakeRead(ForMatchGuard, _6);
43+
// goto -> bb7;
44+
// }
45+
// bb4: {
46+
// FakeRead(ForMatchGuard, _3);
47+
// FakeRead(ForMatchGuard, _4);
48+
// FakeRead(ForMatchGuard, _5);
49+
// FakeRead(ForMatchGuard, _6);
50+
// goto -> bb2;
51+
// }
52+
// bb5: {
53+
// unreachable;
54+
// }
55+
// bb6: {
56+
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb3, otherwise: bb4];
57+
// }
58+
// bb7: {
59+
// goto -> bb1;
60+
// }
61+
// bb8: {
62+
// goto -> bb4;
63+
// }
64+
// bb9: {
65+
// return;
66+
// }
67+
// bb10: {
68+
// resume;
69+
// }
70+
// END rustc.match_guard.CleanFakeReadsAndBorrows.before.mir
71+
72+
// START rustc.match_guard.CleanFakeReadsAndBorrows.after.mir
73+
// bb0: {
74+
// nop;
75+
// _2 = discriminant(_1);
76+
// nop;
77+
// nop;
78+
// nop;
79+
// nop;
80+
// switchInt(move _2) -> [1isize: bb6, otherwise: bb4];
81+
// }
82+
// bb1: {
83+
// _0 = const 0i32;
84+
// goto -> bb9;
85+
// }
86+
// bb2: {
87+
// _0 = const 1i32;
88+
// goto -> bb9;
89+
// }
90+
// bb3: {
91+
// nop;
92+
// nop;
93+
// nop;
94+
// nop;
95+
// goto -> bb7;
96+
// }
97+
// bb4: {
98+
// nop;
99+
// nop;
100+
// nop;
101+
// nop;
102+
// goto -> bb2;
103+
// }
104+
// bb5: {
105+
// unreachable;
106+
// }
107+
// bb6: {
108+
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb3, otherwise: bb4];
109+
// }
110+
// bb7: {
111+
// goto -> bb1;
112+
// }
113+
// bb8: {
114+
// goto -> bb4;
115+
// }
116+
// bb9: {
117+
// return;
118+
// }
119+
// bb10: {
120+
// resume;
121+
// }
122+
// END rustc.match_guard.CleanFakeReadsAndBorrows.after.mir

0 commit comments

Comments
 (0)