3

I found out that I have some dead code in my code base but a not getting a dead code warning as expected. I read the Visibility and Privacy article from the rust book. I am following the example on creating a "helper module" with code to be used in the crate but not exposed in the public API.

Here is a simplified example of what I think is happening:

// private module for in-crate usage only
mod foo {
    // everything in the module is pub
    pub struct Foo {}

    impl Foo {
        // I expect to see a dead code warning here. Where is it? ...
        pub fn dead_code() {}
    }
}

use foo::Foo;

// Uh oh, I'm leaking my helper module here!
// But I'm having trouble finding where this occurs in my large code base :(
pub fn get_foo() -> Foo {
    Foo {}
}

My question: How do I find the code (get_foo) that is "leaking" as public what I intended to be crate-public (Foo)? In a real example, there could be one "leak" that has a domino effect of leaking related types.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
cambunctious
  • 8,391
  • 5
  • 34
  • 53
  • 2
    Maybe try changing `pub` to `pub(crate)` to further restrict it? - although I'm not sure if I 100% follow what you're asking... – Peter Hall Jun 04 '20 at 22:57
  • 2
    If the code is used by other (public) functions then it isn't dead. – Peter Hall Jun 04 '20 at 23:00
  • @PeterHall Yes I could change Foo to pub(crate). The issue is that I want to be aware of ALL cases where a struct in a private module is made public somehow. I could just mark all such entities as pub(crate), but that seems like bad practice and is not the convention suggested by the rust book. For dead code, I am referring to code that is not used anywhere in the crate. – cambunctious Jun 05 '20 at 01:01
  • **If a module is private, this doesn't imply that its content is private as well**. If you want to ensure that a type isn't exposed to the public API, you have to restrict its visibility (e.g. with `pub(crate)`). It's NOT enough to make its module private. – Aloso Jun 05 '20 at 07:58
  • I opened a PR to the rust reference if anyone is interested - https://github.com/rust-lang/reference/pull/830 – cambunctious Jun 09 '20 at 15:12

1 Answers1

3

pub(crate) is idiomatic, and would solve your problem.

// helper module for in-crate usage only
mod foo {
    pub(crate) struct Foo {}

    impl Foo {
        // Dead code warning!
        pub(crate) fn dead_code() {}
    }
}

use foo::Foo;

// pub(crate) prevents leaking helper module here!
pub(crate) fn get_foo() -> Foo {
    Foo{}
}

This code generates (multiple) dead code warnings

To demonstrate that pub(crate) prevents leaking non-pub items, changing the last function to

pub fn get_foo() -> Foo {
    Foo{}
}

gives a compile error - error[E0446]: crate-visible type foo::Foo in public interface

I think the book's example doesn't suggest using pub(crate) because that section was written before the book introduced the idea of pub(restricted). If you look at the RFC for pub(restricted), it specifically calls out what you did

(2.) you can define X as a pub item in some submodule (and import into the root of the module tree via use).

But: Sometimes neither of these options is really what you want.

asky
  • 1,520
  • 12
  • 20
  • Thanks! You are exactly right about the book. (Actually I just noticed it is the rust _reference_, not the book.) That section has not been updated since `pub(restricted)` was stabilized. A section about that feature is there, but the part about "helper module" still seems misleading. Anyways, I will adjust my practice to use `pub(restricted)` more liberally. – cambunctious Jun 05 '20 at 13:52