@@ -28,6 +28,7 @@ mod simplify;
2828mod test;
2929mod util;
3030
31+ use std:: assert_matches:: assert_matches;
3132use std:: borrow:: Borrow ;
3233use std:: mem;
3334
@@ -74,6 +75,17 @@ pub(crate) enum EmitStorageLive {
7475 No ,
7576}
7677
78+ /// Used by [`Builder::storage_live_binding`] and [`Builder::bind_matched_candidate_for_arm_body`]
79+ /// to decide whether to schedule drops.
80+ #[ derive( Clone , Copy , Debug ) ]
81+ pub ( crate ) enum ScheduleDrops {
82+ /// Yes, the relevant functions should also schedule drops as appropriate.
83+ Yes ,
84+ /// No, don't schedule drops. The caller has taken responsibility for any
85+ /// appropriate drops.
86+ No ,
87+ }
88+
7789impl < ' a , ' tcx > Builder < ' a , ' tcx > {
7890 /// Lowers a condition in a way that ensures that variables bound in any let
7991 /// expressions are definitely initialized in the if body.
@@ -535,7 +547,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
535547 fake_borrow_temps,
536548 scrutinee_span,
537549 arm_match_scope,
538- true ,
550+ ScheduleDrops :: Yes ,
539551 emit_storage_live,
540552 )
541553 } else {
@@ -554,7 +566,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
554566 // To handle this we instead unschedule it's drop after each time
555567 // we lower the guard.
556568 let target_block = self . cfg . start_new_block ( ) ;
557- let mut schedule_drops = true ;
569+ let mut schedule_drops = ScheduleDrops :: Yes ;
558570 let arm = arm_match_scope. unzip ( ) . 0 ;
559571 // We keep a stack of all of the bindings and type ascriptions
560572 // from the parent candidates that we visit, that also need to
@@ -576,7 +588,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
576588 emit_storage_live,
577589 ) ;
578590 if arm. is_none ( ) {
579- schedule_drops = false ;
591+ schedule_drops = ScheduleDrops :: No ;
580592 }
581593 self . cfg . goto ( binding_end, outer_source_info, target_block) ;
582594 } ,
@@ -602,8 +614,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
602614 match irrefutable_pat. kind {
603615 // Optimize the case of `let x = ...` to write directly into `x`
604616 PatKind :: Binding { mode : BindingMode ( ByRef :: No , _) , var, subpattern : None , .. } => {
605- let place =
606- self . storage_live_binding ( block, var, irrefutable_pat. span , OutsideGuard , true ) ;
617+ let place = self . storage_live_binding (
618+ block,
619+ var,
620+ irrefutable_pat. span ,
621+ OutsideGuard ,
622+ ScheduleDrops :: Yes ,
623+ ) ;
607624 unpack ! ( block = self . expr_into_dest( place, block, initializer_id) ) ;
608625
609626 // Inject a fake read, see comments on `FakeReadCause::ForLet`.
@@ -636,8 +653,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
636653 } ,
637654 ascription : thir:: Ascription { ref annotation, variance : _ } ,
638655 } => {
639- let place =
640- self . storage_live_binding ( block, var, irrefutable_pat. span , OutsideGuard , true ) ;
656+ let place = self . storage_live_binding (
657+ block,
658+ var,
659+ irrefutable_pat. span ,
660+ OutsideGuard ,
661+ ScheduleDrops :: Yes ,
662+ ) ;
641663 unpack ! ( block = self . expr_into_dest( place, block, initializer_id) ) ;
642664
643665 // Inject a fake read, see comments on `FakeReadCause::ForLet`.
@@ -827,17 +849,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
827849 var : LocalVarId ,
828850 span : Span ,
829851 for_guard : ForGuard ,
830- schedule_drop : bool ,
852+ schedule_drop : ScheduleDrops ,
831853 ) -> Place < ' tcx > {
832854 let local_id = self . var_local_id ( var, for_guard) ;
833855 let source_info = self . source_info ( span) ;
834856 self . cfg . push ( block, Statement { source_info, kind : StatementKind :: StorageLive ( local_id) } ) ;
835857 // Although there is almost always scope for given variable in corner cases
836858 // like #92893 we might get variable with no scope.
837- if let Some ( region_scope) = self . region_scope_tree . var_scope ( var. 0 . local_id )
838- && schedule_drop
839- {
840- self . schedule_drop ( span, region_scope, local_id, DropKind :: Storage ) ;
859+ if let Some ( region_scope) = self . region_scope_tree . var_scope ( var. 0 . local_id ) {
860+ // Match exhaustively, so that it's easy to check how `ScheduleDrops` is used.
861+ match schedule_drop {
862+ ScheduleDrops :: Yes => {
863+ self . schedule_drop ( span, region_scope, local_id, DropKind :: Storage ) ;
864+ }
865+ ScheduleDrops :: No => { }
866+ }
841867 }
842868 Place :: from ( local_id)
843869 }
@@ -2112,7 +2138,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21122138 fake_borrows : & [ ( Place < ' tcx > , Local , FakeBorrowKind ) ] ,
21132139 scrutinee_span : Span ,
21142140 arm_match_scope : Option < ( & Arm < ' tcx > , region:: Scope ) > ,
2115- schedule_drops : bool ,
2141+ schedule_drops : ScheduleDrops ,
21162142 emit_storage_live : EmitStorageLive ,
21172143 ) -> BasicBlock {
21182144 debug ! ( "bind_and_guard_matched_candidate(candidate={:?})" , candidate) ;
@@ -2323,10 +2349,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23232349 let cause = FakeReadCause :: ForGuardBinding ;
23242350 self . cfg . push_fake_read ( post_guard_block, guard_end, cause, Place :: from ( local_id) ) ;
23252351 }
2326- assert ! ( schedule_drops, "patterns with guards must schedule drops" ) ;
2352+ assert_matches ! (
2353+ schedule_drops,
2354+ ScheduleDrops :: Yes ,
2355+ "patterns with guards must schedule drops"
2356+ ) ;
23272357 self . bind_matched_candidate_for_arm_body (
23282358 post_guard_block,
2329- true ,
2359+ ScheduleDrops :: Yes ,
23302360 by_value_bindings,
23312361 emit_storage_live,
23322362 ) ;
@@ -2376,7 +2406,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23762406 fn bind_matched_candidate_for_guard < ' b > (
23772407 & mut self ,
23782408 block : BasicBlock ,
2379- schedule_drops : bool ,
2409+ schedule_drops : ScheduleDrops ,
23802410 bindings : impl IntoIterator < Item = & ' b Binding < ' tcx > > ,
23812411 ) where
23822412 ' tcx : ' b ,
@@ -2429,7 +2459,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24292459 fn bind_matched_candidate_for_arm_body < ' b > (
24302460 & mut self ,
24312461 block : BasicBlock ,
2432- schedule_drops : bool ,
2462+ schedule_drops : ScheduleDrops ,
24332463 bindings : impl IntoIterator < Item = & ' b Binding < ' tcx > > ,
24342464 emit_storage_live : EmitStorageLive ,
24352465 ) where
@@ -2454,8 +2484,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24542484 schedule_drops,
24552485 ) ,
24562486 } ;
2457- if schedule_drops {
2458- self . schedule_drop_for_binding ( binding. var_id , binding. span , OutsideGuard ) ;
2487+ match schedule_drops {
2488+ ScheduleDrops :: Yes => {
2489+ self . schedule_drop_for_binding ( binding. var_id , binding. span , OutsideGuard ) ;
2490+ }
2491+ ScheduleDrops :: No => { }
24592492 }
24602493 let rvalue = match binding. binding_mode . 0 {
24612494 ByRef :: No => Rvalue :: Use ( self . consume_by_copy_or_move ( binding. source ) ) ,
0 commit comments