about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs27
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs62
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs99
-rw-r--r--compiler/rustc_lint/src/builtin.rs8
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs10
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs481
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs35
-rw-r--r--compiler/rustc_privacy/src/lib.rs173
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/convert/mod.rs2
-rw-r--r--library/core/src/iter/adapters/flatten.rs12
-rw-r--r--library/core/src/iter/traits/iterator.rs8
-rw-r--r--library/core/src/marker.rs28
-rw-r--r--library/core/src/ops/index.rs2
-rw-r--r--library/core/src/ops/try_trait.rs45
-rw-r--r--library/core/src/slice/index.rs5
-rw-r--r--src/doc/style-guide/src/README.md5
-rw-r--r--src/doc/style-guide/src/statements.md26
-rw-r--r--tests/ui/associated-inherent-types/private-in-public.rs2
-rw-r--r--tests/ui/associated-type-bounds/implied-in-supertrait.rs19
-rw-r--r--tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs28
-rw-r--r--tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr11
-rw-r--r--tests/ui/closures/issue-113087.rs11
-rw-r--r--tests/ui/closures/issue-113087.stderr16
-rw-r--r--tests/ui/const-generics/generic_const_exprs/eval-privacy.rs2
-rw-r--r--tests/ui/error-codes/E0445.rs1
-rw-r--r--tests/ui/error-codes/E0445.stderr20
-rw-r--r--tests/ui/feature-gates/feature-gate-type_privacy_lints.rs12
-rw-r--r--tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr93
-rw-r--r--tests/ui/issues/issue-18389.rs1
-rw-r--r--tests/ui/issues/issue-18389.stderr8
-rw-r--r--tests/ui/privacy/effective_visibilities_full_priv.rs2
-rw-r--r--tests/ui/privacy/effective_visibilities_full_priv.stderr2
-rw-r--r--tests/ui/privacy/private-in-public-non-principal.rs2
-rw-r--r--tests/ui/privacy/unnameable_types.rs2
-rw-r--r--tests/ui/privacy/where-priv-type.rs2
-rw-r--r--tests/ui/privacy/where-pub-type-impls-priv-trait.rs2
-rw-r--r--tests/ui/pub/issue-33174-restricted-type-in-public-interface.rs1
-rw-r--r--tests/ui/pub/issue-33174-restricted-type-in-public-interface.stderr20
-rw-r--r--tests/ui/traits/auxiliary/trivial3.rs1
-rw-r--r--tests/ui/traits/auxiliary/trivial4.rs3
-rw-r--r--tests/ui/traits/trivial_impl.rs18
-rw-r--r--tests/ui/traits/trivial_impl.stderr14
-rw-r--r--tests/ui/traits/trivial_impl2.rs13
-rw-r--r--tests/ui/traits/trivial_impl2.stderr14
-rw-r--r--tests/ui/traits/trivial_impl3.rs19
-rw-r--r--tests/ui/traits/trivial_impl3.stderr14
-rw-r--r--tests/ui/traits/trivial_impl4.rs21
-rw-r--r--tests/ui/traits/trivial_impl4.stderr14
-rw-r--r--tests/ui/traits/trivial_impl_sized.rs26
-rw-r--r--tests/ui/traits/trivial_impl_sized.stderr25
54 files changed, 906 insertions, 588 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 39b05829888..a068f2d6926 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1730,18 +1730,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             (
                 Some(name),
                 BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
-            ) => self.report_escaping_closure_capture(
-                borrow_spans,
-                borrow_span,
-                &RegionName {
-                    name: self.synthesize_region_name(),
-                    source: RegionNameSource::Static,
-                },
-                ConstraintCategory::CallArgument(None),
-                var_or_use_span,
-                &format!("`{}`", name),
-                "block",
-            ),
+            ) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
+                .report_escaping_closure_capture(
+                    borrow_spans,
+                    borrow_span,
+                    &RegionName {
+                        name: self.synthesize_region_name(),
+                        source: RegionNameSource::Static,
+                    },
+                    ConstraintCategory::CallArgument(None),
+                    var_or_use_span,
+                    &format!("`{}`", name),
+                    "block",
+                ),
             (
                 Some(name),
                 BorrowExplanation::MustBeValidFor {
@@ -1754,7 +1755,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     span,
                     ..
                 },
-            ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
+            ) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
                 .report_escaping_closure_capture(
                     borrow_spans,
                     borrow_span,
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 93f968aa851..906c31c9a3d 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -543,6 +543,8 @@ declare_features! (
     /// Allows creation of instances of a struct by moving fields that have
     /// not changed from prior instances of the same struct (RFC #2528)
     (active, type_changing_struct_update, "1.58.0", Some(86555), None),
+    /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`).
+    (active, type_privacy_lints, "CURRENT_RUSTC_VERSION", Some(48054), None),
     /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
     (active, unix_sigpipe, "1.65.0", Some(97889), None),
     /// Allows unsized fn parameters.
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index d29601e9008..89677141f38 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -9,12 +9,12 @@ use rustc_span::symbol::Ident;
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits;
 
-use crate::astconv::{AstConv, ConvertedBinding, ConvertedBindingKind};
+use crate::astconv::{
+    AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
+};
 use crate::bounds::Bounds;
 use crate::errors::{MultipleRelaxedDefaultBounds, ValueOfAssociatedStructAlreadySpecified};
 
-use super::OnlySelfBounds;
-
 impl<'tcx> dyn AstConv<'tcx> + '_ {
     /// Sets `implicitly_sized` to true on `Bounds` if necessary
     pub(crate) fn add_implicitly_sized(
@@ -176,47 +176,39 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         &self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound<'_>],
-        only_self_bounds: OnlySelfBounds,
+        filter: PredicateFilter,
     ) -> Bounds<'tcx> {
         let mut bounds = Bounds::default();
-        self.add_bounds(
-            param_ty,
-            ast_bounds.iter(),
-            &mut bounds,
-            ty::List::empty(),
-            only_self_bounds,
-        );
-        debug!(?bounds);
 
-        bounds
-    }
-
-    /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
-    /// named `assoc_name` into ty::Bounds. Ignore the rest.
-    pub(crate) fn compute_bounds_that_match_assoc_item(
-        &self,
-        param_ty: Ty<'tcx>,
-        ast_bounds: &[hir::GenericBound<'_>],
-        assoc_name: Ident,
-    ) -> Bounds<'tcx> {
-        let mut result = Vec::new();
-
-        for ast_bound in ast_bounds {
-            if let Some(trait_ref) = ast_bound.trait_ref()
-                && let Some(trait_did) = trait_ref.trait_def_id()
-                && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
-            {
-                result.push(ast_bound.clone());
+        let only_self_bounds = match filter {
+            PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                OnlySelfBounds(false)
             }
-        }
+            PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true),
+        };
 
-        let mut bounds = Bounds::default();
         self.add_bounds(
             param_ty,
-            result.iter(),
+            ast_bounds.iter().filter(|bound| {
+                match filter {
+                PredicateFilter::All
+                | PredicateFilter::SelfOnly
+                | PredicateFilter::SelfAndAssociatedTypeBounds => true,
+                PredicateFilter::SelfThatDefines(assoc_name) => {
+                    if let Some(trait_ref) = bound.trait_ref()
+                        && let Some(trait_did) = trait_ref.trait_def_id()
+                        && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
+                    {
+                        true
+                    } else {
+                        false
+                    }
+                }
+            }
+            }),
             &mut bounds,
             ty::List::empty(),
-            OnlySelfBounds(true),
+            only_self_bounds,
         );
         debug!(?bounds);
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 6a59aa36ec7..5032378923b 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -58,6 +58,24 @@ pub struct PathSeg(pub DefId, pub usize);
 #[derive(Copy, Clone, Debug)]
 pub struct OnlySelfBounds(pub bool);
 
+#[derive(Copy, Clone, Debug)]
+pub enum PredicateFilter {
+    /// All predicates may be implied by the trait.
+    All,
+
+    /// Only traits that reference `Self: ..` are implied by the trait.
+    SelfOnly,
+
+    /// Only traits that reference `Self: ..` and define an associated type
+    /// with the given ident are implied by the trait.
+    SelfThatDefines(Ident),
+
+    /// Only traits that reference `Self: ..` and their associated type bounds.
+    /// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr`
+    /// and `<Self as Tr>::A: B`.
+    SelfAndAssociatedTypeBounds,
+}
+
 pub trait AstConv<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx>;
 
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 44c393bfe82..8b3f98493c1 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -1,5 +1,5 @@
 use super::ItemCtxt;
-use crate::astconv::{AstConv, OnlySelfBounds};
+use crate::astconv::{AstConv, PredicateFilter};
 use rustc_hir as hir;
 use rustc_infer::traits::util;
 use rustc_middle::ty::subst::InternalSubsts;
@@ -26,7 +26,7 @@ fn associated_type_bounds<'tcx>(
     );
 
     let icx = ItemCtxt::new(tcx, assoc_item_def_id);
-    let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
+    let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
     // Associated types are implicitly sized unless a `?Sized` bound is found
     icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
 
@@ -68,7 +68,7 @@ fn opaque_type_bounds<'tcx>(
 ) -> &'tcx [(ty::Clause<'tcx>, Span)] {
     ty::print::with_no_queries!({
         let icx = ItemCtxt::new(tcx, opaque_def_id);
-        let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
+        let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
         icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
         debug!(?bounds);
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index edb6a4cace3..d9b2aacab9d 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -1,4 +1,4 @@
-use crate::astconv::{AstConv, OnlySelfBounds};
+use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
 use crate::bounds::Bounds;
 use crate::collect::ItemCtxt;
 use crate::constrained_generic_params as cgp;
@@ -125,7 +125,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     if let Some(self_bounds) = is_trait {
         predicates.extend(
             icx.astconv()
-                .compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
+                .compute_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
                 .clauses(),
         );
     }
@@ -530,19 +530,6 @@ pub(super) fn explicit_predicates_of<'tcx>(
     }
 }
 
-#[derive(Copy, Clone, Debug)]
-pub enum PredicateFilter {
-    /// All predicates may be implied by the trait
-    All,
-
-    /// Only traits that reference `Self: ..` are implied by the trait
-    SelfOnly,
-
-    /// Only traits that reference `Self: ..` and define an associated type
-    /// with the given ident are implied by the trait
-    SelfThatDefines(Ident),
-}
-
 /// Ensures that the super-predicates of the trait with a `DefId`
 /// of `trait_def_id` are converted and stored. This also ensures that
 /// the transitive super-predicates are converted.
@@ -564,11 +551,15 @@ pub(super) fn implied_predicates_of(
     tcx: TyCtxt<'_>,
     trait_def_id: LocalDefId,
 ) -> ty::GenericPredicates<'_> {
-    if tcx.is_trait_alias(trait_def_id.to_def_id()) {
-        implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All)
-    } else {
-        tcx.super_predicates_of(trait_def_id)
-    }
+    implied_predicates_with_filter(
+        tcx,
+        trait_def_id.to_def_id(),
+        if tcx.is_trait_alias(trait_def_id.to_def_id()) {
+            PredicateFilter::All
+        } else {
+            PredicateFilter::SelfAndAssociatedTypeBounds
+        },
+    )
 }
 
 /// Ensures that the super-predicates of the trait with a `DefId`
