]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/build/mod.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc_mir / build / mod.rs
CommitLineData
e9174d1e
SL
1// Copyright 2012-2014 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
92a42be0 11use hair::cx::Cx;
a7813a04
XL
12use rustc::middle::region::{CodeExtent, CodeExtentData, ROOT_CODE_EXTENT};
13use rustc::ty::{self, Ty};
92a42be0 14use rustc::mir::repr::*;
3157f602 15use rustc::util::nodemap::NodeMap;
54a0048b 16use rustc::hir;
a7813a04 17use syntax::abi::Abi;
b039eaaf 18use syntax::ast;
a7813a04 19use syntax::parse::token::keywords;
3157f602
XL
20use syntax_pos::Span;
21
22use rustc_data_structures::indexed_vec::{IndexVec, Idx};
23
24use std::u32;
b039eaaf 25
a7813a04
XL
26pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
27 hir: Cx<'a, 'gcx, 'tcx>,
b039eaaf 28 cfg: CFG<'tcx>,
54a0048b
SL
29
30 fn_span: Span,
31
a7813a04
XL
32 /// the current set of scopes, updated as we traverse;
33 /// see the `scope` module for more details
b039eaaf 34 scopes: Vec<scope::Scope<'tcx>>,
54a0048b 35
a7813a04
XL
36 /// for each scope, a span of blocks that defines it;
37 /// we track these for use in region and borrow checking,
38 /// but these are liable to get out of date once optimization
39 /// begins. They are also hopefully temporary, and will be
40 /// no longer needed when we adopt graph-based regions.
3157f602 41 scope_auxiliary: IndexVec<ScopeId, ScopeAuxiliary>,
54a0048b 42
a7813a04
XL
43 /// the current set of loops; see the `scope` module for more
44 /// details
b039eaaf 45 loop_scopes: Vec<scope::LoopScope>,
54a0048b 46
a7813a04
XL
47 /// the vector of all scopes that we have created thus far;
48 /// we track this for debuginfo later
3157f602
XL
49 visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
50 visibility_scope: VisibilityScope,
54a0048b 51
3157f602
XL
52 var_decls: IndexVec<Var, VarDecl<'tcx>>,
53 var_indices: NodeMap<Var>,
54 temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
7453a54e 55 unit_temp: Option<Lvalue<'tcx>>,
54a0048b 56
a7813a04
XL
57 /// cached block with the RESUME terminator; this is created
58 /// when first set of cleanups are built.
54a0048b 59 cached_resume_block: Option<BasicBlock>,
a7813a04
XL
60 /// cached block with the RETURN terminator
61 cached_return_block: Option<BasicBlock>,
e9174d1e
SL
62}
63
b039eaaf 64struct CFG<'tcx> {
3157f602
XL
65 basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
66}
67
68#[derive(Copy, Clone, Debug, PartialEq, Eq)]
69pub struct ScopeId(u32);
70
71impl Idx for ScopeId {
72 fn new(index: usize) -> ScopeId {
73 assert!(index < (u32::MAX as usize));
74 ScopeId(index as u32)
75 }
76
77 fn index(self) -> usize {
78 self.0 as usize
79 }
e9174d1e
SL
80}
81
54a0048b
SL
82/// For each scope, we track the extent (from the HIR) and a
83/// single-entry-multiple-exit subgraph that contains all the
84/// statements/terminators within it.
85///
86/// This information is separated out from the main `ScopeData`
87/// because it is short-lived. First, the extent contains node-ids,
88/// so it cannot be saved and re-loaded. Second, any optimization will mess up
89/// the dominator/postdominator information.
90///
91/// The intention is basically to use this information to do
92/// regionck/borrowck and then throw it away once we are done.
93pub struct ScopeAuxiliary {
94 /// extent of this scope from the MIR.
95 pub extent: CodeExtent,
96
97 /// "entry point": dominator of all nodes in the scope
98 pub dom: Location,
99
100 /// "exit points": mutual postdominators of all nodes in the scope
101 pub postdoms: Vec<Location>,
102}
103
3157f602 104pub type ScopeAuxiliaryVec = IndexVec<ScopeId, ScopeAuxiliary>;
54a0048b 105
e9174d1e 106///////////////////////////////////////////////////////////////////////////
7453a54e
SL
107/// The `BlockAnd` "monad" packages up the new basic block along with a
108/// produced value (sometimes just unit, of course). The `unpack!`
109/// macro (and methods below) makes working with `BlockAnd` much more
110/// convenient.
e9174d1e
SL
111
112#[must_use] // if you don't use one of these results, you're leaving a dangling edge
9cc50fc6 113pub struct BlockAnd<T>(BasicBlock, T);
e9174d1e 114
92a42be0
SL
115trait BlockAndExtension {
116 fn and<T>(self, v: T) -> BlockAnd<T>;
117 fn unit(self) -> BlockAnd<()>;
118}
119
120impl BlockAndExtension for BasicBlock {
e9174d1e
SL
121 fn and<T>(self, v: T) -> BlockAnd<T> {
122 BlockAnd(self, v)
123 }
124
125 fn unit(self) -> BlockAnd<()> {
126 BlockAnd(self, ())
127 }
128}
129
130/// Update a block pointer and return the value.
131/// Use it like `let x = unpack!(block = self.foo(block, foo))`.
132macro_rules! unpack {
133 ($x:ident = $c:expr) => {
134 {
135 let BlockAnd(b, v) = $c;
136 $x = b;
137 v
138 }
139 };
140
141 ($c:expr) => {
142 {
143 let BlockAnd(b, ()) = $c;
144 b
145 }
146 };
147}
148
149///////////////////////////////////////////////////////////////////////////
7453a54e 150/// the main entry point for building MIR for a function
e9174d1e 151
a7813a04
XL
152pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
153 fn_id: ast::NodeId,
154 arguments: A,
5bcae85e 155 return_ty: Ty<'gcx>,
a7813a04
XL
156 ast_block: &'gcx hir::Block)
157 -> (Mir<'tcx>, ScopeAuxiliaryVec)
158 where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
159{
54a0048b 160 let tcx = hir.tcx();
a7813a04
XL
161 let span = tcx.map.span(fn_id);
162 let mut builder = Builder::new(hir, span);
54a0048b 163
a7813a04 164 let body_id = ast_block.id;
54a0048b
SL
165 let call_site_extent =
166 tcx.region_maps.lookup_code_extent(
167 CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
a7813a04
XL
168 let arg_extent =
169 tcx.region_maps.lookup_code_extent(
170 CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
171 let mut block = START_BLOCK;
3157f602
XL
172 let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
173 let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| {
174 builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block)
54a0048b
SL
175 }));
176
3157f602 177 let source_info = builder.source_info(span);
a7813a04 178 let return_block = builder.return_block();
3157f602 179 builder.cfg.terminate(block, source_info,
a7813a04 180 TerminatorKind::Goto { target: return_block });
3157f602 181 builder.cfg.terminate(return_block, source_info,
54a0048b 182 TerminatorKind::Return);
a7813a04
XL
183 return_block.and(arg_decls)
184 }));
185 assert_eq!(block, builder.return_block());
186
187 match tcx.node_id_to_type(fn_id).sty {
188 ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
189 // RustCall pseudo-ABI untuples the last argument.
3157f602
XL
190 if let Some(last_arg) = arg_decls.last() {
191 arg_decls[last_arg].spread = true;
a7813a04
XL
192 }
193 }
194 _ => {}
195 }
54a0048b 196
a7813a04
XL
197 // Gather the upvars of a closure, if any.
198 let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
199 freevars.iter().map(|fv| {
9e0c209e 200 let var_id = tcx.map.as_local_node_id(fv.def.def_id()).unwrap();
a7813a04 201 let by_ref = tcx.upvar_capture(ty::UpvarId {
9e0c209e 202 var_id: var_id,
a7813a04
XL
203 closure_expr_id: fn_id
204 }).map_or(false, |capture| match capture {
205 ty::UpvarCapture::ByValue => false,
206 ty::UpvarCapture::ByRef(..) => true
207 });
208 let mut decl = UpvarDecl {
209 debug_name: keywords::Invalid.name(),
210 by_ref: by_ref
211 };
9e0c209e 212 if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(var_id) {
3157f602 213 if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
a7813a04
XL
214 decl.debug_name = ident.node;
215 }
216 }
217 decl
218 }).collect()
54a0048b
SL
219 });
220
a7813a04
XL
221 builder.finish(upvar_decls, arg_decls, return_ty)
222}
223
224pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
225 item_id: ast::NodeId,
226 ast_expr: &'tcx hir::Expr)
227 -> (Mir<'tcx>, ScopeAuxiliaryVec) {
228 let tcx = hir.tcx();
229 let span = tcx.map.span(item_id);
230 let mut builder = Builder::new(hir, span);
231
5bcae85e
SL
232 let extent = tcx.region_maps.temporary_scope(ast_expr.id)
233 .unwrap_or(ROOT_CODE_EXTENT);
a7813a04 234 let mut block = START_BLOCK;
3157f602 235 let _ = builder.in_scope(extent, block, |builder| {
a7813a04
XL
236 let expr = builder.hir.mirror(ast_expr);
237 unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr));
238
3157f602 239 let source_info = builder.source_info(span);
a7813a04 240 let return_block = builder.return_block();
3157f602 241 builder.cfg.terminate(block, source_info,
a7813a04 242 TerminatorKind::Goto { target: return_block });
3157f602 243 builder.cfg.terminate(return_block, source_info,
a7813a04
XL
244 TerminatorKind::Return);
245
246 return_block.unit()
247 });
248
249 let ty = tcx.expr_ty_adjusted(ast_expr);
5bcae85e 250 builder.finish(vec![], IndexVec::new(), ty)
e9174d1e
SL
251}
252
a7813a04
XL
253impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
254 fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> {
255 let mut builder = Builder {
256 hir: hir,
3157f602 257 cfg: CFG { basic_blocks: IndexVec::new() },
a7813a04
XL
258 fn_span: span,
259 scopes: vec![],
3157f602
XL
260 visibility_scopes: IndexVec::new(),
261 visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
262 scope_auxiliary: IndexVec::new(),
a7813a04 263 loop_scopes: vec![],
3157f602
XL
264 temp_decls: IndexVec::new(),
265 var_decls: IndexVec::new(),
266 var_indices: NodeMap(),
a7813a04
XL
267 unit_temp: None,
268 cached_resume_block: None,
269 cached_return_block: None
270 };
271
272 assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
3157f602
XL
273 assert_eq!(builder.new_visibility_scope(span), ARGUMENT_VISIBILITY_SCOPE);
274 builder.visibility_scopes[ARGUMENT_VISIBILITY_SCOPE].parent_scope = None;
a7813a04
XL
275
276 builder
277 }
278
279 fn finish(self,
280 upvar_decls: Vec<UpvarDecl>,
3157f602 281 arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
5bcae85e 282 return_ty: Ty<'tcx>)
a7813a04
XL
283 -> (Mir<'tcx>, ScopeAuxiliaryVec) {
284 for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
285 if block.terminator.is_none() {
286 span_bug!(self.fn_span, "no terminator on block {:?}", index);
287 }
288 }
289
3157f602
XL
290 (Mir::new(self.cfg.basic_blocks,
291 self.visibility_scopes,
292 IndexVec::new(),
293 return_ty,
294 self.var_decls,
295 arg_decls,
296 self.temp_decls,
297 upvar_decls,
298 self.fn_span
299 ), self.scope_auxiliary)
a7813a04
XL
300 }
301
302 fn args_and_body<A>(&mut self,
303 mut block: BasicBlock,
5bcae85e 304 return_ty: Ty<'tcx>,
a7813a04 305 arguments: A,
3157f602 306 argument_extent: CodeExtent,
a7813a04 307 ast_block: &'gcx hir::Block)
3157f602 308 -> BlockAnd<IndexVec<Arg, ArgDecl<'tcx>>>
a7813a04 309 where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
e9174d1e 310 {
54a0048b 311 // to start, translate the argument patterns and collect the argument types.
3157f602 312 let mut scope = None;
a7813a04 313 let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
3157f602 314 let lvalue = Lvalue::Arg(Arg::new(index));
a7813a04
XL
315 if let Some(pattern) = pattern {
316 let pattern = self.hir.irrefutable_pat(pattern);
3157f602
XL
317 scope = self.declare_bindings(scope, ast_block.span, &pattern);
318 unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
a7813a04 319 }
54a0048b 320
a7813a04 321 // Make sure we drop (parts of) the argument even when not matched on.
a7813a04
XL
322 self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
323 argument_extent, &lvalue, ty);
324
325 let mut name = keywords::Invalid.name();
326 if let Some(pat) = pattern {
3157f602
XL
327 if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
328 name = ident.node;
a7813a04
XL
329 }
330 }
54a0048b 331
a7813a04
XL
332 ArgDecl {
333 ty: ty,
334 spread: false,
335 debug_name: name
336 }
337 }).collect();
338
3157f602
XL
339 // Enter the argument pattern bindings visibility scope, if it exists.
340 if let Some(visibility_scope) = scope {
341 self.visibility_scope = visibility_scope;
342 }
343
a7813a04 344 // FIXME(#32959): temporary hack for the issue at hand
5bcae85e 345 let return_is_unit = return_ty.is_nil();
54a0048b 346 // start the first basic block and translate the body
a7813a04 347 unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block));
54a0048b
SL
348
349 block.and(arg_decls)
e9174d1e 350 }
7453a54e
SL
351
352 fn get_unit_temp(&mut self) -> Lvalue<'tcx> {
353 match self.unit_temp {
354 Some(ref tmp) => tmp.clone(),
355 None => {
356 let ty = self.hir.unit_ty();
357 let tmp = self.temp(ty);
358 self.unit_temp = Some(tmp.clone());
359 tmp
360 }
361 }
362 }
a7813a04
XL
363
364 fn return_block(&mut self) -> BasicBlock {
365 match self.cached_return_block {
366 Some(rb) => rb,
367 None => {
368 let rb = self.cfg.start_new_block();
369 self.cached_return_block = Some(rb);
370 rb
371 }
372 }
373 }
e9174d1e
SL
374}
375
376///////////////////////////////////////////////////////////////////////////
377// Builder methods are broken up into modules, depending on what kind
378// of thing is being translated. Note that they use the `unpack` macro
379// above extensively.
380
381mod block;
382mod cfg;
383mod expr;
384mod into;
385mod matches;
386mod misc;
387mod scope;