Tracking issue for private_in_public
compatibility lint. #34537
Description
What is this lint about
RFC 136 describes rules for using private types and traits in interfaces of public items. The main idea is that an entity restricted to some module cannot be used outside of that module. Private items are considered restricted to the module they are defined in, pub
items are considered unrestricted and being accessible for all the universe of crates, RFC 1422 describes some more fine-grained restrictions. Note that the restrictions are determined entirely by item's declarations and don't require any reexport traversal and reachability analysis. "Used" means different things for different entities, for example private modules simply can't be named outside of their module, private types can't be named and additionally values of their type cannot be obtained outside of their module, etc. To enforce these rules more visible entities cannot contain less visible entities in their interfaces. Consider, for example, this function:
mod m {
struct S;
pub fn f() -> S { S } // ERROR
}
If this were allowed, then values of private type S
could leave its module.
Despite the RFC being accepted these rules were not completely enforced until #29973 fixed most of the missing cases. Some more missing cases were covered later by PRs #32674 and #31362. For backward compatibility the new errors were reported as warnings (lints). Now it's time to retire these warnings and turn them into hard errors, which they are supposed to be.
This issue also tracks another very similar lint, pub_use_of_private_extern_crate
, checking for a specific "private-in-public" situation.
How to fix this warning/error
If you really want to use some private unnameable type or trait in a public interface, for example to emulate sealed traits, then there's a universal workaround - make the item public, but put it into a private inner module.
mod m {
mod detail {
pub trait Float {}
impl Float for f32 {}
impl Float for f64 {}
}
pub fn multiply_by_2<T: detail::Float>(arg: T) { .... } // OK
}
The trait Float
is public from the private-in-public checker's point of view, because it uses only local reasoning, however Float
is unnameable from outside of m
and effectively private, because it isn't actually reexported from m
despite being potentially reexportable.
You'll also have to manually document what kind of mystery set of arguments your public function multiply_by_2
accepts, because unnameable traits are effectively private for rustdoc.
Current status
- privacy: Rewrite VisiblePrivateTypesVisitor #29973 introduces the
private_in_public
lint as warn-by-default - Make
private_in_public
compatibility lint deny-by-default #34206 makes theprivate_in_public
lint deny-by-default - Make
private_in_public
compatibility lint warn-by-default again #36270 makes theprivate_in_public
lint warn-by-default again due to relatively large amount of breakage - PR ? makes the
private_in_public
lint deny-by-default - PR ? makes the
private_in_public
lint a hard error
Metadata
Assignees
Labels
Type
Projects
Status
Idea