1
1
//! See docs in build/expr/mod.rs
2
2
3
3
use crate :: build:: expr:: category:: { Category , RvalueFunc } ;
4
+ use crate :: build:: scope:: DropKind ;
4
5
use crate :: build:: { BlockAnd , BlockAndExtension , BlockFrame , Builder , NeedsTemporary } ;
5
6
use rustc_ast:: InlineAsmOptions ;
6
7
use rustc_data_structures:: fx:: FxHashMap ;
7
8
use rustc_data_structures:: stack:: ensure_sufficient_stack;
8
9
use rustc_hir as hir;
10
+ use rustc_index:: IndexVec ;
11
+ use rustc_middle:: middle:: region;
9
12
use rustc_middle:: mir:: * ;
10
13
use rustc_middle:: span_bug;
11
14
use rustc_middle:: thir:: * ;
@@ -14,13 +17,16 @@ use rustc_span::source_map::Spanned;
14
17
use std:: iter;
15
18
use tracing:: { debug, instrument} ;
16
19
20
+ use std:: slice;
21
+
17
22
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
18
23
/// Compile `expr`, storing the result into `destination`, which
19
24
/// is assumed to be uninitialized.
20
25
#[ instrument( level = "debug" , skip( self ) ) ]
21
26
pub ( crate ) fn expr_into_dest (
22
27
& mut self ,
23
28
destination : Place < ' tcx > ,
29
+ scope : Option < region:: Scope > ,
24
30
mut block : BasicBlock ,
25
31
expr_id : ExprId ,
26
32
) -> BlockAnd < ( ) > {
@@ -35,6 +41,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
35
41
let expr_is_block_or_scope =
36
42
matches ! ( expr. kind, ExprKind :: Block { .. } | ExprKind :: Scope { .. } ) ;
37
43
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
+
38
52
if !expr_is_block_or_scope {
39
53
this. block_context . push ( BlockFrame :: SubExpr ) ;
40
54
}
@@ -44,15 +58,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
44
58
let region_scope = ( region_scope, source_info) ;
45
59
ensure_sufficient_stack ( || {
46
60
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)
48
62
} )
49
63
} )
50
64
}
51
65
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)
53
67
}
54
68
ExprKind :: Match { scrutinee, ref arms, .. } => this. match_expr (
55
69
destination,
70
+ scope,
56
71
block,
57
72
scrutinee,
58
73
arms,
@@ -90,7 +105,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
90
105
) ) ;
91
106
92
107
// 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
94
117
} ) ;
95
118
96
119
// Pack `(then_block, else_block)` into `BlockAnd<BasicBlock>`.
@@ -104,7 +127,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
104
127
105
128
// If there is an `else` arm, lower it into `else_blk`.
106
129
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
+ ) ;
108
133
} else {
109
134
// There is no `else` arm, so we know both arms have type `()`.
110
135
// Generate the implicit `else {}` by assigning unit.
@@ -139,6 +164,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
139
164
140
165
// This is an optimization. If the expression was a call then we already have an
141
166
// unreachable block. Don't bother to terminate it and create a new one.
167
+ schedule_drop ( this) ;
142
168
if is_call {
143
169
block. unit ( )
144
170
} else {
@@ -183,7 +209,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
183
209
const_ : Const :: from_bool ( this. tcx , constant) ,
184
210
} ,
185
211
) ;
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) ) ;
187
214
// Instrument the lowered RHS's value for condition coverage.
188
215
// (Does nothing if condition coverage is not enabled.)
189
216
this. visit_coverage_standalone_condition ( rhs, destination, & mut rhs_block) ;
@@ -209,29 +236,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
209
236
// Start the loop.
210
237
this. cfg . goto ( block, source_info, loop_block) ;
211
238
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
+ )
235
270
}
236
271
ExprKind :: Call { ty : _, fun, ref args, from_hir_call, fn_span } => {
237
272
let fun = unpack ! ( block = this. as_local_operand( block, fun) ) ;
@@ -280,9 +315,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
280
315
// FIXME(matthewjasper): Look at this again if Polonius is
281
316
// stabilized.
282
317
this. record_operands_moved ( & args) ;
318
+ schedule_drop ( this) ;
283
319
success. unit ( )
284
320
}
285
- ExprKind :: Use { source } => this. expr_into_dest ( destination, block, source) ,
321
+ ExprKind :: Use { source } => this. expr_into_dest ( destination, scope , block, source) ,
286
322
ExprKind :: Borrow { arg, borrow_kind } => {
287
323
// We don't do this in `as_rvalue` because we use `as_place`
288
324
// for borrow expressions, so we cannot create an `RValue` that
@@ -345,7 +381,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
345
381
346
382
let field_names = adt_def. variant ( variant_index) . fields . indices ( ) ;
347
383
348
- let fields = if let Some ( FruInfo { base, field_types } ) = base {
384
+ let fields: IndexVec < _ , _ > = if let Some ( FruInfo { base, field_types } ) = base {
349
385
let place_builder = unpack ! ( block = this. as_place_builder( block, * base) ) ;
350
386
351
387
// MIR does not natively support FRU, so for each
@@ -386,6 +422,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
386
422
destination,
387
423
Rvalue :: Aggregate ( adt, fields) ,
388
424
) ;
425
+ schedule_drop ( this) ;
389
426
block. unit ( )
390
427
}
391
428
ExprKind :: InlineAsm ( box InlineAsmExpr {
@@ -464,7 +501,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
464
501
targets. push ( target) ;
465
502
466
503
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) ) ;
468
506
this. cfg . terminate (
469
507
target,
470
508
source_info,
@@ -528,6 +566,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
528
566
let place = unpack ! ( block = this. as_place( block, expr_id) ) ;
529
567
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
530
568
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
569
+ schedule_drop ( this) ;
531
570
block. unit ( )
532
571
}
533
572
ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -543,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
543
582
let place = unpack ! ( block = this. as_place( block, expr_id) ) ;
544
583
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
545
584
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
585
+ schedule_drop ( this) ;
546
586
block. unit ( )
547
587
}
548
588
@@ -565,6 +605,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
565
605
TerminatorKind :: Yield { value, resume, resume_arg : destination, drop : None } ,
566
606
) ;
567
607
this. coroutine_drop_cleanup ( block) ;
608
+ schedule_drop ( this) ;
568
609
resume. unit ( )
569
610
}
570
611
@@ -601,6 +642,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
601
642
602
643
let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr_id) ) ;
603
644
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
645
+ schedule_drop ( this) ;
604
646
block. unit ( )
605
647
}
606
648
} ;
0 commit comments