From 6d46382f6f0688df0fc5c67386f86ccd6fdb975f Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Thu, 18 May 2023 14:57:45 +0300 Subject: [PATCH] Private-in-public lints implementation --- compiler/rustc_lint_defs/src/builtin.rs | 95 ++++++ compiler/rustc_privacy/messages.ftl | 7 + compiler/rustc_privacy/src/errors.rs | 29 ++ compiler/rustc_privacy/src/lib.rs | 270 ++++++++++++++---- .../private-in-public.rs | 5 + .../private-in-public.stderr | 52 +++- .../generic_const_exprs/eval-privacy.rs | 6 + .../generic_const_exprs/eval-privacy.stderr | 22 +- tests/ui/error-codes/E0445.rs | 7 + tests/ui/error-codes/E0445.stderr | 52 +++- tests/ui/issues/issue-18389.rs | 6 + tests/ui/issues/issue-18389.stderr | 26 +- .../private-in-public-non-principal.rs | 6 + .../private-in-public-non-principal.stderr | 26 +- tests/ui/privacy/private-inferred-type-1.rs | 10 + .../ui/privacy/private-inferred-type-1.stderr | 18 +- tests/ui/privacy/unnameable_types.rs | 30 ++ tests/ui/privacy/unnameable_types.stderr | 38 +++ tests/ui/privacy/where-priv-type.rs | 6 + tests/ui/privacy/where-priv-type.stderr | 110 ++++++- .../where-pub-type-impls-priv-trait.rs | 5 + .../where-pub-type-impls-priv-trait.stderr | 88 +++++- ...174-restricted-type-in-public-interface.rs | 12 + ...restricted-type-in-public-interface.stderr | 52 +++- 24 files changed, 893 insertions(+), 85 deletions(-) create mode 100644 tests/ui/privacy/unnameable_types.rs create mode 100644 tests/ui/privacy/unnameable_types.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index eb246c3f93e..53ece08ac3d 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3372,7 +3372,9 @@ OVERLAPPING_RANGE_ENDPOINTS, PATTERNS_IN_FNS_WITHOUT_BODY, POINTER_STRUCTURAL_MATCH, + PRIVATE_BOUNDS, PRIVATE_IN_PUBLIC, + PRIVATE_INTERFACES, PROC_MACRO_BACK_COMPAT, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PUB_USE_OF_PRIVATE_EXTERN_CRATE, @@ -3399,6 +3401,7 @@ UNINHABITED_STATIC, UNKNOWN_CRATE_TYPES, UNKNOWN_LINTS, + UNNAMEABLE_TYPES, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, UNSAFE_OP_IN_UNSAFE_FN, @@ -4251,3 +4254,95 @@ Warn, "\"invalid_parameter\" isn't a valid argument for `#[macro_export]`", } + +declare_lint! { + /// The `private_interfaces` lint detects types in a primary interface of an item, + /// that are more private than the item itself. Primary interface of an item is all + /// its interface except for bounds on generic parameters and where clauses. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// # #![allow(private_in_public)] + /// #![deny(private_interfaces)] + /// struct SemiPriv; + /// + /// mod m1 { + /// struct Priv; + /// impl crate::SemiPriv { + /// pub fn f(_: Priv) {} + /// } + /// } + /// + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Having something private in primary interface guarantees that + /// the item will be unusable from outer modules due to type privacy. + pub PRIVATE_INTERFACES, + Allow, + "private type in primary interface of an item", +} + +declare_lint! { + /// The `private_bounds` lint detects types in a secondary interface of an item, + /// that are more private than the item itself. Secondary interface of an item consists of + /// bounds on generic parameters and where clauses, including supertraits for trait items. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(private_in_public)] + /// # #![allow(unused)] + /// #![deny(private_bounds)] + /// + /// struct PrivTy; + /// pub struct S + /// where PrivTy: + /// {} + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Having private types or traits in item bounds makes it less clear what interface + /// the item actually provides. + pub PRIVATE_BOUNDS, + Allow, + "private type in secondary interface of an item" +} + +declare_lint! { + /// The `unnameable_types` lint detects types for which you can get objects of that type, + /// but cannot name the type itself. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// #![deny(unnameable_types)] + /// mod m { + /// pub struct S; + /// } + /// + /// pub fn get_voldemort() -> m::S { m::S } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is often expected that if you can obtain an object of type `T`, then + /// you can name the type `T` as well, this lint attempts to enforce this rule. + pub UNNAMEABLE_TYPES, + Allow, + "effective visibility of a type is larger than the area in which it can be named" +} diff --git a/compiler/rustc_privacy/messages.ftl b/compiler/rustc_privacy/messages.ftl index b68e8a78aab..6f51981cf09 100644 --- a/compiler/rustc_privacy/messages.ftl +++ b/compiler/rustc_privacy/messages.ftl @@ -17,7 +17,14 @@ privacy_private_in_public_lint = *[other] E0446 }) +privacy_private_interface_or_bounds_lint = {$ty_kind} `{$ty_descr}` is more private than the item `{$item_descr}` + .item_note = {$item_kind} `{$item_descr}` is reachable at visibility `{$item_vis_descr}` + .ty_note = but {$ty_kind} `{$ty_descr}` is only usable at visibility `{$ty_vis_descr}` + privacy_report_effective_visibility = {$descr} +privacy_unnameable_types_lint = {$kind} `{$descr}` is reachable but cannot be named + .label = reachable at visibility `{$reachable_vis}`, but can only be named at visibility `{$reexported_vis}` + privacy_unnamed_item_is_private = {$kind} is private .label = private {$kind} diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs index 72b53eefa08..67689b5e713 100644 --- a/compiler/rustc_privacy/src/errors.rs +++ b/compiler/rustc_privacy/src/errors.rs @@ -98,3 +98,32 @@ pub struct PrivateInPublicLint<'a> { pub kind: &'a str, pub descr: DiagnosticArgFromDisplay<'a>, } + +#[derive(LintDiagnostic)] +#[diag(privacy_unnameable_types_lint)] +pub struct UnnameableTypesLint<'a> { + #[label] + pub span: Span, + pub kind: &'a str, + pub descr: DiagnosticArgFromDisplay<'a>, + pub reachable_vis: &'a str, + pub reexported_vis: &'a str, +} + +// Used for `private_interfaces` and `private_bounds` lints. +// They will replace private-in-public errors and compatibility lints in future. +// See https://rust-lang.github.io/rfcs/2145-type-privacy.html for more details. +#[derive(LintDiagnostic)] +#[diag(privacy_private_interface_or_bounds_lint)] +pub struct PrivateInterfacesOrBoundsLint<'a> { + #[note(privacy_item_note)] + pub item_span: Span, + pub item_kind: &'a str, + pub item_descr: DiagnosticArgFromDisplay<'a>, + pub item_vis_descr: &'a str, + #[note(privacy_ty_note)] + pub ty_span: Span, + pub ty_kind: &'a str, + pub ty_descr: DiagnosticArgFromDisplay<'a>, + pub ty_vis_descr: &'a str, +} diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index afd32e38d5b..a51a1c9a8a4 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -22,7 +22,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind}; +use rustc_hir::{AssocItemKind, ForeignItemKind, HirIdSet, ItemId, Node, PatKind}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; @@ -42,8 +42,8 @@ use errors::{ FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, - InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportEffectiveVisibility, - UnnamedItemIsPrivate, + InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, PrivateInterfacesOrBoundsLint, + ReportEffectiveVisibility, UnnameableTypesLint, UnnamedItemIsPrivate, }; fluent_messages! { "../messages.ftl" } @@ -52,6 +52,17 @@ /// Generic infrastructure used to implement specific visitors below. //////////////////////////////////////////////////////////////////////////////// +struct LazyDefPathStr<'tcx> { + def_id: DefId, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.tcx.def_path_str(self.def_id)) + } +} + /// Implemented to visit all `DefId`s in a type. /// Visiting `DefId`s is useful because visibilities and reachabilities are attached to them. /// The idea is to visit "all components of a type", as documented in @@ -259,16 +270,6 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { &LazyDefPathStr { def_id: data.def_id, tcx }, )?; - struct LazyDefPathStr<'tcx> { - def_id: DefId, - tcx: TyCtxt<'tcx>, - } - impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.tcx.def_path_str(self.def_id)) - } - } - // This will also visit substs if necessary, so we don't need to recurse. return if self.def_id_visitor.shallow() { ControlFlow::Continue(()) @@ -409,8 +410,25 @@ fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { } } -impl VisibilityLike for EffectiveVisibility { - const MAX: Self = EffectiveVisibility::from_vis(ty::Visibility::Public); +struct NonShallowEffectiveVis(EffectiveVisibility); + +impl VisibilityLike for NonShallowEffectiveVis { + const MAX: Self = NonShallowEffectiveVis(EffectiveVisibility::from_vis(ty::Visibility::Public)); + const SHALLOW: bool = false; + + fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { + let find = FindMin { + tcx: find.tcx, + effective_visibilities: find.effective_visibilities, + min: ShallowEffectiveVis(find.min.0), + }; + NonShallowEffectiveVis(VisibilityLike::new_min(&find, def_id).0) + } +} + +struct ShallowEffectiveVis(EffectiveVisibility); +impl VisibilityLike for ShallowEffectiveVis { + const MAX: Self = ShallowEffectiveVis(EffectiveVisibility::from_vis(ty::Visibility::Public)); // Type inference is very smart sometimes. // It can make an impl reachable even some components of its type or trait are unreachable. // E.g. methods of `impl ReachableTrait for ReachableTy { ... }` @@ -429,7 +447,7 @@ fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { EffectiveVisibility::from_vis(private_vis) }); - effective_vis.min(find.min, find.tcx) + ShallowEffectiveVis(effective_vis.min(find.min.0, find.tcx)) } } @@ -767,11 +785,13 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { } } hir::ItemKind::Impl(ref impl_) => { - let item_ev = EffectiveVisibility::of_impl( + let item_ev = ShallowEffectiveVis::of_impl( item.owner_id.def_id, self.tcx, &self.effective_visibilities, - ); + ) + .0; + self.update_eff_vis(item.owner_id.def_id, item_ev, None, Level::Direct); self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty().trait_ref(); @@ -912,6 +932,21 @@ pub struct TestReachabilityVisitor<'tcx, 'a> { effective_visibilities: &'a EffectiveVisibilities, } +fn vis_to_string<'tcx>(def_id: LocalDefId, vis: ty::Visibility, tcx: TyCtxt<'tcx>) -> String { + match vis { + ty::Visibility::Restricted(restricted_id) => { + if restricted_id.is_top_level_module() { + "pub(crate)".to_string() + } else if restricted_id == tcx.parent_module_from_def_id(def_id) { + "pub(self)".to_string() + } else { + format!("pub({})", tcx.item_name(restricted_id.to_def_id())) + } + } + ty::Visibility::Public => "pub".to_string(), + } +} + impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) { @@ -919,18 +954,7 @@ fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { let span = self.tcx.def_span(def_id.to_def_id()); if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) { for level in Level::all_levels() { - let vis_str = match effective_vis.at_level(level) { - ty::Visibility::Restricted(restricted_id) => { - if restricted_id.is_top_level_module() { - "pub(crate)".to_string() - } else if *restricted_id == self.tcx.parent_module_from_def_id(def_id) { - "pub(self)".to_string() - } else { - format!("pub({})", self.tcx.item_name(restricted_id.to_def_id())) - } - } - ty::Visibility::Public => "pub".to_string(), - }; + let vis_str = vis_to_string(def_id, *effective_vis.at_level(level), self.tcx); if level != Level::Direct { error_msg.push_str(", "); } @@ -1745,12 +1769,15 @@ struct SearchInterfaceForPrivateItemsVisitor<'tcx> { item_def_id: LocalDefId, /// The visitor checks that each component type is at least this visible. required_visibility: ty::Visibility, + required_effective_vis: Option, has_old_errors: bool, in_assoc_ty: bool, + in_primary_interface: bool, } impl SearchInterfaceForPrivateItemsVisitor<'_> { fn generics(&mut self) -> &mut Self { + self.in_primary_interface = true; for param in &self.tcx.generics_of(self.item_def_id).params { match param.kind { GenericParamDefKind::Lifetime => {} @@ -1769,6 +1796,7 @@ fn generics(&mut self) -> &mut Self { } fn predicates(&mut self) -> &mut Self { + self.in_primary_interface = false; // N.B., we use `explicit_predicates_of` and not `predicates_of` // because we don't want to report privacy errors due to where // clauses that the compiler inferred. We only want to @@ -1780,6 +1808,7 @@ fn predicates(&mut self) -> &mut Self { } fn bounds(&mut self) -> &mut Self { + self.in_primary_interface = false; self.visit_predicates(ty::GenericPredicates { parent: None, predicates: self.tcx.explicit_item_bounds(self.item_def_id).skip_binder(), @@ -1788,6 +1817,7 @@ fn bounds(&mut self) -> &mut Self { } fn ty(&mut self) -> &mut Self { + self.in_primary_interface = true; self.visit(self.tcx.type_of(self.item_def_id).subst_identity()); self } @@ -1811,8 +1841,10 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) }; let vis = self.tcx.local_visibility(local_def_id); + let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); + let span = self.tcx.def_span(self.item_def_id.to_def_id()); + let vis_span = self.tcx.def_span(def_id); if !vis.is_at_least(self.required_visibility, self.tcx) { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); let vis_descr = match vis { ty::Visibility::Public => "public", ty::Visibility::Restricted(vis_def_id) => { @@ -1825,12 +1857,11 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) } } }; - let span = self.tcx.def_span(self.item_def_id.to_def_id()); + if self.has_old_errors || self.in_assoc_ty || self.tcx.resolutions(()).has_pub_restricted { - let vis_span = self.tcx.def_span(def_id); if kind == "trait" { self.tcx.sess.emit_err(InPublicInterfaceTraits { span, @@ -1858,6 +1889,39 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) } } + let Some(effective_vis) = self.required_effective_vis else { + return false; + }; + + // FIXME: `Level::Reachable` should be taken instead of `Level::Reexported` + let reexported_at_vis = *effective_vis.at_level(Level::Reexported); + + if !vis.is_at_least(reexported_at_vis, self.tcx) { + let lint = if self.in_primary_interface { + lint::builtin::PRIVATE_INTERFACES + } else { + lint::builtin::PRIVATE_BOUNDS + }; + self.tcx.emit_lint( + lint, + hir_id, + PrivateInterfacesOrBoundsLint { + item_span: span, + item_kind: self.tcx.def_descr(self.item_def_id.to_def_id()), + item_descr: (&LazyDefPathStr { + def_id: self.item_def_id.to_def_id(), + tcx: self.tcx, + }) + .into(), + item_vis_descr: &vis_to_string(self.item_def_id, reexported_at_vis, self.tcx), + ty_span: vis_span, + ty_kind: kind, + ty_descr: descr.into(), + ty_vis_descr: &vis_to_string(local_def_id, vis, self.tcx), + }, + ); + } + false } @@ -1891,25 +1955,55 @@ fn visit_def_id( } } -struct PrivateItemsInPublicInterfacesChecker<'tcx> { +struct PrivateItemsInPublicInterfacesChecker<'tcx, 'a> { tcx: TyCtxt<'tcx>, old_error_set_ancestry: HirIdSet, + effective_visibilities: &'a EffectiveVisibilities, } -impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { +impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> { fn check( &self, def_id: LocalDefId, required_visibility: ty::Visibility, + required_effective_vis: Option, ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> { SearchInterfaceForPrivateItemsVisitor { tcx: self.tcx, item_def_id: def_id, required_visibility, + required_effective_vis, has_old_errors: self .old_error_set_ancestry .contains(&self.tcx.hir().local_def_id_to_hir_id(def_id)), in_assoc_ty: false, + in_primary_interface: true, + } + } + + fn check_unnameable(&self, def_id: LocalDefId, effective_vis: Option) { + let Some(effective_vis) = effective_vis else { + return; + }; + + let reexported_at_vis = effective_vis.at_level(Level::Reexported); + let reachable_at_vis = effective_vis.at_level(Level::Reachable); + + if reexported_at_vis != reachable_at_vis { + let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let span = self.tcx.def_span(def_id.to_def_id()); + self.tcx.emit_spanned_lint( + lint::builtin::UNNAMEABLE_TYPES, + hir_id, + span, + UnnameableTypesLint { + span, + kind: self.tcx.def_descr(def_id.to_def_id()), + descr: (&LazyDefPathStr { def_id: def_id.to_def_id(), tcx: self.tcx }).into(), + reachable_vis: &vis_to_string(def_id, *reachable_at_vis, self.tcx), + reexported_vis: &vis_to_string(def_id, *reexported_at_vis, self.tcx), + }, + ); } } @@ -1918,13 +2012,19 @@ fn check_assoc_item( def_id: LocalDefId, assoc_item_kind: AssocItemKind, vis: ty::Visibility, + effective_vis: Option, ) { - let mut check = self.check(def_id, vis); + let mut check = self.check(def_id, vis, effective_vis); let (check_ty, is_assoc_ty) = match assoc_item_kind { AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false), AssocItemKind::Type => (self.tcx.defaultness(def_id).has_value(), true), }; + + if is_assoc_ty { + self.check_unnameable(def_id, self.get(def_id)); + } + check.in_assoc_ty = is_assoc_ty; check.generics().predicates(); if check_ty { @@ -1932,50 +2032,72 @@ fn check_assoc_item( } } + fn get(&self, def_id: LocalDefId) -> Option { + self.effective_visibilities.effective_vis(def_id).copied() + } + pub fn check_item(&mut self, id: ItemId) { let tcx = self.tcx; let def_id = id.owner_id.def_id; let item_visibility = tcx.local_visibility(def_id); + let effective_vis = self.get(def_id); let def_kind = tcx.def_kind(def_id); match def_kind { DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => { - self.check(def_id, item_visibility).generics().predicates().ty(); + if let DefKind::TyAlias = def_kind { + self.check_unnameable(def_id, effective_vis); + } + self.check(def_id, item_visibility, effective_vis).generics().predicates().ty(); } DefKind::OpaqueTy => { // `ty()` for opaque types is the underlying type, // it's not a part of interface, so we skip it. - self.check(def_id, item_visibility).generics().bounds(); + self.check(def_id, item_visibility, effective_vis).generics().bounds(); } DefKind::Trait => { let item = tcx.hir().item(id); if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind { - self.check(item.owner_id.def_id, item_visibility).generics().predicates(); + self.check_unnameable(item.owner_id.def_id, effective_vis); + + self.check(item.owner_id.def_id, item_visibility, effective_vis) + .generics() + .predicates(); for trait_item_ref in trait_item_refs { self.check_assoc_item( trait_item_ref.id.owner_id.def_id, trait_item_ref.kind, item_visibility, + effective_vis, ); if let AssocItemKind::Type = trait_item_ref.kind { - self.check(trait_item_ref.id.owner_id.def_id, item_visibility).bounds(); + self.check( + trait_item_ref.id.owner_id.def_id, + item_visibility, + effective_vis, + ) + .bounds(); } } } } DefKind::TraitAlias => { - self.check(def_id, item_visibility).generics().predicates(); + self.check(def_id, item_visibility, effective_vis).generics().predicates(); } DefKind::Enum => { let item = tcx.hir().item(id); if let hir::ItemKind::Enum(ref def, _) = item.kind { - self.check(item.owner_id.def_id, item_visibility).generics().predicates(); + self.check_unnameable(item.owner_id.def_id, effective_vis); + + self.check(item.owner_id.def_id, item_visibility, effective_vis) + .generics() + .predicates(); for variant in def.variants { for field in variant.data.fields() { - self.check(field.def_id, item_visibility).ty(); + self.check(field.def_id, item_visibility, effective_vis).ty(); } } } @@ -1985,8 +2107,16 @@ pub fn check_item(&mut self, id: ItemId) { let item = tcx.hir().item(id); if let hir::ItemKind::ForeignMod { items, .. } = item.kind { for foreign_item in items { - let vis = tcx.local_visibility(foreign_item.id.owner_id.def_id); - self.check(foreign_item.id.owner_id.def_id, vis) + let foreign_item = tcx.hir().foreign_item(foreign_item.id); + + let ev = self.get(foreign_item.owner_id.def_id); + let vis = tcx.local_visibility(foreign_item.owner_id.def_id); + + if let ForeignItemKind::Type = foreign_item.kind { + self.check_unnameable(foreign_item.owner_id.def_id, ev); + } + + self.check(foreign_item.owner_id.def_id, vis, ev) .generics() .predicates() .ty(); @@ -1999,11 +2129,21 @@ pub fn check_item(&mut self, id: ItemId) { if let hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) = item.kind { - self.check(item.owner_id.def_id, item_visibility).generics().predicates(); + self.check_unnameable(item.owner_id.def_id, effective_vis); + self.check(item.owner_id.def_id, item_visibility, effective_vis) + .generics() + .predicates(); for field in struct_def.fields() { let field_visibility = tcx.local_visibility(field.def_id); - self.check(field.def_id, min(item_visibility, field_visibility, tcx)).ty(); + let field_ev = self.get(field.def_id); + + self.check( + field.def_id, + min(item_visibility, field_visibility, tcx), + field_ev, + ) + .ty(); } } } @@ -2016,10 +2156,30 @@ pub fn check_item(&mut self, id: ItemId) { if let hir::ItemKind::Impl(ref impl_) = item.kind { let impl_vis = ty::Visibility::of_impl(item.owner_id.def_id, tcx, &Default::default()); + + // we are using the non-shallow version here, unlike when building the + // effective visisibilities table to avoid large number of false positives. + // For example: + // + // impl From for Pub { + // fn from(_: Priv) -> Pub {...} + // } + // + // lints shouldn't be emmited even `from` effective visibility + // is larger then `Priv` nominal visibility. + let impl_ev = Some( + NonShallowEffectiveVis::of_impl( + item.owner_id.def_id, + tcx, + self.effective_visibilities, + ) + .0, + ); + // check that private components do not appear in the generics or predicates of inherent impls // this check is intentionally NOT performed for impls of traits, per #90586 if impl_.of_trait.is_none() { - self.check(item.owner_id.def_id, impl_vis).generics().predicates(); + self.check(item.owner_id.def_id, impl_vis, impl_ev).generics().predicates(); } for impl_item_ref in impl_.items { let impl_item_vis = if impl_.of_trait.is_none() { @@ -2031,10 +2191,18 @@ pub fn check_item(&mut self, id: ItemId) { } else { impl_vis }; + + let impl_item_ev = if impl_.of_trait.is_none() { + self.get(impl_item_ref.id.owner_id.def_id) + } else { + impl_ev + }; + self.check_assoc_item( impl_item_ref.id.owner_id.def_id, impl_item_ref.kind, impl_item_vis, + impl_item_ev, ); } } @@ -2186,7 +2354,11 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { } // Check for private types and traits in public interfaces. - let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, old_error_set_ancestry }; + let mut checker = PrivateItemsInPublicInterfacesChecker { + tcx, + old_error_set_ancestry, + effective_visibilities, + }; for id in tcx.hir().items() { checker.check_item(id); diff --git a/tests/ui/associated-inherent-types/private-in-public.rs b/tests/ui/associated-inherent-types/private-in-public.rs index a4b372537c7..44a20a79ad6 100644 --- a/tests/ui/associated-inherent-types/private-in-public.rs +++ b/tests/ui/associated-inherent-types/private-in-public.rs @@ -3,6 +3,11 @@ #![crate_type = "lib"] #![deny(private_in_public)] +#![warn(private_interfaces)] + +// In this test both old and new private-in-public diagnostic were emitted. +// Old diagnostic will be deleted soon. +// See https://rust-lang.github.io/rfcs/2145-type-privacy.html. pub type PubAlias0 = PubTy::PrivAssocTy; //~^ ERROR private associated type `PubTy::PrivAssocTy` in public interface (error E0446) diff --git a/tests/ui/associated-inherent-types/private-in-public.stderr b/tests/ui/associated-inherent-types/private-in-public.stderr index f0a64e96179..d40db83707b 100644 --- a/tests/ui/associated-inherent-types/private-in-public.stderr +++ b/tests/ui/associated-inherent-types/private-in-public.stderr @@ -1,5 +1,5 @@ error: private associated type `PubTy::PrivAssocTy` in public interface (error E0446) - --> $DIR/private-in-public.rs:7:1 + --> $DIR/private-in-public.rs:12:1 | LL | pub type PubAlias0 = PubTy::PrivAssocTy; | ^^^^^^^^^^^^^^^^^^ @@ -12,8 +12,26 @@ note: the lint level is defined here LL | #![deny(private_in_public)] | ^^^^^^^^^^^^^^^^^ +warning: associated type `PubTy::PrivAssocTy` is more private than the item `PubAlias0` + | +note: type alias `PubAlias0` is reachable at visibility `pub` + --> $DIR/private-in-public.rs:12:1 + | +LL | pub type PubAlias0 = PubTy::PrivAssocTy; + | ^^^^^^^^^^^^^^^^^^ +note: but associated type `PubTy::PrivAssocTy` is only usable at visibility `pub(crate)` + --> $DIR/private-in-public.rs:24:5 + | +LL | type PrivAssocTy = (); + | ^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/private-in-public.rs:6:9 + | +LL | #![warn(private_interfaces)] + | ^^^^^^^^^^^^^^^^^^ + error: private type `PrivTy` in public interface (error E0446) - --> $DIR/private-in-public.rs:10:1 + --> $DIR/private-in-public.rs:15:1 | LL | pub type PubAlias1 = PrivTy::PubAssocTy; | ^^^^^^^^^^^^^^^^^^ @@ -21,8 +39,21 @@ LL | pub type PubAlias1 = PrivTy::PubAssocTy; = 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 +warning: type `PrivTy` is more private than the item `PubAlias1` + | +note: type alias `PubAlias1` is reachable at visibility `pub` + --> $DIR/private-in-public.rs:15:1 + | +LL | pub type PubAlias1 = PrivTy::PubAssocTy; + | ^^^^^^^^^^^^^^^^^^ +note: but type `PrivTy` is only usable at visibility `pub(crate)` + --> $DIR/private-in-public.rs:28:1 + | +LL | struct PrivTy; + | ^^^^^^^^^^^^^ + error: private type `PrivTy` in public interface (error E0446) - --> $DIR/private-in-public.rs:13:1 + --> $DIR/private-in-public.rs:18:1 | LL | pub type PubAlias2 = PubTy::PubAssocTy; | ^^^^^^^^^^^^^^^^^^ @@ -30,5 +61,18 @@ LL | pub type PubAlias2 = PubTy::PubAssocTy; = 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 -error: aborting due to 3 previous errors +warning: type `PrivTy` is more private than the item `PubAlias2` + | +note: type alias `PubAlias2` is reachable at visibility `pub` + --> $DIR/private-in-public.rs:18:1 + | +LL | pub type PubAlias2 = PubTy::PubAssocTy; + | ^^^^^^^^^^^^^^^^^^ +note: but type `PrivTy` is only usable at visibility `pub(crate)` + --> $DIR/private-in-public.rs:28:1 + | +LL | struct PrivTy; + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 3 warnings emitted diff --git a/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs b/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs index 8023b998a40..96b769699cc 100644 --- a/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs +++ b/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs @@ -2,6 +2,12 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] +#![warn(private_interfaces)] + +// In this test both old and new private-in-public diagnostic were emitted. +// Old diagnostic will be deleted soon. +// See https://rust-lang.github.io/rfcs/2145-type-privacy.html. + pub struct Const; pub trait Trait { diff --git a/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr b/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr index 2d9de8805bb..465621619b4 100644 --- a/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr +++ b/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr @@ -1,5 +1,5 @@ error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface - --> $DIR/eval-privacy.rs:16:5 + --> $DIR/eval-privacy.rs:22:5 | LL | type AssocTy = Const<{ my_const_fn(U) }>; | ^^^^^^^^^^^^ can't leak private type @@ -7,6 +7,24 @@ LL | type AssocTy = Const<{ my_const_fn(U) }>; LL | const fn my_const_fn(val: u8) -> u8 { | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private -error: aborting due to previous error +warning: type `fn(u8) -> u8 {my_const_fn}` is more private than the item ` as Trait>::AssocTy` + | +note: associated type ` as Trait>::AssocTy` is reachable at visibility `pub` + --> $DIR/eval-privacy.rs:22:5 + | +LL | type AssocTy = Const<{ my_const_fn(U) }>; + | ^^^^^^^^^^^^ +note: but type `fn(u8) -> u8 {my_const_fn}` is only usable at visibility `pub(crate)` + --> $DIR/eval-privacy.rs:29:1 + | +LL | const fn my_const_fn(val: u8) -> u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/eval-privacy.rs:5:9 + | +LL | #![warn(private_interfaces)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0446`. diff --git a/tests/ui/error-codes/E0445.rs b/tests/ui/error-codes/E0445.rs index a9a3aee2500..f5f35fb8a4d 100644 --- a/tests/ui/error-codes/E0445.rs +++ b/tests/ui/error-codes/E0445.rs @@ -1,3 +1,10 @@ +#[warn(private_bounds)] +#[warn(private_interfaces)] + +// In this test both old and new private-in-public diagnostic were emitted. +// Old diagnostic will be deleted soon. +// See https://rust-lang.github.io/rfcs/2145-type-privacy.html. + trait Foo { fn dummy(&self) { } } diff --git a/tests/ui/error-codes/E0445.stderr b/tests/ui/error-codes/E0445.stderr index 23b7a335047..ac3637a8218 100644 --- a/tests/ui/error-codes/E0445.stderr +++ b/tests/ui/error-codes/E0445.stderr @@ -1,5 +1,5 @@ error[E0445]: private trait `Foo` in public interface - --> $DIR/E0445.rs:5:1 + --> $DIR/E0445.rs:12:1 | LL | trait Foo { | --------- `Foo` declared as private @@ -7,8 +7,26 @@ LL | trait Foo { LL | pub trait Bar : Foo {} | ^^^^^^^^^^^^^^^^^^^ can't leak private trait +warning: trait `Foo` is more private than the item `Bar` + | +note: trait `Bar` is reachable at visibility `pub` + --> $DIR/E0445.rs:12:1 + | +LL | pub trait Bar : Foo {} + | ^^^^^^^^^^^^^^^^^^^ +note: but trait `Foo` is only usable at visibility `pub(crate)` + --> $DIR/E0445.rs:8:1 + | +LL | trait Foo { + | ^^^^^^^^^ +note: the lint level is defined here + --> $DIR/E0445.rs:1:8 + | +LL | #[warn(private_bounds)] + | ^^^^^^^^^^^^^^ + error[E0445]: private trait `Foo` in public interface - --> $DIR/E0445.rs:7:1 + --> $DIR/E0445.rs:14:1 | LL | trait Foo { | --------- `Foo` declared as private @@ -16,8 +34,21 @@ LL | trait Foo { LL | pub struct Bar2(pub T); | ^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait +warning: trait `Foo` is more private than the item `Bar2` + | +note: struct `Bar2` is reachable at visibility `pub` + --> $DIR/E0445.rs:14:1 + | +LL | pub struct Bar2(pub T); + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: but trait `Foo` is only usable at visibility `pub(crate)` + --> $DIR/E0445.rs:8:1 + | +LL | trait Foo { + | ^^^^^^^^^ + error[E0445]: private trait `Foo` in public interface - --> $DIR/E0445.rs:9:1 + --> $DIR/E0445.rs:16:1 | LL | trait Foo { | --------- `Foo` declared as private @@ -25,6 +56,19 @@ LL | trait Foo { LL | pub fn foo (t: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait -error: aborting due to 3 previous errors +warning: trait `Foo` is more private than the item `foo` + | +note: function `foo` is reachable at visibility `pub` + --> $DIR/E0445.rs:16:1 + | +LL | pub fn foo (t: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: but trait `Foo` is only usable at visibility `pub(crate)` + --> $DIR/E0445.rs:8:1 + | +LL | trait Foo { + | ^^^^^^^^^ + +error: aborting due to 3 previous errors; 3 warnings emitted For more information about this error, try `rustc --explain E0445`. diff --git a/tests/ui/issues/issue-18389.rs b/tests/ui/issues/issue-18389.rs index 654dfb63b88..3686afc48af 100644 --- a/tests/ui/issues/issue-18389.rs +++ b/tests/ui/issues/issue-18389.rs @@ -1,3 +1,9 @@ +#![warn(private_bounds)] + +// In this test both old and new private-in-public diagnostic were emitted. +// Old diagnostic will be deleted soon. +// See https://rust-lang.github.io/rfcs/2145-type-privacy.html. + use std::any::Any; use std::any::TypeId; diff --git a/tests/ui/issues/issue-18389.stderr b/tests/ui/issues/issue-18389.stderr index 6ce78c45d6e..f9ebde48a45 100644 --- a/tests/ui/issues/issue-18389.stderr +++ b/tests/ui/issues/issue-18389.stderr @@ -1,5 +1,5 @@ error[E0445]: private trait `Private<::P, ::R>` in public interface - --> $DIR/issue-18389.rs:7:1 + --> $DIR/issue-18389.rs:13:1 | LL | trait Private { | ------------------- `Private<::P, ::R>` declared as private @@ -11,6 +11,28 @@ LL | | ::R LL | | > { | |_^ can't leak private trait -error: aborting due to previous error +warning: trait `Private<::P, ::R>` is more private than the item `Public` + | +note: trait `Public` is reachable at visibility `pub` + --> $DIR/issue-18389.rs:13:1 + | +LL | / pub trait Public: Private< +LL | | +LL | | ::P, +LL | | ::R +LL | | > { + | |_^ +note: but trait `Private<::P, ::R>` is only usable at visibility `pub(crate)` + --> $DIR/issue-18389.rs:10:1 + | +LL | trait Private { + | ^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/issue-18389.rs:1:9 + | +LL | #![warn(private_bounds)] + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0445`. diff --git a/tests/ui/privacy/private-in-public-non-principal.rs b/tests/ui/privacy/private-in-public-non-principal.rs index ac1d5a9e6a2..a80c1541463 100644 --- a/tests/ui/privacy/private-in-public-non-principal.rs +++ b/tests/ui/privacy/private-in-public-non-principal.rs @@ -1,6 +1,12 @@ #![feature(auto_traits)] #![feature(negative_impls)] +#![deny(private_interfaces)] + +// In this test both old and new private-in-public diagnostic were emitted. +// Old diagnostic will be deleted soon. +// See https://rust-lang.github.io/rfcs/2145-type-privacy.html. + pub trait PubPrincipal {} auto trait PrivNonPrincipal {} diff --git a/tests/ui/privacy/private-in-public-non-principal.stderr b/tests/ui/privacy/private-in-public-non-principal.stderr index de20cada42e..9fc12affe4b 100644 --- a/tests/ui/privacy/private-in-public-non-principal.stderr +++ b/tests/ui/privacy/private-in-public-non-principal.stderr @@ -1,5 +1,5 @@ warning: private trait `PrivNonPrincipal` in public interface (error E0445) - --> $DIR/private-in-public-non-principal.rs:7:1 + --> $DIR/private-in-public-non-principal.rs:13:1 | LL | pub fn leak_dyn_nonprincipal() -> Box { loop {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,17 +8,35 @@ LL | pub fn leak_dyn_nonprincipal() -> Box = note: for more information, see issue #34537 = note: `#[warn(private_in_public)]` on by default +error: trait `PrivNonPrincipal` is more private than the item `leak_dyn_nonprincipal` + | +note: function `leak_dyn_nonprincipal` is reachable at visibility `pub` + --> $DIR/private-in-public-non-principal.rs:13:1 + | +LL | pub fn leak_dyn_nonprincipal() -> Box { loop {} } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: but trait `PrivNonPrincipal` is only usable at visibility `pub(crate)` + --> $DIR/private-in-public-non-principal.rs:11:1 + | +LL | auto trait PrivNonPrincipal {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/private-in-public-non-principal.rs:4:9 + | +LL | #![deny(private_interfaces)] + | ^^^^^^^^^^^^^^^^^^ + error: missing documentation for an associated function - --> $DIR/private-in-public-non-principal.rs:14:9 + --> $DIR/private-in-public-non-principal.rs:20:9 | LL | pub fn check_doc_lint() {} | ^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/private-in-public-non-principal.rs:11:8 + --> $DIR/private-in-public-non-principal.rs:17:8 | LL | #[deny(missing_docs)] | ^^^^^^^^^^^^ -error: aborting due to previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/privacy/private-inferred-type-1.rs b/tests/ui/privacy/private-inferred-type-1.rs index d633189e3fb..b3eba53dd13 100644 --- a/tests/ui/privacy/private-inferred-type-1.rs +++ b/tests/ui/privacy/private-inferred-type-1.rs @@ -5,14 +5,24 @@ trait TyParam { fn ty_param_secret(&self); } +trait Ref { + fn ref_secret(self); +} + mod m { struct Priv; impl ::Arr0 for [Priv; 0] { fn arr0_secret(&self) {} } impl ::TyParam for Option { fn ty_param_secret(&self) {} } + impl<'a> ::Ref for &'a Priv { fn ref_secret(self) {} } } +fn anyref<'a, T>() -> &'a T { panic!() } + fn main() { [].arr0_secret(); //~ ERROR type `Priv` is private None.ty_param_secret(); //~ ERROR type `Priv` is private + Ref::ref_secret(anyref()); + //~^ ERROR type `Priv` is private + //~| ERROR type `Priv` is private } diff --git a/tests/ui/privacy/private-inferred-type-1.stderr b/tests/ui/privacy/private-inferred-type-1.stderr index 245789f4353..47c11d6ec76 100644 --- a/tests/ui/privacy/private-inferred-type-1.stderr +++ b/tests/ui/privacy/private-inferred-type-1.stderr @@ -1,14 +1,26 @@ error: type `Priv` is private - --> $DIR/private-inferred-type-1.rs:16:5 + --> $DIR/private-inferred-type-1.rs:23:5 | LL | [].arr0_secret(); | ^^^^^^^^^^^^^^^^ private type error: type `Priv` is private - --> $DIR/private-inferred-type-1.rs:17:5 + --> $DIR/private-inferred-type-1.rs:24:5 | LL | None.ty_param_secret(); | ^^^^^^^^^^^^^^^^^^^^^^ private type -error: aborting due to 2 previous errors +error: type `Priv` is private + --> $DIR/private-inferred-type-1.rs:25:5 + | +LL | Ref::ref_secret(anyref()); + | ^^^^^^^^^^^^^^^ private type + +error: type `Priv` is private + --> $DIR/private-inferred-type-1.rs:25:21 + | +LL | Ref::ref_secret(anyref()); + | ^^^^^^^^ private type + +error: aborting due to 4 previous errors diff --git a/tests/ui/privacy/unnameable_types.rs b/tests/ui/privacy/unnameable_types.rs new file mode 100644 index 00000000000..8b53f372fc9 --- /dev/null +++ b/tests/ui/privacy/unnameable_types.rs @@ -0,0 +1,30 @@ +#![allow(unused)] +#![allow(private_in_public)] +#![deny(unnameable_types)] + +mod m { + pub struct PubStruct(pub i32); //~ ERROR struct `PubStruct` is reachable but cannot be named + + pub enum PubE { //~ ERROR enum `PubE` is reachable but cannot be named + V(i32), + } + + pub trait PubTr { //~ ERROR trait `PubTr` is reachable but cannot be named + const C : i32 = 0; + type Alias; //~ ERROR associated type `PubTr::Alias` is reachable but cannot be named + fn f() {} + } + + impl PubTr for PubStruct { + type Alias = i32; //~ ERROR associated type `::Alias` is reachable but cannot be named + fn f() {} + } +} + +pub trait Voldemort {} + +impl Voldemort for i32 {} +impl Voldemort for i32 {} +impl Voldemort for u32 where T: m::PubTr {} + +fn main() {} diff --git a/tests/ui/privacy/unnameable_types.stderr b/tests/ui/privacy/unnameable_types.stderr new file mode 100644 index 00000000000..25eb5c9434a --- /dev/null +++ b/tests/ui/privacy/unnameable_types.stderr @@ -0,0 +1,38 @@ +error: struct `PubStruct` is reachable but cannot be named + --> $DIR/unnameable_types.rs:6:5 + | +LL | pub struct PubStruct(pub i32); + | ^^^^^^^^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` + | +note: the lint level is defined here + --> $DIR/unnameable_types.rs:3:9 + | +LL | #![deny(unnameable_types)] + | ^^^^^^^^^^^^^^^^ + +error: enum `PubE` is reachable but cannot be named + --> $DIR/unnameable_types.rs:8:5 + | +LL | pub enum PubE { + | ^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` + +error: trait `PubTr` is reachable but cannot be named + --> $DIR/unnameable_types.rs:12:5 + | +LL | pub trait PubTr { + | ^^^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` + +error: associated type `PubTr::Alias` is reachable but cannot be named + --> $DIR/unnameable_types.rs:14:9 + | +LL | type Alias; + | ^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` + +error: associated type `::Alias` is reachable but cannot be named + --> $DIR/unnameable_types.rs:19:9 + | +LL | type Alias = i32; + | ^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/privacy/where-priv-type.rs b/tests/ui/privacy/where-priv-type.rs index 66ee9c4bbd8..9899902dd88 100644 --- a/tests/ui/privacy/where-priv-type.rs +++ b/tests/ui/privacy/where-priv-type.rs @@ -5,6 +5,12 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] +#![warn(private_bounds)] +#![warn(private_interfaces)] + +// In this test both old and new private-in-public diagnostic were emitted. +// Old diagnostic will be deleted soon. +// See https://rust-lang.github.io/rfcs/2145-type-privacy.html. struct PrivTy; trait PrivTr {} diff --git a/tests/ui/privacy/where-priv-type.stderr b/tests/ui/privacy/where-priv-type.stderr index c5fb2cdb0cf..2830fa6cd44 100644 --- a/tests/ui/privacy/where-priv-type.stderr +++ b/tests/ui/privacy/where-priv-type.stderr @@ -1,5 +1,5 @@ warning: private type `PrivTy` in public interface (error E0446) - --> $DIR/where-priv-type.rs:19:1 + --> $DIR/where-priv-type.rs:25:1 | LL | pub struct S | ^^^^^^^^^^^^ @@ -8,8 +8,26 @@ LL | pub struct S = note: for more information, see issue #34537 = note: `#[warn(private_in_public)]` on by default +warning: type `PrivTy` is more private than the item `S` + | +note: struct `S` is reachable at visibility `pub` + --> $DIR/where-priv-type.rs:25:1 + | +LL | pub struct S + | ^^^^^^^^^^^^ +note: but type `PrivTy` is only usable at visibility `pub(crate)` + --> $DIR/where-priv-type.rs:15:1 + | +LL | struct PrivTy; + | ^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/where-priv-type.rs:8:9 + | +LL | #![warn(private_bounds)] + | ^^^^^^^^^^^^^^ + warning: private type `PrivTy` in public interface (error E0446) - --> $DIR/where-priv-type.rs:27:1 + --> $DIR/where-priv-type.rs:33:1 | LL | pub enum E | ^^^^^^^^^^ @@ -17,8 +35,21 @@ LL | pub enum E = 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 +warning: type `PrivTy` is more private than the item `E` + | +note: enum `E` is reachable at visibility `pub` + --> $DIR/where-priv-type.rs:33:1 + | +LL | pub enum E + | ^^^^^^^^^^ +note: but type `PrivTy` is only usable at visibility `pub(crate)` + --> $DIR/where-priv-type.rs:15:1 + | +LL | struct PrivTy; + | ^^^^^^^^^^^^^ + warning: private type `PrivTy` in public interface (error E0446) - --> $DIR/where-priv-type.rs:35:1 + --> $DIR/where-priv-type.rs:41:1 | LL | / pub fn f() LL | | @@ -30,8 +61,25 @@ LL | | PrivTy: = 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 +warning: type `PrivTy` is more private than the item `f` + | +note: function `f` is reachable at visibility `pub` + --> $DIR/where-priv-type.rs:41:1 + | +LL | / pub fn f() +LL | | +LL | | +LL | | where +LL | | PrivTy: + | |___________^ +note: but type `PrivTy` is only usable at visibility `pub(crate)` + --> $DIR/where-priv-type.rs:15:1 + | +LL | struct PrivTy; + | ^^^^^^^^^^^^^ + error[E0446]: private type `PrivTy` in public interface - --> $DIR/where-priv-type.rs:43:1 + --> $DIR/where-priv-type.rs:49:1 | LL | struct PrivTy; | ------------- `PrivTy` declared as private @@ -39,8 +87,21 @@ LL | struct PrivTy; LL | impl S | ^^^^^^ can't leak private type +warning: type `PrivTy` is more private than the item `S` + | +note: implementation `S` is reachable at visibility `pub` + --> $DIR/where-priv-type.rs:49:1 + | +LL | impl S + | ^^^^^^ +note: but type `PrivTy` is only usable at visibility `pub(crate)` + --> $DIR/where-priv-type.rs:15:1 + | +LL | struct PrivTy; + | ^^^^^^^^^^^^^ + warning: private type `PrivTy` in public interface (error E0446) - --> $DIR/where-priv-type.rs:48:5 + --> $DIR/where-priv-type.rs:54:5 | LL | / pub fn f() LL | | @@ -52,8 +113,25 @@ LL | | PrivTy: = 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 +warning: type `PrivTy` is more private than the item `S::f` + | +note: associated function `S::f` is reachable at visibility `pub` + --> $DIR/where-priv-type.rs:54:5 + | +LL | / pub fn f() +LL | | +LL | | +LL | | where +LL | | PrivTy: + | |_______________^ +note: but type `PrivTy` is only usable at visibility `pub(crate)` + --> $DIR/where-priv-type.rs:15:1 + | +LL | struct PrivTy; + | ^^^^^^^^^^^^^ + error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface - --> $DIR/where-priv-type.rs:80:5 + --> $DIR/where-priv-type.rs:86:5 | LL | type AssocTy = Const<{ my_const_fn(U) }>; | ^^^^^^^^^^^^ can't leak private type @@ -61,6 +139,24 @@ LL | type AssocTy = Const<{ my_const_fn(U) }>; LL | const fn my_const_fn(val: u8) -> u8 { | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private -error: aborting due to 2 previous errors; 4 warnings emitted +warning: type `fn(u8) -> u8 {my_const_fn}` is more private than the item ` as Trait>::AssocTy` + | +note: associated type ` as Trait>::AssocTy` is reachable at visibility `pub` + --> $DIR/where-priv-type.rs:86:5 + | +LL | type AssocTy = Const<{ my_const_fn(U) }>; + | ^^^^^^^^^^^^ +note: but type `fn(u8) -> u8 {my_const_fn}` is only usable at visibility `pub(crate)` + --> $DIR/where-priv-type.rs:93:1 + | +LL | const fn my_const_fn(val: u8) -> u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/where-priv-type.rs:9:9 + | +LL | #![warn(private_interfaces)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 10 warnings emitted For more information about this error, try `rustc --explain E0446`. diff --git a/tests/ui/privacy/where-pub-type-impls-priv-trait.rs b/tests/ui/privacy/where-pub-type-impls-priv-trait.rs index 87c211df169..3aad893eae2 100644 --- a/tests/ui/privacy/where-pub-type-impls-priv-trait.rs +++ b/tests/ui/privacy/where-pub-type-impls-priv-trait.rs @@ -4,6 +4,11 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] +#![warn(private_bounds)] + +// In this test both old and new private-in-public diagnostic were emitted. +// Old diagnostic will be deleted soon. +// See https://rust-lang.github.io/rfcs/2145-type-privacy.html. struct PrivTy; trait PrivTr {} diff --git a/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr b/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr index a433cebbbc0..413f7f781cd 100644 --- a/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr +++ b/tests/ui/privacy/where-pub-type-impls-priv-trait.stderr @@ -1,5 +1,5 @@ error[E0445]: private trait `PrivTr` in public interface - --> $DIR/where-pub-type-impls-priv-trait.rs:19:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:24:1 | LL | trait PrivTr {} | ------------ `PrivTr` declared as private @@ -7,8 +7,26 @@ LL | trait PrivTr {} LL | pub struct S | ^^^^^^^^^^^^ can't leak private trait +warning: trait `PrivTr` is more private than the item `S` + | +note: struct `S` is reachable at visibility `pub` + --> $DIR/where-pub-type-impls-priv-trait.rs:24:1 + | +LL | pub struct S + | ^^^^^^^^^^^^ +note: but trait `PrivTr` is only usable at visibility `pub(crate)` + --> $DIR/where-pub-type-impls-priv-trait.rs:14:1 + | +LL | trait PrivTr {} + | ^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/where-pub-type-impls-priv-trait.rs:7:9 + | +LL | #![warn(private_bounds)] + | ^^^^^^^^^^^^^^ + error[E0445]: private trait `PrivTr` in public interface - --> $DIR/where-pub-type-impls-priv-trait.rs:26:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:31:1 | LL | trait PrivTr {} | ------------ `PrivTr` declared as private @@ -16,8 +34,21 @@ LL | trait PrivTr {} LL | pub enum E | ^^^^^^^^^^ can't leak private trait +warning: trait `PrivTr` is more private than the item `E` + | +note: enum `E` is reachable at visibility `pub` + --> $DIR/where-pub-type-impls-priv-trait.rs:31:1 + | +LL | pub enum E + | ^^^^^^^^^^ +note: but trait `PrivTr` is only usable at visibility `pub(crate)` + --> $DIR/where-pub-type-impls-priv-trait.rs:14:1 + | +LL | trait PrivTr {} + | ^^^^^^^^^^^^ + error[E0445]: private trait `PrivTr` in public interface - --> $DIR/where-pub-type-impls-priv-trait.rs:33:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:38:1 | LL | trait PrivTr {} | ------------ `PrivTr` declared as private @@ -28,8 +59,24 @@ LL | | where LL | | PubTy: PrivTr | |_________________^ can't leak private trait +warning: trait `PrivTr` is more private than the item `f` + | +note: function `f` is reachable at visibility `pub` + --> $DIR/where-pub-type-impls-priv-trait.rs:38:1 + | +LL | / pub fn f() +LL | | +LL | | where +LL | | PubTy: PrivTr + | |_________________^ +note: but trait `PrivTr` is only usable at visibility `pub(crate)` + --> $DIR/where-pub-type-impls-priv-trait.rs:14:1 + | +LL | trait PrivTr {} + | ^^^^^^^^^^^^ + error[E0445]: private trait `PrivTr` in public interface - --> $DIR/where-pub-type-impls-priv-trait.rs:40:1 + --> $DIR/where-pub-type-impls-priv-trait.rs:45:1 | LL | trait PrivTr {} | ------------ `PrivTr` declared as private @@ -37,8 +84,21 @@ LL | trait PrivTr {} LL | impl S | ^^^^^^ can't leak private trait +warning: trait `PrivTr` is more private than the item `S` + | +note: implementation `S` is reachable at visibility `pub` + --> $DIR/where-pub-type-impls-priv-trait.rs:45:1 + | +LL | impl S + | ^^^^^^ +note: but trait `PrivTr` is only usable at visibility `pub(crate)` + --> $DIR/where-pub-type-impls-priv-trait.rs:14:1 + | +LL | trait PrivTr {} + | ^^^^^^^^^^^^ + error[E0445]: private trait `PrivTr` in public interface - --> $DIR/where-pub-type-impls-priv-trait.rs:45:5 + --> $DIR/where-pub-type-impls-priv-trait.rs:50:5 | LL | trait PrivTr {} | ------------ `PrivTr` declared as private @@ -49,6 +109,22 @@ LL | | where LL | | PubTy: PrivTr | |_____________________^ can't leak private trait -error: aborting due to 5 previous errors +warning: trait `PrivTr` is more private than the item `S::f` + | +note: associated function `S::f` is reachable at visibility `pub` + --> $DIR/where-pub-type-impls-priv-trait.rs:50:5 + | +LL | / pub fn f() +LL | | +LL | | where +LL | | PubTy: PrivTr + | |_____________________^ +note: but trait `PrivTr` is only usable at visibility `pub(crate)` + --> $DIR/where-pub-type-impls-priv-trait.rs:14:1 + | +LL | trait PrivTr {} + | ^^^^^^^^^^^^ + +error: aborting due to 5 previous errors; 5 warnings emitted For more information about this error, try `rustc --explain E0445`. diff --git a/tests/ui/pub/issue-33174-restricted-type-in-public-interface.rs b/tests/ui/pub/issue-33174-restricted-type-in-public-interface.rs index 67f888c5e94..9e4ba80a784 100644 --- a/tests/ui/pub/issue-33174-restricted-type-in-public-interface.rs +++ b/tests/ui/pub/issue-33174-restricted-type-in-public-interface.rs @@ -1,15 +1,24 @@ #![allow(non_camel_case_types)] // genus is always capitalized +#![warn(private_interfaces)] +//~^ NOTE the lint level is defined here + +// In this test both old and new private-in-public diagnostic were emitted. +// Old diagnostic will be deleted soon. +// See https://rust-lang.github.io/rfcs/2145-type-privacy.html. pub(crate) struct Snail; //~^ NOTE `Snail` declared as private +//~| NOTE but type `Snail` is only usable at visibility `pub(crate)` mod sea { pub(super) struct Turtle; //~^ NOTE `Turtle` declared as crate-private + //~| NOTE but type `Turtle` is only usable at visibility `pub(crate)` } struct Tortoise; //~^ NOTE `Tortoise` declared as private +//~| NOTE but type `Tortoise` is only usable at visibility `pub(crate)` pub struct Shell { pub(crate) creature: T, @@ -18,11 +27,14 @@ pub struct Shell { pub type Helix_pomatia = Shell; //~^ ERROR private type `Snail` in public interface //~| NOTE can't leak private type +//~| NOTE type alias `Helix_pomatia` is reachable at visibility `pub` pub type Dermochelys_coriacea = Shell; //~^ ERROR crate-private type `Turtle` in public interface //~| NOTE can't leak crate-private type +//~| NOTE type alias `Dermochelys_coriacea` is reachable at visibility `pub` pub type Testudo_graeca = Shell; //~^ ERROR private type `Tortoise` in public interface //~| NOTE can't leak private type +//~| NOTE type alias `Testudo_graeca` is reachable at visibility `pub` fn main() {} diff --git a/tests/ui/pub/issue-33174-restricted-type-in-public-interface.stderr b/tests/ui/pub/issue-33174-restricted-type-in-public-interface.stderr index 39d4f5ac8d3..52f67d4cdd5 100644 --- a/tests/ui/pub/issue-33174-restricted-type-in-public-interface.stderr +++ b/tests/ui/pub/issue-33174-restricted-type-in-public-interface.stderr @@ -1,5 +1,5 @@ error[E0446]: private type `Snail` in public interface - --> $DIR/issue-33174-restricted-type-in-public-interface.rs:18:1 + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:27:1 | LL | pub(crate) struct Snail; | ----------------------- `Snail` declared as private @@ -7,8 +7,26 @@ LL | pub(crate) struct Snail; LL | pub type Helix_pomatia = Shell; | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type +warning: type `Snail` is more private than the item `Helix_pomatia` + | +note: type alias `Helix_pomatia` is reachable at visibility `pub` + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:27:1 + | +LL | pub type Helix_pomatia = Shell; + | ^^^^^^^^^^^^^^^^^^^^^^ +note: but type `Snail` is only usable at visibility `pub(crate)` + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:9:1 + | +LL | pub(crate) struct Snail; + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:2:9 + | +LL | #![warn(private_interfaces)] + | ^^^^^^^^^^^^^^^^^^ + error[E0446]: crate-private type `Turtle` in public interface - --> $DIR/issue-33174-restricted-type-in-public-interface.rs:21:1 + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:31:1 | LL | pub(super) struct Turtle; | ------------------------ `Turtle` declared as crate-private @@ -16,8 +34,21 @@ LL | pub(super) struct Turtle; LL | pub type Dermochelys_coriacea = Shell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-private type +warning: type `Turtle` is more private than the item `Dermochelys_coriacea` + | +note: type alias `Dermochelys_coriacea` is reachable at visibility `pub` + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:31:1 + | +LL | pub type Dermochelys_coriacea = Shell; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: but type `Turtle` is only usable at visibility `pub(crate)` + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:14:5 + | +LL | pub(super) struct Turtle; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0446]: private type `Tortoise` in public interface - --> $DIR/issue-33174-restricted-type-in-public-interface.rs:24:1 + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:35:1 | LL | struct Tortoise; | --------------- `Tortoise` declared as private @@ -25,6 +56,19 @@ LL | struct Tortoise; LL | pub type Testudo_graeca = Shell; | ^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type -error: aborting due to 3 previous errors +warning: type `Tortoise` is more private than the item `Testudo_graeca` + | +note: type alias `Testudo_graeca` is reachable at visibility `pub` + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:35:1 + | +LL | pub type Testudo_graeca = Shell; + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: but type `Tortoise` is only usable at visibility `pub(crate)` + --> $DIR/issue-33174-restricted-type-in-public-interface.rs:19:1 + | +LL | struct Tortoise; + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 3 warnings emitted For more information about this error, try `rustc --explain E0446`.