Open
Description
I tried this code:
#[repr(u8)]
pub enum FooBar {
Foo(i32),
Bar(String),
}
impl FooBar {
fn discriminant(&self) -> u8 {
unsafe { *(self as *const Self as *const u8) }
}
}
fn main() {
println!("{}", FooBar::Foo as u8);
println!("{}", FooBar::Bar as u8);
println!("{}", FooBar::Foo(42).discriminant());
println!("{}", FooBar::Bar("baz".to_owned()).discriminant());
}
I expected to see this happen: The code should fail to compile, as casting to u8 for this enum is not allowed.
Instead, this happened: code compiles fine, and prints garbage. The garbage printed appears to be part of the address of the function that would instantiate the respective variant of the enum. As there are no warnings issued, this can be very nasty. Clippy does detect this and correctly warns.
Playground for easy reproduction on any compiler of choice.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3e3b23e01f545caf4f4fc88ab45edd61
Note
- Making any one field not contain any value will make this fail to compile (which is the expected result)
- This can be especially nasty if you have an enum with no payload in any of the fields (which is safe to cast) and then add payload to all of the fields. The code will still compile, even though its meaning has changed completely.