@@ -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 (
@@ -691,6 +692,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
691692 & initializer,
692693 irrefutable_pat. span ,
693694 & mut [ & mut candidate] ,
695+ false ,
694696 ) ;
695697 self . bind_pattern (
696698 self . source_info ( irrefutable_pat. span ) ,
@@ -1215,52 +1217,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12151217 ///
12161218 /// Modifies `candidates` to store the bindings and type ascriptions for
12171219 /// that candidate.
1220+ ///
1221+ /// `refutable` indicates whether the candidate list is refutable (for `if let` and `let else`)
1222+ /// or not (for `let` and `match`). In the refutable case we return the block to which we branch
1223+ /// on failure.
12181224 fn lower_match_tree < ' pat > (
12191225 & mut self ,
12201226 block : BasicBlock ,
12211227 scrutinee_span : Span ,
12221228 scrutinee_place_builder : & PlaceBuilder < ' tcx > ,
12231229 match_start_span : Span ,
12241230 candidates : & mut [ & mut Candidate < ' pat , ' tcx > ] ,
1225- ) {
1226- // See the doc comment on `match_candidates` for why we have an
1227- // otherwise block. Match checking will ensure this is actually
1228- // unreachable.
1231+ refutable : bool ,
1232+ ) -> BasicBlock {
1233+ // See the doc comment on `match_candidates` for why we have an otherwise block.
12291234 let otherwise_block = self . cfg . start_new_block ( ) ;
12301235
12311236 // This will generate code to test scrutinee_place and branch to the appropriate arm block
12321237 self . match_candidates ( match_start_span, scrutinee_span, block, otherwise_block, candidates) ;
12331238
1234- let source_info = self . source_info ( scrutinee_span) ;
1235-
1236- // Matching on a `scrutinee_place` with an uninhabited type doesn't
1237- // generate any memory reads by itself, and so if the place "expression"
1238- // contains unsafe operations like raw pointer dereferences or union
1239- // field projections, we wouldn't know to require an `unsafe` block
1240- // around a `match` equivalent to `std::intrinsics::unreachable()`.
1241- // See issue #47412 for this hole being discovered in the wild.
1242- //
1243- // HACK(eddyb) Work around the above issue by adding a dummy inspection
1244- // of `scrutinee_place`, specifically by applying `ReadForMatch`.
1245- //
1246- // NOTE: ReadForMatch also checks that the scrutinee is initialized.
1247- // This is currently needed to not allow matching on an uninitialized,
1248- // uninhabited value. If we get never patterns, those will check that
1249- // the place is initialized, and so this read would only be used to
1250- // check safety.
1251- let cause_matched_place = FakeReadCause :: ForMatchedPlace ( None ) ;
1252-
1253- if let Some ( scrutinee_place) = scrutinee_place_builder. try_to_place ( self ) {
1254- self . cfg . push_fake_read (
1255- otherwise_block,
1256- source_info,
1257- cause_matched_place,
1258- scrutinee_place,
1259- ) ;
1260- }
1261-
1262- self . cfg . terminate ( otherwise_block, source_info, TerminatorKind :: Unreachable ) ;
1263-
12641239 // Link each leaf candidate to the `false_edge_start_block` of the next one.
12651240 let mut previous_candidate: Option < & mut Candidate < ' _ , ' _ > > = None ;
12661241 for candidate in candidates {
@@ -1272,6 +1247,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12721247 previous_candidate = Some ( leaf_candidate) ;
12731248 } ) ;
12741249 }
1250+
1251+ if refutable {
1252+ // In refutable cases there's always at least one candidate, and we want a false edge to
1253+ // the failure block.
1254+ previous_candidate. as_mut ( ) . unwrap ( ) . next_candidate_start_block = Some ( otherwise_block)
1255+ } else {
1256+ // Match checking ensures `otherwise_block` is actually unreachable in irrefutable
1257+ // cases.
1258+ let source_info = self . source_info ( scrutinee_span) ;
1259+
1260+ // Matching on a `scrutinee_place` with an uninhabited type doesn't
1261+ // generate any memory reads by itself, and so if the place "expression"
1262+ // contains unsafe operations like raw pointer dereferences or union
1263+ // field projections, we wouldn't know to require an `unsafe` block
1264+ // around a `match` equivalent to `std::intrinsics::unreachable()`.
1265+ // See issue #47412 for this hole being discovered in the wild.
1266+ //
1267+ // HACK(eddyb) Work around the above issue by adding a dummy inspection
1268+ // of `scrutinee_place`, specifically by applying `ReadForMatch`.
1269+ //
1270+ // NOTE: ReadForMatch also checks that the scrutinee is initialized.
1271+ // This is currently needed to not allow matching on an uninitialized,
1272+ // uninhabited value. If we get never patterns, those will check that
1273+ // the place is initialized, and so this read would only be used to
1274+ // check safety.
1275+ let cause_matched_place = FakeReadCause :: ForMatchedPlace ( None ) ;
1276+
1277+ if let Some ( scrutinee_place) = scrutinee_place_builder. try_to_place ( self ) {
1278+ self . cfg . push_fake_read (
1279+ otherwise_block,
1280+ source_info,
1281+ cause_matched_place,
1282+ scrutinee_place,
1283+ ) ;
1284+ }
1285+
1286+ self . cfg . terminate ( otherwise_block, source_info, TerminatorKind :: Unreachable ) ;
1287+ }
1288+
1289+ otherwise_block
12751290 }
12761291
12771292 /// The main match algorithm. It begins with a set of candidates
@@ -1978,21 +1993,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
19781993 ) -> BlockAnd < ( ) > {
19791994 let expr_span = self . thir [ expr_id] . span ;
19801995 let expr_place_builder = unpack ! ( block = self . lower_scrutinee( block, expr_id, expr_span) ) ;
1981- let wildcard = Pat :: wildcard_from_ty ( pat. ty ) ;
19821996 let mut guard_candidate = Candidate :: new ( expr_place_builder. clone ( ) , pat, false , self ) ;
1983- let mut otherwise_candidate =
1984- Candidate :: new ( expr_place_builder. clone ( ) , & wildcard, false , self ) ;
1985- self . lower_match_tree (
1997+ let otherwise_block = self . lower_match_tree (
19861998 block,
19871999 pat. span ,
19882000 & expr_place_builder,
19892001 pat. span ,
1990- & mut [ & mut guard_candidate, & mut otherwise_candidate] ,
2002+ & mut [ & mut guard_candidate] ,
2003+ true ,
19912004 ) ;
19922005 let expr_place = expr_place_builder. try_to_place ( self ) ;
19932006 let opt_expr_place = expr_place. as_ref ( ) . map ( |place| ( Some ( place) , expr_span) ) ;
1994- let otherwise_post_guard_block = otherwise_candidate. pre_binding_block . unwrap ( ) ;
1995- self . break_for_else ( otherwise_post_guard_block, self . source_info ( expr_span) ) ;
2007+ self . break_for_else ( otherwise_block, self . source_info ( expr_span) ) ;
19962008
19972009 if declare_bindings {
19982010 self . declare_bindings ( source_scope, pat. span . to ( span) , pat, None , opt_expr_place) ;
@@ -2008,7 +2020,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
20082020 ) ;
20092021
20102022 // If branch coverage is enabled, record this branch.
2011- self . visit_coverage_conditional_let ( pat, post_guard_block, otherwise_post_guard_block ) ;
2023+ self . visit_coverage_conditional_let ( pat, post_guard_block, otherwise_block ) ;
20122024
20132025 post_guard_block. unit ( )
20142026 }
@@ -2470,15 +2482,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24702482 let else_block_span = self . thir [ else_block] . span ;
24712483 let ( matching, failure) = self . in_if_then_scope ( * let_else_scope, else_block_span, |this| {
24722484 let scrutinee = unpack ! ( block = this. lower_scrutinee( block, init_id, initializer_span) ) ;
2473- let pat = Pat { ty : pattern. ty , span : else_block_span, kind : PatKind :: Wild } ;
2474- let mut wildcard = Candidate :: new ( scrutinee. clone ( ) , & pat, false , this) ;
24752485 let mut candidate = Candidate :: new ( scrutinee. clone ( ) , pattern, false , this) ;
2476- this. lower_match_tree (
2486+ let failure_block = this. lower_match_tree (
24772487 block,
24782488 initializer_span,
24792489 & scrutinee,
24802490 pattern. span ,
2481- & mut [ & mut candidate, & mut wildcard] ,
2491+ & mut [ & mut candidate] ,
2492+ true ,
24822493 ) ;
24832494 // This block is for the matching case
24842495 let matching = this. bind_pattern (
@@ -2489,13 +2500,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24892500 None ,
24902501 true ,
24912502 ) ;
2492- // This block is for the failure case
2493- let failure = wildcard. pre_binding_block . unwrap ( ) ;
24942503
24952504 // If branch coverage is enabled, record this branch.
2496- this. visit_coverage_conditional_let ( pattern, matching, failure ) ;
2505+ this. visit_coverage_conditional_let ( pattern, matching, failure_block ) ;
24972506
2498- this. break_for_else ( failure , this. source_info ( initializer_span) ) ;
2507+ this. break_for_else ( failure_block , this. source_info ( initializer_span) ) ;
24992508 matching. unit ( )
25002509 } ) ;
25012510 matching. and ( failure)
0 commit comments