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 {
@@ -186,7 +212,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
186
212
const_ : Const :: from_bool ( this. tcx , constant) ,
187
213
} ,
188
214
) ;
189
- let mut rhs_block = unpack ! ( this. expr_into_dest( destination, continuation, rhs) ) ;
215
+ let mut rhs_block =
216
+ unpack ! ( this. expr_into_dest( destination, scope, continuation, rhs) ) ;
190
217
// Instrument the lowered RHS's value for condition coverage.
191
218
// (Does nothing if condition coverage is not enabled.)
192
219
this. visit_coverage_standalone_condition ( rhs, destination, & mut rhs_block) ;
@@ -212,29 +239,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
212
239
// Start the loop.
213
240
this. cfg . goto ( block, source_info, loop_block) ;
214
241
215
- this. in_breakable_scope ( Some ( loop_block) , destination, expr_span, move |this| {
216
- // conduct the test, if necessary
217
- let body_block = this. cfg . start_new_block ( ) ;
218
- this. cfg . terminate (
219
- loop_block,
220
- source_info,
221
- TerminatorKind :: FalseUnwind {
222
- real_target : body_block,
223
- unwind : UnwindAction :: Continue ,
224
- } ,
225
- ) ;
226
- this. diverge_from ( loop_block) ;
227
-
228
- // The “return” value of the loop body must always be a unit. We therefore
229
- // introduce a unit temporary as the destination for the loop body.
230
- let tmp = this. get_unit_temp ( ) ;
231
- // Execute the body, branching back to the test.
232
- let body_block_end = unpack ! ( this. expr_into_dest( tmp, body_block, body) ) ;
233
- this. cfg . goto ( body_block_end, source_info, loop_block) ;
234
-
235
- // Loops are only exited by `break` expressions.
236
- None
237
- } )
242
+ this. in_breakable_scope (
243
+ Some ( loop_block) ,
244
+ destination,
245
+ scope,
246
+ expr_span,
247
+ move |this| {
248
+ // conduct the test, if necessary
249
+ let body_block = this. cfg . start_new_block ( ) ;
250
+ this. cfg . terminate (
251
+ loop_block,
252
+ source_info,
253
+ TerminatorKind :: FalseUnwind {
254
+ real_target : body_block,
255
+ unwind : UnwindAction :: Continue ,
256
+ } ,
257
+ ) ;
258
+ this. diverge_from ( loop_block) ;
259
+
260
+ // The “return” value of the loop body must always be a unit. We therefore
261
+ // introduce a unit temporary as the destination for the loop body.
262
+ let tmp = this. get_unit_temp ( ) ;
263
+ // Execute the body, branching back to the test.
264
+ let body_block_end =
265
+ unpack ! ( this. expr_into_dest( tmp, scope, body_block, body) ) ;
266
+ this. cfg . goto ( body_block_end, source_info, loop_block) ;
267
+ schedule_drop ( this) ;
268
+
269
+ // Loops are only exited by `break` expressions.
270
+ None
271
+ } ,
272
+ )
238
273
}
239
274
ExprKind :: Call { ty : _, fun, ref args, from_hir_call, fn_span } => {
240
275
let fun = unpack ! ( block = this. as_local_operand( block, fun) ) ;
@@ -283,9 +318,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
283
318
// FIXME(matthewjasper): Look at this again if Polonius is
284
319
// stabilized.
285
320
this. record_operands_moved ( & args) ;
321
+ schedule_drop ( this) ;
286
322
success. unit ( )
287
323
}
288
- ExprKind :: Use { source } => this. expr_into_dest ( destination, block, source) ,
324
+ ExprKind :: Use { source } => this. expr_into_dest ( destination, scope , block, source) ,
289
325
ExprKind :: Borrow { arg, borrow_kind } => {
290
326
// We don't do this in `as_rvalue` because we use `as_place`
291
327
// for borrow expressions, so we cannot create an `RValue` that
@@ -348,7 +384,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
348
384
349
385
let field_names = adt_def. variant ( variant_index) . fields . indices ( ) ;
350
386
351
- let fields = if let Some ( FruInfo { base, field_types } ) = base {
387
+ let fields: IndexVec < _ , _ > = if let Some ( FruInfo { base, field_types } ) = base {
352
388
let place_builder = unpack ! ( block = this. as_place_builder( block, * base) ) ;
353
389
354
390
// MIR does not natively support FRU, so for each
@@ -389,6 +425,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
389
425
destination,
390
426
Rvalue :: Aggregate ( adt, fields) ,
391
427
) ;
428
+ schedule_drop ( this) ;
392
429
block. unit ( )
393
430
}
394
431
ExprKind :: InlineAsm ( box InlineAsmExpr {
@@ -467,7 +504,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
467
504
targets. push ( target) ;
468
505
469
506
let tmp = this. get_unit_temp ( ) ;
470
- let target = unpack ! ( this. ast_block( tmp, target, block, source_info) ) ;
507
+ let target =
508
+ unpack ! ( this. ast_block( tmp, scope, target, block, source_info) ) ;
471
509
this. cfg . terminate (
472
510
target,
473
511
source_info,
@@ -531,6 +569,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
531
569
let place = unpack ! ( block = this. as_place( block, expr_id) ) ;
532
570
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
533
571
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
572
+ schedule_drop ( this) ;
534
573
block. unit ( )
535
574
}
536
575
ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -546,6 +585,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
546
585
let place = unpack ! ( block = this. as_place( block, expr_id) ) ;
547
586
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
548
587
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
588
+ schedule_drop ( this) ;
549
589
block. unit ( )
550
590
}
551
591
@@ -568,6 +608,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
568
608
TerminatorKind :: Yield { value, resume, resume_arg : destination, drop : None } ,
569
609
) ;
570
610
this. coroutine_drop_cleanup ( block) ;
611
+ schedule_drop ( this) ;
571
612
resume. unit ( )
572
613
}
573
614
@@ -604,6 +645,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
604
645
605
646
let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr_id) ) ;
606
647
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
648
+ schedule_drop ( this) ;
607
649
block. unit ( )
608
650
}
609
651
} ;
0 commit comments