@@ -601,44 +592,14 @@ pub(super) fn implied_predicates_with_filter(
     let icx = ItemCtxt::new(tcx, trait_def_id);
 
     let self_param_ty = tcx.types.self_param;
-    let (superbounds, where_bounds_that_match) = match filter {
-        PredicateFilter::All => (
-            // Convert the bounds that follow the colon (or equal in trait aliases)
-            icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)),
-            // Also include all where clause bounds
-            icx.type_parameter_bounds_in_generics(
-                generics,
-                item.owner_id.def_id,
-                self_param_ty,
-                OnlySelfBounds(false),
-                None,
-            ),
-        ),
-        PredicateFilter::SelfOnly => (
-            // Convert the bounds that follow the colon (or equal in trait aliases)
-            icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)),
-            // Include where clause bounds for `Self`
-            icx.type_parameter_bounds_in_generics(
-                generics,
-                item.owner_id.def_id,
-                self_param_ty,
-                OnlySelfBounds(true),
-                None,
-            ),
-        ),
-        PredicateFilter::SelfThatDefines(assoc_name) => (
-            // Convert the bounds that follow the colon (or equal) that reference the associated name
-            icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name),
-            // Include where clause bounds for `Self` that reference the associated name
-            icx.type_parameter_bounds_in_generics(
-                generics,
-                item.owner_id.def_id,
-                self_param_ty,
-                OnlySelfBounds(true),
-                Some(assoc_name),
-            ),
-        ),
-    };
+    let superbounds = icx.astconv().compute_bounds(self_param_ty, bounds, filter);
+
+    let where_bounds_that_match = icx.type_parameter_bounds_in_generics(
+        generics,
+        item.owner_id.def_id,
+        self_param_ty,
+        filter,
+    );
 
     // Combine the two lists to form the complete set of superbounds:
     let implied_bounds =
@@ -743,8 +704,7 @@ pub(super) fn type_param_predicates(
             ast_generics,
             def_id,
             ty,
-            OnlySelfBounds(true),
-            Some(assoc_name),
+            PredicateFilter::SelfThatDefines(assoc_name),
         )
         .into_iter()
         .filter(|(predicate, _)| match predicate.kind().skip_binder() {
@@ -768,8 +728,7 @@ impl<'tcx> ItemCtxt<'tcx> {
         ast_generics: &'tcx hir::Generics<'tcx>,
         param_def_id: LocalDefId,
         ty: Ty<'tcx>,
-        only_self_bounds: OnlySelfBounds,
-        assoc_name: Option<Ident>,
+        filter: PredicateFilter,
     ) -> Vec<(ty::Clause<'tcx>, Span)> {
         let mut bounds = Bounds::default();
 
@@ -778,9 +737,23 @@ impl<'tcx> ItemCtxt<'tcx> {
                 continue;
             };
 
+            let (only_self_bounds, assoc_name) = match filter {
+                PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                    (OnlySelfBounds(false), None)
+                }
+                PredicateFilter::SelfOnly => (OnlySelfBounds(true), None),
+                PredicateFilter::SelfThatDefines(assoc_name) => {
+                    (OnlySelfBounds(true), Some(assoc_name))
+                }
+            };
+
+            // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
+            // want to only consider predicates with `Self: ...`, but we don't want
+            // `OnlySelfBounds(true)` since we want to collect the nested associated
+            // type bound as well.
             let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
                 ty
-            } else if !only_self_bounds.0 {
+            } else if matches!(filter, PredicateFilter::All) {
                 self.to_ty(predicate.bounded_ty)
             } else {
                 continue;
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 53aad6d8b31..3a177038ca8 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -665,9 +665,7 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS])
 
 impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id)
-            && cx.tcx.local_visibility(item.owner_id.def_id).is_public())
-        {
+        if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
             return;
         }
         let (def, ty) = match item.kind {
@@ -786,9 +784,7 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
 
 impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id)
-            && cx.tcx.local_visibility(item.owner_id.def_id).is_public())
-        {
+        if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
             return;
         }
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index cbb4458d1d4..ef82a6c17ee 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -4264,6 +4264,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
+    /// # #![feature(type_privacy_lints)]
     /// # #![allow(unused)]
     /// # #![allow(private_in_public)]
     /// #![deny(private_interfaces)]
@@ -4288,6 +4289,7 @@ declare_lint! {
     pub PRIVATE_INTERFACES,
     Allow,
     "private type in primary interface of an item",
+    @feature_gate = sym::type_privacy_lints;
 }
 
 declare_lint! {
@@ -4298,6 +4300,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
+    /// # #![feature(type_privacy_lints)]
     /// # #![allow(private_in_public)]
     /// # #![allow(unused)]
     /// #![deny(private_bounds)]
@@ -4317,7 +4320,8 @@ declare_lint! {
     /// the item actually provides.
     pub PRIVATE_BOUNDS,
     Allow,
-    "private type in secondary interface of an item"
+    "private type in secondary interface of an item",
+    @feature_gate = sym::type_privacy_lints;
 }
 
 declare_lint! {
@@ -4327,6 +4331,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
+    /// # #![feature(type_privacy_lints)]
     /// # #![allow(unused)]
     /// #![deny(unnameable_types)]
     /// mod m {
@@ -4345,5 +4350,6 @@ declare_lint! {
     /// 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"
+    "effective visibility of a type is larger than the area in which it can be named",
+    @feature_gate = sym::type_privacy_lints;
 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index eee29d2090a..b80019bf155 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -17,9 +17,8 @@ use rustc_hir::def_id::{
     CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE,
 };
 use rustc_hir::definitions::DefPathData;
-use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::intravisit;
 use rustc_hir::lang_items::LangItem;
-use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
@@ -31,7 +30,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
-use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
+use rustc_middle::ty::{self, AssocItemContainer, SymbolName, Ty, TyCtxt};
 use rustc_middle::util::common::to_readable_str;
 use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
 use rustc_session::config::{CrateType, OptLevel};
@@ -450,18 +449,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         LazyArray::from_position_and_num_elems(pos, len)
     }
 
-    fn encode_info_for_items(&mut self) {
-        self.encode_info_for_mod(CRATE_DEF_ID);
-
-        // Proc-macro crates only export proc-macro items, which are looked
-        // up using `proc_macro_data`
-        if self.is_proc_macro {
-            return;
-        }
-
-        self.tcx.hir().visit_all_item_likes_in_crate(self);
-    }
-
     fn encode_def_path_table(&mut self) {
         let table = self.tcx.def_path_table();
         if self.is_proc_macro {
@@ -607,8 +594,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         _ = stat!("def-ids", || self.encode_def_ids());
 
-        _ = stat!("items", || self.encode_info_for_items());
-
         let interpret_alloc_index = stat!("interpret-alloc-index", || {
             let mut interpret_alloc_index = Vec::new();
             let mut n = 0;
@@ -1193,6 +1178,82 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
     }
 }
 
+fn should_encode_fn_sig(def_kind: DefKind) -> bool {
+    match def_kind {
+        DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) => true,
+
+        DefKind::Struct
+        | DefKind::Union
+        | DefKind::Enum
+        | DefKind::Variant
+        | DefKind::Field
+        | DefKind::Const
+        | DefKind::Static(..)
+        | DefKind::Ctor(..)
+        | DefKind::TyAlias
+        | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
+        | DefKind::ForeignTy
+        | DefKind::Impl { .. }
+        | DefKind::AssocConst
+        | DefKind::Closure
+        | DefKind::Generator
+        | DefKind::ConstParam
+        | DefKind::AnonConst
+        | DefKind::InlineConst
+        | DefKind::AssocTy
+        | DefKind::TyParam
+        | DefKind::Trait
+        | DefKind::TraitAlias
+        | DefKind::Mod
+        | DefKind::ForeignMod
+        | DefKind::Macro(..)
+        | DefKind::Use
+        | DefKind::LifetimeParam
+        | DefKind::GlobalAsm
+        | DefKind::ExternCrate => false,
+    }
+}
+
+fn should_encode_constness(def_kind: DefKind) -> bool {
+    match def_kind {
+        DefKind::Fn
+        | DefKind::AssocFn
+        | DefKind::Closure
+        | DefKind::Impl { of_trait: true }
+        | DefKind::Variant
+        | DefKind::Ctor(..) => true,
+
+        DefKind::Struct
+        | DefKind::Union
+        | DefKind::Enum
+        | DefKind::Field
+        | DefKind::Const
+        | DefKind::AssocConst
+        | DefKind::AnonConst
+        | DefKind::Static(..)
+        | DefKind::TyAlias
+        | DefKind::OpaqueTy
+        | DefKind::Impl { of_trait: false }
+        | DefKind::ImplTraitPlaceholder
+        | DefKind::ForeignTy
+        | DefKind::Generator
+        | DefKind::ConstParam
+        | DefKind::InlineConst
+        | DefKind::AssocTy
+        | DefKind::TyParam
+        | DefKind::Trait
+        | DefKind::TraitAlias
+        | DefKind::Mod
+        | DefKind::ForeignMod
+        | DefKind::Macro(..)
+        | DefKind::Use
+        | DefKind::LifetimeParam
+        | DefKind::GlobalAsm
+        | DefKind::ExternCrate => false,
+    }
+}
+
 fn should_encode_const(def_kind: DefKind) -> bool {
     match def_kind {
         DefKind::Const | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst => true,
@@ -1265,10 +1326,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_def_ids(&mut self) {
+        self.encode_info_for_mod(CRATE_DEF_ID);
+
+        // Proc-macro crates only export proc-macro items, which are looked
+        // up using `proc_macro_data`
         if self.is_proc_macro {
             return;
         }
+
         let tcx = self.tcx;
+
         for local_id in tcx.iter_local_def_id() {
             let def_id = local_id.to_def_id();
             let def_kind = tcx.opt_def_kind(local_id);
@@ -1305,30 +1372,81 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 let v = self.tcx.variances_of(def_id);
                 record_array!(self.tables.variances_of[def_id] <- v);
             }
+            if should_encode_fn_sig(def_kind) {
+                record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
+            }
             if should_encode_generics(def_kind) {
                 let g = tcx.generics_of(def_id);
                 record!(self.tables.generics_of[def_id] <- g);
                 record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id));
                 let inferred_outlives = self.tcx.inferred_outlives_of(def_id);
                 record_defaulted_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
+
+                for param in &g.params {
+                    if let ty::GenericParamDefKind::Const { has_default: true, .. } = param.kind {
+                        let default = self.tcx.const_param_default(param.def_id);
+                        record!(self.tables.const_param_default[param.def_id] <- default);
+                    }
+                }
             }
             if should_encode_type(tcx, local_id, def_kind) {
                 record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id));
             }
+            if should_encode_constness(def_kind) {
+                self.tables.constness.set_some(def_id.index, self.tcx.constness(def_id));
+            }
+            if let DefKind::Fn | DefKind::AssocFn = def_kind {
+                self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id));
+                record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id));
+                self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
+            }
             if let DefKind::TyParam = def_kind {
                 let default = self.tcx.object_lifetime_default(def_id);
                 record!(self.tables.object_lifetime_default[def_id] <- default);
             }
             if let DefKind::Trait = def_kind {
+                record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
                 record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
+
+                let module_children = self.tcx.module_children_local(local_id);
+                record_array!(self.tables.module_children_non_reexports[def_id] <-
+                    module_children.iter().map(|child| child.res.def_id().index));
             }
             if let DefKind::TraitAlias = def_kind {
+                record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
                 record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
                 record!(self.tables.implied_predicates_of[def_id] <- self.tcx.implied_predicates_of(def_id));
             }
