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.
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.
11 use build
::{BlockAnd, BlockAndExtension, Builder}
;
17 impl<'a
, 'gcx
, 'tcx
> Builder
<'a
, 'gcx
, 'tcx
> {
18 pub fn ast_block(&mut self,
19 destination
: &Lvalue
<'tcx
>,
21 ast_block
: &'tcx hir
::Block
,
22 source_info
: SourceInfo
)
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
)
33 this
.cfg
.terminate(unpack
!(block_exit
), source_info
,
34 TerminatorKind
::Goto { target: exit_block }
);
37 this
.ast_block_stmts(destination
, block
, span
, stmts
, expr
)
42 fn ast_block_stmts(&mut self,
43 destination
: &Lvalue
<'tcx
>,
44 mut block
: BasicBlock
,
46 stmts
: Vec
<StmtRef
<'tcx
>>,
47 expr
: Option
<ExprRef
<'tcx
>>)
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:
54 // let x = <init> in {
56 // let y = <init> in {
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.
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
;
70 let Stmt { span: _, kind }
= this
.hir
.mirror(stmt
);
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
)
78 StmtKind
::Let { remainder_scope, init_scope, pattern, initializer }
=> {
79 let tcx
= this
.hir
.tcx();
81 // Enter the remainder scope, i.e. the bindings' destruction scope.
82 this
.push_scope(remainder_scope
);
83 let_extent_stack
.push(remainder_scope
);
85 // Declare the bindings, which may create a visibility scope.
86 let remainder_span
= remainder_scope
.span(&tcx
.hir
);
87 let remainder_span
= remainder_span
.unwrap_or(span
);
88 let scope
= this
.declare_bindings(None
, remainder_span
, &pattern
);
90 // Evaluate the initializer, if present.
91 if let Some(init
) = initializer
{
92 unpack
!(block
= this
.in_scope(init_scope
, block
, move |this
| {
94 this
.expr_into_pattern(block
, pattern
, init
)
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
);
103 // Enter the visibility scope, after evaluating the initializer.
104 if let Some(visibility_scope
) = scope
{
105 this
.visibility_scope
= visibility_scope
;
110 // Then, the block may have an optional trailing expression which is a “return” value
112 if let Some(expr
) = expr
{
113 unpack
!(block
= this
.into(destination
, block
, expr
));
115 let source_info
= this
.source_info(span
);
116 this
.cfg
.push_assign_unit(block
, source_info
, destination
);
118 // Finally, we pop all the let scopes before exiting out from the scope of block
120 for extent
in let_extent_stack
.into_iter().rev() {
121 unpack
!(block
= this
.pop_scope(extent
, block
));
123 // Restore the original visibility scope.
124 this
.visibility_scope
= outer_visibility_scope
;