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 :: 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 ;
@@ -14,13 +16,19 @@ use rustc_target::spec::abi::Abi;
14
16
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
15
17
/// Compile `expr`, storing the result into `destination`, which
16
18
/// is assumed to be uninitialized.
19
+ /// If a `drop_scope` is provided, `destination` is scheduled to be dropped
20
+ /// in `scope` once it has been initialized.
17
21
crate fn into_expr (
18
22
& mut self ,
19
23
destination : & Place < ' tcx > ,
24
+ scope : Option < region:: Scope > ,
20
25
mut block : BasicBlock ,
21
26
expr : Expr < ' tcx > ,
22
27
) -> BlockAnd < ( ) > {
23
- debug ! ( "into_expr(destination={:?}, block={:?}, expr={:?})" , destination, block, expr) ;
28
+ debug ! (
29
+ "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})" ,
30
+ destination, scope, block, expr
31
+ ) ;
24
32
25
33
// since we frequently have to reference `self` from within a
26
34
// closure, where `self` would be shadowed, it's easier to
@@ -35,20 +43,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
35
43
_ => false ,
36
44
} ;
37
45
46
+ let schedule_drop = move |this : & mut Self | {
47
+ if let Some ( drop_scope) = scope {
48
+ let local =
49
+ destination. as_local ( ) . expect ( "cannot schedule drop of non-Local place" ) ;
50
+ this. schedule_drop ( expr_span, drop_scope, local, DropKind :: Value ) ;
51
+ }
52
+ } ;
53
+
38
54
if !expr_is_block_or_scope {
39
55
this. block_context . push ( BlockFrame :: SubExpr ) ;
40
56
}
41
57
42
58
let block_and = match expr. kind {
43
59
ExprKind :: Scope { region_scope, lint_level, value } => {
44
60
let region_scope = ( region_scope, source_info) ;
45
- this. in_scope ( region_scope, lint_level, |this| this. into ( destination, block, value) )
61
+ this. in_scope ( region_scope, lint_level, |this| {
62
+ this. into ( destination, scope, block, value)
63
+ } )
46
64
}
47
65
ExprKind :: Block { body : ast_block } => {
48
- this. ast_block ( destination, block, ast_block, source_info)
66
+ this. ast_block ( destination, scope , block, ast_block, source_info)
49
67
}
50
68
ExprKind :: Match { scrutinee, arms } => {
51
- this. match_expr ( destination, expr_span, block, scrutinee, arms)
69
+ this. match_expr ( destination, scope , expr_span, block, scrutinee, arms)
52
70
}
53
71
ExprKind :: NeverToAny { source } => {
54
72
let source = this. hir . mirror ( source) ;
@@ -63,6 +81,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
63
81
64
82
// This is an optimization. If the expression was a call then we already have an
65
83
// unreachable block. Don't bother to terminate it and create a new one.
84
+ schedule_drop ( this) ;
66
85
if is_call {
67
86
block. unit ( )
68
87
} else {
@@ -141,6 +160,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
141
160
this. in_breakable_scope (
142
161
Some ( loop_block) ,
143
162
destination. clone ( ) ,
163
+ scope,
144
164
expr_span,
145
165
move |this| {
146
166
// conduct the test, if necessary
@@ -156,8 +176,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
156
176
// introduce a unit temporary as the destination for the loop body.
157
177
let tmp = this. get_unit_temp ( ) ;
158
178
// Execute the body, branching back to the test.
159
- let body_block_end = unpack ! ( this. into( & tmp, body_block, body) ) ;
160
- this. cfg . goto ( body_block_end, source_info, loop_block) ;
179
+ // No scope is provided, since we've scheduled the drop above.
180
+ let body_block_end = unpack ! ( this. into( & tmp, None , body_block, body) ) ;
181
+ this. cfg . terminate (
182
+ body_block_end,
183
+ source_info,
184
+ TerminatorKind :: Goto { target : loop_block } ,
185
+ ) ;
186
+ schedule_drop ( this) ;
161
187
None
162
188
} ,
163
189
)
@@ -198,8 +224,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
198
224
is_block_tail : None ,
199
225
} ) ;
200
226
let ptr_temp = Place :: from ( ptr_temp) ;
201
- let block = unpack ! ( this. into( & ptr_temp, block, ptr) ) ;
202
- this. into ( & this. hir . tcx ( ) . mk_place_deref ( ptr_temp) , block, val)
227
+ // No need for a scope, ptr_temp doesn't need drop
228
+ let block = unpack ! ( this. into( & ptr_temp, None , block, ptr) ) ;
229
+ // Maybe we should provide a scope here so that
230
+ // `move_val_init` wouldn't leak on panic even with an
231
+ // arbitrary `val` expression, but `schedule_drop`,
232
+ // borrowck and drop elaboration all prevent us from
233
+ // dropping `ptr_temp.deref()`.
234
+ this. into ( & this. hir . tcx ( ) . mk_place_deref ( ptr_temp) , None , block, val)
203
235
} else {
204
236
let args: Vec < _ > = args
205
237
. into_iter ( )
@@ -229,10 +261,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
229
261
from_hir_call,
230
262
} ,
231
263
) ;
264
+ schedule_drop ( this) ;
232
265
success. unit ( )
233
266
}
234
267
}
235
- ExprKind :: Use { source } => this. into ( destination, block, source) ,
268
+ ExprKind :: Use { source } => this. into ( destination, scope , block, source) ,
236
269
ExprKind :: Borrow { arg, borrow_kind } => {
237
270
// We don't do this in `as_rvalue` because we use `as_place`
238
271
// for borrow expressions, so we cannot create an `RValue` that
@@ -316,6 +349,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
316
349
destination,
317
350
Rvalue :: Aggregate ( adt, fields) ,
318
351
) ;
352
+ schedule_drop ( this) ;
319
353
block. unit ( )
320
354
}
321
355
@@ -341,6 +375,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
341
375
let place = unpack ! ( block = this. as_place( block, expr) ) ;
342
376
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
343
377
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
378
+ schedule_drop ( this) ;
344
379
block. unit ( )
345
380
}
346
381
ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -358,6 +393,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
358
393
let place = unpack ! ( block = this. as_place( block, expr) ) ;
359
394
let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
360
395
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
396
+ schedule_drop ( this) ;
361
397
block. unit ( )
362
398
}
363
399
@@ -371,6 +407,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
371
407
source_info,
372
408
TerminatorKind :: Yield { value, resume, resume_arg : * destination, drop : None } ,
373
409
) ;
410
+ schedule_drop ( this) ;
374
411
resume. unit ( )
375
412
}
376
413
@@ -400,6 +437,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
400
437
401
438
let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr) ) ;
402
439
this. cfg . push_assign ( block, source_info, destination, rvalue) ;
440
+ schedule_drop ( this) ;
403
441
block. unit ( )
404
442
}
405
443
} ;
0 commit comments