+            if let DefKind::Trait | DefKind::Impl { .. } = def_kind {
+                let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
+                record_array!(self.tables.associated_item_or_field_def_ids[def_id] <-
+                    associated_item_def_ids.iter().map(|&def_id| {
+                        assert!(def_id.is_local());
+                        def_id.index
+                    })
+                );
+                for &def_id in associated_item_def_ids {
+                    self.encode_info_for_assoc_item(def_id);
+                }
+            }
+            if let DefKind::Generator = def_kind {
+                self.encode_info_for_generator(local_id);
+            }
             if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
                 self.encode_info_for_adt(local_id);
             }
+            if let DefKind::Mod = def_kind {
+                self.encode_info_for_mod(local_id);
+            }
+            if let DefKind::Macro(_) = def_kind {
+                self.encode_info_for_macro(local_id);
+            }
+            if let DefKind::OpaqueTy = def_kind {
+                self.encode_explicit_item_bounds(def_id);
+                self.tables
+                    .is_type_alias_impl_trait
+                    .set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id));
+            }
             if tcx.impl_method_has_trait_impl_trait_tys(def_id)
                 && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
             {
@@ -1389,26 +1507,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             };
             record!(self.tables.variant_data[variant.def_id] <- data);
 
-            self.tables.constness.set_some(variant.def_id.index, hir::Constness::Const);
             record_array!(self.tables.associated_item_or_field_def_ids[variant.def_id] <- variant.fields.iter().map(|f| {
                 assert!(f.did.is_local());
                 f.did.index
             }));
 
             if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
-                self.tables.constness.set_some(ctor_def_id.index, hir::Constness::Const);
                 let fn_sig = tcx.fn_sig(ctor_def_id);
-                record!(self.tables.fn_sig[ctor_def_id] <- fn_sig);
                 // FIXME only encode signature for ctor_def_id
                 record!(self.tables.fn_sig[variant.def_id] <- fn_sig);
             }
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn encode_info_for_mod(&mut self, local_def_id: LocalDefId) {
         let tcx = self.tcx;
         let def_id = local_def_id.to_def_id();
-        debug!("EncodeContext::encode_info_for_mod({:?})", def_id);
 
         // If we are encoding a proc-macro crates, `encode_info_for_mod` will
         // only ever get called for the crate root. We still want to encode
@@ -1436,70 +1551,28 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
     }
 
-    fn encode_info_for_trait_item(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
+    #[instrument(level = "debug", skip(self))]
+    fn encode_info_for_assoc_item(&mut self, def_id: DefId) {
         let tcx = self.tcx;
+        let item = tcx.associated_item(def_id);
 
-        let defaultness = tcx.defaultness(def_id.expect_local());
-        self.tables.defaultness.set_some(def_id.index, defaultness);
-        let trait_item = tcx.associated_item(def_id);
-        self.tables.assoc_container.set_some(def_id.index, trait_item.container);
+        self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx));
+        self.tables.assoc_container.set_some(def_id.index, item.container);
 
-        match trait_item.kind {
-            ty::AssocKind::Const => {}
-            ty::AssocKind::Fn => {
-                record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id));
-                self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id));
-                self.tables.constness.set_some(def_id.index, hir::Constness::NotConst);
-            }
-            ty::AssocKind::Type => {
-                self.encode_explicit_item_bounds(def_id);
+        match item.container {
+            AssocItemContainer::TraitContainer => {
+                if let ty::AssocKind::Type = item.kind {
+                    self.encode_explicit_item_bounds(def_id);
+                }
             }
-        }
-        if trait_item.kind == ty::AssocKind::Fn {
-            record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
-        }
-        if let Some(rpitit_info) = trait_item.opt_rpitit_info {
-            let rpitit_info = self.lazy(rpitit_info);
-            self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info);
-        }
-    }
-
-    fn encode_info_for_impl_item(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id);
-        let tcx = self.tcx;
-
-        let defaultness = self.tcx.defaultness(def_id.expect_local());
-        self.tables.defaultness.set_some(def_id.index, defaultness);
-        let impl_item = self.tcx.associated_item(def_id);
-        self.tables.assoc_container.set_some(def_id.index, impl_item.container);
-
-        match impl_item.kind {
-            ty::AssocKind::Fn => {
-                let (sig, body) =
-                    self.tcx.hir().expect_impl_item(def_id.expect_local()).expect_fn();
-                self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
-                record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
-                // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
-                let constness = if self.tcx.is_const_fn_raw(def_id) {
-                    hir::Constness::Const
-                } else {
-                    hir::Constness::NotConst
-                };
-                self.tables.constness.set_some(def_id.index, constness);
+            AssocItemContainer::ImplContainer => {
+                if let Some(trait_item_def_id) = item.trait_item_def_id {
+                    self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into());
+                }
             }
-            ty::AssocKind::Const | ty::AssocKind::Type => {}
         }
-        if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
-            self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into());
-        }
-        if impl_item.kind == ty::AssocKind::Fn {
-            record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
-            self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
-        }
-        if let Some(rpitit_info) = impl_item.opt_rpitit_info {
-            let rpitit_info = self.lazy(rpitit_info);
-            self.tables.opt_rpitit_info.set_some(def_id.index, rpitit_info);
+        if let Some(rpitit_info) = item.opt_rpitit_info {
+            record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
         }
     }
 
@@ -1572,9 +1645,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn encode_stability(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_stability({:?})", def_id);
-
         // The query lookup can take a measurable amount of time in crates with many items. Check if
         // the stability attributes are even enabled before using their queries.
         if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
@@ -1584,9 +1656,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn encode_const_stability(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_const_stability({:?})", def_id);
-
         // The query lookup can take a measurable amount of time in crates with many items. Check if
         // the stability attributes are even enabled before using their queries.
         if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
@@ -1596,9 +1667,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn encode_default_body_stability(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_default_body_stability({:?})", def_id);
-
         // The query lookup can take a measurable amount of time in crates with many items. Check if
         // the stability attributes are even enabled before using their queries.
         if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
@@ -1608,8 +1678,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn encode_deprecation(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_deprecation({:?})", def_id);
         if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
             record!(self.tables.lookup_deprecation_entry[def_id] <- depr);
         }
@@ -1623,123 +1693,22 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         })
     }
 
-    fn encode_info_for_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+    #[instrument(level = "debug", skip(self))]
+    fn encode_info_for_macro(&mut self, def_id: LocalDefId) {
         let tcx = self.tcx;
-        let def_id = item.owner_id.to_def_id();
-        debug!("EncodeContext::encode_info_for_item({:?})", def_id);
-
-        let record_associated_item_def_ids = |this: &mut Self, def_ids: &[DefId]| {
-            record_array!(this.tables.associated_item_or_field_def_ids[def_id] <- def_ids.iter().map(|&def_id| {
-                assert!(def_id.is_local());
-                def_id.index
-            }))
-        };
-
-        match item.kind {
-            hir::ItemKind::Fn(ref sig, .., body) => {
-                self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
-                record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
-                self.tables.constness.set_some(def_id.index, sig.header.constness);
-                record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
-                self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
-            }
-            hir::ItemKind::Macro(ref macro_def, _) => {
-                self.tables.is_macro_rules.set(def_id.index, macro_def.macro_rules);
-                record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
-            }
-            hir::ItemKind::Mod(..) => {
-                self.encode_info_for_mod(item.owner_id.def_id);
-            }
-            hir::ItemKind::OpaqueTy(ref opaque) => {
-                self.encode_explicit_item_bounds(def_id);
-                self.tables.is_type_alias_impl_trait.set(
-                    def_id.index,
-                    matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }),
-                );
-            }
-            hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
-                self.tables.defaultness.set_some(def_id.index, *defaultness);
-                self.tables.constness.set_some(def_id.index, *constness);
-                self.tables.impl_polarity.set_some(def_id.index, self.tcx.impl_polarity(def_id));
-
-                if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) {
-                    record!(self.tables.impl_trait_ref[def_id] <- trait_ref);
-
-                    let trait_ref = trait_ref.skip_binder();
-                    let trait_def = self.tcx.trait_def(trait_ref.def_id);
-                    if let Ok(mut an) = trait_def.ancestors(self.tcx, def_id) {
-                        if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
-                            self.tables.impl_parent.set_some(def_id.index, parent.into());
-                        }
-                    }
-
-                    // if this is an impl of `CoerceUnsized`, create its
-                    // "unsized info", else just store None
-                    if Some(trait_ref.def_id) == self.tcx.lang_items().coerce_unsized_trait() {
-                        let coerce_unsized_info =
-                            self.tcx.at(item.span).coerce_unsized_info(def_id);
-                        record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info);
-                    }
-                }
-
-                let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
-                record_associated_item_def_ids(self, associated_item_def_ids);
-                for &trait_item_def_id in associated_item_def_ids {
-                    self.encode_info_for_impl_item(trait_item_def_id);
-                }
-            }
-            hir::ItemKind::Trait(..) => {
-                record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
 
-                let module_children = tcx.module_children_local(item.owner_id.def_id);
-                record_array!(self.tables.module_children_non_reexports[def_id] <-
-                    module_children.iter().map(|child| child.res.def_id().index));
-
-                let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
-                record_associated_item_def_ids(self, associated_item_def_ids);
-                for &item_def_id in associated_item_def_ids {
-                    self.encode_info_for_trait_item(item_def_id);
-                }
-            }
-            hir::ItemKind::TraitAlias(..) => {
-                record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
-            }
-            hir::ItemKind::ExternCrate(_)
-            | hir::ItemKind::Use(..)
-            | hir::ItemKind::Static(..)
-            | hir::ItemKind::Const(..)
-            | hir::ItemKind::Enum(..)
-            | hir::ItemKind::Struct(..)
-            | hir::ItemKind::Union(..)
-            | hir::ItemKind::ForeignMod { .. }
-            | hir::ItemKind::GlobalAsm(..)
-            | hir::ItemKind::TyAlias(..) => {}
-        }
+        let hir::ItemKind::Macro(ref macro_def, _) = tcx.hir().expect_item(def_id).kind else { bug!() };
+        self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules);
+        record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body);
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn encode_info_for_closure(&mut self, def_id: LocalDefId) {
-        // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
-        // including on the signature, which is inferred in `typeck`.
+    fn encode_info_for_generator(&mut self, def_id: LocalDefId) {
         let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id);
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-        let ty = typeck_result.node_type(hir_id);
-        match ty.kind() {
-            ty::Generator(..) => {
-                let data = self.tcx.generator_kind(def_id).unwrap();
-                let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data();
-                record!(self.tables.generator_kind[def_id.to_def_id()] <- data);
-                record!(self.tables.generator_diagnostic_data[def_id.to_def_id()]  <- generator_diagnostic_data);
-            }
-
-            ty::Closure(_, substs) => {
-                let constness = self.tcx.constness(def_id.to_def_id());
-                self.tables.constness.set_some(def_id.to_def_id().index, constness);
-                record!(self.tables.fn_sig[def_id.to_def_id()] <- ty::EarlyBinder::bind(substs.as_closure().sig()));
-            }
-
-            _ => bug!("closure that is neither generator nor closure"),
-        }
+        let data = self.tcx.generator_kind(def_id).unwrap();
+        let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data();
+        record!(self.tables.generator_kind[def_id.to_def_id()] <- data);
+        record!(self.tables.generator_diagnostic_data[def_id.to_def_id()]  <- generator_diagnostic_data);
     }
 
     fn encode_native_libraries(&mut self) -> LazyArray<NativeLib> {
@@ -1960,28 +1929,43 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     /// Encodes an index, mapping each trait to its (local) implementations.
+    #[instrument(level = "debug", skip(self))]
     fn encode_impls(&mut self) -> LazyArray<TraitImpls> {
-        debug!("EncodeContext::encode_traits_and_impls()");
         empty_proc_macro!(self);
         let tcx = self.tcx;
         let mut fx_hash_map: FxHashMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>> =
             FxHashMap::default();
 
         for id in tcx.hir().items() {
-            if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) {
-                if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
-                    let trait_ref = trait_ref.subst_identity();
-
-                    let simplified_self_ty = fast_reject::simplify_type(
-                        self.tcx,
-                        trait_ref.self_ty(),
-                        TreatParams::AsCandidateKey,
-                    );
-
-                    fx_hash_map
-                        .entry(trait_ref.def_id)
-                        .or_default()
-                        .push((id.owner_id.def_id.local_def_index, simplified_self_ty));
+            let DefKind::Impl { of_trait } = tcx.def_kind(id.owner_id) else { continue; };
+            let def_id = id.owner_id.to_def_id();
+
+            self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id));
+            self.tables.impl_polarity.set_some(def_id.index, tcx.impl_polarity(def_id));
+
+            if of_trait && let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
+                record!(self.tables.impl_trait_ref[def_id] <- trait_ref);
+
+                let trait_ref = trait_ref.subst_identity();
+                let simplified_self_ty =
+                    fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey);
+                fx_hash_map
+                    .entry(trait_ref.def_id)
+                    .or_default()
+                    .push((id.owner_id.def_id.local_def_index, simplified_self_ty));
+
+                let trait_def = tcx.trait_def(trait_ref.def_id);
+                if let Some(mut an) = trait_def.ancestors(tcx, def_id).ok() {
+                    if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
+                        self.tables.impl_parent.set_some(def_id.index, parent.into());
+                    }
+                }
+
+                // if this is an impl of `CoerceUnsized`, create its
+                // "unsized info", else just store None
+                if Some(trait_ref.def_id) == tcx.lang_items().coerce_unsized_trait() {
+                    let coerce_unsized_info = tcx.coerce_unsized_info(def_id);
+                    record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info);
                 }
             }
         }
