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;
810
@@ -11,15 +13,18 @@ use rustc_target::spec::abi::Abi;
1113impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1214 /// Compile `expr`, storing the result into `destination`, which
1315 /// 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.
1418 pub fn into_expr (
1519 & mut self ,
1620 destination : & Place < ' tcx > ,
21+ scope : Option < region:: Scope > ,
1722 mut block : BasicBlock ,
1823 expr : Expr < ' tcx > ,
1924 ) -> BlockAnd < ( ) > {
2025 debug ! (
21- "into_expr(destination={:?}, block={:?}, expr={:?})" ,
22- destination, block, expr
26+ "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})" ,
27+ destination, scope , block, expr
2328 ) ;
2429
2530 // since we frequently have to reference `self` from within a
@@ -35,6 +40,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3540 _ => false ,
3641 } ;
3742
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+
3851 if !expr_is_block_or_scope {
3952 this. block_context . push ( BlockFrame :: SubExpr ) ;
4053 }
@@ -47,14 +60,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4760 } => {
4861 let region_scope = ( region_scope, source_info) ;
4962 this. in_scope ( region_scope, lint_level, |this| {
50- this. into ( destination, block, value)
63+ this. into ( destination, scope , block, value)
5164 } )
5265 }
5366 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)
5568 }
5669 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)
5871 }
5972 ExprKind :: NeverToAny { source } => {
6073 let source = this. hir . mirror ( source) ;
@@ -67,6 +80,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6780
6881 // This is an optimization. If the expression was a call then we already have an
6982 // unreachable block. Don't bother to terminate it and create a new one.
83+ schedule_drop ( this) ;
7084 if is_call {
7185 block. unit ( )
7286 } else {
@@ -164,6 +178,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
164178 TerminatorKind :: Goto { target : loop_block } ,
165179 ) ;
166180
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) ;
167184 this. in_breakable_scope (
168185 Some ( loop_block) ,
169186 exit_block,
@@ -185,7 +202,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
185202 // introduce a unit temporary as the destination for the loop body.
186203 let tmp = this. get_unit_temp ( ) ;
187204 // 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) ) ;
189207 this. cfg . terminate (
190208 body_block_end,
191209 source_info,
@@ -234,8 +252,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
234252 is_block_tail : None ,
235253 } ) ;
236254 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)
239263 } else {
240264 let args: Vec < _ > = args
241265 . into_iter ( )
@@ -265,11 +289,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
265289 from_hir_call,
266290 } ,
267291 ) ;
292+ schedule_drop ( this) ;
268293 success. unit ( )
269294 }
270295 }
271296 ExprKind :: Use { source } => {
272- this. into ( destination, block, source)
297+ this. into ( destination, scope , block, source)
273298 }
274299
275300 // These cases don't actually need a destination
@@ -296,6 +321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
296321 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
297322 this. cfg
298323 . push_assign ( block, source_info, destination, rvalue) ;
324+ schedule_drop ( this) ;
299325 block. unit ( )
300326 }
301327 ExprKind :: Index { .. } | ExprKind :: Deref { .. } | ExprKind :: Field { .. } => {
@@ -315,6 +341,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
315341 let rvalue = Rvalue :: Use ( this. consume_by_copy_or_move ( place) ) ;
316342 this. cfg
317343 . push_assign ( block, source_info, destination, rvalue) ;
344+ schedule_drop ( this) ;
318345 block. unit ( )
319346 }
320347
@@ -346,6 +373,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
346373
347374 let rvalue = unpack ! ( block = this. as_local_rvalue( block, expr) ) ;
348375 this. cfg . push_assign ( block, source_info, destination, rvalue) ;
376+ schedule_drop ( this) ;
349377 block. unit ( )
350378 }
351379 } ;
0 commit comments