@@ -319,54 +319,52 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
319319 // them.
320320 let mut fake_borrows = match_has_guard. then ( FxIndexSet :: default) ;
321321
322- let mut otherwise = None ;
322+ let otherwise_block = self . cfg . start_new_block ( ) ;
323323
324324 // This will generate code to test scrutinee_place and
325325 // branch to the appropriate arm block
326326 self . match_candidates (
327327 match_start_span,
328328 scrutinee_span,
329329 block,
330- & mut otherwise ,
330+ otherwise_block ,
331331 candidates,
332332 & mut fake_borrows,
333333 ) ;
334334
335- if let Some ( otherwise_block) = otherwise {
336- // See the doc comment on `match_candidates` for why we may have an
337- // otherwise block. Match checking will ensure this is actually
338- // unreachable.
339- let source_info = self . source_info ( scrutinee_span) ;
340-
341- // Matching on a `scrutinee_place` with an uninhabited type doesn't
342- // generate any memory reads by itself, and so if the place "expression"
343- // contains unsafe operations like raw pointer dereferences or union
344- // field projections, we wouldn't know to require an `unsafe` block
345- // around a `match` equivalent to `std::intrinsics::unreachable()`.
346- // See issue #47412 for this hole being discovered in the wild.
347- //
348- // HACK(eddyb) Work around the above issue by adding a dummy inspection
349- // of `scrutinee_place`, specifically by applying `ReadForMatch`.
350- //
351- // NOTE: ReadForMatch also checks that the scrutinee is initialized.
352- // This is currently needed to not allow matching on an uninitialized,
353- // uninhabited value. If we get never patterns, those will check that
354- // the place is initialized, and so this read would only be used to
355- // check safety.
356- let cause_matched_place = FakeReadCause :: ForMatchedPlace ( None ) ;
357-
358- if let Some ( scrutinee_place) = scrutinee_place_builder. try_to_place ( self ) {
359- self . cfg . push_fake_read (
360- otherwise_block,
361- source_info,
362- cause_matched_place,
363- scrutinee_place,
364- ) ;
365- }
335+ // See the doc comment on `match_candidates` for why we may have an
336+ // otherwise block. Match checking will ensure this is actually
337+ // unreachable.
338+ let source_info = self . source_info ( scrutinee_span) ;
339+
340+ // Matching on a `scrutinee_place` with an uninhabited type doesn't
341+ // generate any memory reads by itself, and so if the place "expression"
342+ // contains unsafe operations like raw pointer dereferences or union
343+ // field projections, we wouldn't know to require an `unsafe` block
344+ // around a `match` equivalent to `std::intrinsics::unreachable()`.
345+ // See issue #47412 for this hole being discovered in the wild.
346+ //
347+ // HACK(eddyb) Work around the above issue by adding a dummy inspection
348+ // of `scrutinee_place`, specifically by applying `ReadForMatch`.
349+ //
350+ // NOTE: ReadForMatch also checks that the scrutinee is initialized.
351+ // This is currently needed to not allow matching on an uninitialized,
352+ // uninhabited value. If we get never patterns, those will check that
353+ // the place is initialized, and so this read would only be used to
354+ // check safety.
355+ let cause_matched_place = FakeReadCause :: ForMatchedPlace ( None ) ;
366356
367- self . cfg . terminate ( otherwise_block, source_info, TerminatorKind :: Unreachable ) ;
357+ if let Some ( scrutinee_place) = scrutinee_place_builder. try_to_place ( self ) {
358+ self . cfg . push_fake_read (
359+ otherwise_block,
360+ source_info,
361+ cause_matched_place,
362+ scrutinee_place,
363+ ) ;
368364 }
369365
366+ self . cfg . terminate ( otherwise_block, source_info, TerminatorKind :: Unreachable ) ;
367+
370368 // Link each leaf candidate to the `pre_binding_block` of the next one.
371369 let mut previous_candidate: Option < & mut Candidate < ' _ , ' _ > > = None ;
372370
@@ -1163,7 +1161,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
11631161 span : Span ,
11641162 scrutinee_span : Span ,
11651163 start_block : BasicBlock ,
1166- otherwise_block : & mut Option < BasicBlock > ,
1164+ otherwise_block : BasicBlock ,
11671165 candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
11681166 fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
11691167 ) {
@@ -1210,7 +1208,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12101208 span : Span ,
12111209 scrutinee_span : Span ,
12121210 start_block : BasicBlock ,
1213- otherwise_block : & mut Option < BasicBlock > ,
1211+ otherwise_block : BasicBlock ,
12141212 candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
12151213 fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
12161214 ) {
@@ -1243,11 +1241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12431241 // never reach this point.
12441242 if unmatched_candidates. is_empty ( ) {
12451243 let source_info = self . source_info ( span) ;
1246- if let Some ( otherwise) = * otherwise_block {
1247- self . cfg . goto ( block, source_info, otherwise) ;
1248- } else {
1249- * otherwise_block = Some ( block) ;
1250- }
1244+ self . cfg . goto ( block, source_info, otherwise_block) ;
12511245 return ;
12521246 }
12531247
@@ -1428,7 +1422,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14281422 scrutinee_span : Span ,
14291423 candidates : & mut [ & mut Candidate < ' _ , ' tcx > ] ,
14301424 block : BasicBlock ,
1431- otherwise_block : & mut Option < BasicBlock > ,
1425+ otherwise_block : BasicBlock ,
14321426 fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
14331427 ) {
14341428 let ( first_candidate, remaining_candidates) = candidates. split_first_mut ( ) . unwrap ( ) ;
@@ -1453,7 +1447,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14531447 let match_pairs = mem:: take ( & mut first_candidate. match_pairs ) ;
14541448 first_candidate. pre_binding_block = Some ( block) ;
14551449
1456- let mut otherwise = None ;
1450+ let remainder_start = self . cfg . start_new_block ( ) ;
14571451 for match_pair in match_pairs {
14581452 let PatKind :: Or { ref pats } = & match_pair. pattern . kind else {
14591453 bug ! ( "Or-patterns should have been sorted to the end" ) ;
@@ -1463,7 +1457,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14631457 first_candidate. visit_leaves ( |leaf_candidate| {
14641458 self . test_or_pattern (
14651459 leaf_candidate,
1466- & mut otherwise ,
1460+ remainder_start ,
14671461 pats,
14681462 or_span,
14691463 & match_pair. place ,
@@ -1472,8 +1466,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14721466 } ) ;
14731467 }
14741468
1475- let remainder_start = otherwise. unwrap_or_else ( || self . cfg . start_new_block ( ) ) ;
1476-
14771469 self . match_candidates (
14781470 span,
14791471 scrutinee_span,
@@ -1491,7 +1483,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14911483 fn test_or_pattern < ' pat > (
14921484 & mut self ,
14931485 candidate : & mut Candidate < ' pat , ' tcx > ,
1494- otherwise : & mut Option < BasicBlock > ,
1486+ otherwise : BasicBlock ,
14951487 pats : & ' pat [ Box < Pat < ' tcx > > ] ,
14961488 or_span : Span ,
14971489 place : & PlaceBuilder < ' tcx > ,
@@ -1503,8 +1495,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
15031495 . map ( |pat| Candidate :: new ( place. clone ( ) , pat, candidate. has_guard , self ) )
15041496 . collect ( ) ;
15051497 let mut or_candidate_refs: Vec < _ > = or_candidates. iter_mut ( ) . collect ( ) ;
1506- let otherwise = if candidate. otherwise_block . is_some ( ) {
1507- & mut candidate . otherwise_block
1498+ let otherwise = if let Some ( otherwise_block ) = candidate. otherwise_block {
1499+ otherwise_block
15081500 } else {
15091501 otherwise
15101502 } ;
@@ -1680,8 +1672,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16801672 span : Span ,
16811673 scrutinee_span : Span ,
16821674 mut candidates : & ' b mut [ & ' c mut Candidate < ' pat , ' tcx > ] ,
1683- block : BasicBlock ,
1684- otherwise_block : & mut Option < BasicBlock > ,
1675+ start_block : BasicBlock ,
1676+ otherwise_block : BasicBlock ,
16851677 fake_borrows : & mut Option < FxIndexSet < Place < ' tcx > > > ,
16861678 ) {
16871679 // extract the match-pair from the highest priority candidate
@@ -1749,12 +1741,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17491741 debug ! ( "untested_candidates: {}" , candidates. len( ) ) ;
17501742
17511743 // The block that we should branch to if none of the
1752- // `target_candidates` match. This is either the block where we
1753- // start matching the untested candidates if there are any,
1754- // otherwise it's the `otherwise_block`.
1755- let remainder_start = & mut None ;
1756- let remainder_start =
1757- if candidates. is_empty ( ) { & mut * otherwise_block } else { remainder_start } ;
1744+ // `target_candidates` match.
1745+ let remainder_start = if !candidates. is_empty ( ) {
1746+ let remainder_start = self . cfg . start_new_block ( ) ;
1747+ self . match_candidates (
1748+ span,
1749+ scrutinee_span,
1750+ remainder_start,
1751+ otherwise_block,
1752+ candidates,
1753+ fake_borrows,
1754+ ) ;
1755+ remainder_start
1756+ } else {
1757+ otherwise_block
1758+ } ;
17581759
17591760 // For each outcome of test, process the candidates that still
17601761 // apply. Collect a list of blocks where control flow will
@@ -1775,24 +1776,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17751776 ) ;
17761777 candidate_start
17771778 } else {
1778- * remainder_start. get_or_insert_with ( || self . cfg . start_new_block ( ) )
1779+ remainder_start
17791780 }
17801781 } )
17811782 . collect ( ) ;
17821783
1783- if !candidates. is_empty ( ) {
1784- let remainder_start = remainder_start. unwrap_or_else ( || self . cfg . start_new_block ( ) ) ;
1785- self . match_candidates (
1786- span,
1787- scrutinee_span,
1788- remainder_start,
1789- otherwise_block,
1790- candidates,
1791- fake_borrows,
1792- ) ;
1793- }
1794-
1795- self . perform_test ( span, scrutinee_span, block, & match_place, & test, target_blocks) ;
1784+ // Perform the test, branching to one of N blocks.
1785+ self . perform_test ( span, scrutinee_span, start_block, & match_place, & test, target_blocks) ;
17961786 }
17971787
17981788 /// Determine the fake borrows that are needed from a set of places that
0 commit comments