Skip to content

Commit 3c68f64

Browse files
committedNov 18, 2015
Auto merge of #29886 - michaelwoerister:mir-erase-regions, r=nikomatsakis
This change adds a `MirPass` erasing all early-bound regions from MIR, right before storing it in the MIR map. I've added some assertions at neuralgic points in `trans::mir` doing cheap checks whether region have actually been erased. Here are some assumptions that I worked under: - AdtDef references stay untouched. It's the `Substs` accompanying them that need to be handled (e.g. in `AggregateKind::Adt`). - We can't really get rid of late-bound regions at this point because there is no version `BareFnTy` (for example) that comes without one. These still have to be handled on demand in trans. Are this assumptions right? r? @nikomatsakis
2 parents 64a6569 + c533902 commit 3c68f64

File tree

8 files changed

+257
-11
lines changed

8 files changed

+257
-11
lines changed
 

‎src/librustc_driver/driver.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ pub fn compile_input(sess: Session,
167167
tcx.print_debug_stats();
168168
}
169169
let trans = phase_4_translate_to_llvm(tcx,
170-
&mir_map,
170+
mir_map,
171171
analysis);
172172

173173
if log_enabled!(::log::INFO) {
@@ -849,7 +849,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
849849
/// Run the translation phase to LLVM, after which the AST and analysis can
850850
/// be discarded.
851851
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
852-
mir_map: &MirMap<'tcx>,
852+
mut mir_map: MirMap<'tcx>,
853853
analysis: ty::CrateAnalysis)
854854
-> trans::CrateTranslation {
855855
let time_passes = tcx.sess.time_passes();
@@ -858,10 +858,14 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
858858
"resolving dependency formats",
859859
|| dependency_format::calculate(&tcx.sess));
860860

861+
time(time_passes,
862+
"erasing regions from MIR",
863+
|| mir::transform::erase_regions::erase_regions(tcx, &mut mir_map));
864+
861865
// Option dance to work around the lack of stack once closures.
862866
time(time_passes,
863867
"translation",
864-
move || trans::trans_crate(tcx, mir_map, analysis))
868+
move || trans::trans_crate(tcx, &mir_map, analysis))
865869
}
866870

