@@ -142,19 +142,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
142
142
143
143
// create binding start block for link them by false edges
144
144
let candidate_count = arms. iter ( ) . map ( |c| c. patterns . len ( ) ) . sum :: < usize > ( ) ;
145
- let pre_binding_blocks: Vec < _ > = ( 0 ..= candidate_count)
145
+ let pre_binding_blocks: Vec < _ > = ( 0 ..candidate_count)
146
146
. map ( |_| self . cfg . start_new_block ( ) )
147
147
. collect ( ) ;
148
148
149
- // There's one more pre_binding block than there are candidates so that
150
- // every candidate can have a `next_candidate_pre_binding_block`.
151
- let outer_source_info = self . source_info ( span) ;
152
- self . cfg . terminate (
153
- * pre_binding_blocks. last ( ) . unwrap ( ) ,
154
- outer_source_info,
155
- TerminatorKind :: Unreachable ,
156
- ) ;
157
-
158
149
let mut match_has_guard = false ;
159
150
160
151
let mut candidate_pre_binding_blocks = pre_binding_blocks. iter ( ) ;
@@ -170,9 +161,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
170
161
let arm_candidates: Vec < _ > = arm. patterns
171
162
. iter ( )
172
163
. zip ( candidate_pre_binding_blocks. by_ref ( ) )
173
- . zip ( next_candidate_pre_binding_blocks. by_ref ( ) )
174
164
. map (
175
- |( ( pattern, pre_binding_block) , next_candidate_pre_binding_block ) | {
165
+ |( pattern, pre_binding_block) | {
176
166
Candidate {
177
167
span : pattern. span ,
178
168
match_pairs : vec ! [
@@ -187,7 +177,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
187
177
} ,
188
178
pre_binding_block : * pre_binding_block,
189
179
next_candidate_pre_binding_block :
190
- * next_candidate_pre_binding_block ,
180
+ next_candidate_pre_binding_blocks . next ( ) . cloned ( ) ,
191
181
}
192
182
} ,
193
183
)
@@ -224,6 +214,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
224
214
& mut fake_borrows,
225
215
) ;
226
216
217
+ let outer_source_info = self . source_info ( span) ;
218
+
227
219
if !otherwise. is_empty ( ) {
228
220
// All matches are exhaustive. However, because some matches
229
221
// only have exponentially-large exhaustive decision trees, we
@@ -250,10 +242,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
250
242
} ;
251
243
252
244
// Step 5. Create everything else: the guards and the arms.
253
-
254
- let outer_source_info = self . source_info ( span) ;
255
- let arm_end_blocks: Vec < _ > = arm_candidates. into_iter ( ) . map ( |( arm, candidates) | {
256
- let mut arm_block = self . cfg . start_new_block ( ) ;
245
+ let arm_end_blocks: Vec < _ > = arm_candidates. into_iter ( ) . map ( |( arm, mut candidates) | {
257
246
258
247
let body = self . hir . mirror ( arm. body . clone ( ) ) ;
259
248
let scope = self . declare_bindings (
@@ -265,14 +254,29 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
265
254
Some ( ( Some ( & scrutinee_place) , scrutinee_span) ) ,
266
255
) ;
267
256
257
+ let mut arm_block;
258
+ if candidates. len ( ) == 1 {
259
+ arm_block = self . bind_and_guard_matched_candidate (
260
+ candidates. pop ( ) . unwrap ( ) ,
261
+ arm. guard . clone ( ) ,
262
+ & fake_borrow_temps,
263
+ scrutinee_span,
264
+ ) ;
265
+ } else {
266
+ arm_block = self . cfg . start_new_block ( ) ;
268
267
for candidate in candidates {
269
- self . bind_and_guard_matched_candidate (
268
+ let binding_end = self . bind_and_guard_matched_candidate (
270
269
candidate,
271
270
arm. guard . clone ( ) ,
272
- arm_block,
273
271
& fake_borrow_temps,
274
272
scrutinee_span,
275
273
) ;
274
+ self . cfg . terminate (
275
+ binding_end,
276
+ source_info,
277
+ TerminatorKind :: Goto { target : arm_block } ,
278
+ ) ;
279
+ }
276
280
}
277
281
278
282
if let Some ( source_scope) = scope {
@@ -431,7 +435,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
431
435
// since we don't call `match_candidates`, next fields are unused
432
436
otherwise_block : None ,
433
437
pre_binding_block : block,
434
- next_candidate_pre_binding_block : block ,
438
+ next_candidate_pre_binding_block : None ,
435
439
} ;
436
440
437
441
// Simplify the candidate. Since the pattern is irrefutable, this should
@@ -701,7 +705,7 @@ pub struct Candidate<'pat, 'tcx: 'pat> {
701
705
702
706
// ...and the blocks for add false edges between candidates
703
707
pre_binding_block : BasicBlock ,
704
- next_candidate_pre_binding_block : BasicBlock ,
708
+ next_candidate_pre_binding_block : Option < BasicBlock > ,
705
709
}
706
710
707
711
#[ derive( Clone , Debug ) ]
@@ -968,14 +972,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
968
972
if let [ first_candidate, second_candidate] = window {
969
973
let source_info = self . source_info ( first_candidate. span ) ;
970
974
if let Some ( otherwise_block) = first_candidate. otherwise_block {
971
- self . cfg . terminate (
975
+ self . false_edges (
972
976
otherwise_block,
977
+ second_candidate. pre_binding_block ,
978
+ first_candidate. next_candidate_pre_binding_block ,
973
979
source_info,
974
- TerminatorKind :: FalseEdges {
975
- real_target : second_candidate. pre_binding_block ,
976
- imaginary_target : first_candidate. next_candidate_pre_binding_block ,
977
- }
978
- )
980
+ ) ;
979
981
} else {
980
982
bug ! ( "candidate other than the last has no guard" ) ;
981
983
}
@@ -989,13 +991,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
989
991
if let Some ( otherwise) = candidate. otherwise_block {
990
992
let source_info = self . source_info ( candidate. span ) ;
991
993
let unreachable = self . cfg . start_new_block ( ) ;
992
- self . cfg . terminate (
994
+ self . false_edges (
993
995
otherwise,
996
+ unreachable,
997
+ candidate. next_candidate_pre_binding_block ,
994
998
source_info,
995
- TerminatorKind :: FalseEdges {
996
- real_target : unreachable,
997
- imaginary_targets : candidate. next_candidate_pre_binding_block ,
998
- }
999
999
) ;
1000
1000
self . cfg . terminate ( unreachable, source_info, TerminatorKind :: Unreachable ) ;
1001
1001
}
@@ -1006,13 +1006,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1006
1006
if let Some ( otherwise) = last_candidate. otherwise_block {
1007
1007
let source_info = self . source_info ( last_candidate. span ) ;
1008
1008
let block = self . cfg . start_new_block ( ) ;
1009
- self . cfg . terminate (
1009
+ self . false_edges (
1010
1010
otherwise,
1011
+ block,
1012
+ last_candidate. next_candidate_pre_binding_block ,
1011
1013
source_info,
1012
- TerminatorKind :: FalseEdges {
1013
- real_target : block,
1014
- imaginary_target : last_candidate. next_candidate_pre_binding_block ,
1015
- }
1016
1014
) ;
1017
1015
Some ( block)
1018
1016
} else {
@@ -1323,26 +1321,36 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1323
1321
& mut self ,
1324
1322
candidate : Candidate < ' pat , ' tcx > ,
1325
1323
guard : Option < Guard < ' tcx > > ,
1326
- arm_block : BasicBlock ,
1327
1324
fake_borrows : & Vec < ( & Place < ' tcx > , Local ) > ,
1328
1325
scrutinee_span : Span ,
1329
- ) {
1326
+ ) -> BasicBlock {
1330
1327
debug ! ( "bind_and_guard_matched_candidate(candidate={:?})" , candidate) ;
1331
1328
1332
1329
debug_assert ! ( candidate. match_pairs. is_empty( ) ) ;
1333
1330
1334
1331
let candidate_source_info = self . source_info ( candidate. span ) ;
1335
1332
1336
- let mut block = self . cfg . start_new_block ( ) ;
1337
- self . cfg . terminate (
1338
- candidate. pre_binding_block ,
1333
+ let mut block = candidate. pre_binding_block ;
1334
+
1335
+ // If we are adding our own statements, then we need a fresh block.
1336
+ let create_fresh_block = candidate. next_candidate_pre_binding_block . is_some ( )
1337
+ || !candidate. bindings . is_empty ( )
1338
+ || !candidate. ascriptions . is_empty ( )
1339
+ || guard. is_some ( ) ;
1340
+
1341
+ if create_fresh_block {
1342
+ let fresh_block = self . cfg . start_new_block ( ) ;
1343
+ self . false_edges (
1344
+ block,
1345
+ fresh_block,
1346
+ candidate. next_candidate_pre_binding_block ,
1339
1347
candidate_source_info,
1340
- TerminatorKind :: FalseEdges {
1341
- real_target : block,
1342
- imaginary_target : candidate. next_candidate_pre_binding_block ,
1343
- } ,
1344
1348
) ;
1349
+ block = fresh_block;
1345
1350
self . ascribe_types ( block, & candidate. ascriptions ) ;
1351
+ } else {
1352
+ return block;
1353
+ }
1346
1354
1347
1355
// rust-lang/rust#27282: The `autoref` business deserves some
1348
1356
// explanation here.
@@ -1487,7 +1495,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1487
1495
// because that would be before we've checked the result
1488
1496
// from the guard.
1489
1497
//
1490
- // But binding them on `arm_block` is *too late*, because
1498
+ // But binding them on the arm is *too late*, because
1491
1499
// then all of the candidates for a single arm would be
1492
1500
// bound in the same place, that would cause a case like:
1493
1501
//
@@ -1540,22 +1548,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
1540
1548
by_value_bindings,
1541
1549
) ;
1542
1550
1543
- self . cfg . terminate (
1544
- post_guard_block,
1545
- source_info,
1546
- TerminatorKind :: Goto { target : arm_block } ,
1547
- ) ;
1551
+ post_guard_block
1548
1552
} else {
1549
1553
assert ! ( candidate. otherwise_block. is_none( ) ) ;
1550
1554
// (Here, it is not too early to bind the matched
1551
1555
// candidate on `block`, because there is no guard result
1552
1556
// that we have to inspect before we bind them.)
1553
1557
self . bind_matched_candidate_for_arm_body ( block, & candidate. bindings ) ;
1554
- self . cfg . terminate (
1555
- block,
1556
- candidate_source_info,
1557
- TerminatorKind :: Goto { target : arm_block } ,
1558
- ) ;
1558
+ block
1559
1559
}
1560
1560
}
1561
1561
0 commit comments