]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/build/block.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.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::repr::*;
14 use rustc::hir;
15
16 impl<'a,'tcx> Builder<'a,'tcx> {
17 pub fn ast_block(&mut self,
18 destination: &Lvalue<'tcx>,
19 mut block: BasicBlock,
20 ast_block: &'tcx hir::Block)
21 -> BlockAnd<()> {
22 let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block);
23 self.in_scope(extent, block, move |this, _| {
24 // This convoluted structure is to avoid using recursion as we walk down a list
25 // of statements. Basically, the structure we get back is something like:
26 //
27 // let x = <init> in {
28 // expr1;
29 // let y = <init> in {
30 // expr2;
31 // expr3;
32 // ...
33 // }
34 // }
35 //
36 // The let bindings are valid till the end of block so all we have to do is to pop all
37 // the let-scopes at the end.
38 //
39 // First we build all the statements in the block.
40 let mut let_extent_stack = Vec::with_capacity(8);
41 for stmt in stmts {
42 let Stmt { span: _, kind } = this.hir.mirror(stmt);
43 match kind {
44 StmtKind::Expr { scope, expr } => {
45 unpack!(block = this.in_scope(scope, block, |this, _| {
46 let expr = this.hir.mirror(expr);
47 let expr_span = expr.span;
48 let temp = this.temp(expr.ty.clone());
49 unpack!(block = this.into(&temp, block, expr));
50 unpack!(block = this.build_drop(block, expr_span, temp));
51 block.unit()
52 }));
53 }
54 StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
55 let remainder_scope_id = this.push_scope(remainder_scope, block);
56 let_extent_stack.push(remainder_scope);
57 unpack!(block = this.in_scope(init_scope, block, move |this, _| {
58 // FIXME #30046 ^~~~
59 if let Some(init) = initializer {
60 this.expr_into_pattern(block, remainder_scope_id, pattern, init)
61 } else {
62 this.declare_bindings(remainder_scope_id, &pattern);
63 block.unit()
64 }
65 }));
66 }
67 }
68 }
69 // Then, the block may have an optional trailing expression which is a “return” value
70 // of the block.
71 if let Some(expr) = expr {
72 unpack!(block = this.into(destination, block, expr));
73 } else {
74 // FIXME(#31472)
75 let scope_id = this.innermost_scope_id();
76 this.cfg.push_assign_unit(block, scope_id, span, destination);
77 }
78 // Finally, we pop all the let scopes before exiting out from the scope of block
79 // itself.
80 for extent in let_extent_stack.into_iter().rev() {
81 unpack!(block = this.pop_scope(extent, block));
82 }
83 block.unit()
84 })
85 }
86 }