867871
/// Run LLVM itself, producing a bitcode file, assembly file or object file
+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! This pass erases all early-bound regions from the types occuring in the MIR.
12+
//! We want to do this once just before trans, so trans does not have to take
13+
//! care erasing regions all over the place.
14+
15+
use repr::*;
16+
use rustc::middle::ty;
17+
use transform::MirPass;
18+
use mir_map::MirMap;
19+
20+
pub fn erase_regions<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &mut MirMap<'tcx>) {
21+
let mut eraser = EraseRegions::new(tcx);
22+
23+
for mir in mir_map.iter_mut().map(|(_, v)| v) {
24+
eraser.run_on_mir(mir);
25+
}
26+
}
27+
28+
pub struct EraseRegions<'a, 'tcx: 'a> {
29+
tcx: &'a ty::ctxt<'tcx>,
30+
}
31+
32+
impl<'a, 'tcx> MirPass<'tcx> for EraseRegions<'a, 'tcx> {
33+
34+
fn run_on_mir(&mut self, mir: &mut Mir<'tcx>) {
35+
36+
for basic_block in &mut mir.basic_blocks {
37+
self.erase_regions_basic_block(basic_block);
38+
}
39+
40+
self.erase_regions_return_ty(&mut mir.return_ty);
41+
42+
self.erase_regions_tys(mir.var_decls.iter_mut().map(|d| &mut d.ty));
43+
self.erase_regions_tys(mir.arg_decls.iter_mut().map(|d| &mut d.ty));
44+
self.erase_regions_tys(mir.temp_decls.iter_mut().map(|d| &mut d.ty));
45+
}
46+
}
47+
48+
impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
49+
50+
pub fn new(tcx: &'a ty::ctxt<'tcx>) -> EraseRegions<'a, 'tcx> {
51+
EraseRegions {
52+
tcx: tcx
53+
}
54+
}
55+
56+
fn erase_regions_basic_block(&mut self,
57+
basic_block: &mut BasicBlockData<'tcx>) {
58+
for statement in &mut basic_block.statements {
59+
self.erase_regions_statement(statement);
60+
}
61+
62+
self.erase_regions_terminator(&mut basic_block.terminator);
63+
}
64+
65+
fn erase_regions_statement(&mut self,
66+
statement: &mut Statement<'tcx>) {
67+
match statement.kind {
68+
StatementKind::Assign(ref mut lvalue, ref mut rvalue) => {
69+
self.erase_regions_lvalue(lvalue);
70+
self.erase_regions_rvalue(rvalue);
71+
}
72+
StatementKind::Drop(_, ref mut lvalue) => {
73+
self.erase_regions_lvalue(lvalue);
74+
}
75+
}
76+
}
77+
78+
fn erase_regions_terminator(&mut self,
79+
terminator: &mut Terminator<'tcx>) {
80+
match *terminator {
81+
Terminator::Goto { .. } |
82+
Terminator::Diverge |
83+
Terminator::Return |
84+
Terminator::Panic { .. } => {
85+
/* nothing to do */
86+
}
87+
Terminator::If { ref mut cond, .. } => {
88+
self.erase_regions_operand(cond);
89+
}
90+
Terminator::Switch { ref mut discr, .. } => {
91+
self.erase_regions_lvalue(discr);
92+
}
93+
Terminator::SwitchInt {
94+
ref mut discr,
95+
ref mut switch_ty,
96+
..
97+
} => {
98+
self.erase_regions_lvalue(discr);
99+
*switch_ty = self.tcx.erase_regions(switch_ty);
100+
},
101+
Terminator::Call {
102+
data: CallData {
103+
ref mut destination,
104+
ref mut func,
105+
ref mut args
106+
},
107+
..
108+
} => {
109+
self.erase_regions_lvalue(destination);
110+
self.erase_regions_operand(func);
111+
for arg in &mut *args {
112+
self.erase_regions_operand(arg);
113+
}
114+
}
115+
}
116+
}
117+
118+
fn erase_regions_operand(&mut self, operand: &mut Operand<'tcx>) {
119+
match *operand {
120+
Operand::Consume(ref mut lvalue) => {
121+
self.erase_regions_lvalue(lvalue);
122+
}
123+
Operand::Constant(ref mut constant) => {
124+
self.erase_regions_constant(constant);
125+
}
126+
}
127+
}
128+
129+
fn erase_regions_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>) {
130+
match *lvalue {
131+
Lvalue::Var(_) |
132+
Lvalue::Temp(_) |
133+
Lvalue::Arg(_) |
134+
Lvalue::Static(_) |
135+
Lvalue::ReturnPointer => {}
136+
Lvalue::Projection(ref mut lvalue_projection) => {
137+
self.erase_regions_lvalue(&mut lvalue_projection.base);
138+
match lvalue_projection.elem {
139+
ProjectionElem::Deref |
140+
ProjectionElem::Field(_) |
141+
ProjectionElem::Downcast(..) |
142+
ProjectionElem::ConstantIndex {..} => { /* nothing to do */ }
143+
ProjectionElem::Index(ref mut index) => {
144+
self.erase_regions_operand(index);
145+
}
146+
}
147+
}
148+
}
149+
}
150+
151+
fn erase_regions_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>) {
152+
match *rvalue {
153+
Rvalue::Use(ref mut operand) => {
154+
self.erase_regions_operand(operand)
155+
}
156+
Rvalue::Repeat(ref mut operand, ref mut constant) => {
157+
self.erase_regions_operand(operand);
158+
self.erase_regions_constant(constant);
159+
}
160+
Rvalue::Ref(ref mut region, _, ref mut lvalue) => {
161+
*region = ty::ReStatic;
162+
self.erase_regions_lvalue(lvalue);
163+
}
164+
Rvalue::Len(ref mut lvalue) => self.erase_regions_lvalue(lvalue),
165+
Rvalue::Cast(_, ref mut operand, ref mut ty) => {
166+
self.erase_regions_operand(operand);
167+
*ty = self.tcx.erase_regions(ty);
168+
}
169+
Rvalue::BinaryOp(_, ref mut operand1, ref mut operand2) => {
170+
self.erase_regions_operand(operand1);
171+
self.erase_regions_operand(operand2);
172+
}
173+
Rvalue::UnaryOp(_, ref mut operand) => {
174+
self.erase_regions_operand(operand);
175+
}
176+
Rvalue::Box(ref mut ty) => *ty = self.tcx.erase_regions(ty),
177+
Rvalue::Aggregate(ref mut aggregate_kind, ref mut operands) => {
178+
match *aggregate_kind {
179+
AggregateKind::Vec |
180+
AggregateKind::Tuple => {},
181+
AggregateKind::Adt(_, _, ref mut substs) => {
182+
let erased = self.tcx.erase_regions(*substs);
183+
*substs = self.tcx.mk_substs(erased);
184+
}
185+
AggregateKind::Closure(def_id, ref mut closure_substs) => {
186+
let cloned = Box::new(closure_substs.clone());
187+
let ty = self.tcx.mk_closure_from_closure_substs(def_id,
188+
cloned);
189+
let erased = self.tcx.erase_regions(&ty);
190+
*closure_substs = match erased.sty {
191+
ty::TyClosure(_, ref closure_substs) => &*closure_substs,
192+
_ => unreachable!()
193+
};
194+
}
195+
}
196+
for operand in &mut *operands {
197+
self.erase_regions_operand(operand);
198+
}
199+
}
200+
Rvalue::Slice { ref mut input, .. } => {
201+
self.erase_regions_lvalue(input);
202+
}
203+
Rvalue::InlineAsm(_) => {},
204+
}
205+
}
206+
207+
fn erase_regions_constant(&mut self, constant: &mut Constant<'tcx>) {
208+
constant.ty = self.tcx.erase_regions(&constant.ty);
209+
match constant.literal {
210+
Literal::Item { ref mut substs, .. } => {
211+
*substs = self.tcx.mk_substs(self.tcx.erase_regions(substs));
212+
}
213+
Literal::Value { .. } => { /* nothing to do */ }
214+
}
215+
}
216+
217+
fn erase_regions_return_ty(&mut self, fn_output: &mut ty::FnOutput<'tcx>) {
218+
match *fn_output {
219+
ty::FnConverging(ref mut ty) => {
220+
*ty = self.tcx.erase_regions(ty);
221+
},
222+
ty::FnDiverging => {}
223+
}
224+
}
225+
226+
fn erase_regions_tys<'b, T>(&mut self, tys: T)
227+
where T: Iterator<Item = &'b mut ty::Ty<'tcx>>,
228+
'tcx: 'b
229+
{
230+
for ty in tys {
231+
*ty = self.tcx.erase_regions(ty);
232+
}
233+
}
234+
}

