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.
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.
14 use rustc
::middle
::region
::{CodeExtent, CodeExtentData, ROOT_CODE_EXTENT}
;
15 use rustc
::ty
::{self, Ty}
;
17 use rustc
::util
::nodemap
::NodeMap
;
21 use syntax
::symbol
::keywords
;
24 use rustc_data_structures
::indexed_vec
::{IndexVec, Idx}
;
28 pub struct Builder
<'a
, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
> {
29 hir
: Cx
<'a
, 'gcx
, 'tcx
>,
35 /// the current set of scopes, updated as we traverse;
36 /// see the `scope` module for more details
37 scopes
: Vec
<scope
::Scope
<'tcx
>>,
39 /// the current set of loops; see the `scope` module for more
41 loop_scopes
: Vec
<scope
::LoopScope
<'tcx
>>,
43 /// the vector of all scopes that we have created thus far;
44 /// we track this for debuginfo later
45 visibility_scopes
: IndexVec
<VisibilityScope
, VisibilityScopeData
>,
46 visibility_scope
: VisibilityScope
,
48 /// 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
>>,
51 unit_temp
: Option
<Lvalue
<'tcx
>>,
53 /// cached block with the RESUME terminator; this is created
54 /// when first set of cleanups are built.
55 cached_resume_block
: Option
<BasicBlock
>,
56 /// cached block with the RETURN terminator
57 cached_return_block
: Option
<BasicBlock
>,
61 basic_blocks
: IndexVec
<BasicBlock
, BasicBlockData
<'tcx
>>,
64 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
65 pub struct ScopeId(u32);
67 impl Idx
for ScopeId
{
68 fn new(index
: usize) -> ScopeId
{
69 assert
!(index
< (u32::MAX
as usize));
73 fn index(self) -> usize {
78 ///////////////////////////////////////////////////////////////////////////
79 /// 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
84 #[must_use] // if you don't use one of these results, you're leaving a dangling edge
85 pub struct BlockAnd
<T
>(BasicBlock
, T
);
87 trait BlockAndExtension
{
88 fn and
<T
>(self, v
: T
) -> BlockAnd
<T
>;
89 fn unit(self) -> BlockAnd
<()>;
92 impl BlockAndExtension
for BasicBlock
{
93 fn and
<T
>(self, v
: T
) -> BlockAnd
<T
> {
97 fn unit(self) -> BlockAnd
<()> {
102 /// Update a block pointer and return the value.
103 /// Use it like `let x = unpack!(block = self.foo(block, foo))`.
104 macro_rules
! unpack
{
105 ($x
:ident
= $c
:expr
) => {
107 let BlockAnd(b
, v
) = $c
;
115 let BlockAnd(b
, ()) = $c
;
121 ///////////////////////////////////////////////////////////////////////////
122 /// the main entry point for building MIR for a function
124 pub fn construct_fn
<'a
, 'gcx
, 'tcx
, A
>(hir
: Cx
<'a
, 'gcx
, 'tcx
>,
129 body
: &'gcx hir
::Body
)
131 where A
: Iterator
<Item
=(Ty
<'gcx
>, Option
<&'gcx hir
::Pat
>)>
133 let arguments
: Vec
<_
> = arguments
.collect();
136 let span
= tcx
.hir
.span(fn_id
);
137 let mut builder
= Builder
::new(hir
, span
, arguments
.len(), return_ty
);
139 let call_site_extent
=
140 tcx
.region_maps
.lookup_code_extent(
141 CodeExtentData
::CallSiteScope { fn_id: fn_id, body_id: body.value.id }
);
143 tcx
.region_maps
.lookup_code_extent(
144 CodeExtentData
::ParameterScope { fn_id: fn_id, body_id: body.value.id }
);
145 let mut block
= START_BLOCK
;
146 unpack
!(block
= builder
.in_scope(call_site_extent
, block
, |builder
| {
147 unpack
!(block
= builder
.in_scope(arg_extent
, block
, |builder
| {
148 builder
.args_and_body(block
, &arguments
, arg_extent
, &body
.value
)
150 // Attribute epilogue to function's closing brace
151 let fn_end
= Span { lo: span.hi, ..span }
;
152 let source_info
= builder
.source_info(fn_end
);
153 let return_block
= builder
.return_block();
154 builder
.cfg
.terminate(block
, source_info
,
155 TerminatorKind
::Goto { target: return_block }
);
156 builder
.cfg
.terminate(return_block
, source_info
,
157 TerminatorKind
::Return
);
160 assert_eq
!(block
, builder
.return_block());
162 let mut spread_arg
= None
;
163 if abi
== Abi
::RustCall
{
164 // RustCall pseudo-ABI untuples the last argument.
165 spread_arg
= Some(Local
::new(arguments
.len()));
168 // Gather the upvars of a closure, if any.
169 let upvar_decls
: Vec
<_
> = tcx
.with_freevars(fn_id
, |freevars
| {
170 freevars
.iter().map(|fv
| {
171 let var_id
= tcx
.hir
.as_local_node_id(fv
.def
.def_id()).unwrap();
172 let by_ref
= hir
.tables().upvar_capture(ty
::UpvarId
{
174 closure_expr_id
: fn_id
175 }).map_or(false, |capture
| match capture
{
176 ty
::UpvarCapture
::ByValue
=> false,
177 ty
::UpvarCapture
::ByRef(..) => true
179 let mut decl
= UpvarDecl
{
180 debug_name
: keywords
::Invalid
.name(),
183 if let Some(hir
::map
::NodeLocal(pat
)) = tcx
.hir
.find(var_id
) {
184 if let hir
::PatKind
::Binding(_
, _
, ref ident
, _
) = pat
.node
{
185 decl
.debug_name
= ident
.node
;
192 let mut mir
= builder
.finish(upvar_decls
, return_ty
);
193 mir
.spread_arg
= spread_arg
;
197 pub fn construct_const
<'a
, 'gcx
, 'tcx
>(hir
: Cx
<'a
, 'gcx
, 'tcx
>,
198 body_id
: hir
::BodyId
)
201 let ast_expr
= &tcx
.hir
.body(body_id
).value
;
202 let ty
= hir
.tables().expr_ty_adjusted(ast_expr
);
203 let span
= tcx
.hir
.span(tcx
.hir
.body_owner(body_id
));
204 let mut builder
= Builder
::new(hir
, span
, 0, ty
);
206 let extent
= tcx
.region_maps
.temporary_scope(ast_expr
.id
)
207 .unwrap_or(ROOT_CODE_EXTENT
);
208 let mut block
= START_BLOCK
;
209 let _
= builder
.in_scope(extent
, block
, |builder
| {
210 let expr
= builder
.hir
.mirror(ast_expr
);
211 unpack
!(block
= builder
.into(&Lvalue
::Local(RETURN_POINTER
), block
, expr
));
213 let source_info
= builder
.source_info(span
);
214 let return_block
= builder
.return_block();
215 builder
.cfg
.terminate(block
, source_info
,
216 TerminatorKind
::Goto { target: return_block }
);
217 builder
.cfg
.terminate(return_block
, source_info
,
218 TerminatorKind
::Return
);
223 builder
.finish(vec
![], ty
)
226 pub fn construct_error
<'a
, 'gcx
, 'tcx
>(hir
: Cx
<'a
, 'gcx
, 'tcx
>,
227 body_id
: hir
::BodyId
)
229 let span
= hir
.tcx().hir
.span(hir
.tcx().hir
.body_owner(body_id
));
230 let ty
= hir
.tcx().types
.err
;
231 let mut builder
= Builder
::new(hir
, span
, 0, ty
);
232 let source_info
= builder
.source_info(span
);
233 builder
.cfg
.terminate(START_BLOCK
, source_info
, TerminatorKind
::Unreachable
);
234 builder
.finish(vec
![], ty
)
237 impl<'a
, 'gcx
, 'tcx
> Builder
<'a
, 'gcx
, 'tcx
> {
238 fn new(hir
: Cx
<'a
, 'gcx
, 'tcx
>,
242 -> Builder
<'a
, 'gcx
, 'tcx
> {
243 let mut builder
= Builder
{
245 cfg
: CFG { basic_blocks: IndexVec::new() }
,
247 arg_count
: arg_count
,
249 visibility_scopes
: IndexVec
::new(),
250 visibility_scope
: ARGUMENT_VISIBILITY_SCOPE
,
252 local_decls
: IndexVec
::from_elem_n(LocalDecl
::new_return_pointer(return_ty
), 1),
253 var_indices
: NodeMap(),
255 cached_resume_block
: None
,
256 cached_return_block
: None
259 assert_eq
!(builder
.cfg
.start_new_block(), START_BLOCK
);
260 assert_eq
!(builder
.new_visibility_scope(span
), ARGUMENT_VISIBILITY_SCOPE
);
261 builder
.visibility_scopes
[ARGUMENT_VISIBILITY_SCOPE
].parent_scope
= None
;
267 upvar_decls
: Vec
<UpvarDecl
>,
270 for (index
, block
) in self.cfg
.basic_blocks
.iter().enumerate() {
271 if block
.terminator
.is_none() {
272 span_bug
!(self.fn_span
, "no terminator on block {:?}", index
);
276 Mir
::new(self.cfg
.basic_blocks
,
277 self.visibility_scopes
,
287 fn args_and_body(&mut self,
288 mut block
: BasicBlock
,
289 arguments
: &[(Ty
<'gcx
>, Option
<&'gcx hir
::Pat
>)],
290 argument_extent
: CodeExtent
,
291 ast_body
: &'gcx hir
::Expr
)
294 // Allocate locals for the function arguments
295 for &(ty
, pattern
) in arguments
.iter() {
296 // If this is a simple binding pattern, give the local a nice name for debuginfo.
298 if let Some(pat
) = pattern
{
299 if let hir
::PatKind
::Binding(_
, _
, ref ident
, _
) = pat
.node
{
300 name
= Some(ident
.node
);
304 self.local_decls
.push(LocalDecl
{
305 mutability
: Mutability
::Not
,
312 let mut scope
= None
;
313 // Bind the argument patterns
314 for (index
, &(ty
, pattern
)) in arguments
.iter().enumerate() {
315 // Function arguments always get the first Local indices after the return pointer
316 let lvalue
= Lvalue
::Local(Local
::new(index
+ 1));
318 if let Some(pattern
) = pattern
{
319 let pattern
= Pattern
::from_hir(self.hir
.tcx(), self.hir
.tables(), pattern
);
320 scope
= self.declare_bindings(scope
, ast_body
.span
, &pattern
);
321 unpack
!(block
= self.lvalue_into_pattern(block
, pattern
, &lvalue
));
324 // Make sure we drop (parts of) the argument even when not matched on.
325 self.schedule_drop(pattern
.as_ref().map_or(ast_body
.span
, |pat
| pat
.span
),
326 argument_extent
, &lvalue
, ty
);
330 // Enter the argument pattern bindings visibility scope, if it exists.
331 if let Some(visibility_scope
) = scope
{
332 self.visibility_scope
= visibility_scope
;
335 let body
= self.hir
.mirror(ast_body
);
336 self.into(&Lvalue
::Local(RETURN_POINTER
), block
, body
)
339 fn get_unit_temp(&mut self) -> Lvalue
<'tcx
> {
340 match self.unit_temp
{
341 Some(ref tmp
) => tmp
.clone(),
343 let ty
= self.hir
.unit_ty();
344 let tmp
= self.temp(ty
);
345 self.unit_temp
= Some(tmp
.clone());
351 fn return_block(&mut self) -> BasicBlock
{
352 match self.cached_return_block
{
355 let rb
= self.cfg
.start_new_block();
356 self.cached_return_block
= Some(rb
);
363 ///////////////////////////////////////////////////////////////////////////
364 // Builder methods are broken up into modules, depending on what kind
365 // of thing is being translated. Note that they use the `unpack` macro
366 // above extensively.