]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/block.rs
f99f41c633e9f0c2b9a53d21e7ee819923dddb85
[rust.git] / src / librustc_mir / build / block.rs
1 // Copyright 2015 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 build::{BlockAnd, BlockAndExtension, Builder};
12 use hair::*;
13 use rustc::mir::*;
14 use rustc::hir;
15 use syntax_pos::Span;
16
17 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
18     pub fn ast_block(&mut self,
19                      destination: &Lvalue<'tcx>,
20                      block: BasicBlock,
21                      ast_block: &'tcx hir::Block,
22                      source_info: SourceInfo)
23                      -> BlockAnd<()> {
24         let Block { extent, span, stmts, expr, targeted_by_break } = self.hir.mirror(ast_block);
25         self.in_scope(extent, block, move |this| {
26             if targeted_by_break {
27                 // This is a `break`-able block (currently only `catch { ... }`)
28                 let exit_block = this.cfg.start_new_block();
29                 let block_exit = this.in_breakable_scope(None, exit_block,
30                                                          destination.clone(), |this| {
31                     this.ast_block_stmts(destination, block, span, stmts, expr)
32                 });
33                 this.cfg.terminate(unpack!(block_exit), source_info,
34                                    TerminatorKind::Goto { target: exit_block });
35                 exit_block.unit()
36             } else {
37                 this.ast_block_stmts(destination, block, span, stmts, expr)
38             }
39         })
40     }
41
42     fn ast_block_stmts(&mut self,
43                        destination: &Lvalue<'tcx>,
44                        mut block: BasicBlock,
45                        span: Span,
46                        stmts: Vec<StmtRef<'tcx>>,
47                        expr: Option<ExprRef<'tcx>>)
48                        -> BlockAnd<()> {
49         let this = self;
50
51         // This convoluted structure is to avoid using recursion as we walk down a list
52         // of statements. Basically, the structure we get back is something like:
53         //
54         //    let x = <init> in {
55         //       expr1;
56         //       let y = <init> in {
57         //           expr2;
58         //           expr3;
59         //           ...
60         //       }
61         //    }
62         //
63         // The let bindings are valid till the end of block so all we have to do is to pop all
64         // the let-scopes at the end.
65         //
66         // First we build all the statements in the block.
67         let mut let_extent_stack = Vec::with_capacity(8);
68         let outer_visibility_scope = this.visibility_scope;
69         for stmt in stmts {
70             let Stmt { span: _, kind } = this.hir.mirror(stmt);
71             match kind {
72                 StmtKind::Expr { scope, expr } => {
73                     unpack!(block = this.in_scope(scope, block, |this| {
74                         let expr = this.hir.mirror(expr);
75                         this.stmt_expr(block, expr)
76                     }));
77                 }
78                 StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
79                     let tcx = this.hir.tcx();
80
81                     // Enter the remainder scope, i.e. the bindings' destruction scope.
82                     this.push_scope(remainder_scope);
83                     let_extent_stack.push(remainder_scope);
84
85                     // Declare the bindings, which may create a visibility scope.
86                     let remainder_span = remainder_scope.span(&tcx.region_maps(), &tcx.hir);
87                     let remainder_span = remainder_span.unwrap_or(span);
88                     let scope = this.declare_bindings(None, remainder_span, &pattern);
89
90                     // Evaluate the initializer, if present.
91                     if let Some(init) = initializer {
92                         unpack!(block = this.in_scope(init_scope, block, move |this| {
93                             // FIXME #30046                              ^~~~
94                             this.expr_into_pattern(block, pattern, init)
95                         }));
96                     } else {
97                         this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
98                             this.storage_live_binding(block, node, span);
99                             this.schedule_drop_for_binding(node, span);
100                         })
101                     }
102
103                     // Enter the visibility scope, after evaluating the initializer.
104                     if let Some(visibility_scope) = scope {
105                         this.visibility_scope = visibility_scope;
106                     }
107                 }
108             }
109         }
110         // Then, the block may have an optional trailing expression which is a “return” value
111         // of the block.
112         if let Some(expr) = expr {
113             unpack!(block = this.into(destination, block, expr));
114         } else {
115             let source_info = this.source_info(span);
116             this.cfg.push_assign_unit(block, source_info, destination);
117         }
118         // Finally, we pop all the let scopes before exiting out from the scope of block
119         // itself.
120         for extent in let_extent_stack.into_iter().rev() {
121             unpack!(block = this.pop_scope(extent, block));
122         }
123         // Restore the original visibility scope.
124         this.visibility_scope = outer_visibility_scope;
125         block.unit()
126     }
127 }