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 , NeedsTemporary } ;
56use rustc_ast:: InlineAsmOptions ;
67use rustc_data_structures:: fx:: FxHashMap ;
78use rustc_data_structures:: stack:: ensure_sufficient_stack;
89use rustc_hir as hir;
10+ use rustc_index:: IndexVec ;
11+ use rustc_middle:: middle:: region;
912use rustc_middle:: mir:: * ;
1013use rustc_middle:: span_bug;
1114use rustc_middle:: thir:: * ;
@@ -14,13 +17,16 @@ use rustc_span::source_map::Spanned;
1417use std:: iter;
1518use tracing:: { debug, instrument} ;
1619
20+ use std:: slice;
21+
1722impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1823 /// Compile `expr`, storing the result into `destination`, which
1924 /// is assumed to be uninitialized.
2025 #[ instrument( level = "debug" , skip( self ) ) ]
2126 pub ( crate ) fn expr_into_dest (
2227 & mut self ,
2328 destination : Place < ' tcx > ,
29+ scope : Option < region:: Scope > ,
2430 mut block : BasicBlock ,
2531 expr_id : ExprId ,
2632 ) -> BlockAnd < ( ) > {
@@ -35,6 +41,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3541 let expr_is_block_or_scope =
3642 matches ! ( expr. kind, ExprKind :: Block { .. } | ExprKind :: Scope { .. } ) ;
3743
44+ let schedule_drop = move |this : & mut Self | {
45+ if let Some ( drop_scope) = scope {
46+ let local =
47+ destination. as_local ( ) . expect ( "cannot schedule drop of non-Local place" ) ;
48+ this. schedule_drop ( expr_span, drop_scope, local, DropKind :: Value ) ;
49+ }
50+ } ;
51+
3852 if !expr_is_block_or_scope {
3953 this. block_context . push ( BlockFrame :: SubExpr ) ;
4054 }
@@ -44,15 +58,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4458 let region_scope = ( region_scope, source_info) ;
4559 ensure_sufficient_stack ( || {
4660 this. in_scope ( region_scope, lint_level, |this| {
47- this. expr_into_dest ( destination, block, value)
61+ this. expr_into_dest ( destination, scope , block, value)
4862 } )
4963 } )
5064 }
5165 ExprKind :: Block { block : ast_block } => {
52- this. ast_block ( destination, block, ast_block, source_info)
66+ this. ast_block ( destination, scope , block, ast_block, source_info)
5367 }
5468 ExprKind :: Match { scrutinee, ref arms, .. } => this. match_expr (
5569 destination,
70+ scope,
5671 block,
5772 scrutinee,
5873 arms,
@@ -90,7 +105,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
90105 ) ) ;
91106
92107 // Lower the `then` arm into its block.
93- this. expr_into_dest ( destination, then_blk, then)
108+ let then_blk =
109+ this. expr_into_dest ( destination, scope, then_blk, then) ;
110+ if let Some ( drop_scope) = scope {
111+ let local = destination
112+ . as_local ( )
113+ . expect ( "cannot unschedule drop of non-Local place" ) ;
114+ this. unschedule_drop ( drop_scope, local) ;
115+ }
116+ then_blk
94117 } ) ;
95118
96119 // Pack `(then_block, else_block)` into `BlockAnd<BasicBlock>`.
@@ -104,7 +127,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
104127
105128 // If there is an `else` arm, lower it into `else_blk`.
106129 if let Some ( else_expr) = else_opt {
107- unpack ! ( else_blk = this. expr_into_dest( destination, else_blk, else_expr) ) ;
130+ unpack ! (
131+ else_blk = this. expr_into_dest( destination, scope, else_blk, else_expr)
132+ ) ;
108133 } else {
109134 // There is no `else` arm, so we know both arms have type `()`.
110135 // Generate the implicit `else {}` by assigning unit.
@@ -139,6 +164,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
139164
140165 // This is an optimization. If the expression was a call then we already have an
141166 // unreachable block. Don't bother to terminate it and create a new one.
167+ schedule_drop ( this) ;
142168 if is_call {
143169 block. unit ( )
144170 } else {
@@ -183,7 +209,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
183209 const_ : Const :: from_bool ( this. tcx , constant) ,
184210 } ,
185211 ) ;
186- let mut rhs_block = unpack ! ( this. expr_into_dest( destination, continuation, rhs) ) ;
212+ let mut rhs_block =
213+ unpack ! ( this. expr_into_dest( destination, scope, continuation, rhs) ) ;
187214 // Instrument the lowered RHS's value for condition coverage.
188215 // (Does nothing if condition coverage is not enabled.)
189216 this. visit_coverage_standalone_condition ( rhs, destination, & mut rhs_block) ;
@@ -209,29 +236,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
209236 // Start the loop.
210237 this. cfg . goto ( block, source_info, loop_block) ;
211238
212- this. in_breakable_scope ( Some ( loop_block) , destination, expr_span, move |this| {
213- // conduct the test, if necessary
214- let body_block = this. cfg . start_new_block ( ) ;
215- this. cfg . terminate (
216- loop_block,
217- source_info,
218- TerminatorKind :: FalseUnwind {
219- real_target : body_block,
220- unwind : UnwindAction :: Continue ,
221- } ,
222- ) ;
223- this. diverge_from ( loop_block) ;
224-
225- // The “return” value of the loop body must always be a unit. We therefore
226- // introduce a unit temporary as the destination for the loop body.
227- let tmp = this. get_unit_temp ( ) ;
228- // Execute the body, branching back to the test.
229- let body_block_end = unpack ! ( this. expr_into_dest( tmp, body_block, body) ) ;
230- this. cfg . goto ( body_block_end, source_info, loop_block) ;
231-
232- // Loops are only exited by `break` expressions.
233- None
234- } )
239+ this. in_breakable_scope (
240+ Some ( loop_block) ,
241+ destination,
242+ scope,
243+ expr_span,
244+ move |this| {
245+ // conduct the test, if necessary
246+ let body_block = this. cfg . start_new_block ( ) ;
247+ this. cfg . terminate (
248+ loop_block,
249+ source_info,
250+ TerminatorKind :: FalseUnwind {
251+ real_target : body_block,
252+ unwind : UnwindAction :: Continue ,
253+ } ,
254+ ) ;
255+ this. diverge_from ( loop_block) ;
256+
257+ // The “return” value of the loop body must always be a unit. We therefore
258+ // introduce a unit temporary as the destination for the loop body.
259+ let tmp = this. get_unit_temp ( ) ;
260+ // Execute the body, branching back to the test.
261+ let body_block_end =
262+ unpack ! ( this. expr_into_dest( tmp, scope, body_block, body) ) ;
263+ this. cfg . goto ( body_block_end, source_info, loop_block) ;
264+ schedule_drop ( this) ;
265+
266+ // Loops are only exited by `break` expressions.
267+ None
268+ } ,
269+ )
235270 }
236271 ExprKind :: Call { ty : _, fun, ref args, from_hir_call, fn_span } => {
237272 let fun = unpack ! ( block = this. as_local_operand( block, fun) ) ;
@@ -280,9 +315,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
280315 // FIXME(matthewjasper): Look at this again if Polonius is
281316 // stabilized.
282317 this. record_operands_moved ( & args) ;
318+ schedule_drop ( this) ;
283319 success. unit ( )
284320 }
285- ExprKind :: Use { source } => this. expr_into_dest ( destination, block, source) ,
321+ ExprKind :: Use { source } => this. expr_into_dest ( destination, scope , block, source) ,
286322 ExprKind :: Borrow { arg, borrow_kind } => {
287323 // We don't do this in `as_rvalue` because we use `as_place`
288324 // for borrow expressions, so we cannot create an `RValue` that
@@ -345,7 +381,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
345381
346382 let field_names = adt_def. variant ( variant_index) . fields . indices ( ) ;
347383
348- let fields = if let Some ( FruInfo { base, field_types } ) = base {
384+ let fields: IndexVec < _ , _ > = if let Some ( FruInfo { base, field_types } ) = base {
349385 let place_builder = unpack ! ( block = this. as_place_builder( block, * base) ) ;
350386
351387 // MIR does not natively support FRU, so for each
@@ -386,6 +422,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
386422 destination,
387423 Rvalue :: Aggregate ( adt, fields) ,
388424 ) ;
425+ schedule_drop ( this) ;
389426 block. unit ( )
390427 }
391428 ExprKind :: InlineAsm ( box InlineAsmExpr {
@@ -464,7 +501,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
464501 targets. push ( target) ;
465502
466503 let tmp = this. get_unit_temp ( ) ;
467- let target = unpack ! ( this. ast_block( tmp, target, block, source_info) ) ;
504+ let target =
505+ unpack ! ( this. ast_block( tmp, scope, target, block, source_info) ) ;
468506 this. cfg . terminate (
469507 target,
470508 source_info,
@@ -528,6 +566,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
528566 let place = unpack ! ( block = this. as_place( block, expr_id) ) ;
529567 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
530568 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
569+ schedule_drop ( this) ;
531570 block. unit ( )
532571 }
533572 ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -543,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
543582 let place = unpack ! ( block = this. as_place( block, expr_id) ) ;
544583 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
545584 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
585+ schedule_drop ( this) ;
546586 block. unit ( )
547587 }
548588
@@ -565,6 +605,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
565605 TerminatorKind :: Yield { value, resume, resume_arg : destination, drop : None } ,
566606 ) ;
567607 this. coroutine_drop_cleanup ( block) ;
608+ schedule_drop ( this) ;
568609 resume. unit ( )
569610 }
570611
@@ -601,6 +642,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
601642
602643 let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr_id) ) ;
603644 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
645+ schedule_drop ( this) ;
604646 block. unit ( )
605647 }
606648 } ;
0 commit comments