11//! See docs in build/expr/mod.rs
22
33use crate :: build:: expr:: category:: { Category , RvalueFunc } ;
4+ use crate :: build:: scope:: DropKind ;
45use crate :: build:: { BlockAnd , BlockAndExtension , BlockFrame , Builder } ;
56use crate :: thir:: * ;
67use rustc_ast:: InlineAsmOptions ;
78use rustc_data_structures:: fx:: FxHashMap ;
89use rustc_data_structures:: stack:: ensure_sufficient_stack;
910use rustc_hir as hir;
11+ use rustc_middle:: middle:: region;
1012use rustc_middle:: mir:: * ;
1113use rustc_middle:: ty:: { self , CanonicalUserTypeAnnotation } ;
1214use rustc_span:: symbol:: sym;
13-
1415use rustc_target:: spec:: abi:: Abi ;
1516
17+ use std:: slice;
18+
1619impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1720 /// Compile `expr`, storing the result into `destination`, which
1821 /// is assumed to be uninitialized.
22+ /// If a `drop_scope` is provided, `destination` is scheduled to be dropped
23+ /// in `scope` once it has been initialized.
1924 crate fn into_expr (
2025 & mut self ,
2126 destination : Place < ' tcx > ,
27+ scope : Option < region:: Scope > ,
2228 mut block : BasicBlock ,
2329 expr : Expr < ' tcx > ,
2430 ) -> BlockAnd < ( ) > {
25- debug ! ( "into_expr(destination={:?}, block={:?}, expr={:?})" , destination, block, expr) ;
31+ debug ! (
32+ "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})" ,
33+ destination, scope, block, expr
34+ ) ;
2635
2736 // since we frequently have to reference `self` from within a
2837 // closure, where `self` would be shadowed, it's easier to
@@ -37,6 +46,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3746 _ => false ,
3847 } ;
3948
49+ let schedule_drop = move |this : & mut Self | {
50+ if let Some ( drop_scope) = scope {
51+ let local =
52+ destination. as_local ( ) . expect ( "cannot schedule drop of non-Local place" ) ;
53+ this. schedule_drop ( expr_span, drop_scope, local, DropKind :: Value ) ;
54+ }
55+ } ;
56+
4057 if !expr_is_block_or_scope {
4158 this. block_context . push ( BlockFrame :: SubExpr ) ;
4259 }
@@ -46,15 +63,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4663 let region_scope = ( region_scope, source_info) ;
4764 ensure_sufficient_stack ( || {
4865 this. in_scope ( region_scope, lint_level, |this| {
49- this. into ( destination, block, value)
66+ this. into ( destination, scope , block, value)
5067 } )
5168 } )
5269 }
5370 ExprKind :: Block { body : ast_block } => {
54- this. ast_block ( destination, block, ast_block, source_info)
71+ this. ast_block ( destination, scope , block, ast_block, source_info)
5572 }
5673 ExprKind :: Match { scrutinee, arms } => {
57- this. match_expr ( destination, expr_span, block, scrutinee, arms)
74+ this. match_expr ( destination, scope , expr_span, block, scrutinee, arms)
5875 }
5976 ExprKind :: NeverToAny { source } => {
6077 let source = this. hir . mirror ( source) ;
@@ -66,6 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6683
6784 // This is an optimization. If the expression was a call then we already have an
6885 // unreachable block. Don't bother to terminate it and create a new one.
86+ schedule_drop ( this) ;
6987 if is_call {
7088 block. unit ( )
7189 } else {
@@ -141,26 +159,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
141159 // Start the loop.
142160 this. cfg . goto ( block, source_info, loop_block) ;
143161
144- this. in_breakable_scope ( Some ( loop_block) , destination, expr_span, move |this| {
145- // conduct the test, if necessary
146- let body_block = this. cfg . start_new_block ( ) ;
147- this. cfg . terminate (
148- loop_block,
149- source_info,
150- TerminatorKind :: FalseUnwind { real_target : body_block, unwind : None } ,
151- ) ;
152- this. diverge_from ( loop_block) ;
153-
154- // The “return” value of the loop body must always be an unit. We therefore
155- // introduce a unit temporary as the destination for the loop body.
156- let tmp = this. get_unit_temp ( ) ;
157- // Execute the body, branching back to the test.
158- let body_block_end = unpack ! ( this. into( tmp, body_block, body) ) ;
159- this. cfg . goto ( body_block_end, source_info, loop_block) ;
160-
161- // Loops are only exited by `break` expressions.
162- None
163- } )
162+ this. in_breakable_scope (
163+ Some ( loop_block) ,
164+ destination,
165+ scope,
166+ expr_span,
167+ move |this| {
168+ // conduct the test, if necessary
169+ let body_block = this. cfg . start_new_block ( ) ;
170+ this. cfg . terminate (
171+ loop_block,
172+ source_info,
173+ TerminatorKind :: FalseUnwind { real_target : body_block, unwind : None } ,
174+ ) ;
175+ this. diverge_from ( loop_block) ;
176+
177+ // The “return” value of the loop body must always be an unit. We therefore
178+ // introduce a unit temporary as the destination for the loop body.
179+ let tmp = this. get_unit_temp ( ) ;
180+ // Execute the body, branching back to the test.
181+ // We don't need to provide a drop scope because `tmp`
182+ // has type `()`.
183+ let body_block_end = unpack ! ( this. into( tmp, None , body_block, body) ) ;
184+ this. cfg . goto ( body_block_end, source_info, loop_block) ;
185+ schedule_drop ( this) ;
186+
187+ // Loops are only exited by `break` expressions.
188+ None
189+ } ,
190+ )
164191 }
165192 ExprKind :: Call { ty, fun, args, from_hir_call, fn_span } => {
166193 let intrinsic = match * ty. kind ( ) {
@@ -192,8 +219,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
192219 . local_decls
193220 . push ( LocalDecl :: with_source_info ( ptr_ty, source_info) . internal ( ) ) ;
194221 let ptr_temp = Place :: from ( ptr_temp) ;
195- let block = unpack ! ( this. into( ptr_temp, block, ptr) ) ;
196- this. into ( this. hir . tcx ( ) . mk_place_deref ( ptr_temp) , block, val)
222+ // No need for a scope, ptr_temp doesn't need drop
223+ let block = unpack ! ( this. into( ptr_temp, None , block, ptr) ) ;
224+ // Maybe we should provide a scope here so that
225+ // `move_val_init` wouldn't leak on panic even with an
226+ // arbitrary `val` expression, but `schedule_drop`,
227+ // borrowck and drop elaboration all prevent us from
228+ // dropping `ptr_temp.deref()`.
229+ this. into ( this. hir . tcx ( ) . mk_place_deref ( ptr_temp) , None , block, val)
197230 } else {
198231 let args: Vec < _ > = args
199232 . into_iter ( )
@@ -226,10 +259,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
226259 } ,
227260 ) ;
228261 this. diverge_from ( block) ;
262+ schedule_drop ( this) ;
229263 success. unit ( )
230264 }
231265 }
232- ExprKind :: Use { source } => this. into ( destination, block, source) ,
266+ ExprKind :: Use { source } => this. into ( destination, scope , block, source) ,
233267 ExprKind :: Borrow { arg, borrow_kind } => {
234268 // We don't do this in `as_rvalue` because we use `as_place`
235269 // for borrow expressions, so we cannot create an `RValue` that
@@ -271,7 +305,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
271305
272306 let field_names = this. hir . all_fields ( adt_def, variant_index) ;
273307
274- let fields = if let Some ( FruInfo { base, field_types } ) = base {
308+ let fields: Vec < _ > = if let Some ( FruInfo { base, field_types } ) = base {
275309 let base = unpack ! ( block = this. as_place( block, base) ) ;
276310
277311 // MIR does not natively support FRU, so for each
@@ -306,12 +340,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
306340 user_ty,
307341 active_field_index,
308342 ) ;
343+ this. record_operands_moved ( & fields) ;
309344 this. cfg . push_assign (
310345 block,
311346 source_info,
312347 destination,
313348 Rvalue :: Aggregate ( adt, fields) ,
314349 ) ;
350+ schedule_drop ( this) ;
315351 block. unit ( )
316352 }
317353 ExprKind :: InlineAsm { template, operands, options, line_spans } => {
@@ -408,6 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
408444 let place = unpack ! ( block = this. as_place( block, expr) ) ;
409445 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
410446 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
447+ schedule_drop ( this) ;
411448 block. unit ( )
412449 }
413450 ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -425,19 +462,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
425462 let place = unpack ! ( block = this. as_place( block, expr) ) ;
426463 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
427464 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
465+ schedule_drop ( this) ;
428466 block. unit ( )
429467 }
430468
431469 ExprKind :: Yield { value } => {
432470 let scope = this. local_scope ( ) ;
433471 let value = unpack ! ( block = this. as_operand( block, scope, value) ) ;
434472 let resume = this. cfg . start_new_block ( ) ;
473+ this. record_operands_moved ( slice:: from_ref ( & value) ) ;
435474 this. cfg . terminate (
436475 block,
437476 source_info,
438477 TerminatorKind :: Yield { value, resume, resume_arg : destination, drop : None } ,
439478 ) ;
440479 this. generator_drop_cleanup ( block) ;
480+ schedule_drop ( this) ;
441481 resume. unit ( )
442482 }
443483
@@ -469,6 +509,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
469509
470510 let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr) ) ;
471511 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
512+ schedule_drop ( this) ;
472513 block. unit ( )
473514 }
474515 } ;
0 commit comments