-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking issue for private_in_public
compatibility lint.
#34537
Comments
Making |
Current status of crates from the regression report: 🌕 encoding - fixed, published |
@petrochenkov @nikomatsakis Any chance of flipping the switch to hard error this year? |
Not without implementing rust-lang/rfcs#1671 (or rather https://internals.rust-lang.org/t/rfc-reduce-false-positives-for-private-type-in-public-interface/3678) first, I suppose. |
Gah, I've been meaning to start a thread to discuss this topic in more depth! I had completely forgotten. |
@nikomatsakis You remembered just in time! 😆 |
Crater report shows 32 root regressions (out of which Some of them are old versions of |
I'll look at the fallout today or tomorrow. |
😞 Would it then make sense to use |
Using forbid for crater runs looks like a good idea. I've looked through about half of regressions, all looks legitimate and many are indeed due to nix and xml-rs. |
There may be another solution to all this private-in-public problem. Implement #30476 and make reporting of this kind of privacy errors late, as opposed to early/preventive as it is today. I expect less fallout from this, because things like this
won't report errors. All private-in-public errors in rustc_privacy (but not in resolve!) could be lowered to lints then, because early reporting is still useful for catching silly human errors. |
Yeah, that's a bit of a pickle. Not sure what the optimal solution is there, nothing obvious works. But that doesn't scale to resolutions of associated types through where clauses, which go through the trait machinery, and at that point you'd have to negate all the benefits of uniform semantical types to get accurate location information for everything. |
Oh, #30476 looks interesting. We can do it uniformly in inference writeback, is intra-function enough? |
A privacy pass simply needs to go through all HIR nodes and check their types* (somehow avoiding duplicated errors, but that's details). * At least adjusted types, not sure about non-adjusted. |
Is there a solution when one wants to have a private trait that has some functionality that only the library's structs should be able to implement. But still have a public function that can accept those library objects that implement the private trait. Because if one ignores the fn main() {
let foo = lib::Foo::new();
lib::print_foo(foo);
}
mod lib {
pub fn print_foo(view: impl PubView) {
println!("foo value: {}", view.value().value);
}
pub trait PubView: View {}
trait View {
fn value(&self) -> &Internal;
}
pub struct Foo {
value: Internal,
}
struct Internal {
value: u32,
}
impl Foo {
pub fn new() -> Self {
Self {
value: Internal { value: 1337 },
}
}
}
impl View for Foo {
fn value(&self) -> &Internal {
&self.value
}
}
impl PubView for Foo {}
} |
@Miha-Rozina sounds like you want the "Sealed Trait" pattern: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed Essentially, you have a public trait that "inherits" a private internal trait. This way, only you can implement the trait, but anyone can use it. |
But that means you need to make the |
Not necessarily, though it is a bit of a hack. |
Oh I see, I missed that! Yes that actually solves the issue I am having, thank you very much! It is a bit hacky though and I hope Rust gets a way to express this. The drawback of this hack is that public things in private module are actually public which means they don't trigger unused warnings when this is in a library. But since no one outside of the library cannot instantiate |
Why do I get a #![feature(generic_const_exprs)]
const fn bit_array_storage_size(bits_required: usize) -> usize {
todo!()
}
pub struct BitArray<const N: usize>
where
[usize; bit_array_storage_size(N)]: Sized,
{
storage: [usize; bit_array_storage_size(N)],
} |
I imagine this is because |
I'm unclear why a public trait cannot extend a private trait. In this example MyWriterPrivate is a helper trait with default fn's. use nested::MyLinearAlgebraPublic;
use nested::DefaultAlign;
fn my_func() {
let da : &dyn MyLinearAlgebraPublic = &DefaultAlign;
da.add_matrices();
}
mod nested {
trait MyWriterPrivate {
fn print_i32(&mut self, i: i32) {
println!("{i:<5}");
}
fn print_vec_i32(&mut self, vec: &Vec<i32>) {
for &item in vec {
self.print_i32(item);
}
}
}
// public interface
// this now gives a warning "private trait `MyWriterPrivate` in public interface (error E0445)"
pub trait MyLinearAlgebraPublic: MyWriterPrivate {
fn print_matrix(&mut self, mat: &Vec<Vec<i32>>) {
for vec in mat {
self.print_vec_i32(vec);
}
}
fn multiply_matrices(&self) {}
fn add_matrices(&self) {}
}
pub struct DefaultAlign;
pub struct RightAlign;
impl MyWriterPrivate for DefaultAlign {}
impl MyWriterPrivate for RightAlign {
fn print_i32(&mut self, i: i32) {
println!("{i:<5}");
}
}
impl MyLinearAlgebraPublic for DefaultAlign {
fn multiply_matrices(&self) {}
fn add_matrices(&self) {}
}
impl MyLinearAlgebraPublic for RightAlign {
fn multiply_matrices(&self) {}
fn add_matrices(&self) {}
}
} |
@akanalytics I think this isn't a good place to ask newbie questions, nevertheless, you can workaround it by marking |
This doesn't work (under rustc 1.68). It compiles without warning, but leaks implementation. The intention is to expose on the trait object and its public methods, hiding how the trait objects are implemented. mod other_unrelated_mod {
use super::nested::{DefaultAlign, MyLinearAlgebraPublic};
// private module "private_nested" cannot be used/imported (this is correct)
fn my_func() {
let da: &mut dyn MyLinearAlgebraPublic = &mut DefaultAlign;
da.pub_add_matrices();
da.pub_print_i32(5);
// rustc --version
// rustc 1.68.1 (8460ca823 2023-03-20)
da.private_print_vec_i32(&vec![]); // <-- this compiles and leaks the trait objects implementation abstraction
}
}
pub mod nested {
mod private_nested {
// trait made private by using a private module
pub trait MyWriterPrivate {
fn pub_print_i32(&mut self, i: i32) {
println!("{i:<5}");
}
fn private_print_vec_i32(&mut self, vec: &Vec<i32>) {
for &item in vec {
self.pub_print_i32(item);
}
}
}
}
// public interface
// this gives a warning "private trait `MyWriterPrivate` in public interface (error E0445)"
// if MyWriterPrivate is private
pub trait MyLinearAlgebraPublic: private_nested::MyWriterPrivate {
fn print_matrix(&mut self, mat: &Vec<Vec<i32>>) {
for vec in mat {
self.private_print_vec_i32(vec);
}
}
fn multiply_matrices(&self) {}
fn pub_add_matrices(&self) {}
}
pub struct DefaultAlign;
pub struct RightAlign;
impl private_nested::MyWriterPrivate for DefaultAlign {}
impl private_nested::MyWriterPrivate for RightAlign {
fn pub_print_i32(&mut self, i: i32) {
println!("{i:>5}");
}
}
impl MyLinearAlgebraPublic for DefaultAlign {
fn multiply_matrices(&self) {}
fn pub_add_matrices(&self) {}
}
impl MyLinearAlgebraPublic for RightAlign {
fn multiply_matrices(&self) {}
fn pub_add_matrices(&self) {}
}
} |
=== stdout === === stderr === error[E0463]: can't find crate for `f` --> /home/runner/work/glacier/glacier/ices/109343.rs:2:1 | 2 | extern crate f; | ^^^^^^^^^^^^^^^ can't find crate error[E0432]: unresolved import `inner` --> /home/runner/work/glacier/glacier/ices/109343.rs:4:9 | 4 | pub use inner::f; | ^^^^^ use of undeclared crate or module `inner` error: extern crate `f` is private, and cannot be re-exported (error E0365), consider declaring with `pub` --> /home/runner/work/glacier/glacier/ices/109343.rs:7:9 | 7 | pub use f as g; | ^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <rust-lang/rust#34537> = note: `#[deny(pub_use_of_private_extern_crate)]` on by default error: aborting due to 3 previous errors Some errors have detailed explanations: E0432, E0463. For more information about an error, try `rustc --explain E0432`. ==============
The racking issue title refers to a lint that does not exist any more apparently. Would be good to update the tracking issue to the current status. |
Wait, I thought I closed this issue long time ago. |
For the latest relevant activities here see #48054 (which is also closed now). |
|
…rate, r= WIP: make pub_use_of_private_extern_crate a hard error This got tracked in rust-lang#34537 which recently got closed so I assume we want this to be a hard error? It's been a lint for many years. Should probably be cratered though. TODO: - actually remove the lint r? `@petrochenkov`
#127909 now tracks |
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: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.
The trait
Float
is public from the private-in-public checker's point of view, because it uses only local reasoning, howeverFloat
is unnameable from outside ofm
and effectively private, because it isn't actually reexported fromm
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
private_in_public
lint as warn-by-defaultprivate_in_public
compatibility lint deny-by-default #34206 makes theprivate_in_public
lint deny-by-defaultprivate_in_public
compatibility lint warn-by-default again #36270 makes theprivate_in_public
lint warn-by-default again due to relatively large amount of breakageprivate_in_public
lint deny-by-defaultprivate_in_public
lint a hard errorThe text was updated successfully, but these errors were encountered: