Reputation: 2062
Update: this is an old bug solved in 1.12
Here is some contrived but simple pattern matching example (demo):
fn main() {
let x = 'a';
match x {
'a'...'b' if false => {
println!("one");
},
'a' => {
println!("two");
},
'a'...'b' => {
println!("three");
},
_ => panic!("what?")
}
}
When I run it, I get three
as output. Why is this happening? Shouldn't the second branch match first?
Upvotes: 11
Views: 184
Reputation: 299890
Looking at the LLVM IR in Debug, it is already flawed, so this is definitely a bug in rustc
; we'll use the curated IR below to check what's going on.
So, %x
is assigned 'a' (97 in ASCII), and %10
is assigned the result of x >= 'a' and x <= 'b'
; if this is true, we go to match_case
, otherwise to compare_next
. match_case
redirect to cond
, which redirects to case_body2
which prints "three"
.
In theory, we would have wanted to go to case_body1
(printing "two"
), from cond7
, from match_case4
, from compare_next
. But compare_next
is only reached if x
is not in ['a', 'b']
according to the IR.
This clearly looks like a bug.
; Function Attrs: uwtable
define internal void @_ZN4main20h4f7b0d7962de19d8eaaE() unnamed_addr #0 {
entry-block:
%x = alloca i32
; [...]
store i32 97, i32* %x
%7 = load i32* %x, !range !0
%8 = icmp uge i32 %7, 97
%9 = icmp ule i32 %7, 98
%10 = and i1 %8, %9
br i1 %10, label %match_case, label %compare_next
case_body: ; preds = %next6, %next
; println!("one")
br label %case_body8
case_body1: ; preds = %cond7
; println!("two")
br label %case_body10
case_body2: ; preds = %cond
; println!("three")
br label %case_body15
case_body3: ; preds = %match_else
; panic!("what")
unreachable
match_else: ; preds = %compare_next5
br label %case_body3
match_case: ; preds = %entry-block
br i1 true, label %cond, label %next
compare_next: ; preds = %entry-block
%16 = icmp eq i32 %7, 97
br i1 %16, label %match_case4, label %compare_next5
next: ; preds = %match_case
br label %case_body
cond: ; preds = %match_case
br label %case_body2
match_case4: ; preds = %compare_next
br i1 true, label %cond7, label %next6
; [...]
cond7: ; preds = %match_case4
br label %case_body1
; [...]
}
Upvotes: 4