1 use crate::build
::matches
::ArmHasGuard
;
2 use crate::build
::ForGuard
::OutsideGuard
;
3 use crate::build
::{BlockAnd, BlockAndExtension, BlockFrame, Builder}
;
4 use rustc_middle
::thir
::*;
5 use rustc_middle
::{mir::*, ty}
;
8 impl<'a
, 'tcx
> Builder
<'a
, 'tcx
> {
11 destination
: Place
<'tcx
>,
14 source_info
: SourceInfo
,
18 opt_destruction_scope
,
25 let expr
= expr
.map(|expr
| &self.thir
[expr
]);
26 self.in_opt_scope(opt_destruction_scope
.map(|de
| (de
, source_info
)), move |this
| {
27 this
.in_scope((region_scope
, source_info
), LintLevel
::Inherited
, move |this
| {
28 if targeted_by_break
{
29 this
.in_breakable_scope(None
, destination
, span
, |this
| {
30 Some(this
.ast_block_stmts(
40 this
.ast_block_stmts(destination
, block
, span
, &stmts
, expr
, safety_mode
)
48 destination
: Place
<'tcx
>,
49 mut block
: BasicBlock
,
52 expr
: Option
<&Expr
<'tcx
>>,
53 safety_mode
: BlockSafety
,
57 // This convoluted structure is to avoid using recursion as we walk down a list
58 // of statements. Basically, the structure we get back is something like:
60 // let x = <init> in {
62 // let y = <init> in {
69 // The let bindings are valid till the end of block so all we have to do is to pop all
70 // the let-scopes at the end.
72 // First we build all the statements in the block.
73 let mut let_scope_stack
= Vec
::with_capacity(8);
74 let outer_source_scope
= this
.source_scope
;
75 let outer_in_scope_unsafe
= this
.in_scope_unsafe
;
76 this
.update_source_scope_for_safety_mode(span
, safety_mode
);
78 let source_info
= this
.source_info(span
);
80 let Stmt { ref kind, opt_destruction_scope }
= this
.thir
[*stmt
];
82 StmtKind
::Expr { scope, expr }
=> {
83 this
.block_context
.push(BlockFrame
::Statement { ignores_expr_result: true }
);
85 block
= this
.in_opt_scope(
86 opt_destruction_scope
.map(|de
| (de
, source_info
)),
88 let si
= (*scope
, source_info
);
89 this
.in_scope(si
, LintLevel
::Inherited
, |this
| {
90 this
.stmt_expr(block
, &this
.thir
[*expr
], Some(*scope
))
103 let ignores_expr_result
= matches
!(*pattern
.kind
, PatKind
::Wild
);
104 this
.block_context
.push(BlockFrame
::Statement { ignores_expr_result }
);
106 // Enter the remainder scope, i.e., the bindings' destruction scope.
107 this
.push_scope((*remainder_scope
, source_info
));
108 let_scope_stack
.push(remainder_scope
);
110 // Declare the bindings, which may create a source scope.
111 let remainder_span
= remainder_scope
.span(this
.tcx
, this
.region_scope_tree
);
113 let visibility_scope
=
114 Some(this
.new_source_scope(remainder_span
, LintLevel
::Inherited
, None
));
116 // Evaluate the initializer, if present.
117 if let Some(init
) = initializer
{
118 let init
= &this
.thir
[*init
];
119 let initializer_span
= init
.span
;
122 block
= this
.in_opt_scope(
123 opt_destruction_scope
.map(|de
| (de
, source_info
)),
125 let scope
= (*init_scope
, source_info
);
126 this
.in_scope(scope
, *lint_level
, |this
| {
127 this
.declare_bindings(
132 Some((None
, initializer_span
)),
134 this
.expr_into_pattern(block
, pattern
.clone(), init
)
140 let scope
= (*init_scope
, source_info
);
141 unpack
!(this
.in_scope(scope
, *lint_level
, |this
| {
142 this
.declare_bindings(
152 debug
!("ast_block_stmts: pattern={:?}", pattern
);
153 this
.visit_primary_bindings(
155 UserTypeProjections
::none(),
156 &mut |this
, _
, _
, _
, node
, span
, _
, _
| {
157 this
.storage_live_binding(block
, node
, span
, OutsideGuard
, true);
158 this
.schedule_drop_for_binding(node
, span
, OutsideGuard
);
163 // Enter the visibility scope, after evaluating the initializer.
164 if let Some(source_scope
) = visibility_scope
{
165 this
.source_scope
= source_scope
;
170 let popped
= this
.block_context
.pop();
171 assert
!(popped
.map_or(false, |bf
| bf
.is_statement()));
174 // Then, the block may have an optional trailing expression which is a “return” value
175 // of the block, which is stored into `destination`.
177 let destination_ty
= destination
.ty(&this
.local_decls
, tcx
).ty
;
178 if let Some(expr
) = expr
{
179 let tail_result_is_ignored
=
180 destination_ty
.is_unit() || this
.block_context
.currently_ignores_tail_results();
182 .push(BlockFrame
::TailExpr { tail_result_is_ignored, span: expr.span }
);
184 unpack
!(block
= this
.expr_into_dest(destination
, block
, expr
));
185 let popped
= this
.block_context
.pop();
187 assert
!(popped
.map_or(false, |bf
| bf
.is_tail_expr()));
189 // If a block has no trailing expression, then it is given an implicit return type.
190 // This return type is usually `()`, unless the block is diverging, in which case the
191 // return type is `!`. For the unit type, we need to actually return the unit, but in
192 // the case of `!`, no return value is required, as the block will never return.
193 // Opaque types of empty bodies also need this unit assignment, in order to infer that their
194 // type is actually unit. Otherwise there will be no defining use found in the MIR.
195 if destination_ty
.is_unit() || matches
!(destination_ty
.kind(), ty
::Opaque(..)) {
196 // We only want to assign an implicit `()` as the return value of the block if the
197 // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
198 this
.cfg
.push_assign_unit(block
, source_info
, destination
, this
.tcx
);
201 // Finally, we pop all the let scopes before exiting out from the scope of block
203 for scope
in let_scope_stack
.into_iter().rev() {
204 unpack
!(block
= this
.pop_scope((*scope
, source_info
), block
));
206 // Restore the original source scope.
207 this
.source_scope
= outer_source_scope
;
208 this
.in_scope_unsafe
= outer_in_scope_unsafe
;
212 /// If we are entering an unsafe block, create a new source scope
213 fn update_source_scope_for_safety_mode(&mut self, span
: Span
, safety_mode
: BlockSafety
) {
214 debug
!("update_source_scope_for({:?}, {:?})", span
, safety_mode
);
215 let new_unsafety
= match safety_mode
{
216 BlockSafety
::Safe
=> return,
217 BlockSafety
::BuiltinUnsafe
=> Safety
::BuiltinUnsafe
,
218 BlockSafety
::ExplicitUnsafe(hir_id
) => {
219 self.in_scope_unsafe
= Safety
::ExplicitUnsafe(hir_id
);
220 Safety
::ExplicitUnsafe(hir_id
)
224 self.source_scope
= self.new_source_scope(span
, LintLevel
::Inherited
, Some(new_unsafety
));