Skip to content

Commit cde2f5f

Browse files
committed
mir: factor out the parts of MIR building which are not fn-specific.
1 parent bbc41aa commit cde2f5f

File tree

2 files changed

+157
-181
lines changed

2 files changed

+157
-181
lines changed

src/librustc_mir/build/mod.rs

Lines changed: 116 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010

1111
use hair::cx::Cx;
1212
use rustc::middle::region::{CodeExtent, CodeExtentData};
13-
use rustc::ty::{self, FnOutput, Ty};
13+
use rustc::ty::{self, Ty};
1414
use rustc::mir::repr::*;
1515
use rustc_data_structures::fnv::FnvHashMap;
1616
use rustc::hir;
1717
use rustc::hir::pat_util::pat_is_binding;
1818
use std::ops::{Index, IndexMut};
19+
use syntax::abi::Abi;
1920
use syntax::ast;
2021
use syntax::codemap::Span;
2122
use syntax::parse::token::keywords;
@@ -159,74 +160,51 @@ macro_rules! unpack {
159160
///////////////////////////////////////////////////////////////////////////
160161
/// the main entry point for building MIR for a function
161162
162-
pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
163-
span: Span,
164-
fn_id: ast::NodeId,
165-
body_id: ast::NodeId,
166-
implicit_arguments: Vec<Ty<'tcx>>,
167-
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
168-
return_ty: FnOutput<'tcx>,
169-
ast_block: &'tcx hir::Block)
170-
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
163+
pub fn construct_fn<'a, 'tcx, A>(hir: Cx<'a,'tcx>,
164+
fn_id: ast::NodeId,
165+
arguments: A,
166+
return_ty: ty::FnOutput<'tcx>,
167+
ast_block: &'tcx hir::Block)
168+
-> (Mir<'tcx>, ScopeAuxiliaryVec)
169+
where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::Pat>)>
170+
{
171171
let tcx = hir.tcx();
172-
let cfg = CFG { basic_blocks: vec![] };
173-
174-
let mut builder = Builder {
175-
hir: hir,
176-
cfg: cfg,
177-
fn_span: span,
178-
scopes: vec![],
179-
scope_datas: vec![],
180-
scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
181-
loop_scopes: vec![],
182-
temp_decls: vec![],
183-
var_decls: vec![],
184-
var_indices: FnvHashMap(),
185-
unit_temp: None,
186-
cached_resume_block: None,
187-
cached_return_block: None
188-
};
189-
190-
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
172+
let span = tcx.map.span(fn_id);
173+
let mut builder = Builder::new(hir, span);
191174

192-
let mut arg_decls = None; // assigned to `Some` in closures below
175+
let body_id = ast_block.id;
193176
let call_site_extent =
194177
tcx.region_maps.lookup_code_extent(
195178
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
196-
let _ = builder.in_scope(call_site_extent, START_BLOCK, |builder, call_site_scope_id| {
197-
let mut block = START_BLOCK;
198-
let arg_extent =
199-
tcx.region_maps.lookup_code_extent(
200-
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
201-
unpack!(block = builder.in_scope(arg_extent, block, |builder, arg_scope_id| {
202-
arg_decls = Some(unpack!(block = builder.args_and_body(block,
203-
return_ty,
204-
implicit_arguments,
205-
explicit_arguments,
206-
arg_scope_id,
207-
ast_block)));
208-
block.unit()
179+
let arg_extent =
180+
tcx.region_maps.lookup_code_extent(
181+
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
182+
let mut block = START_BLOCK;
183+
let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block,
184+
|builder, call_site_scope_id| {
185+
let arg_decls = unpack!(block = builder.in_scope(arg_extent, block,
186+
|builder, arg_scope_id| {
187+
builder.args_and_body(block, return_ty, arguments, arg_scope_id, ast_block)
209188
}));
210189

211190
let return_block = builder.return_block();
212191
builder.cfg.terminate(block, call_site_scope_id, span,
213192
TerminatorKind::Goto { target: return_block });
214193
builder.cfg.terminate(return_block, call_site_scope_id, span,
215194
TerminatorKind::Return);
216-
return_block.unit()
217-
});
218-
219-
assert!(
220-
builder.cfg.basic_blocks
221-
.iter()
222-
.enumerate()
223-
.all(|(index, block)| {
224-
if block.terminator.is_none() {
225-
bug!("no terminator on block {:?} in fn {:?}",
226-
index, fn_id)
227-
}
228-
true
229-
}));
195+
return_block.and(arg_decls)
196+
}));
197+
assert_eq!(block, builder.return_block());
198+
199+
match tcx.node_id_to_type(fn_id).sty {
200+
ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
201+
// RustCall pseudo-ABI untuples the last argument.
202+
if let Some(arg_decl) = arg_decls.last_mut() {
203+
arg_decl.spread = true;
204+
}
205+
}
206+
_ => {}
207+
}
230208

231209
// Gather the upvars of a closure, if any.
232210
let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
@@ -251,72 +229,98 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
251229
}).collect()
252230
});
253231

254-
(
255-
Mir {
256-
basic_blocks: builder.cfg.basic_blocks,
257-
scopes: builder.scope_datas,
258-
var_decls: builder.var_decls,
259-
arg_decls: arg_decls.take().expect("args never built?"),
260-
temp_decls: builder.temp_decls,
261-
upvar_decls: upvar_decls,
262-
return_ty: return_ty,
263-
span: span
264-
},
265-
builder.scope_auxiliary,
266-
)
232+
builder.finish(upvar_decls, arg_decls, return_ty)
267233
}
268234

269235
impl<'a,'tcx> Builder<'a,'tcx> {
270-
fn args_and_body(&mut self,
271-
mut block: BasicBlock,
272-
return_ty: FnOutput<'tcx>,
273-
implicit_arguments: Vec<Ty<'tcx>>,
274-
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
275-
argument_scope_id: ScopeId,
276-
ast_block: &'tcx hir::Block)
277-
-> BlockAnd<Vec<ArgDecl<'tcx>>>
236+
fn new(hir: Cx<'a, 'tcx>, span: Span) -> Builder<'a, 'tcx> {
237+
let mut builder = Builder {
238+
hir: hir,
239+
cfg: CFG { basic_blocks: vec![] },
240+
fn_span: span,
241+
scopes: vec![],
242+
scope_datas: vec![],
243+
scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] },
244+
loop_scopes: vec![],
245+
temp_decls: vec![],
246+
var_decls: vec![],
247+
var_indices: FnvHashMap(),
248+
unit_temp: None,
249+
cached_resume_block: None,
250+
cached_return_block: None
251+
};
252+
253+
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
254+
255+
builder
256+
}
257+
258+
fn finish(self,
259+
upvar_decls: Vec<UpvarDecl>,
260+
arg_decls: Vec<ArgDecl<'tcx>>,
261+
return_ty: ty::FnOutput<'tcx>)
262+
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
263+
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
264+
if block.terminator.is_none() {
265+
span_bug!(self.fn_span, "no terminator on block {:?}", index);
266+
}
267+
}
268+
269+
(Mir {
270+
basic_blocks: self.cfg.basic_blocks,
271+
scopes: self.scope_datas,
272+
var_decls: self.var_decls,
273+
arg_decls: arg_decls,
274+
temp_decls: self.temp_decls,
275+
upvar_decls: upvar_decls,
276+
return_ty: return_ty,
277+
span: self.fn_span
278+
}, self.scope_auxiliary)
279+
}
280+
281+
fn args_and_body<A>(&mut self,
282+
mut block: BasicBlock,
283+
return_ty: ty::FnOutput<'tcx>,
284+
arguments: A,
285+
argument_scope_id: ScopeId,
286+
ast_block: &'tcx hir::Block)
287+
-> BlockAnd<Vec<ArgDecl<'tcx>>>
288+
where A: Iterator<Item=(Ty<'tcx>, Option<&'tcx hir::Pat>)>
278289
{
279290
// to start, translate the argument patterns and collect the argument types.
280-
let implicits = implicit_arguments.into_iter().map(|ty| (ty, None));
281-
let explicits = explicit_arguments.into_iter().map(|(ty, pat)| (ty, Some(pat)));
282-
let arg_decls =
283-
implicits
284-
.chain(explicits)
285-
.enumerate()
286-
.map(|(index, (ty, pattern))| {
287-
let lvalue = Lvalue::Arg(index as u32);
288-
if let Some(pattern) = pattern {
289-
let pattern = self.hir.irrefutable_pat(pattern);
290-
unpack!(block = self.lvalue_into_pattern(block,
291-
argument_scope_id,
292-
pattern,
293-
&lvalue));
294-
}
291+
let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
292+
let lvalue = Lvalue::Arg(index as u32);
293+
if let Some(pattern) = pattern {
294+
let pattern = self.hir.irrefutable_pat(pattern);
295+
unpack!(block = self.lvalue_into_pattern(block,
296+
argument_scope_id,
297+
pattern,
298+
&lvalue));
299+
}
295300

296-
// Make sure we drop (parts of) the argument even when not matched on.
297-
let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
298-
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
299-
argument_extent, &lvalue, ty);
300-
301-
let mut name = keywords::Invalid.name();
302-
if let Some(pat) = pattern {
303-
if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
304-
if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) {
305-
name = ident.node.name;
306-
}
301+
// Make sure we drop (parts of) the argument even when not matched on.
302+
let argument_extent = self.scope_auxiliary[argument_scope_id].extent;
303+
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
304+
argument_extent, &lvalue, ty);
305+
306+
let mut name = keywords::Invalid.name();
307+
if let Some(pat) = pattern {
308+
if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
309+
if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) {
310+
name = ident.node.name;
307311
}
308312
}
313+
}
309314

310-
ArgDecl {
311-
ty: ty,
312-
spread: false,
313-
debug_name: name
314-
}
315-
})
316-
.collect();
315+
ArgDecl {
316+
ty: ty,
317+
spread: false,
318+
debug_name: name
319+
}
320+
}).collect();
317321

318322
// FIXME(#32959): temporary hack for the issue at hand
319-
let return_is_unit = if let FnOutput::FnConverging(t) = return_ty {
323+
let return_is_unit = if let ty::FnConverging(t) = return_ty {
320324
t.is_nil()
321325
} else {
322326
false

0 commit comments

Comments
 (0)