@@ -2009,8 +1993,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy_array(&all_impls)
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn encode_incoherent_impls(&mut self) -> LazyArray<IncoherentImpls> {
-        debug!("EncodeContext::encode_traits_and_impls()");
         empty_proc_macro!(self);
         let tcx = self.tcx;
         let mut all_impls: Vec<_> = tcx.crate_inherent_impls(()).incoherent_impls.iter().collect();
@@ -2079,77 +2063,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
         LazyArray::default()
     }
-
-    fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) {
-        let tcx = self.tcx;
-
-        debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id);
-
-        match nitem.kind {
-            hir::ForeignItemKind::Fn(_, ref names, _) => {
-                self.tables.asyncness.set_some(def_id.index, hir::IsAsync::NotAsync);
-                record_array!(self.tables.fn_arg_names[def_id] <- *names);
-                let constness = if self.tcx.is_const_fn_raw(def_id) {
-                    hir::Constness::Const
-                } else {
-                    hir::Constness::NotConst
-                };
-                self.tables.constness.set_some(def_id.index, constness);
-                record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
-            }
-            hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {}
-        }
-        if let hir::ForeignItemKind::Fn(..) = nitem.kind {
-            self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
-        }
-    }
-}
-
-// FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR.
-impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> {
-    type NestedFilter = nested_filter::OnlyBodies;
-
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
-    }
-    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
-        intravisit::walk_expr(self, ex);
-        self.encode_info_for_expr(ex);
-    }
-    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        intravisit::walk_item(self, item);
-        self.encode_info_for_item(item);
-    }
-    fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) {
-        intravisit::walk_foreign_item(self, ni);
-        self.encode_info_for_foreign_item(ni.owner_id.to_def_id(), ni);
-    }
-    fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
-        intravisit::walk_generics(self, generics);
-        self.encode_info_for_generics(generics);
-    }
-}
-
-impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    fn encode_info_for_generics(&mut self, generics: &hir::Generics<'tcx>) {
-        for param in generics.params {
-            match param.kind {
-                hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => {}
-                hir::GenericParamKind::Const { ref default, .. } => {
-                    let def_id = param.def_id.to_def_id();
-                    if default.is_some() {
-                        record!(self.tables.const_param_default[def_id] <- self.tcx.const_param_default(def_id))
-                    }
-                }
-            }
-        }
-    }
-
-    fn encode_info_for_expr(&mut self, expr: &hir::Expr<'_>) {
-        if let hir::ExprKind::Closure(closure) = expr.kind {
-            self.encode_info_for_closure(closure.def_id);
-        }
-    }
 }
 
 /// Used to prefetch queries which will be needed later by metadata encoding.
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index f45cf788dd9..5baeb1ee0cf 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -4,6 +4,7 @@
 use crate::ty::{TyCtxt, Visibility};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::def::DefKind;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -148,13 +149,12 @@ impl EffectiveVisibilities {
         };
     }
 
-    pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) {
+    pub fn check_invariants(&self, tcx: TyCtxt<'_>) {
         if !cfg!(debug_assertions) {
             return;
         }
         for (&def_id, ev) in &self.map {
             // More direct visibility levels can never go farther than less direct ones,
-            // neither of effective visibilities can go farther than nominal visibility,
             // and all effective visibilities are larger or equal than private visibility.
             let private_vis = Visibility::Restricted(tcx.parent_module_from_def_id(def_id));
             let span = tcx.def_span(def_id.to_def_id());
@@ -175,17 +175,20 @@ impl EffectiveVisibilities {
                     ev.reachable_through_impl_trait
                 );
             }
-            let nominal_vis = tcx.visibility(def_id);
-            // FIXME: `rustc_privacy` is not yet updated for the new logic and can set
-            // effective visibilities that are larger than the nominal one.
-            if !nominal_vis.is_at_least(ev.reachable_through_impl_trait, tcx) && early {
-                span_bug!(
-                    span,
-                    "{:?}: reachable_through_impl_trait {:?} > nominal {:?}",
-                    def_id,
-                    ev.reachable_through_impl_trait,
-                    nominal_vis
-                );
+            // All effective visibilities except `reachable_through_impl_trait` are limited to
+            // nominal visibility. For some items nominal visibility doesn't make sense so we
+            // don't check this condition for them.
+            if !matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) {
+                let nominal_vis = tcx.visibility(def_id);
+                if !nominal_vis.is_at_least(ev.reachable, tcx) {
+                    span_bug!(
+                        span,
+                        "{:?}: reachable {:?} > nominal {:?}",
+                        def_id,
+                        ev.reachable,
+                        nominal_vis
+                    );
+                }
             }
         }
     }
