Rust: cargo test incorrectly warns for dead code

Created on 29 Nov 2017  路  10Comments  路  Source: rust-lang/rust

Hi!

I got unexpected dead code warnings when executing cargo test with multiple test files. I use a very simple example below that reproduces the issue.

I have two files that contains tests, tests/test_one.rs and tests/test_two.rs. Both contains exactly the same content (except for the unique test function name they contain):

mod routines;

#[test]
fn test_one() {
    routines::my_routine();
}

And another file called tests/routines.rs that simply contains:

pub fn my_routine() {
}

When I execute cargo test, the two tests are executed successfully and there is no raised warning. But if I remove the my_routine() call from one of the two tests, cargo test stills end up successfully but raises a warning on pub fn routine() saying function is never used. However, one test still calls the function, so there is no dead code as stated.

I got the same issue with both rust stable (1.22.1) and rust nightly (1.24.0).

Thanks.

C-enhancement T-cargo

Most helpful comment

We are still encountering this issue with the last version of Rust (1.45.0 nightly)

All 10 comments

This is not actually a bug, as far as I know!

And another file called tests/routines.rs that simply contains:

Cargo is also attempting to compile this file as its own test. See the explanation here: https://doc.rust-lang.org/book/second-edition/ch11-03-test-organization.html#submodules-in-integration-tests

I believe if you move this file to tests/routines/mod.rs, this will work without warning.

Yes, when replacing tests/routines.rs by tests/routines/mod.rs, Cargo does not attempt to compile routines.rs as a test.

But, the warning is still raised at the first execution of cargo test (and only at the first execution).

Here the details of what I do after changing tests/routines.rs to tests/routines/mod.rs:

  1. execute cargo test multiple times with two calls to my_routine() (one in each test) -> no warning
  2. remove one call to my_routine() from one of the two tests
  3. execute cargo test -> one warning function is never used is raised for my_routine()
  4. execute cargo test again (without code modification) -> no warning anymore

For exactly the same code, cargo test outputs a warning only during the first execution. Furthermore, for each execution, the two tests are run so my_routine() is called. Maybe I just miss something, but this is kind of weird, isn't it ?

I believe cargo compiles each "integration test" (i.e. file in tests/*.rs) independently. So if the helper in a common module tests/routines/mod.rs is used in tests/test_one.rs, but not in tests/test_two.rs, there will be a warning when compiling test_two.rs.

(cargo test re-builds only what needs to be rebuilt, that's why it only warns on the first execution.)

I've worked around this by using mod routines; pub use routines::*; in tests/*.rs.

So we're running into the same issue and I think the workaround mod routines; pub use routines::*; is not optimal as that does hide truly dead code. I think this is a legitimate cargo bug.

This is either a bug or a design flaw.

In TypeScript, an exported item (even if it is never used) is never considered dead code. I don't why it is in Rust.

@KSXGitHub well, if you export the items from the crate with mod routines; pub use routines::*; it's not considered dead code.

What @svenstaro is asking for would require considering all targets/configurations before determining if an item is dead code instead of letting the rust compiler report them when compiling an individual crate...

I am noticing this issue,

when will the PR above be released in rust ? ^

We are encountering the same issue. I am not sure I am comfortable with no dead code warnings. Perhaps an alternative approach to organizing code people would suggest if there is no re-design any time soon?

If the module is implemented in tests/routines/mod.rs, just using pub mod routines;, in every test file that I wish to use routines module, solved the problem for me. This works as expected, imo, because:

  1. It allows to declare a shared module for different tests
  2. Does not report unused code warning if you don't use all the functions from the shared module, which is good, imo
  3. Does not report unused code warning in the test file that does not use routines at all.

So, it looks to me that exported stuff is also not considered a dead code in rust, but it needs to be declared/imported with pub.
There is a nice example of the similar use-case in the rust book: https://doc.rust-lang.org/1.29.2/book/2018-edition/ch07-02-controlling-visibility-with-pub.html.

We are still encountering this issue with the last version of Rust (1.45.0 nightly)

Was this page helpful?
0 / 5 - 0 ratings