]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/build/block.rs
New upstream version 1.26.0+dfsg1
[rustc.git] / src / librustc_mir / build / block.rs
CommitLineData
e9174d1e
SL
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
9cc50fc6 11use build::{BlockAnd, BlockAndExtension, Builder};
e9174d1e 12use hair::*;
c30ab7b3 13use rustc::mir::*;
54a0048b 14use rustc::hir;
cc61c64b 15use syntax_pos::Span;
e9174d1e 16
a7813a04 17impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
e9174d1e 18 pub fn ast_block(&mut self,
ff7c6d11 19 destination: &Place<'tcx>,
cc61c64b
XL
20 block: BasicBlock,
21 ast_block: &'tcx hir::Block,
22 source_info: SourceInfo)
e9174d1e 23 -> BlockAnd<()> {
ea8adc8c
XL
24 let Block {
25 region_scope,
26 opt_destruction_scope,
27 span,
28 stmts,
29 expr,
30 targeted_by_break,
31 safety_mode
32 } =
041b39d2 33 self.hir.mirror(ast_block);
ea8adc8c
XL
34 self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
35 this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| {
041b39d2
XL
36 if targeted_by_break {
37 // This is a `break`-able block (currently only `catch { ... }`)
38 let exit_block = this.cfg.start_new_block();
39 let block_exit = this.in_breakable_scope(
40 None, exit_block, destination.clone(), |this| {
ea8adc8c
XL
41 this.ast_block_stmts(destination, block, span, stmts, expr,
42 safety_mode)
041b39d2
XL
43 });
44 this.cfg.terminate(unpack!(block_exit), source_info,
45 TerminatorKind::Goto { target: exit_block });
46 exit_block.unit()
47 } else {
ea8adc8c
XL
48 this.ast_block_stmts(destination, block, span, stmts, expr,
49 safety_mode)
041b39d2
XL
50 }
51 })
cc61c64b
XL
52 })
53 }
3157f602 54
cc61c64b 55 fn ast_block_stmts(&mut self,
ff7c6d11 56 destination: &Place<'tcx>,
cc61c64b
XL
57 mut block: BasicBlock,
58 span: Span,
59 stmts: Vec<StmtRef<'tcx>>,
ea8adc8c
XL
60 expr: Option<ExprRef<'tcx>>,
61 safety_mode: BlockSafety)
cc61c64b
XL
62 -> BlockAnd<()> {
63 let this = self;
64
65 // This convoluted structure is to avoid using recursion as we walk down a list
66 // of statements. Basically, the structure we get back is something like:
67 //
68 // let x = <init> in {
69 // expr1;
70 // let y = <init> in {
71 // expr2;
72 // expr3;
73 // ...
74 // }
75 // }
76 //
77 // The let bindings are valid till the end of block so all we have to do is to pop all
78 // the let-scopes at the end.
79 //
80 // First we build all the statements in the block.
ea8adc8c 81 let mut let_scope_stack = Vec::with_capacity(8);
cc61c64b 82 let outer_visibility_scope = this.visibility_scope;
ea8adc8c
XL
83 let outer_push_unsafe_count = this.push_unsafe_count;
84 let outer_unpushed_unsafe = this.unpushed_unsafe;
85 this.update_visibility_scope_for_safety_mode(span, safety_mode);
86
041b39d2 87 let source_info = this.source_info(span);
cc61c64b 88 for stmt in stmts {
ea8adc8c 89 let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt);
cc61c64b
XL
90 match kind {
91 StmtKind::Expr { scope, expr } => {
041b39d2 92 unpack!(block = this.in_opt_scope(
ea8adc8c
XL
93 opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
94 let si = (scope, source_info);
95 this.in_scope(si, LintLevel::Inherited, block, |this| {
041b39d2
XL
96 let expr = this.hir.mirror(expr);
97 this.stmt_expr(block, expr)
98 })
99 }));
cc61c64b 100 }
ea8adc8c
XL
101 StmtKind::Let {
102 remainder_scope,
103 init_scope,
104 pattern,
0531ce1d 105 ty,
ea8adc8c
XL
106 initializer,
107 lint_level
108 } => {
cc61c64b 109 // Enter the remainder scope, i.e. the bindings' destruction scope.
3b2f2976 110 this.push_scope((remainder_scope, source_info));
ea8adc8c 111 let_scope_stack.push(remainder_scope);
3157f602 112
cc61c64b 113 // Declare the bindings, which may create a visibility scope.
ea8adc8c
XL
114 let remainder_span = remainder_scope.span(this.hir.tcx(),
115 &this.hir.region_scope_tree);
116 let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern);
3157f602 117
cc61c64b
XL
118 // Evaluate the initializer, if present.
119 if let Some(init) = initializer {
041b39d2 120 unpack!(block = this.in_opt_scope(
0531ce1d 121 opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
ea8adc8c 122 let scope = (init_scope, source_info);
0531ce1d
XL
123 this.in_scope(scope, lint_level, block, |this| {
124 this.expr_into_pattern(block, ty, pattern, init)
041b39d2
XL
125 })
126 }));
cc61c64b 127 } else {
0531ce1d
XL
128 // FIXME(#47184): We currently only insert `UserAssertTy` statements for
129 // patterns that are bindings, this is as we do not want to deconstruct
130 // the type being assertion to match the pattern.
131 if let PatternKind::Binding { var, .. } = *pattern.kind {
132 if let Some(ty) = ty {
133 this.user_assert_ty(block, ty, var, span);
134 }
135 }
136
cc61c64b
XL
137 this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
138 this.storage_live_binding(block, node, span);
139 this.schedule_drop_for_binding(node, span);
140 })
141 }
142
143 // Enter the visibility scope, after evaluating the initializer.
144 if let Some(visibility_scope) = scope {
145 this.visibility_scope = visibility_scope;
54a0048b 146 }
9cc50fc6
SL
147 }
148 }
cc61c64b
XL
149 }
150 // Then, the block may have an optional trailing expression which is a “return” value
151 // of the block.
152 if let Some(expr) = expr {
153 unpack!(block = this.into(destination, block, expr));
154 } else {
2c00a5a8
XL
155 // If a block has no trailing expression, then it is given an implicit return type.
156 // This return type is usually `()`, unless the block is diverging, in which case the
157 // return type is `!`. For the unit type, we need to actually return the unit, but in
158 // the case of `!`, no return value is required, as the block will never return.
159 let tcx = this.hir.tcx();
160 let ty = destination.ty(&this.local_decls, tcx).to_ty(tcx);
161 if ty.is_nil() {
162 // We only want to assign an implicit `()` as the return value of the block if the
163 // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
164 this.cfg.push_assign_unit(block, source_info, destination);
165 }
cc61c64b
XL
166 }
167 // Finally, we pop all the let scopes before exiting out from the scope of block
168 // itself.
ea8adc8c
XL
169 for scope in let_scope_stack.into_iter().rev() {
170 unpack!(block = this.pop_scope((scope, source_info), block));
cc61c64b
XL
171 }
172 // Restore the original visibility scope.
173 this.visibility_scope = outer_visibility_scope;
ea8adc8c
XL
174 this.push_unsafe_count = outer_push_unsafe_count;
175 this.unpushed_unsafe = outer_unpushed_unsafe;
cc61c64b 176 block.unit()
e9174d1e 177 }
ea8adc8c
XL
178
179 /// If we are changing the safety mode, create a new visibility scope
180 fn update_visibility_scope_for_safety_mode(&mut self,
181 span: Span,
182 safety_mode: BlockSafety)
183 {
184 debug!("update_visibility_scope_for({:?}, {:?})", span, safety_mode);
185 let new_unsafety = match safety_mode {
186 BlockSafety::Safe => None,
187 BlockSafety::ExplicitUnsafe(node_id) => {
188 assert_eq!(self.push_unsafe_count, 0);
189 match self.unpushed_unsafe {
190 Safety::Safe => {}
191 _ => return
192 }
193 self.unpushed_unsafe = Safety::ExplicitUnsafe(node_id);
194 Some(Safety::ExplicitUnsafe(node_id))
195 }
196 BlockSafety::PushUnsafe => {
197 self.push_unsafe_count += 1;
198 Some(Safety::BuiltinUnsafe)
199 }
200 BlockSafety::PopUnsafe => {
201 self.push_unsafe_count =
202 self.push_unsafe_count.checked_sub(1).unwrap_or_else(|| {
203 span_bug!(span, "unsafe count underflow")
204 });
205 if self.push_unsafe_count == 0 {
206 Some(self.unpushed_unsafe)
207 } else {
208 None
209 }
210 }
211 };
212
213 if let Some(unsafety) = new_unsafety {
214 self.visibility_scope = self.new_visibility_scope(
215 span, LintLevel::Inherited, Some(unsafety));
216 }
217 }
e9174d1e 218}