]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/build/mod.rs
Imported Upstream version 1.7.0+dfsg1
[rustc.git] / src / librustc_mir / build / mod.rs
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
11 use hair::cx::Cx;
12 use rustc::middle::region::CodeExtent;
13 use rustc::middle::ty::{FnOutput, Ty};
14 use rustc::mir::repr::*;
15 use rustc_data_structures::fnv::FnvHashMap;
16 use rustc_front::hir;
17
18 use syntax::ast;
19 use syntax::codemap::Span;
20
21 pub struct Builder<'a, 'tcx: 'a> {
22 hir: Cx<'a, 'tcx>,
23 cfg: CFG<'tcx>,
24 scopes: Vec<scope::Scope<'tcx>>,
25 loop_scopes: Vec<scope::LoopScope>,
26 var_decls: Vec<VarDecl<'tcx>>,
27 var_indices: FnvHashMap<ast::NodeId, u32>,
28 temp_decls: Vec<TempDecl<'tcx>>,
29 }
30
31 struct CFG<'tcx> {
32 basic_blocks: Vec<BasicBlockData<'tcx>>,
33 }
34
35 ///////////////////////////////////////////////////////////////////////////
36 // The `BlockAnd` "monad" packages up the new basic block along with a
37 // produced value (sometimes just unit, of course). The `unpack!`
38 // macro (and methods below) makes working with `BlockAnd` much more
39 // convenient.
40
41 #[must_use] // if you don't use one of these results, you're leaving a dangling edge
42 pub struct BlockAnd<T>(BasicBlock, T);
43
44 trait BlockAndExtension {
45 fn and<T>(self, v: T) -> BlockAnd<T>;
46 fn unit(self) -> BlockAnd<()>;
47 }
48
49 impl BlockAndExtension for BasicBlock {
50 fn and<T>(self, v: T) -> BlockAnd<T> {
51 BlockAnd(self, v)
52 }
53
54 fn unit(self) -> BlockAnd<()> {
55 BlockAnd(self, ())
56 }
57 }
58
59 /// Update a block pointer and return the value.
60 /// Use it like `let x = unpack!(block = self.foo(block, foo))`.
61 macro_rules! unpack {
62 ($x:ident = $c:expr) => {
63 {
64 let BlockAnd(b, v) = $c;
65 $x = b;
66 v
67 }
68 };
69
70 ($c:expr) => {
71 {
72 let BlockAnd(b, ()) = $c;
73 b
74 }
75 };
76 }
77
78 ///////////////////////////////////////////////////////////////////////////
79 // construct() -- the main entry point for building MIR for a function
80
81 pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
82 _span: Span,
83 implicit_arguments: Vec<Ty<'tcx>>,
84 explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
85 argument_extent: CodeExtent,
86 return_ty: FnOutput<'tcx>,
87 ast_block: &'tcx hir::Block)
88 -> Mir<'tcx> {
89 let cfg = CFG { basic_blocks: vec![] };
90
91 let mut builder = Builder {
92 hir: hir,
93 cfg: cfg,
94 scopes: vec![],
95 loop_scopes: vec![],
96 temp_decls: vec![],
97 var_decls: vec![],
98 var_indices: FnvHashMap(),
99 };
100
101 assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
102 assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
103
104 let mut block = START_BLOCK;
105 let arg_decls = unpack!(block = builder.args_and_body(block,
106 implicit_arguments,
107 explicit_arguments,
108 argument_extent,
109 ast_block));
110
111 builder.cfg.terminate(block, Terminator::Goto { target: END_BLOCK });
112 builder.cfg.terminate(END_BLOCK, Terminator::Return);
113
114 Mir {
115 basic_blocks: builder.cfg.basic_blocks,
116 var_decls: builder.var_decls,
117 arg_decls: arg_decls,
118 temp_decls: builder.temp_decls,
119 return_ty: return_ty,
120 }
121 }
122
123 impl<'a,'tcx> Builder<'a,'tcx> {
124 fn args_and_body(&mut self,
125 mut block: BasicBlock,
126 implicit_arguments: Vec<Ty<'tcx>>,
127 explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
128 argument_extent: CodeExtent,
129 ast_block: &'tcx hir::Block)
130 -> BlockAnd<Vec<ArgDecl<'tcx>>>
131 {
132 self.in_scope(argument_extent, block, |this| {
133 // to start, translate the argument patterns and collect the argument types.
134 let implicits = implicit_arguments.into_iter().map(|ty| (ty, None));
135 let explicits = explicit_arguments.into_iter().map(|(ty, pat)| (ty, Some(pat)));
136 let arg_decls =
137 implicits
138 .chain(explicits)
139 .enumerate()
140 .map(|(index, (ty, pattern))| {
141 if let Some(pattern) = pattern {
142 let lvalue = Lvalue::Arg(index as u32);
143 let pattern = this.hir.irrefutable_pat(pattern);
144 unpack!(block = this.lvalue_into_pattern(block,
145 argument_extent,
146 pattern,
147 &lvalue));
148 }
149 ArgDecl { ty: ty }
150 })
151 .collect();
152
153 // start the first basic block and translate the body
154 unpack!(block = this.ast_block(&Lvalue::ReturnPointer, block, ast_block));
155
156 block.and(arg_decls)
157 })
158 }
159 }
160
161 ///////////////////////////////////////////////////////////////////////////
162 // Builder methods are broken up into modules, depending on what kind
163 // of thing is being translated. Note that they use the `unpack` macro
164 // above extensively.
165
166 mod block;
167 mod cfg;
168 mod expr;
169 mod into;
170 mod matches;
171 mod misc;
172 mod scope;
173 mod stmt;