Why does this produce the dead code warnings it does?

If I do this:

const A: i32 = 323i32;
const fn a_ref() -> & 'static i32 { &A }
static B: &'static i32 = a_ref();

fn main() -> () {
    // With the following line uncommented there's no dead code
    // let _b = B.clone();
    
}

I get the following warnings:

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
warning: constant `A` is never used
 --> src/main.rs:1:7
  |
1 | const A: i32 = 323i32;
  |       ^
  |
  = note: `#[warn(dead_code)]` on by default

warning: function `a_ref` is never used
 --> src/main.rs:2:10
  |
2 | const fn a_ref() -> & 'static i32 { &A }
  |          ^^^^^

warning: static `B` is never used
 --> src/main.rs:3:8
  |
3 | static B: &'static i32 = a_ref();
  |        ^

warning: `playground` (bin "playground") generated 3 warnings
    Finished dev [unoptimized + debuginfo] target(s) in 0.88s
     Running `target/debug/playground`

I understand that B is dead code because I don't use it anywhere. But why aren't a_ref and A used?

In the Rust Reference, it says that " The static initializer is a constant expression evaluated at compile time." I would have thought that applied here.

Code that is only used by unused code is also considered unused code.

5 Likes

You only use A within a_ref.

But as you don't use a_ref, you never use A.

a_ref and A are not pub, so no one else can use them either.

Thus the compiler can tell they're dead code that need not be in the compiled output.

1 Like

I'm confused; I thought I used a_ref here in the initializer? Maybe I'm misunderstanding what "used" entails?

Does this mean the initializer doesn't get evaluated, or just that the compiler is warning me?

I guess what I'm trying to figure out is whether the initializer of B does not constitute "use".

Fair point, you did use it to initialize B. But const fn aren't allowed to have side effects (so far and as far as I know that's the plan going forward), so it's still valid to optimize the call out (and consider the function unused) if B is never used.

It's dead code from the POV of the compiled program, even if it happened to be ran by the compiler in the course of compilation. [1]

Try putting pub in front of each of const A, const fn as_ref, and static B and you can see how reachability changes what code is considered dead.


  1. I'm not actually sure if it's smart enough to just not do that too, honestly. ↩ī¸Ž

1 Like

Not sure why you initially asked, but as a side note, I do sometimes run

RUSTFLAGS='-A unused' cargo check ...

to silence the lint when in the middle of development or refactoring, as the dead code warnings can be quite noisy. (But I never add it to a committed file and pay attention when at a good waypoint, because the dead code checks have also caught numerous privacy-whoopses and logic errors for me.)

3 Likes

Yes, you are. Unused-ness is transitive — if you only "use" something from code that is itself unused, then it's also unused.

2 Likes