2
2
3
3
use crate :: build:: expr:: category:: { Category , RvalueFunc } ;
4
4
use crate :: build:: { BlockAnd , BlockAndExtension , BlockFrame , Builder } ;
5
+ use crate :: build:: scope:: DropKind ;
5
6
use crate :: hair:: * ;
7
+ use rustc:: middle:: region;
6
8
use rustc:: mir:: * ;
7
9
use rustc:: ty;
8
10
@@ -11,15 +13,18 @@ use rustc_target::spec::abi::Abi;
11
13
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
12
14
/// Compile `expr`, storing the result into `destination`, which
13
15
/// is assumed to be uninitialized.
16
+ /// If a `drop_scope` is provided, `destination` is scheduled to be dropped
17
+ /// in `scope` once it has been initialized.
14
18
pub fn into_expr (
15
19
& mut self ,
16
20
destination : & Place < ' tcx > ,
21
+ scope : Option < region:: Scope > ,
17
22
mut block : BasicBlock ,
18
23
expr : Expr < ' tcx > ,
19
24
) -> BlockAnd < ( ) > {
20
25
debug ! (
21
- "into_expr(destination={:?}, block={:?}, expr={:?})" ,
22
- destination, block, expr
26
+ "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})" ,
27
+ destination, scope , block, expr
23
28
) ;
24
29
25
30
// since we frequently have to reference `self` from within a
@@ -35,6 +40,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
35
40
_ => false ,
36
41
} ;
37
42
43
+ let schedule_drop = move |this : & mut Self | {
44
+ if let Some ( drop_scope) = scope {
45
+ let local = destination. as_local ( )
46
+ . expect ( "cannot schedule drop of non-Local place" ) ;
47
+ this. schedule_drop ( expr_span, drop_scope, local, DropKind :: Value ) ;
48
+ }
49
+ } ;
50
+
38
51
if !expr_is_block_or_scope {
39
52
this. block_context . push ( BlockFrame :: SubExpr ) ;
40
53
}
@@ -47,14 +60,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
47
60
} => {
48
61
let region_scope = ( region_scope, source_info) ;
49
62
this. in_scope ( region_scope, lint_level, |this| {
50
- this. into ( destination, block, value)
63
+ this. into ( destination, scope , block, value)
51
64
} )
52
65
}
53
66
ExprKind :: Block { body : ast_block } => {
54
- this. ast_block ( destination, block, ast_block, source_info)
67
+ this. ast_block ( destination, scope , block, ast_block, source_info)
55
68
}
56
69
ExprKind :: Match { scrutinee, arms } => {
57
- this. match_expr ( destination, expr_span, block, scrutinee, arms)
70
+ this. match_expr ( destination, scope , expr_span, block, scrutinee, arms)
58
71
}
59
72
ExprKind :: NeverToAny { source } => {
60
73
let source = this. hir . mirror ( source) ;
@@ -67,6 +80,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
67
80
68
81
// This is an optimization. If the expression was a call then we already have an
69
82
// unreachable block. Don't bother to terminate it and create a new one.
83
+ schedule_drop ( this) ;
70
84
if is_call {
71
85
block. unit ( )
72
86
} else {
@@ -164,6 +178,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
164
178
TerminatorKind :: Goto { target : loop_block } ,
165
179
) ;
166
180
181
+ // Loops assign to their destination on each `break`. Since we
182
+ // can't easily unschedule drops, we schedule the drop now.
183
+ schedule_drop ( this) ;
167
184
this. in_breakable_scope (
168
185
Some ( loop_block) ,
169
186
exit_block,
@@ -185,7 +202,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
185
202
// introduce a unit temporary as the destination for the loop body.
186
203
let tmp = this. get_unit_temp ( ) ;
187
204
// Execute the body, branching back to the test.
188
- let body_block_end = unpack ! ( this. into( & tmp, body_block, body) ) ;
205
+ // No scope is provided, since we've scheduled the drop above.
206
+ let body_block_end = unpack ! ( this. into( & tmp, None , body_block, body) ) ;
189
207
this. cfg . terminate (
190
208
body_block_end,
191
209
source_info,
@@ -234,8 +252,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
234
252
is_block_tail : None ,
235
253
} ) ;
236
254
let ptr_temp = Place :: from ( ptr_temp) ;
237
- let block = unpack ! ( this. into( & ptr_temp, block, ptr) ) ;
238
- this. into ( & ptr_temp. deref ( ) , block, val)
255
+ // No need for a scope, ptr_temp doesn't need drop
256
+ let block = unpack ! ( this. into( & ptr_temp, None , block, ptr) ) ;
257
+ // Maybe we should provide a scope here so that
258
+ // `move_val_init` wouldn't leak on panic even with an
259
+ // arbitrary `val` expression, but `schedule_drop`,
260
+ // borrowck and drop elaboration all prevent us from
261
+ // dropping `ptr_temp.deref()`.
262
+ this. into ( & ptr_temp. deref ( ) , None , block, val)
239
263
} else {
240
264
let args: Vec < _ > = args
241
265
. into_iter ( )
@@ -265,11 +289,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
265
289
from_hir_call,
266
290
} ,
267
291
) ;
292
+ schedule_drop ( this) ;
268
293
success. unit ( )
269
294
}
270
295
}
271
296
ExprKind :: Use { source } => {
272
- this. into ( destination, block, source)
297
+ this. into ( destination, scope , block, source)
273
298
}
274
299
275
300
// These cases don't actually need a destination
@@ -296,6 +321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
296
321
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
297
322
this. cfg
298
323
. push_assign ( block, source_info, destination, rvalue) ;
324
+ schedule_drop ( this) ;
299
325
block. unit ( )
300
326
}
301
327
ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -315,6 +341,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
315
341
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
316
342
this. cfg
317
343
. push_assign ( block, source_info, destination, rvalue) ;
344
+ schedule_drop ( this) ;
318
345
block. unit ( )
319
346
}
320
347
@@ -346,6 +373,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
346
373
347
374
let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr) ) ;
348
375
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
376
+ schedule_drop ( this) ;
349
377
block. unit ( )
350
378
}
351
379
} ;
0 commit comments