@@ -212,7 +215,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
     pub fn update(
         &mut self,
         id: Id,
-        nominal_vis: Option<Visibility>,
+        max_vis: Option<Visibility>,
         lazy_private_vis: impl FnOnce() -> Visibility,
         inherited_effective_vis: EffectiveVisibility,
         level: Level,
@@ -236,8 +239,8 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
                 if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level
                     && level != l)
                 {
-                    calculated_effective_vis = if let Some(nominal_vis) = nominal_vis && !nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
-                        nominal_vis
+                    calculated_effective_vis = if let Some(max_vis) = max_vis && !max_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
+                        max_vis
                     } else {
                         inherited_effective_vis_at_level
                     }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 5f7313dcca6..3841beb733f 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -73,14 +73,10 @@ impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
 /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`.
 trait DefIdVisitor<'tcx> {
     type BreakTy = ();
+    const SHALLOW: bool = false;
+    const SKIP_ASSOC_TYS: bool = false;
 
     fn tcx(&self) -> TyCtxt<'tcx>;
-    fn shallow(&self) -> bool {
-        false
-    }
-    fn skip_assoc_tys(&self) -> bool {
-        false
-    }
     fn visit_def_id(
         &mut self,
         def_id: DefId,
@@ -135,11 +131,7 @@ where
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy> {
         let TraitRef { def_id, substs, .. } = trait_ref;
         self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
-        if self.def_id_visitor.shallow() {
-            ControlFlow::Continue(())
-        } else {
-            substs.visit_with(self)
-        }
+        if V::SHALLOW { ControlFlow::Continue(()) } else { substs.visit_with(self) }
     }
 
     fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> {
@@ -158,7 +150,7 @@ where
             )
         };
         self.visit_trait(trait_ref)?;
-        if self.def_id_visitor.shallow() {
+        if V::SHALLOW {
             ControlFlow::Continue(())
         } else {
             assoc_substs.iter().try_for_each(|subst| subst.visit_with(self))
@@ -208,7 +200,7 @@ where
             | ty::Closure(def_id, ..)
             | ty::Generator(def_id, ..) => {
                 self.def_id_visitor.visit_def_id(def_id, "type", &ty)?;
-                if self.def_id_visitor.shallow() {
+                if V::SHALLOW {
                     return ControlFlow::Continue(());
                 }
                 // Default type visitor doesn't visit signatures of fn types.
@@ -232,7 +224,7 @@ where
                 self.def_id_visitor.visit_def_id(alias.def_id, "type alias", &ty);
             }
             ty::Alias(ty::Projection, proj) => {
-                if self.def_id_visitor.skip_assoc_tys() {
+                if V::SKIP_ASSOC_TYS {
                     // Visitors searching for minimal visibility/reachability want to
                     // conservatively approximate associated types like `<Type as Trait>::Alias`
                     // as visible/reachable even if both `Type` and `Trait` are private.
@@ -244,7 +236,7 @@ where
                 return self.visit_projection_ty(proj);
             }
             ty::Alias(ty::Inherent, data) => {
-                if self.def_id_visitor.skip_assoc_tys() {
+                if V::SKIP_ASSOC_TYS {
                     // Visitors searching for minimal visibility/reachability want to
                     // conservatively approximate associated types like `Type::Alias`
                     // as visible/reachable even if `Type` is private.
@@ -260,7 +252,7 @@ where
                 )?;
 
                 // This will also visit substs if necessary, so we don't need to recurse.
-                return if self.def_id_visitor.shallow() {
+                return if V::SHALLOW {
                     ControlFlow::Continue(())
                 } else {
                     data.substs.iter().try_for_each(|subst| subst.visit_with(self))
@@ -319,11 +311,7 @@ where
             }
         }
 
-        if self.def_id_visitor.shallow() {
-            ControlFlow::Continue(())
-        } else {
-            ty.super_visit_with(self)
-        }
+        if V::SHALLOW { ControlFlow::Continue(()) } else { ty.super_visit_with(self) }
     }
 
     fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -340,22 +328,20 @@ fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visib
 /// Visitor used to determine impl visibility and reachability.
 ////////////////////////////////////////////////////////////////////////////////
 
-struct FindMin<'a, 'tcx, VL: VisibilityLike> {
+struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> {
     tcx: TyCtxt<'tcx>,
     effective_visibilities: &'a EffectiveVisibilities,
     min: VL,
 }
 
-impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> {
+impl<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> DefIdVisitor<'tcx>
+    for FindMin<'a, 'tcx, VL, SHALLOW>
+{
+    const SHALLOW: bool = SHALLOW;
+    const SKIP_ASSOC_TYS: bool = true;
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
-    fn shallow(&self) -> bool {
-        VL::SHALLOW
-    }
-    fn skip_assoc_tys(&self) -> bool {
-        true
-    }
     fn visit_def_id(
         &mut self,
         def_id: DefId,
@@ -371,17 +357,19 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL>
 
 trait VisibilityLike: Sized {
     const MAX: Self;
-    const SHALLOW: bool = false;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self;
+    fn new_min<const SHALLOW: bool>(
+        find: &FindMin<'_, '_, Self, SHALLOW>,
+        def_id: LocalDefId,
+    ) -> Self;
 
-    // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
+    // Returns an over-approximation (`SKIP_ASSOC_TYS` = true) of visibility due to
     // associated types for which we can't determine visibility precisely.
-    fn of_impl(
+    fn of_impl<const SHALLOW: bool>(
         def_id: LocalDefId,
         tcx: TyCtxt<'_>,
         effective_visibilities: &EffectiveVisibilities,
     ) -> Self {
-        let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX };
+        let mut find = FindMin::<_, SHALLOW> { tcx, effective_visibilities, min: Self::MAX };
         find.visit(tcx.type_of(def_id).subst_identity());
         if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
             find.visit_trait(trait_ref.subst_identity());
@@ -391,49 +379,28 @@ trait VisibilityLike: Sized {
 }
 impl VisibilityLike for ty::Visibility {
     const MAX: Self = ty::Visibility::Public;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
+    fn new_min<const SHALLOW: bool>(
+        find: &FindMin<'_, '_, Self, SHALLOW>,
+        def_id: LocalDefId,
+    ) -> Self {
         min(find.tcx.local_visibility(def_id), find.min, find.tcx)
     }
 }
 
-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> { ... }`
-    // can be usable from other crates (#57264). So we skip substs when calculating reachability
-    // and consider an impl reachable if its "shallow" type and trait are reachable.
-    //
-    // The assumption we make here is that type-inference won't let you use an impl without knowing
-    // both "shallow" version of its self type and "shallow" version of its trait if it exists
-    // (which require reaching the `DefId`s in them).
-    const SHALLOW: bool = true;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
+impl VisibilityLike for EffectiveVisibility {
+    const MAX: Self = EffectiveVisibility::from_vis(ty::Visibility::Public);
+    fn new_min<const SHALLOW: bool>(
+        find: &FindMin<'_, '_, Self, SHALLOW>,
+        def_id: LocalDefId,
+    ) -> Self {
         let effective_vis =
-            find.effective_visibilities.effective_vis(def_id).cloned().unwrap_or_else(|| {
+            find.effective_visibilities.effective_vis(def_id).copied().unwrap_or_else(|| {
                 let private_vis =
                     ty::Visibility::Restricted(find.tcx.parent_module_from_def_id(def_id));
                 EffectiveVisibility::from_vis(private_vis)
             });
 
-        ShallowEffectiveVis(effective_vis.min(find.min.0, find.tcx))
+        effective_vis.min(find.min, find.tcx)
     }
 }
 
@@ -492,14 +459,14 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         &mut self,
         def_id: LocalDefId,
         inherited_effective_vis: EffectiveVisibility,
-        nominal_vis: Option<ty::Visibility>,
+        max_vis: Option<ty::Visibility>,
         level: Level,
     ) {
         let private_vis = ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id));
-        if Some(private_vis) != nominal_vis {
+        if max_vis != Some(private_vis) {
             self.changed |= self.effective_visibilities.update(
                 def_id,
-                nominal_vis,
+                max_vis,
                 || private_vis,
                 inherited_effective_vis,
                 level,
@@ -771,12 +738,21 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                 }
             }
             hir::ItemKind::Impl(ref impl_) => {
-                let item_ev = ShallowEffectiveVis::of_impl(
+                // 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> { ... }`
+                // can be usable from other crates (#57264). So we skip substs when calculating
+                // reachability and consider an impl reachable if its "shallow" type and trait are
+                // reachable.
+                //
+                // The assumption we make here is that type-inference won't let you use an impl
+                // without knowing both "shallow" version of its self type and "shallow" version of
+                // its trait if it exists (which require reaching the `DefId`s in them).
+                let item_ev = EffectiveVisibility::of_impl::<true>(
                     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);
 
@@ -784,9 +760,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
 
                 for impl_item_ref in impl_.items {
                     let def_id = impl_item_ref.id.owner_id.def_id;
-                    let nominal_vis =
+                    let max_vis =
                         impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id));
-                    self.update_eff_vis(def_id, item_ev, nominal_vis, Level::Direct);
+                    self.update_eff_vis(def_id, item_ev, max_vis, Level::Direct);
 
                     if let Some(impl_item_ev) = self.get(def_id) {
                         self.reach(def_id, impl_item_ev).generics().predicates().ty();
@@ -904,7 +880,12 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
         _descr: &dyn fmt::Display,
     ) -> ControlFlow<Self::BreakTy> {
         if let Some(def_id) = def_id.as_local() {
-            self.ev.update_eff_vis(def_id, self.effective_vis, None, self.level);
+            // All effective visibilities except `reachable_through_impl_trait` are limited to
+            // nominal visibility. If any type or trait is leaked farther than that, it will
+            // produce type privacy errors on any use, so we don't consider it leaked.
+            let max_vis = (self.level != Level::ReachableThroughImplTrait)
+                .then(|| self.ev.tcx.local_visibility(def_id));
+            self.ev.update_eff_vis(def_id, self.effective_vis, max_vis, self.level);
         }
         ControlFlow::Continue(())
     }
@@ -1876,10 +1857,9 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
             return false;
         };
 
-        // FIXME: `Level::Reachable` should be taken instead of `Level::Reexported`
-        let reexported_at_vis = *effective_vis.at_level(Level::Reexported);
+        let reachable_at_vis = *effective_vis.at_level(Level::Reachable);
 
-        if !vis.is_at_least(reexported_at_vis, self.tcx) {
+        if !vis.is_at_least(reachable_at_vis, self.tcx) {
             let lint = if self.in_primary_interface {
                 lint::builtin::PRIVATE_INTERFACES
             } else {
@@ -1896,7 +1876,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                         tcx: self.tcx,
                     })
                         .into(),
-                    item_vis_descr: &vis_to_string(self.item_def_id, reexported_at_vis, self.tcx),
+                    item_vis_descr: &vis_to_string(self.item_def_id, reachable_at_vis, self.tcx),
                     ty_span: vis_span,
                     ty_kind: kind,
                     ty_descr: descr.into(),
@@ -2137,27 +2117,28 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> {
             DefKind::Impl { .. } => {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::Impl(ref impl_) = item.kind {
-                    let impl_vis =
-                        ty::Visibility::of_impl(item.owner_id.def_id, tcx, &Default::default());
+                    let impl_vis = ty::Visibility::of_impl::<false>(
+                        item.owner_id.def_id,
+                        tcx,
+                        &Default::default(),
+                    );
 
-                    // we are using the non-shallow version here, unlike when building the
+                    // We are using the non-shallow version here, unlike when building the
                     // effective visisibilities table to avoid large number of false positives.
-                    // For example:
+                    // For example in
                     //
                     // 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,
-                    );
+                    // lints shouldn't be emmited even if `from` effective visibility
+                    // is larger than `Priv` nominal visibility and if `Priv` can leak
+                    // in some scenarios due to type inference.
+                    let impl_ev = Some(EffectiveVisibility::of_impl::<false>(
+                        item.owner_id.def_id,
+                        tcx,
+                        self.effective_visibilities,
+                    ));
 
                     // 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
@@ -2284,7 +2265,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
         changed: false,
     };
 
-    visitor.effective_visibilities.check_invariants(tcx, true);
+    visitor.effective_visibilities.check_invariants(tcx);
     if visitor.impl_trait_pass {
         // Underlying types of `impl Trait`s are marked as reachable unconditionally,
         // so this pass doesn't need to be a part of the fixed point iteration below.
@@ -2301,7 +2282,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
             break;
         }
     }
-    visitor.effective_visibilities.check_invariants(tcx, false);
+    visitor.effective_visibilities.check_invariants(tcx);
 
     let mut check_visitor =
         TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index c71ed2097b8..c58d85b99f7 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1558,6 +1558,7 @@ symbols! {
         type_length_limit,
         type_macros,
         type_name,
+        type_privacy_lints,
         u128,
         u16,
         u32,
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 799085e9a83..ff5a4c913b7 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -532,7 +532,7 @@ pub trait Into<T>: Sized {
 #[rustc_diagnostic_item = "From"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(on(
-    all(_Self = "&str", T = "std::string::String"),
+    all(_Self = "&str", any(T = "alloc::string::String", T = "std::string::String")),
     note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
 ))]
 pub trait From<T>: Sized {
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 2568aaf34f3..d3e45456351 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -310,7 +310,7 @@ where
 /// Real logic of both `Flatten` and `FlatMap` which simply delegate to
 /// this type.
 #[derive(Clone, Debug)]
-#[unstable(feature = "trusted_len", issue = "37572")]
+#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
 struct FlattenCompat<I, U> {
     iter: Fuse<I>,
     frontiter: Option<U>,
@@ -464,7 +464,7 @@ where
     }
 }
 
-#[unstable(feature = "trusted_len", issue = "37572")]
+#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
 impl<I, U> Iterator for FlattenCompat<I, U>
 where
     I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -579,7 +579,7 @@ where
     }
 }
 
-#[unstable(feature = "trusted_len", issue = "37572")]
+#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
 impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
 where
     I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -649,7 +649,7 @@ where
     }
 }
 
-#[unstable(feature = "trusted_len", issue = "37572")]
+#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
 unsafe impl<const N: usize, I, T> TrustedLen
     for FlattenCompat<I, <[T; N] as IntoIterator>::IntoIter>
 where
