@@ -143,19 +143,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
143
143
144
144
// create binding start block for link them by false edges
145
145
let candidate_count = arms. iter ( ) . map ( |c| c. patterns . len ( ) ) . sum :: < usize > ( ) ;
146
- let pre_binding_blocks: Vec < _ > = ( 0 ..= candidate_count)
146
+ let pre_binding_blocks: Vec < _ > = ( 0 ..candidate_count)
147
147
. map ( |_| self . cfg . start_new_block ( ) )
148
148
. collect ( ) ;
149
149
150
- // There's one more pre_binding block than there are candidates so that
151
- // every candidate can have a `next_candidate_pre_binding_block`.
152
- let outer_source_info = self . source_info ( span) ;
153
- self . cfg . terminate (
154
- * pre_binding_blocks. last ( ) . unwrap ( ) ,
155
- outer_source_info,
156
- TerminatorKind :: Unreachable ,
157
- ) ;
158
-
159
150
let mut match_has_guard = false ;
160
151
161
152
let mut candidate_pre_binding_blocks = pre_binding_blocks. iter ( ) ;
@@ -171,9 +162,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
171
162
let arm_candidates: Vec < _ > = arm. patterns
172
163
. iter ( )
173
164
. zip ( candidate_pre_binding_blocks. by_ref ( ) )
174
- . zip ( next_candidate_pre_binding_blocks. by_ref ( ) )
175
165
. map (
176
- |( ( pattern, pre_binding_block) , next_candidate_pre_binding_block ) | {
166
+ |( pattern, pre_binding_block) | {
177
167
Candidate {
178
168
span : pattern. span ,
179
169
match_pairs : vec ! [
@@ -188,7 +178,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
188
178
} ,
189
179
pre_binding_block : * pre_binding_block,
190
180
next_candidate_pre_binding_block :
191
- * next_candidate_pre_binding_block ,
181
+ next_candidate_pre_binding_blocks . next ( ) . copied ( ) ,
192
182
}
193
183
} ,
194
184
)
@@ -225,6 +215,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
225
215
& mut fake_borrows,
226
216
) ;
227
217
218
+ let outer_source_info = self . source_info ( span) ;
219
+
228
220
if !otherwise. is_empty ( ) {
229
221
// All matches are exhaustive. However, because some matches
230
222
// only have exponentially-large exhaustive decision trees, we
@@ -251,12 +243,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
251
243
} ;
252
244
253
245
// Step 5. Create everything else: the guards and the arms.
254
-
255
- let arm_end_blocks: Vec < _ > = arm_candidates. into_iter ( ) . map ( |( arm, candidates) | {
246
+ let arm_end_blocks: Vec < _ > = arm_candidates. into_iter ( ) . map ( |( arm, mut candidates) | {
256
247
let arm_source_info = self . source_info ( arm. span ) ;
257
248
let region_scope = ( arm. scope , arm_source_info) ;
258
249
self . in_scope ( region_scope, arm. lint_level , |this| {
259
- let arm_block = this. cfg . start_new_block ( ) ;
250
+ let mut arm_block = this. cfg . start_new_block ( ) ;
260
251
261
252
let body = this. hir . mirror ( arm. body . clone ( ) ) ;
262
253
let scope = this. declare_bindings (
@@ -267,6 +258,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
267
258
Some ( ( Some ( & scrutinee_place) , scrutinee_span) ) ,
268
259
) ;
269
260
261
+ if candidates. len ( ) == 1 {
262
+ arm_block = self . bind_and_guard_matched_candidate (
263
+ candidates. pop ( ) . unwrap ( ) ,
264
+ arm. guard . clone ( ) ,
265
+ & fake_borrow_temps,
266
+ scrutinee_span,
267
+ ) ;
268
+ } else {
269
+ arm_block = self . cfg . start_new_block ( ) ;
270
+ for candidate in candidates {
271
+ let binding_end = self . bind_and_guard_matched_candidate (
272
+ candidate,
273
+ arm. guard . clone ( ) ,
274
+ & fake_borrow_temps,
275
+ scrutinee_span,
276
+ ) ;
277
+ self . cfg . terminate (
278
+ binding_end,
279
+ source_info,
280
+ TerminatorKind :: Goto { target : arm_block } ,
281
+ ) ;
282
+ }
283
+ }
284
+
270
285
if let Some ( source_scope) = scope {
271
286
this. source_scope = source_scope;
272
287
}
@@ -434,7 +449,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
434
449
// since we don't call `match_candidates`, next fields are unused
435
450
otherwise_block : None ,
436
451
pre_binding_block : block,
437
- next_candidate_pre_binding_block : block ,
452
+ next_candidate_pre_binding_block : None ,
438
453
} ;
439
454
440
455
// Simplify the candidate. Since the pattern is irrefutable, this should
@@ -689,7 +704,7 @@ pub struct Candidate<'pat, 'tcx: 'pat> {
689
704
690
705
// ...and the blocks for add false edges between candidates
691
706
pre_binding_block : BasicBlock ,
692
- next_candidate_pre_binding_block : BasicBlock ,
707
+ next_candidate_pre_binding_block : Option < BasicBlock > ,
693
708
}
694
709
695
710
#[ derive( Clone , Debug ) ]
@@ -956,14 +971,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
956
971
if let [ first_candidate, second_candidate] = window {
957
972
let source_info = self . source_info ( first_candidate. span ) ;
958
973
if let Some ( otherwise_block) = first_candidate. otherwise_block {
959
- self . cfg . terminate (
974
+ self . false_edges (
960
975
otherwise_block,
976
+ second_candidate. pre_binding_block ,
977
+ first_candidate. next_candidate_pre_binding_block ,
961
978
source_info,
962
- TerminatorKind :: FalseEdges {
963
- real_target : second_candidate. pre_binding_block ,
964
- imaginary_target : first_candidate. next_candidate_pre_binding_block ,
965
- }
966
- )
979
+ ) ;
967
980
} else {
968
981
bug ! ( "candidate other than the last has no guard" ) ;
969
982
}
@@ -977,13 +990,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
977
990
if let Some ( otherwise) = candidate. otherwise_block {
978
991
let source_info = self . source_info ( candidate. span ) ;
979
992
let unreachable = self . cfg . start_new_block ( ) ;
980
- self . cfg . terminate (
993
+ self . false_edges (
981
994
otherwise,
995
+ unreachable,
996
+ candidate. next_candidate_pre_binding_block ,
982
997
source_info,
983
- TerminatorKind :: FalseEdges {
984
- real_target : unreachable,
985
- imaginary_targets : candidate. next_candidate_pre_binding_block ,
986
- }
987
998
) ;
988
999
self . cfg . terminate ( unreachable, source_info, TerminatorKind :: Unreachable ) ;
989
1000
}
@@ -994,13 +1005,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
994
1005
if let Some ( otherwise) = last_candidate. otherwise_block {
995
1006
let source_info = self . source_info ( last_candidate. span ) ;
996
1007
let block = self . cfg . start_new_block ( ) ;
997
- self . cfg . terminate (
1008
+ self . false_edges (
998
1009
otherwise,
1010
+ block,
1011
+ last_candidate. next_candidate_pre_binding_block ,
999
1012
source_info,
1000
- TerminatorKind :: FalseEdges {
1001
- real_target : block,
1002
- imaginary_target : last_candidate. next_candidate_pre_binding_block ,
1003
- }
1004
1013
) ;
1005
1014
Some ( block)
1006
1015
} else {
@@ -1311,27 +1320,38 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1311
1320
& mut self ,
1312
1321
candidate : Candidate < ' pat , ' tcx > ,
1313
1322
guard : Option < Guard < ' tcx > > ,
1314
- arm_block : BasicBlock ,
1315
1323
fake_borrows : & Vec < ( & Place < ' tcx > , Local ) > ,
1316
1324
scrutinee_span : Span ,
1317
1325
region_scope : ( region:: Scope , SourceInfo ) ,
1318
1326
) {
1327
+ ) -> BasicBlock {
1319
1328
debug ! ( "bind_and_guard_matched_candidate(candidate={:?})" , candidate) ;
1320
1329
1321
1330
debug_assert ! ( candidate. match_pairs. is_empty( ) ) ;
1322
1331
1323
1332
let candidate_source_info = self . source_info ( candidate. span ) ;
1324
1333
1325
- let mut block = self . cfg . start_new_block ( ) ;
1326
- self . cfg . terminate (
1327
- candidate. pre_binding_block ,
1334
+ let mut block = candidate. pre_binding_block ;
1335
+
1336
+ // If we are adding our own statements, then we need a fresh block.
1337
+ let create_fresh_block = candidate. next_candidate_pre_binding_block . is_some ( )
1338
+ || !candidate. bindings . is_empty ( )
1339
+ || !candidate. ascriptions . is_empty ( )
1340
+ || guard. is_some ( ) ;
1341
+
1342
+ if create_fresh_block {
1343
+ let fresh_block = self . cfg . start_new_block ( ) ;
1344
+ self . false_edges (
1345
+ block,
1346
+ fresh_block,
1347
+ candidate. next_candidate_pre_binding_block ,
1328
1348
candidate_source_info,
1329
- TerminatorKind :: FalseEdges {
1330
- real_target : block,
1331
- imaginary_target : candidate. next_candidate_pre_binding_block ,
1332
- } ,
1333
1349
) ;
1350
+ block = fresh_block;
1334
1351
self . ascribe_types ( block, & candidate. ascriptions ) ;
1352
+ } else {
1353
+ return block;
1354
+ }
1335
1355
1336
1356
// rust-lang/rust#27282: The `autoref` business deserves some
1337
1357
// explanation here.
@@ -1476,7 +1496,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1476
1496
// because that would be before we've checked the result
1477
1497
// from the guard.
1478
1498
//
1479
- // But binding them on `arm_block` is *too late*, because
1499
+ // But binding them on the arm is *too late*, because
1480
1500
// then all of the candidates for a single arm would be
1481
1501
// bound in the same place, that would cause a case like:
1482
1502
//
@@ -1552,22 +1572,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1552
1572
by_value_bindings,
1553
1573
) ;
1554
1574
1555
- self . cfg . terminate (
1556
- post_guard_block,
1557
- source_info,
1558
- TerminatorKind :: Goto { target : arm_block } ,
1559
- ) ;
1575
+ post_guard_block
1560
1576
} else {
1561
1577
assert ! ( candidate. otherwise_block. is_none( ) ) ;
1562
1578
// (Here, it is not too early to bind the matched
1563
1579
// candidate on `block`, because there is no guard result
1564
1580
// that we have to inspect before we bind them.)
1565
1581
self . bind_matched_candidate_for_arm_body ( block, & candidate. bindings ) ;
1566
- self . cfg . terminate (
1567
- block,
1568
- candidate_source_info,
1569
- TerminatorKind :: Goto { target : arm_block } ,
1570
- ) ;
1582
+ block
1571
1583
}
1572
1584
}
1573
1585
0 commit comments