@@ -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 (
@@ -691,6 +692,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
691
692
& initializer,
692
693
irrefutable_pat. span ,
693
694
& mut [ & mut candidate] ,
695
+ false ,
694
696
) ;
695
697
self . bind_pattern (
696
698
self . source_info ( irrefutable_pat. span ) ,
@@ -1215,52 +1217,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1215
1217
///
1216
1218
/// Modifies `candidates` to store the bindings and type ascriptions for
1217
1219
/// 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.
1218
1224
fn lower_match_tree < ' pat > (
1219
1225
& mut self ,
1220
1226
block : BasicBlock ,
1221
1227
scrutinee_span : Span ,
1222
1228
scrutinee_place_builder : & PlaceBuilder < ' tcx > ,
1223
1229
match_start_span : Span ,
1224
1230
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.
1229
1234
let otherwise_block = self . cfg . start_new_block ( ) ;
1230
1235
1231
1236
// This will generate code to test scrutinee_place and branch to the appropriate arm block
1232
1237
self . match_candidates ( match_start_span, scrutinee_span, block, otherwise_block, candidates) ;
1233
1238
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
-
1264
1239
// Link each leaf candidate to the `false_edge_start_block` of the next one.
1265
1240
let mut previous_candidate: Option < & mut Candidate < ' _ , ' _ > > = None ;
1266
1241
for candidate in candidates {
@@ -1272,6 +1247,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1272
1247
previous_candidate = Some ( leaf_candidate) ;
1273
1248
} ) ;
1274
1249
}
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
1275
1290
}
1276
1291
1277
1292
/// The main match algorithm. It begins with a set of candidates
@@ -1978,21 +1993,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1978
1993
) -> BlockAnd < ( ) > {
1979
1994
let expr_span = self . thir [ expr_id] . span ;
1980
1995
let expr_place_builder = unpack ! ( block = self . lower_scrutinee( block, expr_id, expr_span) ) ;
1981
- let wildcard = Pat :: wildcard_from_ty ( pat. ty ) ;
1982
1996
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 (
1986
1998
block,
1987
1999
pat. span ,
1988
2000
& expr_place_builder,
1989
2001
pat. span ,
1990
- & mut [ & mut guard_candidate, & mut otherwise_candidate] ,
2002
+ & mut [ & mut guard_candidate] ,
2003
+ true ,
1991
2004
) ;
1992
2005
let expr_place = expr_place_builder. try_to_place ( self ) ;
1993
2006
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) ) ;
1996
2008
1997
2009
if declare_bindings {
1998
2010
self . declare_bindings ( source_scope, pat. span . to ( span) , pat, None , opt_expr_place) ;
@@ -2008,7 +2020,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2008
2020
) ;
2009
2021
2010
2022
// 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 ) ;
2012
2024
2013
2025
post_guard_block. unit ( )
2014
2026
}
@@ -2470,15 +2482,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2470
2482
let else_block_span = self . thir [ else_block] . span ;
2471
2483
let ( matching, failure) = self . in_if_then_scope ( * let_else_scope, else_block_span, |this| {
2472
2484
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) ;
2475
2485
let mut candidate = Candidate :: new ( scrutinee. clone ( ) , pattern, false , this) ;
2476
- this. lower_match_tree (
2486
+ let failure_block = this. lower_match_tree (
2477
2487
block,
2478
2488
initializer_span,
2479
2489
& scrutinee,
2480
2490
pattern. span ,
2481
- & mut [ & mut candidate, & mut wildcard] ,
2491
+ & mut [ & mut candidate] ,
2492
+ true ,
2482
2493
) ;
2483
2494
// This block is for the matching case
2484
2495
let matching = this. bind_pattern (
@@ -2489,13 +2500,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2489
2500
None ,
2490
2501
true ,
2491
2502
) ;
2492
- // This block is for the failure case
2493
- let failure = wildcard. pre_binding_block . unwrap ( ) ;
2494
2503
2495
2504
// 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 ) ;
2497
2506
2498
- this. break_for_else ( failure , this. source_info ( initializer_span) ) ;
2507
+ this. break_for_else ( failure_block , this. source_info ( initializer_span) ) ;
2499
2508
matching. unit ( )
2500
2509
} ) ;
2501
2510
matching. and ( failure)
0 commit comments