@@ -657,7 +657,7 @@ where
 {
 }
 
-#[unstable(feature = "trusted_len", issue = "37572")]
+#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
 unsafe impl<'a, const N: usize, I, T> TrustedLen
     for FlattenCompat<I, <&'a [T; N] as IntoIterator>::IntoIter>
 where
@@ -665,7 +665,7 @@ where
 {
 }
 
-#[unstable(feature = "trusted_len", issue = "37572")]
+#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
 unsafe impl<'a, const N: usize, I, T> TrustedLen
     for FlattenCompat<I, <&'a mut [T; N] as IntoIterator>::IntoIter>
 where
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index dabfce14474..98835228308 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -26,13 +26,13 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
     on(
-        _Self = "std::ops::RangeTo<Idx>",
+        any(_Self = "core::ops::RangeTo<Idx>", _Self = "std::ops::RangeTo<Idx>"),
         label = "if you meant to iterate until a value, add a starting value",
         note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
               bounded `Range`: `0..end`"
     ),
     on(
-        _Self = "std::ops::RangeToInclusive<Idx>",
+        any(_Self = "core::ops::RangeToInclusive<Idx>", _Self = "std::ops::RangeToInclusive<Idx>"),
         label = "if you meant to iterate until a value (including it), add a starting value",
         note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
               to have a bounded `RangeInclusive`: `0..=end`"
@@ -43,7 +43,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
     ),
     on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
     on(
-        _Self = "std::vec::Vec<T, A>",
+        any(_Self = "alloc::vec::Vec<T, A>", _Self = "std::vec::Vec<T, A>"),
         label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
     ),
     on(
@@ -51,7 +51,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
     on(
-        _Self = "std::string::String",
+        any(_Self = "alloc::string::String", _Self = "std::string::String"),
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
     on(
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 760e58276fc..e251015dd86 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -575,59 +575,59 @@ impl<T: ?Sized> Copy for &T {}
 #[lang = "sync"]
 #[rustc_on_unimplemented(
     on(
-        _Self = "std::cell::OnceCell<T>",
+        any(_Self = "core::cell:OnceCell<T>", _Self = "std::cell::OnceCell<T>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead"
     ),
     on(
-        _Self = "std::cell::Cell<u8>",
+        any(_Self = "core::cell::Cell<u8>", _Self = "std::cell::Cell<u8>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead",
     ),
     on(
-        _Self = "std::cell::Cell<u16>",
+        any(_Self = "core::cell::Cell<u16>", _Self = "std::cell::Cell<u16>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead",
     ),
     on(
-        _Self = "std::cell::Cell<u32>",
+        any(_Self = "core::cell::Cell<u32>", _Self = "std::cell::Cell<u32>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead",
     ),
     on(
-        _Self = "std::cell::Cell<u64>",
+        any(_Self = "core::cell::Cell<u64>", _Self = "std::cell::Cell<u64>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead",
     ),
     on(
-        _Self = "std::cell::Cell<usize>",
+        any(_Self = "core::cell::Cell<usize>", _Self = "std::cell::Cell<usize>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead",
     ),
     on(
-        _Self = "std::cell::Cell<i8>",
+        any(_Self = "core::cell::Cell<i8>", _Self = "std::cell::Cell<i8>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead",
     ),
     on(
-        _Self = "std::cell::Cell<i16>",
+        any(_Self = "core::cell::Cell<i16>", _Self = "std::cell::Cell<i16>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead",
     ),
     on(
-        _Self = "std::cell::Cell<i32>",
+        any(_Self = "core::cell::Cell<i32>", _Self = "std::cell::Cell<i32>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead",
     ),
     on(
-        _Self = "std::cell::Cell<i64>",
+        any(_Self = "core::cell::Cell<i64>", _Self = "std::cell::Cell<i64>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead",
     ),
     on(
-        _Self = "std::cell::Cell<isize>",
+        any(_Self = "core::cell::Cell<isize>", _Self = "std::cell::Cell<isize>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead",
     ),
     on(
-        _Self = "std::cell::Cell<bool>",
+        any(_Self = "core::cell::Cell<bool>", _Self = "std::cell::Cell<bool>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead",
     ),
     on(
-        _Self = "std::cell::Cell<T>",
+        any(_Self = "core::cell::Cell<T>", _Self = "std::cell::Cell<T>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`",
     ),
     on(
-        _Self = "std::cell::RefCell<T>",
+        any(_Self = "core::cell::RefCell<T>", _Self = "std::cell::RefCell<T>"),
         note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead",
     ),
     message = "`{Self}` cannot be shared between threads safely",
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
index 1f1784ec9b2..f4649be54d5 100644
--- a/library/core/src/ops/index.rs
+++ b/library/core/src/ops/index.rs
@@ -153,7 +153,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
 see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
     ),
     on(
-        _Self = "std::string::String",
+        any(_Self = "alloc::string::String", _Self = "std::string::String"),
         note = "you can use `.chars().nth()` or `.bytes().nth()`
 see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
     ),
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index b4f69d0b213..17625daccbc 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -226,8 +226,14 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "std::result::Result<T, E>",
-            R = "std::option::Option<std::convert::Infallible>"
+            any(
+                _Self = "core::result::Result<T, E>",
+                _Self = "std::result::Result<T, E>",
+            ),
+            any(
+                R = "core::option::Option<core::convert::Infallible>",
+                R = "std::option::Option<std::convert::Infallible>",
+            )
         ),
         message = "the `?` operator can only be used on `Result`s, not `Option`s, \
             in {ItemContext} that returns `Result`",
@@ -237,7 +243,10 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "std::result::Result<T, E>",
+            any(
+                _Self = "core::result::Result<T, E>",
+                _Self = "std::result::Result<T, E>",
+            )
         ),
         // There's a special error message in the trait selection code for
         // `From` in `?`, so this is not shown for result-in-result errors,
@@ -250,8 +259,14 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "std::option::Option<T>",
-            R = "std::result::Result<T, E>",
+            any(
+                _Self = "core::option::Option<T>",
+                _Self = "std::option::Option<T>",
+            ),
+            any(
+                R = "core::result::Result<T, E>",
+                R = "std::result::Result<T, E>",
+            )
         ),
         message = "the `?` operator can only be used on `Option`s, not `Result`s, \
             in {ItemContext} that returns `Option`",
@@ -261,7 +276,10 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "std::option::Option<T>",
+            any(
+                _Self = "core::option::Option<T>",
+                _Self = "std::option::Option<T>",
+            )
         ),
         // `Option`-in-`Option` always works, as there's only one possible
         // residual, so this can also be phrased strongly.
@@ -273,8 +291,14 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "std::ops::ControlFlow<B, C>",
-            R = "std::ops::ControlFlow<B, C>",
+            any(
+                _Self = "core::ops::ControlFlow<B, C>",
+                _Self = "std::ops::ControlFlow<B, C>",
+            ),
+            any(
+                R = "core::ops::ControlFlow<B, C>",
+                R = "std::ops::ControlFlow<B, C>",
+            )
         ),
         message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
             can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
@@ -285,7 +309,10 @@ pub trait Try: FromResidual {
     on(
         all(
             from_desugaring = "QuestionMark",
-            _Self = "std::ops::ControlFlow<B, C>",
+            any(
+                _Self = "core::ops::ControlFlow<B, C>",
+                _Self = "std::ops::ControlFlow<B, C>",
+            )
             // `R` is not a `ControlFlow`, as that case was matched previously
         ),
         message = "the `?` operator can only be used on `ControlFlow`s \
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 6ef9f9c95e8..e1e3bcc05e7 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -152,7 +152,10 @@ mod private_slice_index {
 #[rustc_on_unimplemented(
     on(T = "str", label = "string indices are ranges of `usize`",),
     on(
-        all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"),
+        all(
+            any(T = "str", T = "&str", T = "alloc::string::String", T = "std::string::String"),
+            _Self = "{integer}"
+        ),
         note = "you can use `.chars().nth()` or `.bytes().nth()`\n\
                 for more information, see chapter 8 in The Book: \
                 <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md
index 75013bb3df9..b8aa64ba14f 100644
--- a/src/doc/style-guide/src/README.md
+++ b/src/doc/style-guide/src/README.md
@@ -186,6 +186,11 @@ For attributes with argument lists, format like functions.
 ```rust
 #[repr(C)]
 #[foo(foo, bar)]
+#[long_multi_line_attribute(
+    split,
+    across,
+    lines,
+)]
 struct CRepr {
     #![repr(C)]
     x: f32,
diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md
index 9bc521e1c7b..a5cd6da1061 100644
--- a/src/doc/style-guide/src/statements.md
+++ b/src/doc/style-guide/src/statements.md
@@ -159,8 +159,8 @@ before the `else`.
 
 If the initializer expression is multi-line, the `else` keyword and opening
 brace of the block (i.e. `else {`) should be put on the same line as the end of
-the initializer expression, with a space between them, if all the following are
-true:
+the initializer expression, with a space between them, if and only if all the
+following are true:
 
 * The initializer expression ends with one or more closing
   parentheses, square brackets, and/or braces
@@ -209,6 +209,28 @@ fn main() {
     else {
         return;
     };
+
+    let LongStructName(AnotherStruct {
+        multi,
+        line,
+        pattern,
+    }) = slice.as_ref()
+    else {
+        return;
+    };
+
+    let LongStructName(AnotherStruct {
+        multi,
+        line,
+        pattern,
+    }) = multi_line_function_call(
+        arg1,
+        arg2,
+        arg3,
+        arg4,
+    ) else {
+        return;
+    };
 }
 ```
 
diff --git a/tests/ui/associated-inherent-types/private-in-public.rs b/tests/ui/associated-inherent-types/private-in-public.rs
index 44a20a79ad6..33b84fc9506 100644
--- a/tests/ui/associated-inherent-types/private-in-public.rs
+++ b/tests/ui/associated-inherent-types/private-in-public.rs
@@ -1,7 +1,7 @@
 #![feature(inherent_associated_types)]
+#![feature(type_privacy_lints)]
 #![allow(incomplete_features)]
 #![crate_type = "lib"]
-
 #![deny(private_in_public)]
 #![warn(private_interfaces)]
 
diff --git a/tests/ui/associated-type-bounds/implied-in-supertrait.rs b/tests/ui/associated-type-bounds/implied-in-supertrait.rs
new file mode 100644
index 00000000000..ea7e7c984da
--- /dev/null
+++ b/tests/ui/associated-type-bounds/implied-in-supertrait.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+#![feature(associated_type_bounds)]
+
+trait Trait: Super<Assoc: Bound> {}
+
+trait Super {
+    type Assoc;
+}
+
+trait Bound {}
+
+fn foo<T>(x: T)
+where
+    T: Trait,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs
new file mode 100644
index 00000000000..e55104ee968
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs
@@ -0,0 +1,28 @@
+// edition:2021
+// check-pass
+
+#![feature(async_fn_in_trait, return_position_impl_trait_in_trait, return_type_notation)]
+//~^ WARN the feature `return_type_notation` is incomplete
+
+use std::future::Future;
+
+struct JoinHandle<T>(fn() -> T);
+
+fn spawn<T>(_: impl Future<Output = T>) -> JoinHandle<T> {
+    todo!()
+}
+
+trait Foo {
+    async fn bar(&self) -> i32;
+}
+
+trait SendFoo: Foo<bar(): Send> + Send {}
+
+fn foobar(foo: impl SendFoo) -> JoinHandle<i32> {
+    spawn(async move {
+        let future = foo.bar();
+        future.await
+    })
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr
new file mode 100644
index 00000000000..8626648b523
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr
@@ -0,0 +1,11 @@
+warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/rtn-implied-in-supertrait.rs:4:68
+   |
+LL | #![feature(async_fn_in_trait, return_position_impl_trait_in_trait, return_type_notation)]
+   |                                                                    ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/closures/issue-113087.rs b/tests/ui/closures/issue-113087.rs
new file mode 100644
index 00000000000..a4edc2f2f0b
--- /dev/null
+++ b/tests/ui/closures/issue-113087.rs
@@ -0,0 +1,11 @@
+fn some_fn<'a>(_: &'a i32, _: impl FnOnce(&'a i32)) {}
+
+fn main() {
+    let some_closure = |_| {};
+
+    for a in [1] {
+        some_fn(&a, |c| { //~ ERROR does not live long enough
+            some_closure(c);
+        });
+    }
+}
diff --git a/tests/ui/closures/issue-113087.stderr b/tests/ui/closures/issue-113087.stderr
new file mode 100644
index 00000000000..8ccef4a54f5
--- /dev/null
+++ b/tests/ui/closures/issue-113087.stderr
@@ -0,0 +1,16 @@
+error[E0597]: `a` does not live long enough
+  --> $DIR/issue-113087.rs:7:17
+   |
+LL |     for a in [1] {
+   |         - binding `a` declared here
+LL |         some_fn(&a, |c| {
+   |                 ^^ borrowed value does not live long enough
+LL |             some_closure(c);
+   |             ------------ borrow later captured here by closure
+LL |         });
+LL |     }
+   |     - `a` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
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 96b769699cc..5c43213e898 100644
--- a/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs
+++ b/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs
@@ -1,7 +1,7 @@
 #![crate_type = "lib"]
 #![feature(generic_const_exprs)]
+#![feature(type_privacy_lints)]
 #![allow(incomplete_features)]
-
 #![warn(private_interfaces)]
 
 // In this test both old and new private-in-public diagnostic were emitted.
diff --git a/tests/ui/error-codes/E0445.rs b/tests/ui/error-codes/E0445.rs
index f5f35fb8a4d..30c222ae6f2 100644
--- a/tests/ui/error-codes/E0445.rs
+++ b/tests/ui/error-codes/E0445.rs
@@ -1,3 +1,4 @@
+#![feature(type_privacy_lints)]
 #[warn(private_bounds)]
 #[warn(private_interfaces)]
 
diff --git a/tests/ui/error-codes/E0445.stderr b/tests/ui/error-codes/E0445.stderr
index ac3637a8218..ba2c21485ef 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:12:1
+  --> $DIR/E0445.rs:13:1
    |
 LL | trait Foo {
    | --------- `Foo` declared as private
@@ -10,23 +10,23 @@ LL | pub trait Bar : Foo {}
 warning: trait `Foo` is more private than the item `Bar`
    |
 note: trait `Bar` is reachable at visibility `pub`
-  --> $DIR/E0445.rs:12:1
+  --> $DIR/E0445.rs:13:1
    |
 LL | pub trait Bar : Foo {}
    | ^^^^^^^^^^^^^^^^^^^
 note: but trait `Foo` is only usable at visibility `pub(crate)`
-  --> $DIR/E0445.rs:8:1
+  --> $DIR/E0445.rs:9:1
    |
 LL | trait Foo {
    | ^^^^^^^^^
 note: the lint level is defined here
-  --> $DIR/E0445.rs:1:8
+  --> $DIR/E0445.rs:2:8
    |
 LL | #[warn(private_bounds)]
    |        ^^^^^^^^^^^^^^
 
 error[E0445]: private trait `Foo` in public interface
-  --> $DIR/E0445.rs:14:1
+  --> $DIR/E0445.rs:15:1
    |
 LL | trait Foo {
    | --------- `Foo` declared as private
@@ -37,18 +37,18 @@ LL | pub struct Bar2<T: Foo>(pub T);
 warning: trait `Foo` is more private than the item `Bar2`
    |
 note: struct `Bar2` is reachable at visibility `pub`
-  --> $DIR/E0445.rs:14:1
+  --> $DIR/E0445.rs:15: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
+  --> $DIR/E0445.rs:9:1
    |
 LL | trait Foo {
    | ^^^^^^^^^
 
 error[E0445]: private trait `Foo` in public interface
-  --> $DIR/E0445.rs:16:1
+  --> $DIR/E0445.rs:17:1
    |
 LL | trait Foo {
    | --------- `Foo` declared as private
@@ -59,12 +59,12 @@ LL | pub fn foo<T: Foo> (t: T) {}
 warning: trait `Foo` is more private than the item `foo`
    |
 note: function `foo` is reachable at visibility `pub`
-  --> $DIR/E0445.rs:16:1
+  --> $DIR/E0445.rs:17: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
+  --> $DIR/E0445.rs:9:1
    |
 LL | trait Foo {
    | ^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs b/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs
new file mode 100644
index 00000000000..aad64c9d073
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![warn(private_interfaces)] //~ WARN unknown lint
+                             //~| WARN unknown lint
+                             //~| WARN unknown lint
+#![warn(private_bounds)] //~ WARN unknown lint
+                         //~| WARN unknown lint
+                         //~| WARN unknown lint
+#![warn(unnameable_types)] //~ WARN unknown lint
+                           //~| WARN unknown lint
+                           //~| WARN unknown lint
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr b/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr
new file mode 100644
index 00000000000..79cc974cca1
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr
@@ -0,0 +1,93 @@
+warning: unknown lint: `private_interfaces`
+  --> $DIR/feature-gate-type_privacy_lints.rs:3:1
+   |
+LL | #![warn(private_interfaces)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `private_interfaces` lint is unstable
+   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
+   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
+   = note: `#[warn(unknown_lints)]` on by default
+
+warning: unknown lint: `private_bounds`
+  --> $DIR/feature-gate-type_privacy_lints.rs:6:1
+   |
+LL | #![warn(private_bounds)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `private_bounds` lint is unstable
+   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
+   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
+
+warning: unknown lint: `unnameable_types`
+  --> $DIR/feature-gate-type_privacy_lints.rs:9:1
+   |
+LL | #![warn(unnameable_types)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `unnameable_types` lint is unstable
+   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
+   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
+
+warning: unknown lint: `private_interfaces`
+  --> $DIR/feature-gate-type_privacy_lints.rs:3:1
+   |
+LL | #![warn(private_interfaces)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `private_interfaces` lint is unstable
+   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
+   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
+
+warning: unknown lint: `private_bounds`
+  --> $DIR/feature-gate-type_privacy_lints.rs:6:1
+   |
+LL | #![warn(private_bounds)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `private_bounds` lint is unstable
+   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
+   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
+
+warning: unknown lint: `unnameable_types`
+  --> $DIR/feature-gate-type_privacy_lints.rs:9:1
+   |
+LL | #![warn(unnameable_types)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `unnameable_types` lint is unstable
+   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
+   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
+
+warning: unknown lint: `private_interfaces`
+  --> $DIR/feature-gate-type_privacy_lints.rs:3:1
+   |
+LL | #![warn(private_interfaces)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `private_interfaces` lint is unstable
+   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
+   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
+
+warning: unknown lint: `private_bounds`
+  --> $DIR/feature-gate-type_privacy_lints.rs:6:1
+   |
+LL | #![warn(private_bounds)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `private_bounds` lint is unstable
+   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
+   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
+
+warning: unknown lint: `unnameable_types`
+  --> $DIR/feature-gate-type_privacy_lints.rs:9:1
+   |
+LL | #![warn(unnameable_types)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `unnameable_types` lint is unstable
+   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
+   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
+
+warning: 9 warnings emitted
+
diff --git a/tests/ui/issues/issue-18389.rs b/tests/ui/issues/issue-18389.rs
index 3686afc48af..0af693c4e0f 100644
--- a/tests/ui/issues/issue-18389.rs
+++ b/tests/ui/issues/issue-18389.rs
@@ -1,3 +1,4 @@
+#![feature(type_privacy_lints)]
 #![warn(private_bounds)]
 
 // In this test both old and new private-in-public diagnostic were emitted.
diff --git a/tests/ui/issues/issue-18389.stderr b/tests/ui/issues/issue-18389.stderr
index f9ebde48a45..6b78151c606 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:13:1
+  --> $DIR/issue-18389.rs:14:1
    |
 LL |   trait Private<P, R> {
    |   ------------------- `Private<<Self as Public>::P, <Self as Public>::R>` declared as private
@@ -14,7 +14,7 @@ LL | | > {
 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
+  --> $DIR/issue-18389.rs:14:1
    |
 LL | / pub trait Public: Private<
 LL | |
@@ -23,12 +23,12 @@ 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
+  --> $DIR/issue-18389.rs:11:1
    |
 LL | trait Private<P, R> {
    | ^^^^^^^^^^^^^^^^^^^
 note: the lint level is defined here
-  --> $DIR/issue-18389.rs:1:9
+  --> $DIR/issue-18389.rs:2:9
    |
 LL | #![warn(private_bounds)]
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/privacy/effective_visibilities_full_priv.rs b/tests/ui/privacy/effective_visibilities_full_priv.rs
index cc708917586..a26ae3bd122 100644
--- a/tests/ui/privacy/effective_visibilities_full_priv.rs
+++ b/tests/ui/privacy/effective_visibilities_full_priv.rs
@@ -6,7 +6,7 @@ struct SemiPriv;
 mod m {
     #[rustc_effective_visibility]
     struct Priv;
-    //~^ ERROR Direct: pub(self), Reexported: pub(self), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+    //~^ ERROR not in the table
     //~| ERROR not in the table
 
     #[rustc_effective_visibility]
diff --git a/tests/ui/privacy/effective_visibilities_full_priv.stderr b/tests/ui/privacy/effective_visibilities_full_priv.stderr
index a856aa20d92..29d82e2ee01 100644
--- a/tests/ui/privacy/effective_visibilities_full_priv.stderr
+++ b/tests/ui/privacy/effective_visibilities_full_priv.stderr
@@ -1,4 +1,4 @@
-error: Direct: pub(self), Reexported: pub(self), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+error: not in the table
   --> $DIR/effective_visibilities_full_priv.rs:8:5
    |
 LL |     struct Priv;
diff --git a/tests/ui/privacy/private-in-public-non-principal.rs b/tests/ui/privacy/private-in-public-non-principal.rs
index a80c1541463..9ae7512c509 100644
--- a/tests/ui/privacy/private-in-public-non-principal.rs
+++ b/tests/ui/privacy/private-in-public-non-principal.rs
@@ -1,6 +1,6 @@
 #![feature(auto_traits)]
 #![feature(negative_impls)]
-
+#![feature(type_privacy_lints)]
 #![deny(private_interfaces)]
 
 // In this test both old and new private-in-public diagnostic were emitted.
diff --git a/tests/ui/privacy/unnameable_types.rs b/tests/ui/privacy/unnameable_types.rs
index 8b53f372fc9..eae20dd9df3 100644
--- a/tests/ui/privacy/unnameable_types.rs
+++ b/tests/ui/privacy/unnameable_types.rs
@@ -1,4 +1,4 @@
-#![allow(unused)]
+#![feature(type_privacy_lints)]
 #![allow(private_in_public)]
 #![deny(unnameable_types)]
 
diff --git a/tests/ui/privacy/where-priv-type.rs b/tests/ui/privacy/where-priv-type.rs
index 9899902dd88..468d6e98a74 100644
--- a/tests/ui/privacy/where-priv-type.rs
+++ b/tests/ui/privacy/where-priv-type.rs
@@ -3,8 +3,8 @@
 
 #![crate_type = "lib"]
 #![feature(generic_const_exprs)]
+#![feature(type_privacy_lints)]
 #![allow(incomplete_features)]
-
 #![warn(private_bounds)]
 #![warn(private_interfaces)]
 
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 3aad893eae2..35e33bcb3b7 100644
--- a/tests/ui/privacy/where-pub-type-impls-priv-trait.rs
+++ b/tests/ui/privacy/where-pub-type-impls-priv-trait.rs
@@ -2,8 +2,8 @@
 
 #![crate_type = "lib"]
 #![feature(generic_const_exprs)]
+#![feature(type_privacy_lints)]
 #![allow(incomplete_features)]
-
 #![warn(private_bounds)]
 
 // In this test both old and new private-in-public diagnostic were emitted.
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 9e4ba80a784..bd8f6585f48 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,3 +1,4 @@
+#![feature(type_privacy_lints)]
 #![allow(non_camel_case_types)] // genus is always capitalized
 #![warn(private_interfaces)]
 //~^ NOTE the lint level is defined here
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 52f67d4cdd5..5ebda47558c 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:27:1
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:28:1
    |
 LL | pub(crate) struct Snail;
    | ----------------------- `Snail` declared as private
@@ -10,23 +10,23 @@ LL | pub type Helix_pomatia = Shell<Snail>;
 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
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:28: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
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:10:1
    |
 LL | pub(crate) struct Snail;
    | ^^^^^^^^^^^^^^^^^^^^^^^
 note: the lint level is defined here
-  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:2:9
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:3:9
    |
 LL | #![warn(private_interfaces)]
    |         ^^^^^^^^^^^^^^^^^^
 
 error[E0446]: crate-private type `Turtle` in public interface
-  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:31:1
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:32:1
    |
 LL |     pub(super) struct Turtle;
    |     ------------------------ `Turtle` declared as crate-private
@@ -37,18 +37,18 @@ LL | pub type Dermochelys_coriacea = Shell<sea::Turtle>;
 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
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:32: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
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:15:5
    |
 LL |     pub(super) struct Turtle;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0446]: private type `Tortoise` in public interface
-  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:35:1
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:36:1
    |
 LL | struct Tortoise;
    | --------------- `Tortoise` declared as private
@@ -59,12 +59,12 @@ LL | pub type Testudo_graeca = Shell<Tortoise>;
 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
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:36: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
+  --> $DIR/issue-33174-restricted-type-in-public-interface.rs:20:1
    |
 LL | struct Tortoise;
    | ^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/auxiliary/trivial3.rs b/tests/ui/traits/auxiliary/trivial3.rs
new file mode 100644
index 00000000000..0a47fdc74d7
--- /dev/null
+++ b/tests/ui/traits/auxiliary/trivial3.rs
@@ -0,0 +1 @@
+pub trait Trait {}
diff --git a/tests/ui/traits/auxiliary/trivial4.rs b/tests/ui/traits/auxiliary/trivial4.rs
new file mode 100644
index 00000000000..a527d1a9526
--- /dev/null
+++ b/tests/ui/traits/auxiliary/trivial4.rs
@@ -0,0 +1,3 @@
+pub trait Trait {}
+
+impl Trait for () {}
diff --git a/tests/ui/traits/trivial_impl.rs b/tests/ui/traits/trivial_impl.rs
new file mode 100644
index 00000000000..6ac8c744bc4
--- /dev/null
+++ b/tests/ui/traits/trivial_impl.rs
@@ -0,0 +1,18 @@
+//! This test checks that we do need to implement
+//! all members, even if their where bounds only hold
+//! due to other impls.
+
+trait Foo<T> {
+    fn foo()
+    where
+        Self: Foo<()>;
+}
+
+impl Foo<()> for () {
+    fn foo() {}
+}
+
+impl Foo<u32> for () {}
+//~^ ERROR: not all trait items implemented, missing: `foo`
+
+fn main() {}
diff --git a/tests/ui/traits/trivial_impl.stderr b/tests/ui/traits/trivial_impl.stderr
new file mode 100644
index 00000000000..4b29b55bea1
--- /dev/null
+++ b/tests/ui/traits/trivial_impl.stderr
@@ -0,0 +1,14 @@
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/trivial_impl.rs:15:1
+   |
+LL | /     fn foo()
+LL | |     where
+LL | |         Self: Foo<()>;
+   | |______________________- `foo` from trait
+...
+LL |   impl Foo<u32> for () {}
+   |   ^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/traits/trivial_impl2.rs b/tests/ui/traits/trivial_impl2.rs
new file mode 100644
index 00000000000..be58096007f
--- /dev/null
+++ b/tests/ui/traits/trivial_impl2.rs
@@ -0,0 +1,13 @@
+//! This test checks that we currently need to implement
+//! members, even if their where bounds don't hold for the impl type.
+
+trait Foo<T> {
+    fn foo()
+    where
+        Self: Foo<()>;
+}
+
+impl Foo<u32> for () {}
+//~^ ERROR: not all trait items implemented, missing: `foo`
+
+fn main() {}
diff --git a/tests/ui/traits/trivial_impl2.stderr b/tests/ui/traits/trivial_impl2.stderr
new file mode 100644
index 00000000000..04c05df0616
--- /dev/null
+++ b/tests/ui/traits/trivial_impl2.stderr
@@ -0,0 +1,14 @@
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/trivial_impl2.rs:10:1
+   |
+LL | /     fn foo()
+LL | |     where
+LL | |         Self: Foo<()>;
+   | |______________________- `foo` from trait
+...
+LL |   impl Foo<u32> for () {}
+   |   ^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/traits/trivial_impl3.rs b/tests/ui/traits/trivial_impl3.rs
new file mode 100644
index 00000000000..714f643bc99
--- /dev/null
+++ b/tests/ui/traits/trivial_impl3.rs
@@ -0,0 +1,19 @@
+//! Check that we don't break orphan rules.
+//! The dependency may add an impl for `u8` later,
+//! which would break this crate. We want to avoid adding
+//! more ways in which adding an impl can be a breaking change.
+
+// aux-build:trivial3.rs
+
+extern crate trivial3;
+
+pub trait Foo {
+    fn foo()
+    where
+        Self: trivial3::Trait;
+}
+
+impl Foo for u8 {}
+//~^ ERROR not all trait items implemented, missing: `foo`
+
+fn main() {}
diff --git a/tests/ui/traits/trivial_impl3.stderr b/tests/ui/traits/trivial_impl3.stderr
new file mode 100644
index 00000000000..dfb39d6ce15
--- /dev/null
+++ b/tests/ui/traits/trivial_impl3.stderr
@@ -0,0 +1,14 @@
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/trivial_impl3.rs:16:1
+   |
+LL | /     fn foo()
+LL | |     where
+LL | |         Self: trivial3::Trait;
+   | |______________________________- `foo` from trait
+...
+LL |   impl Foo for u8 {}
+   |   ^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/traits/trivial_impl4.rs b/tests/ui/traits/trivial_impl4.rs
new file mode 100644
index 00000000000..518f159c1fb
--- /dev/null
+++ b/tests/ui/traits/trivial_impl4.rs
@@ -0,0 +1,21 @@
+//! Check that we don't break orphan rules.
+//! The dependency may add an impl for `u8` later,
+//! which would break this crate. We want to avoid adding
+//! more ways in which adding an impl can be a breaking change.
+//! This test differs from `trivial_impl3` because there actually
+//! exists any impl for `Trait`, which has an effect on coherence.
+
+// aux-build:trivial4.rs
+
+extern crate trivial4;
+
+pub trait Foo {
+    fn foo()
+    where
+        Self: trivial4::Trait;
+}
+
+impl Foo for u8 {}
+//~^ ERROR not all trait items implemented, missing: `foo`
+
+fn main() {}
diff --git a/tests/ui/traits/trivial_impl4.stderr b/tests/ui/traits/trivial_impl4.stderr
new file mode 100644
index 00000000000..04b29ed7734
--- /dev/null
+++ b/tests/ui/traits/trivial_impl4.stderr
@@ -0,0 +1,14 @@
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/trivial_impl4.rs:18:1
+   |
+LL | /     fn foo()
+LL | |     where
+LL | |         Self: trivial4::Trait;
+   | |______________________________- `foo` from trait
+...
+LL |   impl Foo for u8 {}
+   |   ^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/traits/trivial_impl_sized.rs b/tests/ui/traits/trivial_impl_sized.rs
new file mode 100644
index 00000000000..501a3405090
--- /dev/null
+++ b/tests/ui/traits/trivial_impl_sized.rs
@@ -0,0 +1,26 @@
+//! This test checks that we currently need to implement
+//! members, even if their where bounds don't hold for the impl type.
+
+trait Foo {
+    fn foo()
+    where
+        Self: Sized;
+}
+
+impl Foo for () {
+    fn foo() {}
+}
+
+// Must not be allowed
+impl Foo for i32 {}
+//~^ ERROR: not all trait items implemented, missing: `foo`
+
+// Should be allowed
+impl Foo for dyn std::fmt::Debug {}
+//~^ ERROR: not all trait items implemented, missing: `foo`
+
+impl Foo for dyn std::fmt::Display {
+    fn foo() {}
+}
+
+fn main() {}
diff --git a/tests/ui/traits/trivial_impl_sized.stderr b/tests/ui/traits/trivial_impl_sized.stderr
new file mode 100644
index 00000000000..ebf6dfc9dd2
--- /dev/null
+++ b/tests/ui/traits/trivial_impl_sized.stderr
@@ -0,0 +1,25 @@
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/trivial_impl_sized.rs:15:1
+   |
+LL | /     fn foo()
+LL | |     where
+LL | |         Self: Sized;
+   | |____________________- `foo` from trait
+...
+LL |   impl Foo for i32 {}
+   |   ^^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/trivial_impl_sized.rs:19:1
+   |
+LL | /     fn foo()
+LL | |     where
+LL | |         Self: Sized;
+   | |____________________- `foo` from trait
+...
+LL |   impl Foo for dyn std::fmt::Debug {}
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0046`.