@@ -329,6 +329,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
329329 & scrutinee_place,
330330 match_start_span,
331331 & mut candidates,
332+ false ,
332333 ) ;
333334
334335 self . lower_match_arms (
@@ -694,6 +695,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
694695 & initializer,
695696 irrefutable_pat. span ,
696697 & mut [ & mut candidate] ,
698+ false ,
697699 ) ;
698700 self . bind_pattern (
699701 self . source_info ( irrefutable_pat. span ) ,
@@ -1229,52 +1231,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12291231 ///
12301232 /// Modifies `candidates` to store the bindings and type ascriptions for
12311233 /// that candidate.
1234+ ///
1235+ /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
1236+ /// or not (for `let` and `match`). In the refutable case we return the block to which we branch
1237+ /// on failure.
12321238 fn lower_match_tree < ' pat > (
12331239 & mut self ,
12341240 block : BasicBlock ,
12351241 scrutinee_span : Span ,
12361242 scrutinee_place_builder : & PlaceBuilder < ' tcx > ,
12371243 match_start_span : Span ,
12381244 candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1239- ) {
1240- // See the doc comment on `match_candidates` for why we have an
1241- // otherwise block. Match checking will ensure this is actually
1242- // unreachable.
1245+ refutable : bool ,
1246+ ) -> BasicBlock {
1247+ // See the doc comment on `match_candidates` for why we have an otherwise block.
12431248 let otherwise_block = self . cfg . start_new_block ( ) ;
12441249
12451250 // This will generate code to test scrutinee_place and branch to the appropriate arm block
12461251 self . match_candidates ( match_start_span, scrutinee_span, block, otherwise_block, candidates) ;
12471252
1248- let source_info = self . source_info ( scrutinee_span) ;
1249-
1250- // Matching on a `scrutinee_place` with an uninhabited type doesn't
1251- // generate any memory reads by itself, and so if the place "expression"
1252- // contains unsafe operations like raw pointer dereferences or union
1253- // field projections, we wouldn't know to require an `unsafe` block
1254- // around a `match` equivalent to `std::intrinsics::unreachable()`.
1255- // See issue #47412 for this hole being discovered in the wild.
1256- //
1257- // HACK(eddyb) Work around the above issue by adding a dummy inspection
1258- // of `scrutinee_place`, specifically by applying `ReadForMatch`.
1259- //
1260- // NOTE: ReadForMatch also checks that the scrutinee is initialized.
1261- // This is currently needed to not allow matching on an uninitialized,
1262- // uninhabited value. If we get never patterns, those will check that
1263- // the place is initialized, and so this read would only be used to
1264- // check safety.
1265- let cause_matched_place = FakeReadCause :: ForMatchedPlace ( None ) ;
1266-
1267- if let Some ( scrutinee_place) = scrutinee_place_builder. try_to_place ( self ) {
1268- self . cfg . push_fake_read (
1269- otherwise_block,
1270- source_info,
1271- cause_matched_place,
1272- scrutinee_place,
1273- ) ;
1274- }
1275-
1276- self . cfg . terminate ( otherwise_block, source_info, TerminatorKind :: Unreachable ) ;
1277-
12781253 // Link each leaf candidate to the `false_edge_start_block` of the next one.
12791254 let mut previous_candidate: Option < & mut Candidate < ' _ , ' _ > > = None ;
12801255 for candidate in candidates {
@@ -1286,6 +1261,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12861261 previous_candidate = Some ( leaf_candidate) ;
12871262 } ) ;
12881263 }
1264+
1265+ if refutable {
1266+ // In refutable cases there's always at least one candidate, and we want a false edge to
1267+ // the failure block.
1268+ previous_candidate. as_mut ( ) . unwrap ( ) . next_candidate_start_block = Some ( otherwise_block)
1269+ } else {
1270+ // Match checking ensures `otherwise_block` is actually unreachable in irrefutable
1271+ // cases.
1272+ let source_info = self . source_info ( scrutinee_span) ;
1273+
1274+ // Matching on a `scrutinee_place` with an uninhabited type doesn't
1275+ // generate any memory reads by itself, and so if the place "expression"
1276+ // contains unsafe operations like raw pointer dereferences or union
1277+ // field projections, we wouldn't know to require an `unsafe` block
1278+ // around a `match` equivalent to `std::intrinsics::unreachable()`.
1279+ // See issue #47412 for this hole being discovered in the wild.
1280+ //
1281+ // HACK(eddyb) Work around the above issue by adding a dummy inspection
1282+ // of `scrutinee_place`, specifically by applying `ReadForMatch`.
1283+ //
1284+ // NOTE: ReadForMatch also checks that the scrutinee is initialized.
1285+ // This is currently needed to not allow matching on an uninitialized,
1286+ // uninhabited value. If we get never patterns, those will check that
1287+ // the place is initialized, and so this read would only be used to
1288+ // check safety.
1289+ let cause_matched_place = FakeReadCause :: ForMatchedPlace ( None ) ;
1290+
1291+ if let Some ( scrutinee_place) = scrutinee_place_builder. try_to_place ( self ) {
1292+ self . cfg . push_fake_read (
1293+ otherwise_block,
1294+ source_info,
1295+ cause_matched_place,
1296+ scrutinee_place,
1297+ ) ;
1298+ }
1299+
1300+ self . cfg . terminate ( otherwise_block, source_info, TerminatorKind :: Unreachable ) ;
1301+ }
1302+
1303+ otherwise_block
12891304 }
12901305
12911306 /// The main match algorithm. It begins with a set of candidates
@@ -1992,21 +2007,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
19922007 ) -> BlockAnd < ( ) > {
19932008 let expr_span = self . thir [ expr_id] . span ;
19942009 let expr_place_builder = unpack ! ( block = self . lower_scrutinee( block, expr_id, expr_span) ) ;
1995- let wildcard = Pat :: wildcard_from_ty ( pat. ty ) ;
19962010 let mut guard_candidate = Candidate :: new ( expr_place_builder. clone ( ) , pat, false , self ) ;
1997- let mut otherwise_candidate =
1998- Candidate :: new ( expr_place_builder. clone ( ) , & wildcard, false , self ) ;
1999- self . lower_match_tree (
2011+ let otherwise_block = self . lower_match_tree (
20002012 block,
20012013 pat. span ,
20022014 & expr_place_builder,
20032015 pat. span ,
2004- & mut [ & mut guard_candidate, & mut otherwise_candidate] ,
2016+ & mut [ & mut guard_candidate] ,
2017+ true ,
20052018 ) ;
20062019 let expr_place = expr_place_builder. try_to_place ( self ) ;
20072020 let opt_expr_place = expr_place. as_ref ( ) . map ( |place| ( Some ( place) , expr_span) ) ;
2008- let otherwise_post_guard_block = otherwise_candidate. pre_binding_block . unwrap ( ) ;
2009- self . break_for_else ( otherwise_post_guard_block, self . source_info ( expr_span) ) ;
2021+ self . break_for_else ( otherwise_block, self . source_info ( expr_span) ) ;
20102022
20112023 if declare_bindings {
20122024 self . declare_bindings ( source_scope, pat. span . to ( span) , pat, None , opt_expr_place) ;
@@ -2022,7 +2034,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
20222034 ) ;
20232035
20242036 // If branch coverage is enabled, record this branch.
2025- self . visit_coverage_conditional_let ( pat, post_guard_block, otherwise_post_guard_block ) ;
2037+ self . visit_coverage_conditional_let ( pat, post_guard_block, otherwise_block ) ;
20262038
20272039 post_guard_block. unit ( )
20282040 }
@@ -2484,15 +2496,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24842496 let else_block_span = self . thir [ else_block] . span ;
24852497 let ( matching, failure) = self . in_if_then_scope ( * let_else_scope, else_block_span, |this| {
24862498 let scrutinee = unpack ! ( block = this. lower_scrutinee( block, init_id, initializer_span) ) ;
2487- let pat = Pat { ty : pattern. ty , span : else_block_span, kind : PatKind :: Wild } ;
2488- let mut wildcard = Candidate :: new ( scrutinee. clone ( ) , & pat, false , this) ;
24892499 let mut candidate = Candidate :: new ( scrutinee. clone ( ) , pattern, false , this) ;
2490- this. lower_match_tree (
2500+ let failure_block = this. lower_match_tree (
24912501 block,
24922502 initializer_span,
24932503 & scrutinee,
24942504 pattern. span ,
2495- & mut [ & mut candidate, & mut wildcard] ,
2505+ & mut [ & mut candidate] ,
2506+ true ,
24962507 ) ;
24972508 // This block is for the matching case
24982509 let matching = this. bind_pattern (
@@ -2503,13 +2514,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
25032514 None ,
25042515 true ,
25052516 ) ;
2506- // This block is for the failure case
2507- let failure = wildcard. pre_binding_block . unwrap ( ) ;
25082517
25092518 // If branch coverage is enabled, record this branch.
2510- this. visit_coverage_conditional_let ( pattern, matching, failure ) ;
2519+ this. visit_coverage_conditional_let ( pattern, matching, failure_block ) ;
25112520
2512- this. break_for_else ( failure , this. source_info ( initializer_span) ) ;
2521+ this. break_for_else ( failure_block , this. source_info ( initializer_span) ) ;
25132522 matching. unit ( )
25142523 } ) ;
25152524 matching. and ( failure)
0 commit comments