@@ -1093,8 +1093,6 @@ struct Candidate<'pat, 'tcx> {
10931093 /// The earliest block that has only candidates >= this one as descendents. Used for false
10941094 /// edges, see the doc for [`Builder::match_expr`].
10951095 false_edge_start_block : Option < BasicBlock > ,
1096- /// The `false_edge_start_block` of the next candidate.
1097- next_candidate_start_block : Option < BasicBlock > ,
10981096}
10991097
11001098impl < ' tcx , ' pat > Candidate < ' pat , ' tcx > {
@@ -1120,7 +1118,6 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
11201118 otherwise_block : None ,
11211119 pre_binding_block : None ,
11221120 false_edge_start_block : None ,
1123- next_candidate_start_block : None ,
11241121 }
11251122 }
11261123
@@ -1344,12 +1341,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13441341 let otherwise_block =
13451342 self . match_candidates ( match_start_span, scrutinee_span, block, candidates) ;
13461343
1347- // Link each leaf candidate to the `false_edge_start_block` of the next one. In the
1348- // refutable case we also want a false edge to the failure block.
1344+ // Set up false edges so that the borrow-checker cannot make use of the specific CFG we
1345+ // generated. We falsely branch from each candidate to the one below it to make it as if we
1346+ // were testing match branches one by one in order. In the refutable case we also want a
1347+ // false edge to the final failure block.
13491348 let mut next_candidate_start_block = if refutable { Some ( otherwise_block) } else { None } ;
13501349 for candidate in candidates. iter_mut ( ) . rev ( ) {
1350+ let has_guard = candidate. has_guard ;
13511351 candidate. visit_leaves_rev ( |leaf_candidate| {
1352- leaf_candidate. next_candidate_start_block = next_candidate_start_block;
1352+ if let Some ( next_candidate_start_block) = next_candidate_start_block {
1353+ let source_info = self . source_info ( leaf_candidate. extra_data . span ) ;
1354+ // Falsely branch to `next_candidate_start_block` before reaching pre_binding.
1355+ let old_pre_binding = leaf_candidate. pre_binding_block . unwrap ( ) ;
1356+ let new_pre_binding = self . cfg . start_new_block ( ) ;
1357+ self . false_edges (
1358+ old_pre_binding,
1359+ new_pre_binding,
1360+ next_candidate_start_block,
1361+ source_info,
1362+ ) ;
1363+ leaf_candidate. pre_binding_block = Some ( new_pre_binding) ;
1364+ if has_guard {
1365+ // Falsely branch to `next_candidate_start_block` also if the guard fails.
1366+ let new_otherwise = self . cfg . start_new_block ( ) ;
1367+ let old_otherwise = leaf_candidate. otherwise_block . unwrap ( ) ;
1368+ self . false_edges (
1369+ new_otherwise,
1370+ old_otherwise,
1371+ next_candidate_start_block,
1372+ source_info,
1373+ ) ;
1374+ leaf_candidate. otherwise_block = Some ( new_otherwise) ;
1375+ }
1376+ }
13531377 assert ! ( leaf_candidate. false_edge_start_block. is_some( ) ) ;
13541378 next_candidate_start_block = leaf_candidate. false_edge_start_block ;
13551379 } ) ;
@@ -2135,20 +2159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21352159
21362160 debug_assert ! ( candidate. match_pairs. is_empty( ) ) ;
21372161
2138- let candidate_source_info = self . source_info ( candidate. extra_data . span ) ;
2139-
2140- let mut block = candidate. pre_binding_block . unwrap ( ) ;
2141-
2142- if candidate. next_candidate_start_block . is_some ( ) {
2143- let fresh_block = self . cfg . start_new_block ( ) ;
2144- self . false_edges (
2145- block,
2146- fresh_block,
2147- candidate. next_candidate_start_block ,
2148- candidate_source_info,
2149- ) ;
2150- block = fresh_block;
2151- }
2162+ let block = candidate. pre_binding_block . unwrap ( ) ;
21522163
21532164 if candidate. extra_data . is_never {
21542165 // This arm has a dummy body, we don't need to generate code for it. `block` is already
@@ -2215,16 +2226,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
22152226 self . cfg . push_fake_read ( post_guard_block, guard_end, cause, Place :: from ( temp) ) ;
22162227 }
22172228
2218- let otherwise_block = candidate. otherwise_block . unwrap_or_else ( || {
2219- let unreachable = self . cfg . start_new_block ( ) ;
2220- self . cfg . terminate ( unreachable, source_info, TerminatorKind :: Unreachable ) ;
2221- unreachable
2222- } ) ;
2223- self . false_edges (
2229+ self . cfg . goto (
22242230 otherwise_post_guard_block,
2225- otherwise_block,
2226- candidate. next_candidate_start_block ,
22272231 source_info,
2232+ candidate. otherwise_block . unwrap ( ) ,
22282233 ) ;
22292234
22302235 // We want to ensure that the matched candidates are bound
0 commit comments