@@ -96,11 +96,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
96
96
let mut arm_candidates = self . create_match_candidates ( & scrutinee_place, & arms) ;
97
97
98
98
let match_has_guard = arms. iter ( ) . any ( |arm| arm. guard . is_some ( ) ) ;
99
- let candidates =
99
+ let mut candidates =
100
100
arm_candidates. iter_mut ( ) . map ( |( _, candidate) | candidate) . collect :: < Vec < _ > > ( ) ;
101
101
102
102
let fake_borrow_temps =
103
- self . lower_match_tree ( block, scrutinee_span, match_has_guard, candidates) ;
103
+ self . lower_match_tree ( block, scrutinee_span, match_has_guard, & mut candidates) ;
104
104
105
105
self . lower_match_arms (
106
106
& destination,
@@ -181,7 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
181
181
block : BasicBlock ,
182
182
scrutinee_span : Span ,
183
183
match_has_guard : bool ,
184
- mut candidates : Vec < & mut Candidate < ' pat , ' tcx > > ,
184
+ candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
185
185
) -> Vec < ( Place < ' tcx > , Local ) > {
186
186
// The set of places that we are creating fake borrows of. If there are
187
187
// no match guards then we don't need any fake borrows, so don't track
@@ -192,13 +192,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
192
192
193
193
// This will generate code to test scrutinee_place and
194
194
// branch to the appropriate arm block
195
- self . match_candidates (
196
- scrutinee_span,
197
- block,
198
- & mut otherwise,
199
- & mut candidates,
200
- & mut fake_borrows,
201
- ) ;
195
+ self . match_candidates ( scrutinee_span, block, & mut otherwise, candidates, & mut fake_borrows) ;
202
196
203
197
if let Some ( otherwise_block) = otherwise {
204
198
let source_info = self . source_info ( scrutinee_span) ;
@@ -207,7 +201,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
207
201
208
202
let mut previous_candidate: Option < & mut Candidate < ' _ , ' _ > > = None ;
209
203
210
- for candidate in candidates. into_iter ( ) {
204
+ for candidate in candidates {
211
205
candidate. visit_leaves ( |leaf_candidate| {
212
206
if let Some ( ref mut prev) = previous_candidate {
213
207
prev. next_candidate_pre_binding_block = leaf_candidate. pre_binding_block ;
@@ -263,7 +257,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
263
257
arm. guard . as_ref ( ) . map ( |g| ( g, match_scope) ) ,
264
258
& fake_borrow_temps,
265
259
scrutinee_span,
266
- arm. scope ,
260
+ Some ( arm. scope ) ,
267
261
) ;
268
262
269
263
if let Some ( source_scope) = scope {
@@ -297,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
297
291
guard : Option < ( & Guard < ' tcx > , region:: Scope ) > ,
298
292
fake_borrow_temps : & Vec < ( Place < ' tcx > , Local ) > ,
299
293
scrutinee_span : Span ,
300
- arm_scope : region:: Scope ,
294
+ arm_scope : Option < region:: Scope > ,
301
295
) -> BasicBlock {
302
296
if candidate. subcandidates . is_empty ( ) {
303
297
// Avoid generating another `BasicBlock` when we only have one
@@ -308,25 +302,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
308
302
guard,
309
303
fake_borrow_temps,
310
304
scrutinee_span,
305
+ true ,
311
306
)
312
307
} else {
313
308
let target_block = self . cfg . start_new_block ( ) ;
314
-
309
+ let mut schedule_drops = true ;
315
310
// We keep a stack of all of the bindings and type asciptions
316
311
// from the the parent candidates that we visit, that also need to
317
312
// be bound for each candidate.
318
313
traverse_candidate (
319
314
candidate,
320
315
& mut Vec :: new ( ) ,
321
316
& mut |leaf_candidate, parent_bindings| {
322
- self . clear_top_scope ( arm_scope) ;
317
+ if let Some ( arm_scope) = arm_scope {
318
+ // Avoid scheduling drops multiple times by unscheduling drops.
319
+ self . clear_top_scope ( arm_scope) ;
320
+ }
323
321
let binding_end = self . bind_and_guard_matched_candidate (
324
322
leaf_candidate,
325
323
parent_bindings,
326
324
guard,
327
325
& fake_borrow_temps,
328
326
scrutinee_span,
327
+ schedule_drops,
329
328
) ;
329
+ if arm_scope. is_none ( ) {
330
+ // If we aren't in a match, then our bindings may not be
331
+ // the only thing in the top scope, so only schedule
332
+ // them to drop for the first pattern instead.
333
+ schedule_drops = false ;
334
+ }
330
335
self . cfg . goto ( binding_end, outer_source_info, target_block) ;
331
336
} ,
332
337
|inner_candidate, parent_bindings| {
@@ -460,51 +465,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
460
465
subcandidates : vec ! [ ] ,
461
466
} ;
462
467
463
- // Simplify the candidate. Since the pattern is irrefutable, this should
464
- // always convert all match-pairs into bindings.
465
- self . simplify_candidate ( & mut candidate) ;
466
-
467
- if !candidate. match_pairs . is_empty ( ) {
468
- // ICE if no other errors have been emitted. This used to be a hard error that wouldn't
469
- // be reached because `hair::pattern::check_match::check_match` wouldn't have let the
470
- // compiler continue. In our tests this is only ever hit by
471
- // `ui/consts/const-match-check.rs` with `--cfg eval1`, and that file already generates
472
- // a different error before hand.
473
- self . hir . tcx ( ) . sess . delay_span_bug (
474
- candidate. match_pairs [ 0 ] . pattern . span ,
475
- & format ! (
476
- "match pairs {:?} remaining after simplifying irrefutable pattern" ,
477
- candidate. match_pairs,
478
- ) ,
479
- ) ;
480
- }
468
+ let fake_borrow_temps =
469
+ self . lower_match_tree ( block, irrefutable_pat. span , false , & mut [ & mut candidate] ) ;
481
470
482
471
// for matches and function arguments, the place that is being matched
483
472
// can be set when creating the variables. But the place for
484
473
// let PATTERN = ... might not even exist until we do the assignment.
485
474
// so we set it here instead
486
475
if set_match_place {
487
- for binding in & candidate. bindings {
488
- let local = self . var_local_id ( binding. var_id , OutsideGuard ) ;
489
-
490
- if let LocalInfo :: User ( ClearCrossCrate :: Set ( BindingForm :: Var ( VarBindingForm {
491
- opt_match_place : Some ( ( ref mut match_place, _) ) ,
492
- ..
493
- } ) ) ) = self . local_decls [ local] . local_info
494
- {
495
- * match_place = Some ( initializer. clone ( ) ) ;
496
- } else {
497
- bug ! ( "Let binding to non-user variable." )
476
+ let mut candidate_ref = & candidate;
477
+ while let Some ( next) = {
478
+ for binding in & candidate_ref. bindings {
479
+ let local = self . var_local_id ( binding. var_id , OutsideGuard ) ;
480
+
481
+ if let LocalInfo :: User ( ClearCrossCrate :: Set ( BindingForm :: Var (
482
+ VarBindingForm { opt_match_place : Some ( ( ref mut match_place, _) ) , .. } ,
483
+ ) ) ) = self . local_decls [ local] . local_info
484
+ {
485
+ * match_place = Some ( initializer. clone ( ) ) ;
486
+ } else {
487
+ bug ! ( "Let binding to non-user variable." )
488
+ }
498
489
}
490
+ candidate_ref. subcandidates . get ( 0 )
491
+ } {
492
+ candidate_ref = next;
499
493
}
500
494
}
501
495
502
- self . ascribe_types ( block, & candidate. ascriptions ) ;
503
-
504
- // now apply the bindings, which will also declare the variables
505
- self . bind_matched_candidate_for_arm_body ( block, & candidate. bindings ) ;
506
-
507
- block. unit ( )
496
+ self . bind_pattern (
497
+ self . source_info ( irrefutable_pat. span ) ,
498
+ candidate,
499
+ None ,
500
+ & fake_borrow_temps,
501
+ irrefutable_pat. span ,
502
+ None ,
503
+ )
504
+ . unit ( )
508
505
}
509
506
510
507
/// Declares the bindings of the given patterns and returns the visibility
@@ -1486,6 +1483,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1486
1483
guard : Option < ( & Guard < ' tcx > , region:: Scope ) > ,
1487
1484
fake_borrows : & Vec < ( Place < ' tcx > , Local ) > ,
1488
1485
scrutinee_span : Span ,
1486
+ schedule_drops : bool ,
1489
1487
) -> BasicBlock {
1490
1488
debug ! ( "bind_and_guard_matched_candidate(candidate={:?})" , candidate) ;
1491
1489
@@ -1692,7 +1690,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1692
1690
let cause = FakeReadCause :: ForGuardBinding ;
1693
1691
self . cfg . push_fake_read ( post_guard_block, guard_end, cause, Place :: from ( local_id) ) ;
1694
1692
}
1695
- self . bind_matched_candidate_for_arm_body ( post_guard_block, by_value_bindings) ;
1693
+ assert ! ( schedule_drops, "patterns with guards must schedule drops" ) ;
1694
+ self . bind_matched_candidate_for_arm_body ( post_guard_block, true , by_value_bindings) ;
1696
1695
1697
1696
post_guard_block
1698
1697
} else {
@@ -1701,6 +1700,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1701
1700
// that we have to inspect before we bind them.)
1702
1701
self . bind_matched_candidate_for_arm_body (
1703
1702
block,
1703
+ schedule_drops,
1704
1704
parent_bindings
1705
1705
. iter ( )
1706
1706
. flat_map ( |( bindings, _) | bindings)
@@ -1793,6 +1793,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1793
1793
fn bind_matched_candidate_for_arm_body < ' b > (
1794
1794
& mut self ,
1795
1795
block : BasicBlock ,
1796
+ schedule_drops : bool ,
1796
1797
bindings : impl IntoIterator < Item = & ' b Binding < ' tcx > > ,
1797
1798
) where
1798
1799
' tcx : ' b ,
@@ -1805,7 +1806,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1805
1806
let source_info = self . source_info ( binding. span ) ;
1806
1807
let local =
1807
1808
self . storage_live_binding ( block, binding. var_id , binding. span , OutsideGuard ) ;
1808
- self . schedule_drop_for_binding ( binding. var_id , binding. span , OutsideGuard ) ;
1809
+ if schedule_drops {
1810
+ self . schedule_drop_for_binding ( binding. var_id , binding. span , OutsideGuard ) ;
1811
+ }
1809
1812
let rvalue = match binding. binding_mode {
1810
1813
BindingMode :: ByValue => {
1811
1814
Rvalue :: Use ( self . consume_by_copy_or_move ( binding. source . clone ( ) ) )
0 commit comments