Skip to content

Commit 1612594

Browse files
bkirwicarolynzech
andauthored
Fix a bug codegening SwitchInts with only an otherwise branch (#4095)
The first commit adds a failing test: it exposes a bug dealing with dropping single-variant enums. ``` thread 'rustc' panicked at kani-compiler/src/codegen_cprover_gotoc/codegen/statement.rs:499:9: assertion failed: targets.len() > 1 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Kani unexpectedly panicked during compilation. Please file an issue here: https://github.com/model-checking/kani/issues/new?labels=bug&template=bug_report.md [Kani] current codegen item: codegen_function: std::ptr::drop_in_place::<Reference> _RINvNtCs4AkhfejoRTd_4core3ptr13drop_in_placeNtCs6S0fALEP9ee_19single_variant_enum9ReferenceEBI_ [Kani] current codegen location: Loc { file: "/Users/bkirwi/.rustup/toolchains/nightly-2025-05-20-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ptr/mod.rs", function: None, start_line: 524, start_col: Some(1), end_line: 524, end_col: Some(56), pragmas: [] } error: /Users/bkirwi/Code/kani/target/kani/bin/kani-compiler exited with status exit status: 101 ``` This seems to affect both `main` and the latest release. Resolves #4103 --------- Co-authored-by: Carolyn Zech <[email protected]>
1 parent 1c7dedc commit 1612594

File tree

2 files changed

+45
-26
lines changed

2 files changed

+45
-26
lines changed

kani-compiler/src/codegen_cprover_gotoc/codegen/statement.rs

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -497,32 +497,39 @@ impl GotocCtx<'_> {
497497
let switch_ty = v.typ().clone();
498498

499499
// Switches with empty branches should've been eliminated already.
500-
assert!(targets.len() > 1);
501-
if targets.len() == 2 {
502-
// Translate to a guarded goto
503-
let (case, first_target) = targets.branches().next().unwrap();
504-
Stmt::block(
505-
vec![
506-
v.eq(Expr::int_constant(case, switch_ty)).if_then_else(
507-
Stmt::goto(bb_label(first_target), loc),
508-
None,
509-
loc,
510-
),
511-
Stmt::goto(bb_label(targets.otherwise()), loc),
512-
],
513-
loc,
514-
)
515-
} else {
516-
let cases = targets
517-
.branches()
518-
.map(|(c, bb)| {
519-
Expr::int_constant(c, switch_ty.clone())
520-
.with_location(loc)
521-
.switch_case(Stmt::goto(bb_label(bb), loc))
522-
})
523-
.collect();
524-
let default = Stmt::goto(bb_label(targets.otherwise()), loc);
525-
v.switch(cases, Some(default), loc)
500+
match targets.len() {
501+
0 => unreachable!("switches have at least one target"),
502+
1 => {
503+
// Trivial switch.
504+
Stmt::goto(bb_label(targets.otherwise()), loc)
505+
}
506+
2 => {
507+
// Translate to a guarded goto
508+
let (case, first_target) = targets.branches().next().unwrap();
509+
Stmt::block(
510+
vec![
511+
v.eq(Expr::int_constant(case, switch_ty)).if_then_else(
512+
Stmt::goto(bb_label(first_target), loc),
513+
None,
514+
loc,
515+
),
516+
Stmt::goto(bb_label(targets.otherwise()), loc),
517+
],
518+
loc,
519+
)
520+
}
521+
3.. => {
522+
let cases = targets
523+
.branches()
524+
.map(|(c, bb)| {
525+
Expr::int_constant(c, switch_ty.clone())
526+
.with_location(loc)
527+
.switch_case(Stmt::goto(bb_label(bb), loc))
528+
})
529+
.collect();
530+
let default = Stmt::goto(bb_label(targets.otherwise()), loc);
531+
v.switch(cases, Some(default), loc)
532+
}
526533
}
527534
}
528535

tests/kani/SwitchInt/main.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,15 @@ fn main() {
3838
let v = doswitch_bytes();
3939
assert!(v == 1);
4040
}
41+
42+
// Check that Kani can codegen a SwitchInt that has no targets (only an otherwise)
43+
// c.f. https://github.com/model-checking/kani/issues/4103
44+
pub enum Reference {
45+
ByName { alias: String },
46+
}
47+
48+
#[kani::proof]
49+
fn check_nontrivial_drop() {
50+
let result: Reference = Reference::ByName { alias: "foo".into() };
51+
drop(result)
52+
}

0 commit comments

Comments
 (0)