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:: { self , CanonicalUserTypeAnnotation } ;
8
10
use rustc_data_structures:: fx:: FxHashMap ;
@@ -13,15 +15,18 @@ use rustc_target::spec::abi::Abi;
13
15
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
14
16
/// Compile `expr`, storing the result into `destination`, which
15
17
/// is assumed to be uninitialized.
18
+ /// If a `drop_scope` is provided, `destination` is scheduled to be dropped
19
+ /// in `scope` once it has been initialized.
16
20
pub fn into_expr (
17
21
& mut self ,
18
22
destination : & Place < ' tcx > ,
23
+ scope : Option < region:: Scope > ,
19
24
mut block : BasicBlock ,
20
25
expr : Expr < ' tcx > ,
21
26
) -> BlockAnd < ( ) > {
22
27
debug ! (
23
- "into_expr(destination={:?}, block={:?}, expr={:?})" ,
24
- destination, block, expr
28
+ "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})" ,
29
+ destination, scope , block, expr
25
30
) ;
26
31
27
32
// since we frequently have to reference `self` from within a
@@ -37,6 +42,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
37
42
_ => false ,
38
43
} ;
39
44
45
+ let schedule_drop = move |this : & mut Self | {
46
+ if let Some ( drop_scope) = scope {
47
+ let local = destination. as_local ( )
48
+ . expect ( "cannot schedule drop of non-Local place" ) ;
49
+ this. schedule_drop ( expr_span, drop_scope, local, DropKind :: Value ) ;
50
+ }
51
+ } ;
52
+
40
53
if !expr_is_block_or_scope {
41
54
this. block_context . push ( BlockFrame :: SubExpr ) ;
42
55
}
@@ -49,14 +62,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
49
62
} => {
50
63
let region_scope = ( region_scope, source_info) ;
51
64
this. in_scope ( region_scope, lint_level, |this| {
52
- this. into ( destination, block, value)
65
+ this. into ( destination, scope , block, value)
53
66
} )
54
67
}
55
68
ExprKind :: Block { body : ast_block } => {
56
- this. ast_block ( destination, block, ast_block, source_info)
69
+ this. ast_block ( destination, scope , block, ast_block, source_info)
57
70
}
58
71
ExprKind :: Match { scrutinee, arms } => {
59
- this. match_expr ( destination, expr_span, block, scrutinee, arms)
72
+ this. match_expr ( destination, scope , expr_span, block, scrutinee, arms)
60
73
}
61
74
ExprKind :: NeverToAny { source } => {
62
75
let source = this. hir . mirror ( source) ;
@@ -69,6 +82,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
69
82
70
83
// This is an optimization. If the expression was a call then we already have an
71
84
// unreachable block. Don't bother to terminate it and create a new one.
85
+ schedule_drop ( this) ;
72
86
if is_call {
73
87
block. unit ( )
74
88
} else {
@@ -168,6 +182,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
168
182
this. in_breakable_scope (
169
183
Some ( loop_block) ,
170
184
destination. clone ( ) ,
185
+ scope,
171
186
expr_span,
172
187
move |this| {
173
188
// conduct the test, if necessary
@@ -186,12 +201,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
186
201
// introduce a unit temporary as the destination for the loop body.
187
202
let tmp = this. get_unit_temp ( ) ;
188
203
// Execute the body, branching back to the test.
189
- let body_block_end = unpack ! ( this. into( & tmp, body_block, body) ) ;
204
+ // No scope is provided, since we've scheduled the drop above.
205
+ let body_block_end = unpack ! ( this. into( & tmp, None , body_block, body) ) ;
190
206
this. cfg . terminate (
191
207
body_block_end,
192
208
source_info,
193
209
TerminatorKind :: Goto { target : loop_block } ,
194
210
) ;
211
+ schedule_drop ( this) ;
195
212
None
196
213
} ,
197
214
)
@@ -234,8 +251,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
234
251
is_block_tail : None ,
235
252
} ) ;
236
253
let ptr_temp = Place :: from ( ptr_temp) ;
237
- let block = unpack ! ( this. into( & ptr_temp, block, ptr) ) ;
238
- this. into ( & this. hir . tcx ( ) . mk_place_deref ( ptr_temp) , block, val)
254
+ // No need for a scope, ptr_temp doesn't need drop
255
+ let block = unpack ! ( this. into( & ptr_temp, None , block, ptr) ) ;
256
+ // Maybe we should provide a scope here so that
257
+ // `move_val_init` wouldn't leak on panic even with an
258
+ // arbitrary `val` expression, but `schedule_drop`,
259
+ // borrowck and drop elaboration all prevent us from
260
+ // dropping `ptr_temp.deref()`.
261
+ this. into ( & this. hir . tcx ( ) . mk_place_deref ( ptr_temp) , None , block, val)
239
262
} else {
240
263
let args: Vec < _ > = args
241
264
. into_iter ( )
@@ -265,11 +288,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
265
288
from_hir_call,
266
289
} ,
267
290
) ;
291
+ schedule_drop ( this) ;
268
292
success. unit ( )
269
293
}
270
294
}
271
295
ExprKind :: Use { source } => {
272
- this. into ( destination, block, source)
296
+ this. into ( destination, scope , block, source)
273
297
}
274
298
ExprKind :: Borrow { arg, borrow_kind } => {
275
299
// We don't do this in `as_rvalue` because we use `as_place`
@@ -364,6 +388,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
364
388
destination,
365
389
Rvalue :: Aggregate ( adt, fields)
366
390
) ;
391
+ schedule_drop ( this) ;
367
392
block. unit ( )
368
393
}
369
394
@@ -391,6 +416,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
391
416
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
392
417
this. cfg
393
418
. push_assign ( block, source_info, destination, rvalue) ;
419
+ schedule_drop ( this) ;
394
420
block. unit ( )
395
421
}
396
422
ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -410,6 +436,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
410
436
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
411
437
this. cfg
412
438
. push_assign ( block, source_info, destination, rvalue) ;
439
+ schedule_drop ( this) ;
413
440
block. unit ( )
414
441
}
415
442
@@ -440,6 +467,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
440
467
441
468
let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr) ) ;
442
469
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
470
+ schedule_drop ( this) ;
443
471
block. unit ( )
444
472
}
445
473
} ;
0 commit comments