about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBryanskiy <ivakin.kir@gmail.com>2023-05-18 14:57:45 +0300
committerBryanskiy <ivakin.kir@gmail.com>2023-06-12 01:02:19 +0300
commit6d46382f6f0688df0fc5c67386f86ccd6fdb975f (patch)
treeda222fe6ab404e953e1683070bdd60a700b5991c
parentd0ee1908ed791d3e91d2ad74ba502eaa203cff6d (diff)
downloadrust-6d46382f6f0688df0fc5c67386f86ccd6fdb975f.tar.gz
rust-6d46382f6f0688df0fc5c67386f86ccd6fdb975f.zip
Private-in-public lints implementation
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs95
-rw-r--r--compiler/rustc_privacy/messages.ftl7
-rw-r--r--compiler/rustc_privacy/src/errors.rs29
-rw-r--r--compiler/rustc_privacy/src/lib.rs270
-rw-r--r--tests/ui/associated-inherent-types/private-in-public.rs5
-rw-r--r--tests/ui/associated-inherent-types/private-in-public.stderr52
-rw-r--r--tests/ui/const-generics/generic_const_exprs/eval-privacy.rs6
-rw-r--r--tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr22
-rw-r--r--tests/ui/error-codes/E0445.rs7
-rw-r--r--tests/ui/error-codes/E0445.stderr52
-rw-r--r--tests/ui/issues/issue-18389.rs6
-rw-r--r--tests/ui/issues/issue-18389.stderr26
-rw-r--r--tests/ui/privacy/private-in-public-non-principal.rs6
-rw-r--r--tests/ui/privacy/private-in-public-non-principal.stderr26
-rw-r--r--tests/ui/privacy/private-inferred-type-1.rs10
-rw-r--r--tests/ui/privacy/private-inferred-type-1.stderr18
-rw-r--r--tests/ui/privacy/unnameable_types.rs30
-rw-r--r--tests/ui/privacy/unnameable_types.stderr38
-rw-r--r--tests/ui/privacy/where-priv-type.rs6
-rw-r--r--tests/ui/privacy/where-priv-type.stderr110
-rw-r--r--tests/ui/privacy/where-pub-type-impls-priv-trait.rs5
-rw-r--r--tests/ui/privacy/where-pub-type-impls-priv-trait.stderr88
-rw-r--r--tests/ui/pub/issue-33174-restricted-type-in-public-interface.rs12
-rw-r--r--tests/ui/pub/issue-33174-restricted-type-in-public-interface.stderr52
24 files changed, 893 insertions, 85 deletions
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 @@ declare_lint_pass! {
         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 @@ declare_lint_pass! {
         UNINHABITED_STATIC,
         UNKNOWN_CRATE_TYPES,
         UNKNOWN_LINTS,
+        UNNAMEABLE_TYPES,
         UNREACHABLE_CODE,
         UNREACHABLE_PATTERNS,
         UNSAFE_OP_IN_UNSAFE_FN,
@@ -4251,3 +4254,95 @@ declare_lint! {
     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 as hir;
 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 std::{fmt, mem};
 
 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 @@ fluent_messages! { "../messages.ftl" }
 /// 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 @@ where
                     &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 @@ impl VisibilityLike for ty::Visibility {
     }
 }
 
-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<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
@@ -429,7 +447,7 @@ impl VisibilityLike for EffectiveVisibility {
                 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 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'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 @@ impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
             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<EffectiveVisibility>,
     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 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
     }
 
     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 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
     }
 
     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 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
     }
 
     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 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
         };
 
         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 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                     }
                 }
             };
-            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 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
             }
         }
 
+        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 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
     }
 }
 
-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<EffectiveVisibility>,
     ) -> 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<EffectiveVisibility>) {
+        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 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
         def_id: LocalDefId,
         assoc_item_kind: AssocItemKind,
         vis: ty::Visibility,
+        effective_vis: Option<EffectiveVisibility>,
     ) {
-        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 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
         }
     }
 
+    fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
+        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 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                 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 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                 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 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                 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<Priv> 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 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                         } 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 <https://github.com/rust-lang/rust/issues/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<PrivTy>;
    | ^^^^^^^^^^^^^^^^^^
@@ -30,5 +61,18 @@ LL | pub type PubAlias2 = PubTy::PubAssocTy<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 <https://github.com/rust-lang/rust/issues/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<PrivTy>;
+   | ^^^^^^^^^^^^^^^^^^
+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<const U: u8>;
 
 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 `<Const<U> as Trait>::AssocTy`
+   |
+note: associated type `<Const<U> 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<T: Foo>(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<T: Foo>(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: 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: 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<<Self as Public>::P, <Self as Public>::R>` in public interface
-  --> $DIR/issue-18389.rs:7:1
+  --> $DIR/issue-18389.rs:13:1
    |
 LL |   trait Private<P, R> {
    |   ------------------- `Private<<Self as Public>::P, <Self as Public>::R>` declared as private
@@ -11,6 +11,28 @@ LL | |     <Self as Public>::R
 LL | | > {
    | |_^ can't leak private trait
 
-error: aborting due to previous error
+warning: trait `Private<<Self as Public>::P, <Self as Public>::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 | |     <Self as Public>::P,
+LL | |     <Self as Public>::R
+LL | | > {
+   | |_^
+note: but trait `Private<<Self as Public>::P, <Self as Public>::R>` is only usable at visibility `pub(crate)`
+  --> $DIR/issue-18389.rs:10:1
+   |
+LL | trait Private<P, R> {
+   | ^^^^^^^^^^^^^^^^^^^
+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<dyn PubPrincipal + PrivNonPrincipal> { loop {} }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,17 +8,35 @@ LL | pub fn leak_dyn_nonprincipal() -> Box<dyn PubPrincipal + PrivNonPrincipal>
    = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/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<dyn PubPrincipal + PrivNonPrincipal> { 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<Priv> { 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 `<PubStruct as PubTr>::Alias` is reachable but cannot be named
+        fn f() {}
+    }
+}
+
+pub trait Voldemort<T> {}
+
+impl Voldemort<m::PubStruct> for i32 {}
+impl Voldemort<m::PubE> for i32 {}
+impl<T> Voldemort<T> 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 `<PubStruct as PubTr>::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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 `<Const<U> as Trait>::AssocTy`
+   |
+note: associated type `<Const<U> 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<T> {
     pub(crate) creature: T,
@@ -18,11 +27,14 @@ pub struct Shell<T> {
 pub type Helix_pomatia = Shell<Snail>;
 //~^ 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<sea::Turtle>;
 //~^ 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<Tortoise>;
 //~^ 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<Snail>;
    | ^^^^^^^^^^^^^^^^^^^^^^ 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<Snail>;
+   | ^^^^^^^^^^^^^^^^^^^^^^
+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<sea::Turtle>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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<sea::Turtle>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+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<Tortoise>;
    | ^^^^^^^^^^^^^^^^^^^^^^^ 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<Tortoise>;
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+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`.