@@ -329,6 +329,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
329
329
& scrutinee_place,
330
330
match_start_span,
331
331
& mut candidates,
332
+ false ,
332
333
) ;
333
334
334
335
self . lower_match_arms (
@@ -694,6 +695,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
694
695
& initializer,
695
696
irrefutable_pat. span ,
696
697
& mut [ & mut candidate] ,
698
+ false ,
697
699
) ;
698
700
self . bind_pattern (
699
701
self . source_info ( irrefutable_pat. span ) ,
@@ -1229,52 +1231,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1229
1231
///
1230
1232
/// Modifies `candidates` to store the bindings and type ascriptions for
1231
1233
/// 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.
1232
1238
fn lower_match_tree < ' pat > (
1233
1239
& mut self ,
1234
1240
block : BasicBlock ,
1235
1241
scrutinee_span : Span ,
1236
1242
scrutinee_place_builder : & PlaceBuilder < ' tcx > ,
1237
1243
match_start_span : Span ,
1238
1244
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.
1243
1248
let otherwise_block = self . cfg . start_new_block ( ) ;
1244
1249
1245
1250
// This will generate code to test scrutinee_place and branch to the appropriate arm block
1246
1251
self . match_candidates ( match_start_span, scrutinee_span, block, otherwise_block, candidates) ;
1247
1252
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
-
1278
1253
// Link each leaf candidate to the `false_edge_start_block` of the next one.
1279
1254
let mut previous_candidate: Option < & mut Candidate < ' _ , ' _ > > = None ;
1280
1255
for candidate in candidates {
@@ -1286,6 +1261,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1286
1261
previous_candidate = Some ( leaf_candidate) ;
1287
1262
} ) ;
1288
1263
}
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
1289
1304
}
1290
1305
1291
1306
/// The main match algorithm. It begins with a set of candidates
@@ -1992,21 +2007,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1992
2007
) -> BlockAnd < ( ) > {
1993
2008
let expr_span = self . thir [ expr_id] . span ;
1994
2009
let expr_place_builder = unpack ! ( block = self . lower_scrutinee( block, expr_id, expr_span) ) ;
1995
- let wildcard = Pat :: wildcard_from_ty ( pat. ty ) ;
1996
2010
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 (
2000
2012
block,
2001
2013
pat. span ,
2002
2014
& expr_place_builder,
2003
2015
pat. span ,
2004
- & mut [ & mut guard_candidate, & mut otherwise_candidate] ,
2016
+ & mut [ & mut guard_candidate] ,
2017
+ true ,
2005
2018
) ;
2006
2019
let expr_place = expr_place_builder. try_to_place ( self ) ;
2007
2020
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) ) ;
2010
2022
2011
2023
if declare_bindings {
2012
2024
self . declare_bindings ( source_scope, pat. span . to ( span) , pat, None , opt_expr_place) ;
@@ -2022,7 +2034,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2022
2034
) ;
2023
2035
2024
2036
// 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 ) ;
2026
2038
2027
2039
post_guard_block. unit ( )
2028
2040
}
@@ -2484,15 +2496,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2484
2496
let else_block_span = self . thir [ else_block] . span ;
2485
2497
let ( matching, failure) = self . in_if_then_scope ( * let_else_scope, else_block_span, |this| {
2486
2498
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) ;
2489
2499
let mut candidate = Candidate :: new ( scrutinee. clone ( ) , pattern, false , this) ;
2490
- this. lower_match_tree (
2500
+ let failure_block = this. lower_match_tree (
2491
2501
block,
2492
2502
initializer_span,
2493
2503
& scrutinee,
2494
2504
pattern. span ,
2495
- & mut [ & mut candidate, & mut wildcard] ,
2505
+ & mut [ & mut candidate] ,
2506
+ true ,
2496
2507
) ;
2497
2508
// This block is for the matching case
2498
2509
let matching = this. bind_pattern (
@@ -2503,13 +2514,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2503
2514
None ,
2504
2515
true ,
2505
2516
) ;
2506
- // This block is for the failure case
2507
- let failure = wildcard. pre_binding_block . unwrap ( ) ;
2508
2517
2509
2518
// 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 ) ;
2511
2520
2512
- this. break_for_else ( failure , this. source_info ( initializer_span) ) ;
2521
+ this. break_for_else ( failure_block , this. source_info ( initializer_span) ) ;
2513
2522
matching. unit ( )
2514
2523
} ) ;
2515
2524
matching. and ( failure)
0 commit comments