Skip to content

Commit f875983

Browse files
authored
Rollup merge of #135409 - Shunpoco:issue-133117-ICE-never-false-edge-start-block, r=Nadrieril
Fix ICE-133117: multiple never-pattern arm doesn't have false_edge_start_block Fixes #133117 , and close fixes #133063 , fixes #130779 In order to fix ICE-133117, at first I needed to tackle to ICE-133063 (this fixed 130779 as well). ### ICE-133063 and ICE-130779 This ICE is caused by those steps: 1. An arm has or-pattern, and all of the sub-candidates are never-pattern 2. In that case, all sub-candidates are removed in remove_never_subcandidates(). So the arm (candidate) has no sub-candidate. 3. In the current implementation, if there is no sub-candidate, the function assigns `pre_binding_block` into the candidate ([here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_build/src/builder/matches/mod.rs#L2002-L2004)). However, otherwise_block should be assigned to the candidate as well, because the otherwise_block is unwrapped in multiple place (like in lower_match_tree()). As a result, it causes the panic. I simply added the same block as pre_binding_block into otherwise_block, but I'm wondering if there is a better block to assign to otherwise_block (is it ok to assign the same block into pre_binding and otherwise?) ### ICE-133117 This is caused by those steps: 1. There are two arms, both are or-pattern and each has one match-pair (in the test code, both are `(!|!)`), and the second arm has a guard. 2. In match_candidate() for the first arm, it expands the second arm’s sub-candidates as well ([here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_build/src/builder/matches/mod.rs#L1800-L1805)). As a result, the root candidate of the second arm is not evaluated/modified in match_candidate(). So a false_edge_start_block is not assigned to the candidate. 3. merge_trivial_subcandidates() is called against the candidate for the second arm. It just returns immediately because the candidate has a guard. So a flase_edge_start_block is not assigned to the candidate also in this function. 4. remove_never_subcandidates() is called against the candidate. Since all sub-candidates are never-pattern. they are removed. 5. In lower_match_tree(), since there is no sub-candidate for the candidate, the candidate itself is evaluated in visit_leave_rev ([here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_build/src/builder/matches/mod.rs#L1532)). Because the candidate has no false_edge_start_block, it causes the panic. So I modified the order of if blocks in merge_trivial_subcandidates() to assign a false_edge_start_block if the candidate doesn't have.
2 parents 9206ba5 + 7275bdf commit f875983

10 files changed

+115
-29
lines changed

compiler/rustc_mir_build/src/builder/matches/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
19861986
return;
19871987
}
19881988

1989+
let false_edge_start_block = candidate.subcandidates[0].false_edge_start_block;
19891990
candidate.subcandidates.retain_mut(|candidate| {
19901991
if candidate.extra_data.is_never {
19911992
candidate.visit_leaves(|subcandidate| {
@@ -2000,8 +2001,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
20002001
}
20012002
});
20022003
if candidate.subcandidates.is_empty() {
2003-
// If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`.
2004-
candidate.pre_binding_block = Some(self.cfg.start_new_block());
2004+
// If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block` and `otherwise_block`.
2005+
let next_block = self.cfg.start_new_block();
2006+
candidate.pre_binding_block = Some(next_block);
2007+
candidate.otherwise_block = Some(next_block);
2008+
// In addition, if `candidate` doesn't have `false_edge_start_block`, it should be assigned here.
2009+
if candidate.false_edge_start_block.is_none() {
2010+
candidate.false_edge_start_block = false_edge_start_block;
2011+
}
20052012
}
20062013
}
20072014

tests/crashes/130779.rs

-11
This file was deleted.

tests/crashes/133063.rs

-8
This file was deleted.

tests/crashes/133117.rs

-8
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(never_patterns)]
2+
#![allow(incomplete_features)]
3+
4+
enum E { A }
5+
6+
fn main() {
7+
match E::A {
8+
! | //~ ERROR: a trailing `|` is not allowed in an or-pattern
9+
//~^ ERROR: mismatched types
10+
if true => {} //~ ERROR: a never pattern is always unreachable
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error: a trailing `|` is not allowed in an or-pattern
2+
--> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:8:11
3+
|
4+
LL | ! |
5+
| - ^
6+
| |
7+
| while parsing this or-pattern starting here
8+
|
9+
help: remove the `|`
10+
|
11+
LL - ! |
12+
LL + !
13+
|
14+
15+
error: a never pattern is always unreachable
16+
--> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:10:20
17+
|
18+
LL | if true => {}
19+
| ^^
20+
| |
21+
| this will never be executed
22+
| help: remove this expression
23+
24+
error: mismatched types
25+
--> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:8:9
26+
|
27+
LL | ! |
28+
| ^ a never pattern must be used on an uninhabited type
29+
|
30+
= note: the matched value is of type `E`
31+
32+
error: aborting due to 3 previous errors
33+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![feature(never_type)]
2+
#![feature(never_patterns)]
3+
#![allow(incomplete_features)]
4+
5+
enum Void {}
6+
7+
fn foo(x: Void) {
8+
loop {
9+
match x {
10+
(!|!) if false => {} //~ ERROR a never pattern is always unreachable
11+
_ => {}
12+
}
13+
}
14+
}
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: a never pattern is always unreachable
2+
--> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:10:31
3+
|
4+
LL | (!|!) if false => {}
5+
| ^^
6+
| |
7+
| this will never be executed
8+
| help: remove this expression
9+
10+
error: aborting due to 1 previous error
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(never_type)]
2+
#![feature(never_patterns)]
3+
#![allow(incomplete_features)]
4+
5+
enum Void {}
6+
7+
fn foo(x: Void) {
8+
match x {
9+
(!|!) if true => {} //~ ERROR a never pattern is always unreachable
10+
(!|!) if true => {} //~ ERROR a never pattern is always unreachable
11+
}
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: a never pattern is always unreachable
2+
--> $DIR/ICE-133117-duplicate-never-arm.rs:9:26
3+
|
4+
LL | (!|!) if true => {}
5+
| ^^
6+
| |
7+
| this will never be executed
8+
| help: remove this expression
9+
10+
error: a never pattern is always unreachable
11+
--> $DIR/ICE-133117-duplicate-never-arm.rs:10:26
12+
|
13+
LL | (!|!) if true => {}
14+
| ^^
15+
| |
16+
| this will never be executed
17+
| help: remove this expression
18+
19+
error: aborting due to 2 previous errors
20+

0 commit comments

Comments
 (0)