@@ -274,9 +274,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
274274        end_block. unit ( ) 
275275    } 
276276
277-     /// Binds the variables and ascribes types for a given `match` arm. 
277+     /// Binds the variables and ascribes types for a given `match` arm or 
278+      /// `let` binding. 
278279     /// 
279280     /// Also check if the guard matches, if it's provided. 
281+      /// `arm_scope` should be `Some` if and only if this is called for a 
282+      /// `match` arm. 
280283     fn  bind_pattern ( 
281284        & mut  self , 
282285        outer_source_info :  SourceInfo , 
@@ -298,6 +301,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
298301                true , 
299302            ) 
300303        }  else  { 
304+             // It's helpful to avoid scheduling drops multiple times to save 
305+             // drop elaboration from having to clean up the extra drops. 
306+             // 
307+             // If we are in a `let` then we only schedule drops for the first 
308+             // candidate. 
309+             // 
310+             // If we're in a `match` arm then we could have a case like so: 
311+             // 
312+             // Ok(x) | Err(x) if return => { /* ... */ } 
313+             // 
314+             // In this case we don't want a drop of `x` scheduled when we 
315+             // return: it isn't bound by move until right before enter the arm. 
316+             // To handle this we instead unschedule it's drop after each time 
317+             // we lower the guard. 
301318            let  target_block = self . cfg . start_new_block ( ) ; 
302319            let  mut  schedule_drops = true ; 
303320            // We keep a stack of all of the bindings and type asciptions 
@@ -308,7 +325,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
308325                & mut  Vec :: new ( ) , 
309326                & mut  |leaf_candidate,  parent_bindings| { 
310327                    if  let  Some ( arm_scope)  = arm_scope { 
311-                         // Avoid scheduling drops multiple times by unscheduling drops. 
312328                        self . clear_top_scope ( arm_scope) ; 
313329                    } 
314330                    let  binding_end = self . bind_and_guard_matched_candidate ( 
@@ -320,9 +336,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
320336                        schedule_drops, 
321337                    ) ; 
322338                    if  arm_scope. is_none ( )  { 
323-                         // If we aren't in a match, then our bindings may not be 
324-                         // the only thing in the top scope, so only schedule 
325-                         // them to drop for the first pattern instead. 
326339                        schedule_drops = false ; 
327340                    } 
328341                    self . cfg . goto ( binding_end,  outer_source_info,  target_block) ; 
@@ -350,7 +363,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
350363            // Optimize the case of `let x = ...` to write directly into `x` 
351364            PatKind :: Binding  {  mode :  BindingMode :: ByValue ,  var,  subpattern :  None ,  .. }  => { 
352365                let  place =
353-                     self . storage_live_binding ( block,  var,  irrefutable_pat. span ,  OutsideGuard ) ; 
366+                     self . storage_live_binding ( block,  var,  irrefutable_pat. span ,  OutsideGuard ,   true ) ; 
354367                unpack ! ( block = self . into( & place,  block,  initializer) ) ; 
355368
356369                // Inject a fake read, see comments on `FakeReadCause::ForLet`. 
@@ -385,7 +398,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
385398                    hair:: pattern:: Ascription  {  user_ty :  pat_ascription_ty,  variance :  _,  user_ty_span } , 
386399            }  => { 
387400                let  place =
388-                     self . storage_live_binding ( block,  var,  irrefutable_pat. span ,  OutsideGuard ) ; 
401+                     self . storage_live_binding ( block,  var,  irrefutable_pat. span ,  OutsideGuard ,   true ) ; 
389402                unpack ! ( block = self . into( & place,  block,  initializer) ) ; 
390403
391404                // Inject a fake read, see comments on `FakeReadCause::ForLet`. 
@@ -532,12 +545,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
532545        var :  HirId , 
533546        span :  Span , 
534547        for_guard :  ForGuard , 
548+         schedule_drop :  bool , 
535549    )  -> Place < ' tcx >  { 
536550        let  local_id = self . var_local_id ( var,  for_guard) ; 
537551        let  source_info = self . source_info ( span) ; 
538552        self . cfg . push ( block,  Statement  {  source_info,  kind :  StatementKind :: StorageLive ( local_id)  } ) ; 
539553        let  region_scope = self . hir . region_scope_tree . var_scope ( var. local_id ) ; 
540-         self . schedule_drop ( span,  region_scope,  local_id,  DropKind :: Storage ) ; 
554+         if  schedule_drop { 
555+             self . schedule_drop ( span,  region_scope,  local_id,  DropKind :: Storage ) ; 
556+         } 
541557        Place :: from ( local_id) 
542558    } 
543559
@@ -1060,25 +1076,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10601076     ///      | 
10611077     ///      +----------------------------------------+------------------------------------+ 
10621078     ///      |                                        |                                    | 
1079+      ///      V                                        V                                    V 
10631080     /// [ P matches ]                           [ Q matches ]                        [ otherwise ] 
10641081     ///      |                                        |                                    | 
1082+      ///      V                                        V                                    | 
10651083     /// [ match R, S ]                          [ match R, S ]                             | 
10661084     ///      |                                        |                                    | 
10671085     ///      +--------------+------------+            +--------------+------------+        | 
10681086     ///      |              |            |            |              |            |        | 
1087+      ///      V              V            V            V              V            V        | 
10691088     /// [ R matches ] [ S matches ] [otherwise ] [ R matches ] [ S matches ] [otherwise ]  | 
10701089     ///      |              |            |            |              |            |        | 
10711090     ///      +--------------+------------|------------+--------------+            |        | 
10721091     ///      |                           |                                        |        | 
10731092     ///      |                           +----------------------------------------+--------+ 
10741093     ///      |                           | 
1094+      ///      V                           V 
10751095     /// [ Success ]                 [ Failure ] 
10761096     /// ``` 
10771097     /// 
10781098     /// In practice there are some complications: 
10791099     /// 
10801100     /// * If there's a guard, then the otherwise branch of the first match on 
1081-      ///   `R | S` goes to a test for whether `Q` matches. 
1101+      ///   `R | S` goes to a test for whether `Q` matches, and the control flow 
1102+      ///   doesn't merge into a single success block until after the guard is 
1103+      ///   tested. 
10821104     /// * If neither `P` or `Q` has any bindings or type ascriptions and there 
10831105     ///   isn't a match guard, then we create a smaller CFG like: 
10841106     /// 
@@ -1658,7 +1680,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16581680                . flat_map ( |( bindings,  _) | bindings) 
16591681                . chain ( & candidate. bindings ) ; 
16601682
1661-             self . bind_matched_candidate_for_guard ( block,  bindings. clone ( ) ) ; 
1683+             self . bind_matched_candidate_for_guard ( block,  schedule_drops ,   bindings. clone ( ) ) ; 
16621684            let  guard_frame = GuardFrame  { 
16631685                locals :  bindings. map ( |b| GuardFrameLocal :: new ( b. var_id ,  b. binding_mode ) ) . collect ( ) , 
16641686            } ; 
@@ -1807,6 +1829,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18071829    fn  bind_matched_candidate_for_guard < ' b > ( 
18081830        & mut  self , 
18091831        block :  BasicBlock , 
1832+         schedule_drops :  bool , 
18101833        bindings :  impl  IntoIterator < Item  = & ' b  Binding < ' tcx > > , 
18111834    )  where 
18121835        ' tcx :  ' b , 
@@ -1825,8 +1848,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18251848            // a reference R: &T pointing to the location matched by 
18261849            // the pattern, and every occurrence of P within a guard 
18271850            // denotes *R. 
1828-             let  ref_for_guard =
1829-                 self . storage_live_binding ( block,  binding. var_id ,  binding. span ,  RefWithinGuard ) ; 
1851+             let  ref_for_guard = self . storage_live_binding ( 
1852+                 block, 
1853+                 binding. var_id , 
1854+                 binding. span , 
1855+                 RefWithinGuard , 
1856+                 schedule_drops, 
1857+             ) ; 
18301858            match  binding. binding_mode  { 
18311859                BindingMode :: ByValue  => { 
18321860                    let  rvalue = Rvalue :: Ref ( re_erased,  BorrowKind :: Shared ,  binding. source ) ; 
@@ -1838,6 +1866,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18381866                        binding. var_id , 
18391867                        binding. span , 
18401868                        OutsideGuard , 
1869+                         schedule_drops, 
18411870                    ) ; 
18421871
18431872                    let  rvalue = Rvalue :: Ref ( re_erased,  borrow_kind,  binding. source ) ; 
@@ -1863,8 +1892,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18631892        // Assign each of the bindings. This may trigger moves out of the candidate. 
18641893        for  binding in  bindings { 
18651894            let  source_info = self . source_info ( binding. span ) ; 
1866-             let  local =
1867-                 self . storage_live_binding ( block,  binding. var_id ,  binding. span ,  OutsideGuard ) ; 
1895+             let  local = self . storage_live_binding ( 
1896+                 block, 
1897+                 binding. var_id , 
1898+                 binding. span , 
1899+                 OutsideGuard , 
1900+                 schedule_drops, 
1901+             ) ; 
18681902            if  schedule_drops { 
18691903                self . schedule_drop_for_binding ( binding. var_id ,  binding. span ,  OutsideGuard ) ; 
18701904            } 
0 commit comments