11//! See docs in build/expr/mod.rs
22
33use crate :: build:: expr:: category:: { Category , RvalueFunc } ;
4+ use crate :: build:: scope:: DropKind ;
45use crate :: build:: { BlockAnd , BlockAndExtension , BlockFrame , Builder } ;
56use crate :: hair:: * ;
7+ use rustc:: middle:: region;
68use rustc:: mir:: * ;
79use rustc:: ty:: { self , CanonicalUserTypeAnnotation } ;
810use rustc_data_structures:: fx:: FxHashMap ;
@@ -14,13 +16,19 @@ use rustc_target::spec::abi::Abi;
1416impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1517 /// Compile `expr`, storing the result into `destination`, which
1618 /// 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.
1721 crate fn into_expr (
1822 & mut self ,
1923 destination : & Place < ' tcx > ,
24+ scope : Option < region:: Scope > ,
2025 mut block : BasicBlock ,
2126 expr : Expr < ' tcx > ,
2227 ) -> 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+ ) ;
2432
2533 // since we frequently have to reference `self` from within a
2634 // closure, where `self` would be shadowed, it's easier to
@@ -35,20 +43,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3543 _ => false ,
3644 } ;
3745
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+
3854 if !expr_is_block_or_scope {
3955 this. block_context . push ( BlockFrame :: SubExpr ) ;
4056 }
4157
4258 let block_and = match expr. kind {
4359 ExprKind :: Scope { region_scope, lint_level, value } => {
4460 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+ } )
4664 }
4765 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)
4967 }
5068 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)
5270 }
5371 ExprKind :: NeverToAny { source } => {
5472 let source = this. hir . mirror ( source) ;
@@ -63,6 +81,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6381
6482 // This is an optimization. If the expression was a call then we already have an
6583 // unreachable block. Don't bother to terminate it and create a new one.
84+ schedule_drop ( this) ;
6685 if is_call {
6786 block. unit ( )
6887 } else {
@@ -141,6 +160,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
141160 this. in_breakable_scope (
142161 Some ( loop_block) ,
143162 destination. clone ( ) ,
163+ scope,
144164 expr_span,
145165 move |this| {
146166 // conduct the test, if necessary
@@ -156,8 +176,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
156176 // introduce a unit temporary as the destination for the loop body.
157177 let tmp = this. get_unit_temp ( ) ;
158178 // 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) ;
161187 None
162188 } ,
163189 )
@@ -198,8 +224,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
198224 is_block_tail : None ,
199225 } ) ;
200226 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)
203235 } else {
204236 let args: Vec < _ > = args
205237 . into_iter ( )
@@ -229,10 +261,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
229261 from_hir_call,
230262 } ,
231263 ) ;
264+ schedule_drop ( this) ;
232265 success. unit ( )
233266 }
234267 }
235- ExprKind :: Use { source } => this. into ( destination, block, source) ,
268+ ExprKind :: Use { source } => this. into ( destination, scope , block, source) ,
236269 ExprKind :: Borrow { arg, borrow_kind } => {
237270 // We don't do this in `as_rvalue` because we use `as_place`
238271 // for borrow expressions, so we cannot create an `RValue` that
@@ -316,6 +349,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
316349 destination,
317350 Rvalue :: Aggregate ( adt, fields) ,
318351 ) ;
352+ schedule_drop ( this) ;
319353 block. unit ( )
320354 }
321355
@@ -341,6 +375,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
341375 let place = unpack ! ( block = this. as_place( block, expr) ) ;
342376 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
343377 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
378+ schedule_drop ( this) ;
344379 block. unit ( )
345380 }
346381 ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -358,6 +393,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
358393 let place = unpack ! ( block = this. as_place( block, expr) ) ;
359394 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
360395 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
396+ schedule_drop ( this) ;
361397 block. unit ( )
362398 }
363399
@@ -371,6 +407,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
371407 source_info,
372408 TerminatorKind :: Yield { value, resume, resume_arg : * destination, drop : None } ,
373409 ) ;
410+ schedule_drop ( this) ;
374411 resume. unit ( )
375412 }
376413
@@ -400,6 +437,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
400437
401438 let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr) ) ;
402439 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
440+ schedule_drop ( this) ;
403441 block. unit ( )
404442 }
405443 } ;
0 commit comments