Are public fields and methods in private types meaningful?

Hi!

I was wondering if there was any situation where it would be required to make a field or method public inside of a private struct? I've been asking about this to some colleagues and we couldn't get any relevant example.

Take the following example as an illustration:

struct MyStruct {
    pub field: i32, // this `pub` is useless?
}

impl MyStruct {
    pub fn drop(self) {}  // this `pub` is useless?
}

If pub is never actualy useful inside of a private type I would gladly implement a lint for clippy or even rustc (which could be desired as having pub marked on some methods may lead to think that over methods are hidden at some level).

There's already a lint for this, it's just turned off by default.

#![warn(unreachable_pub)]

struct MyStruct {
    pub field: i32, // this `pub` is useless?
}

impl MyStruct {
    pub fn drop(self) {}  // this `pub` is useless?
}
warning: unreachable `pub` field
 --> src/lib.rs:4:5
  |
4 |     pub field: i32, // this `pub` is useless?
  |     ---^^^^^^^^^^^
  |     |
  |     help: consider restricting its visibility: `pub(crate)`
  |
note: the lint level is defined here
 --> src/lib.rs:1:9
  |
1 | #![warn(unreachable_pub)]
  |         ^^^^^^^^^^^^^^^

warning: unreachable `pub` item
 --> src/lib.rs:8:5
  |
8 |     pub fn drop(self) {}  // this `pub` is useless?
  |     ---^^^^^^^^^^^^^^
  |     |
  |     help: consider restricting its visibility: `pub(crate)`
2 Likes

It’s a bit of a different lint though. It doesn’t say anything about

#![warn(unreachable_pub)]

struct S;
impl S {
    pub(crate) fn foo() {}
}

and it does do a global analysis, e.g. it warns about

#![warn(unreachable_pub)]

mod m {
    pub fn foo() {}
}

but adding one (or a chain of) pub use that expose(s) the function publicly (on a crate level) makes the warning go away

#![warn(unreachable_pub)]

mod m {
    pub fn foo() {}
}
pub use m::foo as m_foo;

Thank for your answers, it sounds weird that unreachable_pub isn't turned on by default.

However the later case does require pub in pub fn foo() {}, overwise I get:

error[E0603]: function `foo` is private
  --> tt.rs:10:18
   |
10 | pub use self::m::foo as m_foo;
   |                  ^^^ private function

And this reexport makes m_foo callable from parent modules.


In this case I still don't understand how foo could be reached just by replacing pub by pub(crate) (which is only more restrictive, right?). Is this an issue with the lint?