rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
99.2k stars 12.81k forks source link

Dead code lint emits unused code warning for code that is clearly used. #39034

Open quadrupleslap opened 7 years ago

quadrupleslap commented 7 years ago

It looks like the dead code lint is too eager, and doesn't consider two signs that the variants are used:

Playground

use helpers::Animal;

#[forbid(dead_code)]
mod helpers {
    #[repr(u32)]
    pub enum Animal {
        Cat = 0,
        Dog = 1,
        Frog = 2
    }

    extern "C" {
        pub fn transmute_the_animal(animal: &mut Animal);
    }
}

fn main() {
    let mut animal = Animal::Cat;

    unsafe {
        helpers::transmute_the_animal(&mut animal);
    }

    match animal {
        Animal::Cat => println!("My cat didn't change! :("),
        Animal::Dog => println!("Yay. my cat became a dog!"),
        Animal::Frog => println!("Eww, my cat turned into a frog!")
    }
}

Expected: A clean build (I think.)

What I got:

rustc 1.16.0-nightly (2782e8f8f 2017-01-12)
error: variant is never used: `Dog`
  --> <anon>:13:9
   |
13 |         Dog = 1,
   |         ^^^^^^^
   |
note: lint level defined here
  --> <anon>:3:10
   |
3  | #[forbid(dead_code)]
   |          ^^^^^^^^^

error: variant is never used: `Frog`
  --> <anon>:14:9
   |
14 |         Frog = 2
   |         ^^^^^^^^

error: aborting due to 2 previous errors
Mark-Simulacrum commented 7 years ago

I think the underlying problem here is that we continue to reason about the enum variant after passing to external code (e.g., C code).

molenzwiebel commented 4 years ago

Hey there! I've been wanting to get my feet wet with rustc, figured I'd start to see if I can fix this issue.

From what I can see, there's several options that would mitigate this issue:

For the last option, this'd mean the following:

use helpers::Animal;

#[forbid(dead_code)]
mod helpers {
    #[repr(u32)]
    pub enum Animal {
        Cat = 0, // Used: constructed
        Dog = 1, // Used: as pattern
        Frog = 2 // Error: variant is never used
    }
}

fn main() {
    let animal = Animal::Cat;

    match animal {
        Animal::Dog => println!("Woof!"),
        _ => println!("Something else.")
    }
}

For the last option, we would additionally need to figure out whether we want this to apply to just enums or also ADTs with associated data.

Edit: The last option would also solve #56750.