22
33use crate :: build:: expr:: category:: { Category , RvalueFunc } ;
44use crate :: build:: { BlockAnd , BlockAndExtension , BlockFrame , Builder } ;
5+ use crate :: build:: scope:: DropKind ;
56use crate :: hair:: * ;
7+ use rustc:: middle:: region;
68use rustc:: mir:: * ;
79use rustc:: ty:: { self , CanonicalUserTypeAnnotation } ;
810use rustc_data_structures:: fx:: FxHashMap ;
@@ -13,15 +15,18 @@ use rustc_target::spec::abi::Abi;
1315impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1416 /// Compile `expr`, storing the result into `destination`, which
1517 /// 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.
1620 pub fn into_expr (
1721 & mut self ,
1822 destination : & Place < ' tcx > ,
23+ scope : Option < region:: Scope > ,
1924 mut block : BasicBlock ,
2025 expr : Expr < ' tcx > ,
2126 ) -> BlockAnd < ( ) > {
2227 debug ! (
23- "into_expr(destination={:?}, block={:?}, expr={:?})" ,
24- destination, block, expr
28+ "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})" ,
29+ destination, scope , block, expr
2530 ) ;
2631
2732 // since we frequently have to reference `self` from within a
@@ -37,6 +42,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3742 _ => false ,
3843 } ;
3944
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+
4053 if !expr_is_block_or_scope {
4154 this. block_context . push ( BlockFrame :: SubExpr ) ;
4255 }
@@ -49,14 +62,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4962 } => {
5063 let region_scope = ( region_scope, source_info) ;
5164 this. in_scope ( region_scope, lint_level, |this| {
52- this. into ( destination, block, value)
65+ this. into ( destination, scope , block, value)
5366 } )
5467 }
5568 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)
5770 }
5871 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)
6073 }
6174 ExprKind :: NeverToAny { source } => {
6275 let source = this. hir . mirror ( source) ;
@@ -69,6 +82,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6982
7083 // This is an optimization. If the expression was a call then we already have an
7184 // unreachable block. Don't bother to terminate it and create a new one.
85+ schedule_drop ( this) ;
7286 if is_call {
7387 block. unit ( )
7488 } else {
@@ -168,6 +182,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
168182 this. in_breakable_scope (
169183 Some ( loop_block) ,
170184 destination. clone ( ) ,
185+ scope,
171186 expr_span,
172187 move |this| {
173188 // conduct the test, if necessary
@@ -186,12 +201,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
186201 // introduce a unit temporary as the destination for the loop body.
187202 let tmp = this. get_unit_temp ( ) ;
188203 // 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) ) ;
190206 this. cfg . terminate (
191207 body_block_end,
192208 source_info,
193209 TerminatorKind :: Goto { target : loop_block } ,
194210 ) ;
211+ schedule_drop ( this) ;
195212 None
196213 } ,
197214 )
@@ -234,8 +251,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
234251 is_block_tail : None ,
235252 } ) ;
236253 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)
239262 } else {
240263 let args: Vec < _ > = args
241264 . into_iter ( )
@@ -265,11 +288,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
265288 from_hir_call,
266289 } ,
267290 ) ;
291+ schedule_drop ( this) ;
268292 success. unit ( )
269293 }
270294 }
271295 ExprKind :: Use { source } => {
272- this. into ( destination, block, source)
296+ this. into ( destination, scope , block, source)
273297 }
274298 ExprKind :: Borrow { arg, borrow_kind } => {
275299 // We don't do this in `as_rvalue` because we use `as_place`
@@ -364,6 +388,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
364388 destination,
365389 Rvalue :: Aggregate ( adt, fields)
366390 ) ;
391+ schedule_drop ( this) ;
367392 block. unit ( )
368393 }
369394
@@ -391,6 +416,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
391416 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
392417 this. cfg
393418 . push_assign ( block, source_info, destination, rvalue) ;
419+ schedule_drop ( this) ;
394420 block. unit ( )
395421 }
396422 ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -410,6 +436,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
410436 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
411437 this. cfg
412438 . push_assign ( block, source_info, destination, rvalue) ;
439+ schedule_drop ( this) ;
413440 block. unit ( )
414441 }
415442
@@ -440,6 +467,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
440467
441468 let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr) ) ;
442469 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
470+ schedule_drop ( this) ;
443471 block. unit ( )
444472 }
445473 } ;
0 commit comments