2
2
3
3
use crate :: build:: expr:: category:: { Category , RvalueFunc } ;
4
4
use crate :: build:: matches:: DeclareLetBindings ;
5
+ use crate :: build:: scope:: DropKind ;
5
6
use crate :: build:: { BlockAnd , BlockAndExtension , BlockFrame , Builder , NeedsTemporary } ;
6
7
use rustc_ast:: InlineAsmOptions ;
7
8
use rustc_data_structures:: fx:: FxHashMap ;
8
9
use rustc_data_structures:: stack:: ensure_sufficient_stack;
9
10
use rustc_hir as hir;
11
+ use rustc_index:: IndexVec ;
12
+ use rustc_middle:: middle:: region;
10
13
use rustc_middle:: mir:: * ;
11
14
use rustc_middle:: span_bug;
12
15
use rustc_middle:: thir:: * ;
@@ -15,13 +18,16 @@ use rustc_span::source_map::Spanned;
15
18
use std:: iter;
16
19
use tracing:: { debug, instrument} ;
17
20
21
+ use std:: slice;
22
+
18
23
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
19
24
/// Compile `expr`, storing the result into `destination`, which
20
25
/// is assumed to be uninitialized.
21
26
#[ instrument( level = "debug" , skip( self ) ) ]
22
27
pub ( crate ) fn expr_into_dest (
23
28
& mut self ,
24
29
destination : Place < ' tcx > ,
30
+ scope : Option < region:: Scope > ,
25
31
mut block : BasicBlock ,
26
32
expr_id : ExprId ,
27
33
) -> BlockAnd < ( ) > {
@@ -36,6 +42,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
36
42
let expr_is_block_or_scope =
37
43
matches ! ( expr. kind, ExprKind :: Block { .. } | ExprKind :: Scope { .. } ) ;
38
44
45
+ let schedule_drop = move |this : & mut Self | {
46
+ if let Some ( drop_scope) = scope {
47
+ let local =
48
+ destination. as_local ( ) . expect ( "cannot schedule drop of non-Local place" ) ;
49
+ this. schedule_drop ( expr_span, drop_scope, local, DropKind :: Value ) ;
50
+ }
51
+ } ;
52
+
39
53
if !expr_is_block_or_scope {
40
54
this. block_context . push ( BlockFrame :: SubExpr ) ;
41
55
}
@@ -45,15 +59,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
45
59
let region_scope = ( region_scope, source_info) ;
46
60
ensure_sufficient_stack ( || {
47
61
this. in_scope ( region_scope, lint_level, |this| {
48
- this. expr_into_dest ( destination, block, value)
62
+ this. expr_into_dest ( destination, scope , block, value)
49
63
} )
50
64
} )
51
65
}
52
66
ExprKind :: Block { block : ast_block } => {
53
- this. ast_block ( destination, block, ast_block, source_info)
67
+ this. ast_block ( destination, scope , block, ast_block, source_info)
54
68
}
55
69
ExprKind :: Match { scrutinee, ref arms, .. } => this. match_expr (
56
70
destination,
71
+ scope,
57
72
block,
58
73
scrutinee,
59
74
arms,
@@ -91,7 +106,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
91
106
) ) ;
92
107
93
108
// Lower the `then` arm into its block.
94
- this. expr_into_dest ( destination, then_blk, then)
109
+ let then_blk =
110
+ this. expr_into_dest ( destination, scope, then_blk, then) ;
111
+ if let Some ( drop_scope) = scope {
112
+ let local = destination
113
+ . as_local ( )
114
+ . expect ( "cannot unschedule drop of non-Local place" ) ;
115
+ this. unschedule_drop ( drop_scope, local) ;
116
+ }
117
+ then_blk
95
118
} ) ;
96
119
97
120
// Pack `(then_block, else_block)` into `BlockAnd<BasicBlock>`.
@@ -105,7 +128,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
105
128
106
129
// If there is an `else` arm, lower it into `else_blk`.
107
130
if let Some ( else_expr) = else_opt {
108
- unpack ! ( else_blk = this. expr_into_dest( destination, else_blk, else_expr) ) ;
131
+ unpack ! (
132
+ else_blk = this. expr_into_dest( destination, scope, else_blk, else_expr)
133
+ ) ;
109
134
} else {
110
135
// There is no `else` arm, so we know both arms have type `()`.
111
136
// Generate the implicit `else {}` by assigning unit.
@@ -140,6 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
140
165
141
166
// This is an optimization. If the expression was a call then we already have an
142
167
// unreachable block. Don't bother to terminate it and create a new one.
168
+ schedule_drop ( this) ;
143
169
if is_call {
144
170
block. unit ( )
145
171
} else {
@@ -187,7 +213,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
187
213
const_ : Const :: from_bool ( this. tcx , constant) ,
188
214
} ,
189
215
) ;
190
- let mut rhs_block = unpack ! ( this. expr_into_dest( destination, continuation, rhs) ) ;
216
+ let mut rhs_block =
217
+ unpack ! ( this. expr_into_dest( destination, scope, continuation, rhs) ) ;
191
218
// Instrument the lowered RHS's value for condition coverage.
192
219
// (Does nothing if condition coverage is not enabled.)
193
220
this. visit_coverage_standalone_condition ( rhs, destination, & mut rhs_block) ;
@@ -213,29 +240,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
213
240
// Start the loop.
214
241
this. cfg . goto ( block, source_info, loop_block) ;
215
242
216
- this. in_breakable_scope ( Some ( loop_block) , destination, expr_span, move |this| {
217
- // conduct the test, if necessary
218
- let body_block = this. cfg . start_new_block ( ) ;
219
- this. cfg . terminate (
220
- loop_block,
221
- source_info,
222
- TerminatorKind :: FalseUnwind {
223
- real_target : body_block,
224
- unwind : UnwindAction :: Continue ,
225
- } ,
226
- ) ;
227
- this. diverge_from ( loop_block) ;
228
-
229
- // The “return” value of the loop body must always be a unit. We therefore
230
- // introduce a unit temporary as the destination for the loop body.
231
- let tmp = this. get_unit_temp ( ) ;
232
- // Execute the body, branching back to the test.
233
- let body_block_end = unpack ! ( this. expr_into_dest( tmp, body_block, body) ) ;
234
- this. cfg . goto ( body_block_end, source_info, loop_block) ;
235
-
236
- // Loops are only exited by `break` expressions.
237
- None
238
- } )
243
+ this. in_breakable_scope (
244
+ Some ( loop_block) ,
245
+ destination,
246
+ scope,
247
+ expr_span,
248
+ move |this| {
249
+ // conduct the test, if necessary
250
+ let body_block = this. cfg . start_new_block ( ) ;
251
+ this. cfg . terminate (
252
+ loop_block,
253
+ source_info,
254
+ TerminatorKind :: FalseUnwind {
255
+ real_target : body_block,
256
+ unwind : UnwindAction :: Continue ,
257
+ } ,
258
+ ) ;
259
+ this. diverge_from ( loop_block) ;
260
+
261
+ // The “return” value of the loop body must always be a unit. We therefore
262
+ // introduce a unit temporary as the destination for the loop body.
263
+ let tmp = this. get_unit_temp ( ) ;
264
+ // Execute the body, branching back to the test.
265
+ let body_block_end =
266
+ unpack ! ( this. expr_into_dest( tmp, scope, body_block, body) ) ;
267
+ this. cfg . goto ( body_block_end, source_info, loop_block) ;
268
+ schedule_drop ( this) ;
269
+
270
+ // Loops are only exited by `break` expressions.
271
+ None
272
+ } ,
273
+ )
239
274
}
240
275
ExprKind :: Call { ty : _, fun, ref args, from_hir_call, fn_span } => {
241
276
let fun = unpack ! ( block = this. as_local_operand( block, fun) ) ;
@@ -284,9 +319,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
284
319
// FIXME(matthewjasper): Look at this again if Polonius is
285
320
// stabilized.
286
321
this. record_operands_moved ( & args) ;
322
+ schedule_drop ( this) ;
287
323
success. unit ( )
288
324
}
289
- ExprKind :: Use { source } => this. expr_into_dest ( destination, block, source) ,
325
+ ExprKind :: Use { source } => this. expr_into_dest ( destination, scope , block, source) ,
290
326
ExprKind :: Borrow { arg, borrow_kind } => {
291
327
// We don't do this in `as_rvalue` because we use `as_place`
292
328
// for borrow expressions, so we cannot create an `RValue` that
@@ -349,7 +385,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
349
385
350
386
let field_names = adt_def. variant ( variant_index) . fields . indices ( ) ;
351
387
352
- let fields = if let Some ( FruInfo { base, field_types } ) = base {
388
+ let fields: IndexVec < _ , _ > = if let Some ( FruInfo { base, field_types } ) = base {
353
389
let place_builder = unpack ! ( block = this. as_place_builder( block, * base) ) ;
354
390
355
391
// MIR does not natively support FRU, so for each
@@ -390,6 +426,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
390
426
destination,
391
427
Rvalue :: Aggregate ( adt, fields) ,
392
428
) ;
429
+ schedule_drop ( this) ;
393
430
block. unit ( )
394
431
}
395
432
ExprKind :: InlineAsm ( box InlineAsmExpr {
@@ -468,7 +505,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
468
505
targets. push ( target) ;
469
506
470
507
let tmp = this. get_unit_temp ( ) ;
471
- let target = unpack ! ( this. ast_block( tmp, target, block, source_info) ) ;
508
+ let target =
509
+ unpack ! ( this. ast_block( tmp, scope, target, block, source_info) ) ;
472
510
this. cfg . terminate (
473
511
target,
474
512
source_info,
@@ -532,6 +570,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
532
570
let place = unpack ! ( block = this. as_place( block, expr_id) ) ;
533
571
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
534
572
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
573
+ schedule_drop ( this) ;
535
574
block. unit ( )
536
575
}
537
576
ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -547,6 +586,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
547
586
let place = unpack ! ( block = this. as_place( block, expr_id) ) ;
548
587
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
549
588
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
589
+ schedule_drop ( this) ;
550
590
block. unit ( )
551
591
}
552
592
@@ -569,6 +609,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
569
609
TerminatorKind :: Yield { value, resume, resume_arg : destination, drop : None } ,
570
610
) ;
571
611
this. coroutine_drop_cleanup ( block) ;
612
+ schedule_drop ( this) ;
572
613
resume. unit ( )
573
614
}
574
615
@@ -605,6 +646,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
605
646
606
647
let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr_id) ) ;
607
648
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
649
+ schedule_drop ( this) ;
608
650
block. unit ( )
609
651
}
610
652
} ;
0 commit comments