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 } ;
5
6
use crate :: thir:: * ;
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_middle:: middle:: region;
10
12
use rustc_middle:: mir:: * ;
11
13
use rustc_middle:: ty:: { self , CanonicalUserTypeAnnotation } ;
12
14
use rustc_span:: symbol:: sym;
13
-
14
15
use rustc_target:: spec:: abi:: Abi ;
15
16
17
+ use std:: slice;
18
+
16
19
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
17
20
/// Compile `expr`, storing the result into `destination`, which
18
21
/// 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.
19
24
crate fn into_expr (
20
25
& mut self ,
21
26
destination : Place < ' tcx > ,
27
+ scope : Option < region:: Scope > ,
22
28
mut block : BasicBlock ,
23
29
expr : Expr < ' tcx > ,
24
30
) -> 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
+ ) ;
26
35
27
36
// since we frequently have to reference `self` from within a
28
37
// closure, where `self` would be shadowed, it's easier to
@@ -37,6 +46,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
37
46
_ => false ,
38
47
} ;
39
48
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
+
40
57
if !expr_is_block_or_scope {
41
58
this. block_context . push ( BlockFrame :: SubExpr ) ;
42
59
}
@@ -46,15 +63,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
46
63
let region_scope = ( region_scope, source_info) ;
47
64
ensure_sufficient_stack ( || {
48
65
this. in_scope ( region_scope, lint_level, |this| {
49
- this. into ( destination, block, value)
66
+ this. into ( destination, scope , block, value)
50
67
} )
51
68
} )
52
69
}
53
70
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)
55
72
}
56
73
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)
58
75
}
59
76
ExprKind :: NeverToAny { source } => {
60
77
let source = this. hir . mirror ( source) ;
@@ -66,6 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
66
83
67
84
// This is an optimization. If the expression was a call then we already have an
68
85
// unreachable block. Don't bother to terminate it and create a new one.
86
+ schedule_drop ( this) ;
69
87
if is_call {
70
88
block. unit ( )
71
89
} else {
@@ -141,26 +159,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
141
159
// Start the loop.
142
160
this. cfg . goto ( block, source_info, loop_block) ;
143
161
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
+ )
164
191
}
165
192
ExprKind :: Call { ty, fun, args, from_hir_call, fn_span } => {
166
193
let intrinsic = match * ty. kind ( ) {
@@ -192,8 +219,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
192
219
. local_decls
193
220
. push ( LocalDecl :: with_source_info ( ptr_ty, source_info) . internal ( ) ) ;
194
221
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)
197
230
} else {
198
231
let args: Vec < _ > = args
199
232
. into_iter ( )
@@ -226,10 +259,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
226
259
} ,
227
260
) ;
228
261
this. diverge_from ( block) ;
262
+ schedule_drop ( this) ;
229
263
success. unit ( )
230
264
}
231
265
}
232
- ExprKind :: Use { source } => this. into ( destination, block, source) ,
266
+ ExprKind :: Use { source } => this. into ( destination, scope , block, source) ,
233
267
ExprKind :: Borrow { arg, borrow_kind } => {
234
268
// We don't do this in `as_rvalue` because we use `as_place`
235
269
// for borrow expressions, so we cannot create an `RValue` that
@@ -271,7 +305,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
271
305
272
306
let field_names = this. hir . all_fields ( adt_def, variant_index) ;
273
307
274
- let fields = if let Some ( FruInfo { base, field_types } ) = base {
308
+ let fields: Vec < _ > = if let Some ( FruInfo { base, field_types } ) = base {
275
309
let base = unpack ! ( block = this. as_place( block, base) ) ;
276
310
277
311
// MIR does not natively support FRU, so for each
@@ -306,12 +340,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
306
340
user_ty,
307
341
active_field_index,
308
342
) ;
343
+ this. record_operands_moved ( & fields) ;
309
344
this. cfg . push_assign (
310
345
block,
311
346
source_info,
312
347
destination,
313
348
Rvalue :: Aggregate ( adt, fields) ,
314
349
) ;
350
+ schedule_drop ( this) ;
315
351
block. unit ( )
316
352
}
317
353
ExprKind :: InlineAsm { template, operands, options, line_spans } => {
@@ -408,6 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
408
444
let place = unpack ! ( block = this. as_place( block, expr) ) ;
409
445
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
410
446
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
447
+ schedule_drop ( this) ;
411
448
block. unit ( )
412
449
}
413
450
ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -425,19 +462,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
425
462
let place = unpack ! ( block = this. as_place( block, expr) ) ;
426
463
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
427
464
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
465
+ schedule_drop ( this) ;
428
466
block. unit ( )
429
467
}
430
468
431
469
ExprKind :: Yield { value } => {
432
470
let scope = this. local_scope ( ) ;
433
471
let value = unpack ! ( block = this. as_operand( block, scope, value) ) ;
434
472
let resume = this. cfg . start_new_block ( ) ;
473
+ this. record_operands_moved ( slice:: from_ref ( & value) ) ;
435
474
this. cfg . terminate (
436
475
block,
437
476
source_info,
438
477
TerminatorKind :: Yield { value, resume, resume_arg : destination, drop : None } ,
439
478
) ;
440
479
this. generator_drop_cleanup ( block) ;
480
+ schedule_drop ( this) ;
441
481
resume. unit ( )
442
482
}
443
483
@@ -469,6 +509,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
469
509
470
510
let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr) ) ;
471
511
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
512
+ schedule_drop ( this) ;
472
513
block. unit ( )
473
514
}
474
515
} ;
0 commit comments