@@ -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
@@ -691,7 +706,7 @@ pub struct Candidate<'pat, 'tcx: 'pat> {
691
706
692
707
// ...and the blocks for add false edges between candidates
693
708
pre_binding_block : BasicBlock ,
694
- next_candidate_pre_binding_block : BasicBlock ,
709
+ next_candidate_pre_binding_block : Option < BasicBlock > ,
695
710
}
696
711
697
712
#[ derive( Clone , Debug ) ]
@@ -958,14 +973,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
958
973
if let [ first_candidate, second_candidate] = window {
959
974
let source_info = self . source_info ( first_candidate. span ) ;
960
975
if let Some ( otherwise_block) = first_candidate. otherwise_block {
961
- self . cfg . terminate (
976
+ self . false_edges (
962
977
otherwise_block,
978
+ second_candidate. pre_binding_block ,
979
+ first_candidate. next_candidate_pre_binding_block ,
963
980
source_info,
964
- TerminatorKind :: FalseEdges {
965
- real_target : second_candidate. pre_binding_block ,
966
- imaginary_target : first_candidate. next_candidate_pre_binding_block ,
967
- }
968
- )
981
+ ) ;
969
982
} else {
970
983
bug ! ( "candidate other than the last has no guard" ) ;
971
984
}
@@ -979,13 +992,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
979
992
if let Some ( otherwise) = candidate. otherwise_block {
980
993
let source_info = self . source_info ( candidate. span ) ;
981
994
let unreachable = self . cfg . start_new_block ( ) ;
982
- self . cfg . terminate (
995
+ self . false_edges (
983
996
otherwise,
997
+ unreachable,
998
+ candidate. next_candidate_pre_binding_block ,
984
999
source_info,
985
- TerminatorKind :: FalseEdges {
986
- real_target : unreachable,
987
- imaginary_targets : candidate. next_candidate_pre_binding_block ,
988
- }
989
1000
) ;
990
1001
self . cfg . terminate ( unreachable, source_info, TerminatorKind :: Unreachable ) ;
991
1002
}
@@ -996,13 +1007,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
996
1007
if let Some ( otherwise) = last_candidate. otherwise_block {
997
1008
let source_info = self . source_info ( last_candidate. span ) ;
998
1009
let block = self . cfg . start_new_block ( ) ;
999
- self . cfg . terminate (
1010
+ self . false_edges (
1000
1011
otherwise,
1012
+ block,
1013
+ last_candidate. next_candidate_pre_binding_block ,
1001
1014
source_info,
1002
- TerminatorKind :: FalseEdges {
1003
- real_target : block,
1004
- imaginary_target : last_candidate. next_candidate_pre_binding_block ,
1005
- }
1006
1015
) ;
1007
1016
Some ( block)
1008
1017
} else {
@@ -1313,27 +1322,38 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1313
1322
& mut self ,
1314
1323
candidate : Candidate < ' pat , ' tcx > ,
1315
1324
guard : Option < Guard < ' tcx > > ,
1316
- arm_block : BasicBlock ,
1317
1325
fake_borrows : & Vec < ( & Place < ' tcx > , Local ) > ,
1318
1326
scrutinee_span : Span ,
1319
1327
region_scope : ( region:: Scope , SourceInfo ) ,
1320
1328
) {
1329
+ ) -> BasicBlock {
1321
1330
debug ! ( "bind_and_guard_matched_candidate(candidate={:?})" , candidate) ;
1322
1331
1323
1332
debug_assert ! ( candidate. match_pairs. is_empty( ) ) ;
1324
1333
1325
1334
let candidate_source_info = self . source_info ( candidate. span ) ;
1326
1335
1327
- let mut block = self . cfg . start_new_block ( ) ;
1328
- self . cfg . terminate (
1329
- candidate. pre_binding_block ,
1336
+ let mut block = candidate. pre_binding_block ;
1337
+
1338
+ // If we are adding our own statements, then we need a fresh block.
1339
+ let create_fresh_block = candidate. next_candidate_pre_binding_block . is_some ( )
1340
+ || !candidate. bindings . is_empty ( )
1341
+ || !candidate. ascriptions . is_empty ( )
1342
+ || guard. is_some ( ) ;
1343
+
1344
+ if create_fresh_block {
1345
+ let fresh_block = self . cfg . start_new_block ( ) ;
1346
+ self . false_edges (
1347
+ block,
1348
+ fresh_block,
1349
+ candidate. next_candidate_pre_binding_block ,
1330
1350
candidate_source_info,
1331
- TerminatorKind :: FalseEdges {
1332
- real_target : block,
1333
- imaginary_target : candidate. next_candidate_pre_binding_block ,
1334
- } ,
1335
1351
) ;
1352
+ block = fresh_block;
1336
1353
self . ascribe_types ( block, & candidate. ascriptions ) ;
1354
+ } else {
1355
+ return block;
1356
+ }
1337
1357
1338
1358
// rust-lang/rust#27282: The `autoref` business deserves some
1339
1359
// explanation here.
@@ -1478,7 +1498,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1478
1498
// because that would be before we've checked the result
1479
1499
// from the guard.
1480
1500
//
1481
- // But binding them on `arm_block` is *too late*, because
1501
+ // But binding them on the arm is *too late*, because
1482
1502
// then all of the candidates for a single arm would be
1483
1503
// bound in the same place, that would cause a case like:
1484
1504
//
@@ -1554,22 +1574,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1554
1574
by_value_bindings,
1555
1575
) ;
1556
1576
1557
- self . cfg . terminate (
1558
- post_guard_block,
1559
- source_info,
1560
- TerminatorKind :: Goto { target : arm_block } ,
1561
- ) ;
1577
+ post_guard_block
1562
1578
} else {
1563
1579
assert ! ( candidate. otherwise_block. is_none( ) ) ;
1564
1580
// (Here, it is not too early to bind the matched
1565
1581
// candidate on `block`, because there is no guard result
1566
1582
// that we have to inspect before we bind them.)
1567
1583
self . bind_matched_candidate_for_arm_body ( block, & candidate. bindings ) ;
1568
- self . cfg . terminate (
1569
- block,
1570
- candidate_source_info,
1571
- TerminatorKind :: Goto { target : arm_block } ,
1572
- ) ;
1584
+ block
1573
1585
}
1574
1586
}
1575
1587
0 commit comments