blob: d281b2a32d045619b08460aa394a904b8d2bb92e [file] [log] [blame]
Niko Matsakis9bd35c02015-08-18 21:59:211// 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
Niko Matsakis87358722015-11-10 01:54:1711use hair::cx::Cx;
Ariel Ben-Yehuda732f2272016-09-24 14:45:2412use hair::Pattern;
13
Eduard Burtescud4346882016-05-02 20:11:1914use rustc::middle::region::{CodeExtent, CodeExtentData, ROOT_CODE_EXTENT};
Eduard Burtescucde2f5f2016-04-15 14:11:2415use rustc::ty::{self, Ty};
Eduard Burtescu36340ba2016-09-19 20:50:0016use rustc::mir::*;
Ariel Ben-Yehudabc1eb672016-06-07 14:28:3617use rustc::util::nodemap::NodeMap;
Eduard Burtescu8b093722016-03-29 05:50:4418use rustc::hir;
Eduard Burtescucde2f5f2016-04-15 14:11:2419use syntax::abi::Abi;
Niko Matsakise02ddff2015-10-05 16:31:4820use syntax::ast;
Jeffrey Seyfriedd2f8fb02016-11-16 08:21:5221use syntax::symbol::keywords;
Jonathan Turner6ae350212016-06-21 22:08:1322use syntax_pos::Span;
Niko Matsakis9bd35c02015-08-18 21:59:2123
Ariel Ben-Yehudabc1eb672016-06-07 14:28:3624use rustc_data_structures::indexed_vec::{IndexVec, Idx};
25
26use std::u32;
27
Eduard Burtescua1c170f2016-05-11 01:14:4128pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
29 hir: Cx<'a, 'gcx, 'tcx>,
Niko Matsakise02ddff2015-10-05 16:31:4830 cfg: CFG<'tcx>,
Niko Matsakis464c02e2016-03-09 16:04:2631
Niko Matsakisf66fd892016-03-23 00:41:0732 fn_span: Span,
Jonas Schievink393db2d2016-09-24 23:38:2733 arg_count: usize,
Niko Matsakisf66fd892016-03-23 00:41:0734
Simonas Kazlauskasd1180af2016-04-19 21:13:3035 /// the current set of scopes, updated as we traverse;
36 /// see the `scope` module for more details
Niko Matsakise02ddff2015-10-05 16:31:4837 scopes: Vec<scope::Scope<'tcx>>,
Niko Matsakis464c02e2016-03-09 16:04:2638
Simonas Kazlauskasd1180af2016-04-19 21:13:3039 /// the current set of loops; see the `scope` module for more
40 /// details
Niko Matsakise02ddff2015-10-05 16:31:4841 loop_scopes: Vec<scope::LoopScope>,
Niko Matsakis464c02e2016-03-09 16:04:2642
Simonas Kazlauskasd1180af2016-04-19 21:13:3043 /// the vector of all scopes that we have created thus far;
44 /// we track this for debuginfo later
Ariel Ben-Yehudabc1eb672016-06-07 14:28:3645 visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
Eduard Burtescu719a5912016-05-31 17:27:3646 visibility_scope: VisibilityScope,
Niko Matsakis464c02e2016-03-09 16:04:2647
Jonas Schievink393db2d2016-09-24 23:38:2748 /// Maps node ids of variable bindings to the `Local`s created for them.
49 var_indices: NodeMap<Local>,
50 local_decls: IndexVec<Local, LocalDecl<'tcx>>,
Simonas Kazlauskasf9f6e3a2016-01-15 22:36:3251 unit_temp: Option<Lvalue<'tcx>>,
Niko Matsakis07698652016-03-24 00:46:3852
Simonas Kazlauskasd1180af2016-04-19 21:13:3053 /// cached block with the RESUME terminator; this is created
54 /// when first set of cleanups are built.
Niko Matsakis07698652016-03-24 00:46:3855 cached_resume_block: Option<BasicBlock>,
Simonas Kazlauskasd1180af2016-04-19 21:13:3056 /// cached block with the RETURN terminator
57 cached_return_block: Option<BasicBlock>,
Niko Matsakis9bd35c02015-08-18 21:59:2158}
59
Niko Matsakise02ddff2015-10-05 16:31:4860struct CFG<'tcx> {
Ariel Ben-Yehudabc1eb672016-06-07 14:28:3661 basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
Niko Matsakis9bd35c02015-08-18 21:59:2162}
63
Eduard Burtescu719a5912016-05-31 17:27:3664#[derive(Copy, Clone, Debug, PartialEq, Eq)]
65pub struct ScopeId(u32);
66
Ariel Ben-Yehudabc1eb672016-06-07 14:28:3667impl Idx for ScopeId {
68 fn new(index: usize) -> ScopeId {
Eduard Burtescu719a5912016-05-31 17:27:3669 assert!(index < (u32::MAX as usize));
70 ScopeId(index as u32)
71 }
72
Ariel Ben-Yehudabc1eb672016-06-07 14:28:3673 fn index(self) -> usize {
Eduard Burtescu719a5912016-05-31 17:27:3674 self.0 as usize
75 }
76}
77
Niko Matsakis9bd35c02015-08-18 21:59:2178///////////////////////////////////////////////////////////////////////////
Oliver Schneider4e44ef12016-02-03 12:25:0779/// The `BlockAnd` "monad" packages up the new basic block along with a
80/// produced value (sometimes just unit, of course). The `unpack!`
81/// macro (and methods below) makes working with `BlockAnd` much more
82/// convenient.
Niko Matsakis9bd35c02015-08-18 21:59:2183
84#[must_use] // if you don't use one of these results, you're leaving a dangling edge
Vadim Petrochenkov26a2f852015-11-21 14:39:1585pub struct BlockAnd<T>(BasicBlock, T);
Niko Matsakis9bd35c02015-08-18 21:59:2186
Michael Woeristerbbe1d282015-11-19 15:37:3487trait BlockAndExtension {
88 fn and<T>(self, v: T) -> BlockAnd<T>;
89 fn unit(self) -> BlockAnd<()>;
90}
91
92impl BlockAndExtension for BasicBlock {
Niko Matsakis9bd35c02015-08-18 21:59:2193 fn and<T>(self, v: T) -> BlockAnd<T> {
94 BlockAnd(self, v)
95 }
96
97 fn unit(self) -> BlockAnd<()> {
98 BlockAnd(self, ())
99 }
100}
101
102/// Update a block pointer and return the value.
103/// Use it like `let x = unpack!(block = self.foo(block, foo))`.
104macro_rules! unpack {
105 ($x:ident = $c:expr) => {
106 {
107 let BlockAnd(b, v) = $c;
108 $x = b;
109 v
110 }
111 };
112
113 ($c:expr) => {
114 {
115 let BlockAnd(b, ()) = $c;
116 b
117 }
118 };
119}
120
121///////////////////////////////////////////////////////////////////////////
Oliver Schneider4e44ef12016-02-03 12:25:07122/// the main entry point for building MIR for a function
Niko Matsakis9bd35c02015-08-18 21:59:21123
Eduard Burtescua1c170f2016-05-11 01:14:41124pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
125 fn_id: ast::NodeId,
126 arguments: A,
Eduard Burtescu3f9eba12016-11-10 14:49:53127 abi: Abi,
Andrew Cannf0a8b6d2016-08-02 05:46:39128 return_ty: Ty<'gcx>,
Eduard Burtescuff0830d2016-10-25 23:27:14129 ast_body: &'gcx hir::Expr)
Nicholas Nethercoted7755702016-11-03 03:22:57130 -> Mir<'tcx>
Eduard Burtescua1c170f2016-05-11 01:14:41131 where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
Eduard Burtescucde2f5f2016-04-15 14:11:24132{
Jonas Schievink393db2d2016-09-24 23:38:27133 let arguments: Vec<_> = arguments.collect();
134
Niko Matsakisa276e752016-03-23 16:26:37135 let tcx = hir.tcx();
Eduard Burtescucde2f5f2016-04-15 14:11:24136 let span = tcx.map.span(fn_id);
Jonas Schievink393db2d2016-09-24 23:38:27137 let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
Niko Matsakis9bd35c02015-08-18 21:59:21138
Eduard Burtescuff0830d2016-10-25 23:27:14139 let body_id = ast_body.id;
Niko Matsakisa276e752016-03-23 16:26:37140 let call_site_extent =
141 tcx.region_maps.lookup_code_extent(
142 CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
Eduard Burtescucde2f5f2016-04-15 14:11:24143 let arg_extent =
144 tcx.region_maps.lookup_code_extent(
145 CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
146 let mut block = START_BLOCK;
Jonas Schievink393db2d2016-09-24 23:38:27147 unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
148 unpack!(block = builder.in_scope(arg_extent, block, |builder| {
Eduard Burtescuff0830d2016-10-25 23:27:14149 builder.args_and_body(block, &arguments, arg_extent, ast_body)
Niko Matsakisa276e752016-03-23 16:26:37150 }));
Vadim Chugunov209fe0d2016-10-19 07:25:03151 // Attribute epilogue to function's closing brace
152 let fn_end = Span { lo: span.hi, ..span };
153 let source_info = builder.source_info(fn_end);
Simonas Kazlauskasd1180af2016-04-19 21:13:30154 let return_block = builder.return_block();
Eduard Burtescu0c5930e2016-06-07 16:21:56155 builder.cfg.terminate(block, source_info,
Simonas Kazlauskasd1180af2016-04-19 21:13:30156 TerminatorKind::Goto { target: return_block });
Eduard Burtescu0c5930e2016-06-07 16:21:56157 builder.cfg.terminate(return_block, source_info,
Niko Matsakisa276e752016-03-23 16:26:37158 TerminatorKind::Return);
Jonas Schievink393db2d2016-09-24 23:38:27159 return_block.unit()
Eduard Burtescucde2f5f2016-04-15 14:11:24160 }));
161 assert_eq!(block, builder.return_block());
Niko Matsakis9bd35c02015-08-18 21:59:21162
Jonas Schievink3b0c3182016-09-26 20:44:01163 let mut spread_arg = None;
Eduard Burtescu3f9eba12016-11-10 14:49:53164 if abi == Abi::RustCall {
165 // RustCall pseudo-ABI untuples the last argument.
166 spread_arg = Some(Local::new(arguments.len()));
Eduard Burtescucde2f5f2016-04-15 14:11:24167 }
Niko Matsakisa61c1752016-03-22 20:05:28168
Eduard Burtescuf06bab72016-04-16 18:51:26169 // Gather the upvars of a closure, if any.
170 let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| {
171 freevars.iter().map(|fv| {
Eduard Burtescu903ec522016-08-31 11:08:22172 let var_id = tcx.map.as_local_node_id(fv.def.def_id()).unwrap();
Eduard Burtescu6a8d1312016-10-27 01:52:10173 let by_ref = tcx.tables().upvar_capture(ty::UpvarId {
Eduard Burtescu903ec522016-08-31 11:08:22174 var_id: var_id,
Eduard Burtescuf06bab72016-04-16 18:51:26175 closure_expr_id: fn_id
176 }).map_or(false, |capture| match capture {
177 ty::UpvarCapture::ByValue => false,
178 ty::UpvarCapture::ByRef(..) => true
179 });
180 let mut decl = UpvarDecl {
Vadim Petrochenkovb32d7b52016-04-18 19:53:50181 debug_name: keywords::Invalid.name(),
Eduard Burtescuf06bab72016-04-16 18:51:26182 by_ref: by_ref
183 };
Eduard Burtescu903ec522016-08-31 11:08:22184 if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(var_id) {
Vadim Petrochenkov216f5fb2016-03-06 12:54:44185 if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
Vadim Petrochenkovaad347c2016-03-06 12:54:44186 decl.debug_name = ident.node;
Eduard Burtescuf06bab72016-04-16 18:51:26187 }
188 }
189 decl
190 }).collect()
191 });
192
Nicholas Nethercoted7755702016-11-03 03:22:57193 let mut mir = builder.finish(upvar_decls, return_ty);
Jonas Schievink3b0c3182016-09-26 20:44:01194 mir.spread_arg = spread_arg;
Nicholas Nethercoted7755702016-11-03 03:22:57195 mir
Niko Matsakis9bd35c02015-08-18 21:59:21196}
197
Eduard Burtescua1c170f2016-05-11 01:14:41198pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
199 item_id: ast::NodeId,
200 ast_expr: &'tcx hir::Expr)
Nicholas Nethercoted7755702016-11-03 03:22:57201 -> Mir<'tcx> {
Eduard Burtescud4346882016-05-02 20:11:19202 let tcx = hir.tcx();
Eduard Burtescu0d7201e2016-10-20 03:33:20203 let ty = tcx.tables().expr_ty_adjusted(ast_expr);
Eduard Burtescud4346882016-05-02 20:11:19204 let span = tcx.map.span(item_id);
Jonas Schievink393db2d2016-09-24 23:38:27205 let mut builder = Builder::new(hir, span, 0, ty);
Eduard Burtescud4346882016-05-02 20:11:19206
Eduard Burtescu02aec402016-08-14 03:34:14207 let extent = tcx.region_maps.temporary_scope(ast_expr.id)
208 .unwrap_or(ROOT_CODE_EXTENT);
Eduard Burtescud4346882016-05-02 20:11:19209 let mut block = START_BLOCK;
Eduard Burtescu719a5912016-05-31 17:27:36210 let _ = builder.in_scope(extent, block, |builder| {
Eduard Burtescud4346882016-05-02 20:11:19211 let expr = builder.hir.mirror(ast_expr);
Jonas Schievink393db2d2016-09-24 23:38:27212 unpack!(block = builder.into(&Lvalue::Local(RETURN_POINTER), block, expr));
Eduard Burtescud4346882016-05-02 20:11:19213
Eduard Burtescu0c5930e2016-06-07 16:21:56214 let source_info = builder.source_info(span);
Eduard Burtescud4346882016-05-02 20:11:19215 let return_block = builder.return_block();
Eduard Burtescu0c5930e2016-06-07 16:21:56216 builder.cfg.terminate(block, source_info,
Eduard Burtescud4346882016-05-02 20:11:19217 TerminatorKind::Goto { target: return_block });
Eduard Burtescu0c5930e2016-06-07 16:21:56218 builder.cfg.terminate(return_block, source_info,
Eduard Burtescud4346882016-05-02 20:11:19219 TerminatorKind::Return);
220
221 return_block.unit()
222 });
223
Jonas Schievink393db2d2016-09-24 23:38:27224 builder.finish(vec![], ty)
Eduard Burtescud4346882016-05-02 20:11:19225}
226
Eduard Burtescua1c170f2016-05-11 01:14:41227impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Jonas Schievink393db2d2016-09-24 23:38:27228 fn new(hir: Cx<'a, 'gcx, 'tcx>,
229 span: Span,
230 arg_count: usize,
231 return_ty: Ty<'tcx>)
232 -> Builder<'a, 'gcx, 'tcx> {
Eduard Burtescucde2f5f2016-04-15 14:11:24233 let mut builder = Builder {
234 hir: hir,
Ariel Ben-Yehudabc1eb672016-06-07 14:28:36235 cfg: CFG { basic_blocks: IndexVec::new() },
Eduard Burtescucde2f5f2016-04-15 14:11:24236 fn_span: span,
Jonas Schievink393db2d2016-09-24 23:38:27237 arg_count: arg_count,
Eduard Burtescucde2f5f2016-04-15 14:11:24238 scopes: vec![],
Ariel Ben-Yehudabc1eb672016-06-07 14:28:36239 visibility_scopes: IndexVec::new(),
Eduard Burtescu719a5912016-05-31 17:27:36240 visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
Eduard Burtescucde2f5f2016-04-15 14:11:24241 loop_scopes: vec![],
Jonas Schievink393db2d2016-09-24 23:38:27242 local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1),
Ariel Ben-Yehudabc1eb672016-06-07 14:28:36243 var_indices: NodeMap(),
Eduard Burtescucde2f5f2016-04-15 14:11:24244 unit_temp: None,
245 cached_resume_block: None,
246 cached_return_block: None
247 };
248
249 assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
Eduard Burtescu719a5912016-05-31 17:27:36250 assert_eq!(builder.new_visibility_scope(span), ARGUMENT_VISIBILITY_SCOPE);
251 builder.visibility_scopes[ARGUMENT_VISIBILITY_SCOPE].parent_scope = None;
Eduard Burtescucde2f5f2016-04-15 14:11:24252
253 builder
254 }
255
256 fn finish(self,
257 upvar_decls: Vec<UpvarDecl>,
Andrew Cannf0a8b6d2016-08-02 05:46:39258 return_ty: Ty<'tcx>)
Nicholas Nethercoted7755702016-11-03 03:22:57259 -> Mir<'tcx> {
Eduard Burtescucde2f5f2016-04-15 14:11:24260 for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
261 if block.terminator.is_none() {
262 span_bug!(self.fn_span, "no terminator on block {:?}", index);
263 }
264 }
265
Nicholas Nethercoted7755702016-11-03 03:22:57266 Mir::new(self.cfg.basic_blocks,
267 self.visibility_scopes,
268 IndexVec::new(),
269 return_ty,
270 self.local_decls,
271 self.arg_count,
272 upvar_decls,
273 self.fn_span
274 )
Eduard Burtescucde2f5f2016-04-15 14:11:24275 }
276
Jonas Schievink393db2d2016-09-24 23:38:27277 fn args_and_body(&mut self,
278 mut block: BasicBlock,
Jonas Schievink393db2d2016-09-24 23:38:27279 arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
280 argument_extent: CodeExtent,
Eduard Burtescuff0830d2016-10-25 23:27:14281 ast_body: &'gcx hir::Expr)
Jonas Schievink393db2d2016-09-24 23:38:27282 -> BlockAnd<()>
Niko Matsakis9bd35c02015-08-18 21:59:21283 {
Jonas Schievink393db2d2016-09-24 23:38:27284 // Allocate locals for the function arguments
285 for &(ty, pattern) in arguments.iter() {
286 // If this is a simple binding pattern, give the local a nice name for debuginfo.
287 let mut name = None;
288 if let Some(pat) = pattern {
289 if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
290 name = Some(ident.node);
291 }
292 }
293
294 self.local_decls.push(LocalDecl {
295 mutability: Mutability::Not,
296 ty: ty,
297 source_info: None,
298 name: name,
299 });
300 }
301
Eduard Burtescu719a5912016-05-31 17:27:36302 let mut scope = None;
Jonas Schievink393db2d2016-09-24 23:38:27303 // Bind the argument patterns
304 for (index, &(ty, pattern)) in arguments.iter().enumerate() {
305 // Function arguments always get the first Local indices after the return pointer
306 let lvalue = Lvalue::Local(Local::new(index + 1));
307
Eduard Burtescucde2f5f2016-04-15 14:11:24308 if let Some(pattern) = pattern {
Ariel Ben-Yehuda732f2272016-09-24 14:45:24309 let pattern = Pattern::from_hir(self.hir.tcx(), pattern);
Eduard Burtescuff0830d2016-10-25 23:27:14310 scope = self.declare_bindings(scope, ast_body.span, &pattern);
Eduard Burtescu719a5912016-05-31 17:27:36311 unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
Eduard Burtescucde2f5f2016-04-15 14:11:24312 }
Niko Matsakis9bd35c02015-08-18 21:59:21313
Eduard Burtescucde2f5f2016-04-15 14:11:24314 // Make sure we drop (parts of) the argument even when not matched on.
Eduard Burtescuff0830d2016-10-25 23:27:14315 self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span),
Eduard Burtescucde2f5f2016-04-15 14:11:24316 argument_extent, &lvalue, ty);
Niko Matsakis9bd35c02015-08-18 21:59:21317
Jonas Schievink393db2d2016-09-24 23:38:27318 }
Niko Matsakisa276e752016-03-23 16:26:37319
Eduard Burtescu719a5912016-05-31 17:27:36320 // Enter the argument pattern bindings visibility scope, if it exists.
321 if let Some(visibility_scope) = scope {
322 self.visibility_scope = visibility_scope;
323 }
324
Eduard Burtescuff0830d2016-10-25 23:27:14325 let body = self.hir.mirror(ast_body);
326 self.into(&Lvalue::Local(RETURN_POINTER), block, body)
Niko Matsakis9bd35c02015-08-18 21:59:21327 }
Simonas Kazlauskasf9f6e3a2016-01-15 22:36:32328
329 fn get_unit_temp(&mut self) -> Lvalue<'tcx> {
330 match self.unit_temp {
331 Some(ref tmp) => tmp.clone(),
332 None => {
333 let ty = self.hir.unit_ty();
334 let tmp = self.temp(ty);
335 self.unit_temp = Some(tmp.clone());
336 tmp
337 }
338 }
339 }
Simonas Kazlauskasd1180af2016-04-19 21:13:30340
341 fn return_block(&mut self) -> BasicBlock {
342 match self.cached_return_block {
343 Some(rb) => rb,
344 None => {
345 let rb = self.cfg.start_new_block();
346 self.cached_return_block = Some(rb);
347 rb
348 }
349 }
350 }
Niko Matsakis9bd35c02015-08-18 21:59:21351}
352
353///////////////////////////////////////////////////////////////////////////
354// Builder methods are broken up into modules, depending on what kind
355// of thing is being translated. Note that they use the `unpack` macro
356// above extensively.
357
358mod block;
359mod cfg;
360mod expr;
361mod into;
362mod matches;
363mod misc;
364mod scope;