Fix an assertion failure with an empty Switch (#5650)
Fix an error introduced in #5644, where an unsigned subtraction from zero was possible with an empty Switch structure. Additionally, missing the empty case caused us to not emit a branch to the default block. This PR fixes the issue by detecting the empty Switch case early, and emitting a jump.
This commit is contained in:
@@ -114,6 +114,12 @@ impl Switch {
|
|||||||
otherwise: Block,
|
otherwise: Block,
|
||||||
contiguous_case_ranges: &'a [ContiguousCaseRange],
|
contiguous_case_ranges: &'a [ContiguousCaseRange],
|
||||||
) {
|
) {
|
||||||
|
// If no switch cases were added to begin with, we can just emit `jump otherwise`.
|
||||||
|
if contiguous_case_ranges.is_empty() {
|
||||||
|
bx.ins().jump(otherwise, &[]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid allocation in the common case
|
// Avoid allocation in the common case
|
||||||
if contiguous_case_ranges.len() <= 3 {
|
if contiguous_case_ranges.len() <= 3 {
|
||||||
Self::build_search_branches(bx, val, otherwise, contiguous_case_ranges);
|
Self::build_search_branches(bx, val, otherwise, contiguous_case_ranges);
|
||||||
@@ -159,9 +165,8 @@ impl Switch {
|
|||||||
otherwise: Block,
|
otherwise: Block,
|
||||||
contiguous_case_ranges: &'a [ContiguousCaseRange],
|
contiguous_case_ranges: &'a [ContiguousCaseRange],
|
||||||
) {
|
) {
|
||||||
let last_ix = contiguous_case_ranges.len() - 1;
|
for (ix, range) in contiguous_case_ranges.iter().enumerate().rev() {
|
||||||
for (ix, range) in contiguous_case_ranges.iter().rev().enumerate() {
|
let alternate = if ix == 0 {
|
||||||
let alternate = if ix == last_ix {
|
|
||||||
otherwise
|
otherwise
|
||||||
} else {
|
} else {
|
||||||
bx.create_block()
|
bx.create_block()
|
||||||
@@ -343,6 +348,7 @@ mod tests {
|
|||||||
let block = bx.create_block();
|
let block = bx.create_block();
|
||||||
bx.switch_to_block(block);
|
bx.switch_to_block(block);
|
||||||
let val = bx.ins().iconst(types::I8, 0);
|
let val = bx.ins().iconst(types::I8, 0);
|
||||||
|
#[allow(unused_mut)]
|
||||||
let mut switch = Switch::new();
|
let mut switch = Switch::new();
|
||||||
$(
|
$(
|
||||||
let block = bx.create_block();
|
let block = bx.create_block();
|
||||||
@@ -360,18 +366,28 @@ mod tests {
|
|||||||
|
|
||||||
macro_rules! assert_eq_output {
|
macro_rules! assert_eq_output {
|
||||||
($actual:ident, $expected:literal) => {
|
($actual:ident, $expected:literal) => {
|
||||||
if $actual != $expected {
|
assert_eq!(
|
||||||
assert!(
|
$actual,
|
||||||
false,
|
$expected,
|
||||||
"\n{}",
|
"\n{}",
|
||||||
similar::TextDiff::from_lines($expected, &$actual)
|
similar::TextDiff::from_lines($expected, &$actual)
|
||||||
.unified_diff()
|
.unified_diff()
|
||||||
.header("expected", "actual")
|
.header("expected", "actual")
|
||||||
);
|
)
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn switch_empty() {
|
||||||
|
let func = setup!(42, []);
|
||||||
|
assert_eq_output!(
|
||||||
|
func,
|
||||||
|
"block0:
|
||||||
|
v0 = iconst.i8 0
|
||||||
|
jump block42"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn switch_zero() {
|
fn switch_zero() {
|
||||||
let func = setup!(0, [0,]);
|
let func = setup!(0, [0,]);
|
||||||
|
|||||||
Reference in New Issue
Block a user