‎src/librustc_mir/transform/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
// except according to those terms.
1010

1111
pub mod simplify_cfg;
12+
pub mod erase_regions;
1213
mod util;
1314

1415
use repr::Mir;
1516

16-
pub trait MirPass {
17-
fn run_on_mir(&mut self, mir: &mut Mir);
17+
pub trait MirPass<'tcx> {
18+
fn run_on_mir(&mut self, mir: &mut Mir<'tcx>);
1819
}

‎src/librustc_mir/transform/simplify_cfg.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ impl SimplifyCfg {
120120
}
121121
}
122122

123-
impl MirPass for SimplifyCfg {
124-
fn run_on_mir(&mut self, mir: &mut Mir) {
123+
impl<'tcx> MirPass<'tcx> for SimplifyCfg {
124+
fn run_on_mir(&mut self, mir: &mut Mir<'tcx>) {
125125
let mut changed = true;
126126
while changed {
127127
changed = self.simplify_branches(mir);

‎src/librustc_trans/trans/mir/constant.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use middle::ty::Ty;
11+
use middle::ty::{Ty, HasTypeFlags};
1212
use rustc::middle::const_eval::ConstVal;
1313
use rustc_mir::repr as mir;
1414
use trans::consts::{self, TrueConst};
@@ -63,6 +63,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
6363
unimplemented!()
6464
}
6565
};
66+
67+
assert!(!ty.has_erasable_regions());
68+
6669
OperandRef {
6770
ty: ty,
6871
val: val

‎src/librustc_trans/trans/mir/lvalue.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use llvm::ValueRef;
12-
use rustc::middle::ty::{self, Ty};
12+
use rustc::middle::ty::{self, Ty, HasTypeFlags};
1313
use rustc_mir::repr as mir;
1414
use rustc_mir::tcx::LvalueTy;
1515
use trans::adt;
@@ -45,6 +45,7 @@ impl<'tcx> LvalueRef<'tcx> {
4545
name: &str)
4646
-> LvalueRef<'tcx>
4747
{
48+
assert!(!ty.has_erasable_regions());
4849
let lltemp = base::alloc_ty(bcx, ty, name);
4950
LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty))
5051
}

‎src/librustc_trans/trans/mir/operand.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use llvm::ValueRef;
12-
use rustc::middle::ty::Ty;
12+
use rustc::middle::ty::{Ty, HasTypeFlags};
1313
use rustc_mir::repr as mir;
1414
use trans::base;
1515
use trans::common::{self, Block};
@@ -122,6 +122,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
122122
}
123123
datum::ByRef => OperandValue::Ref(tr_lvalue.llval)
124124
};
125+
126+
assert!(!ty.has_erasable_regions());
127+
125128
OperandRef {
126129
val: val,
127130
ty: ty

‎src/test/run-make/execution-engine/test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ fn compile_program(input: &str, sysroot: PathBuf)
231231
driver::phase_3_run_analysis_passes(
232232
&sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, mir_map, analysis| {
233233

234-
let trans = driver::phase_4_translate_to_llvm(tcx, &mir_map, analysis);
234+
let trans = driver::phase_4_translate_to_llvm(tcx, mir_map, analysis);
235235

236236
let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);
237237

0 commit comments

Comments
 (0)
Please sign in to comment.