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