diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index c9786328565ba..63ef821279397 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -470,7 +470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         ty: &Ty,
         span: Span,
         body: Option<&Expr>,
-        impl_trait_position: ImplTraitPosition,
+        impl_trait_position: ImplTraitPosition<'_>,
     ) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
         let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(impl_trait_position));
         (ty, self.lower_const_body(span, body))
@@ -1418,7 +1418,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         generics: &Generics,
         constness: Const,
         parent_node_id: NodeId,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
         f: impl FnOnce(&mut Self) -> T,
     ) -> (&'hir hir::Generics<'hir>, T) {
         debug_assert!(self.impl_trait_defs.is_empty());
@@ -1624,7 +1624,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         bounds: &[GenericBound],
         colon_span: Option<Span>,
         parent_span: Span,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
         origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
         // Do not create a clause if we do not have anything inside it.
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 833b0e9b5679e..9e5f669630891 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -255,7 +255,7 @@ impl ResolverAstLowering {
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
 /// and if so, what meaning it has.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
-enum ImplTraitContext {
+enum ImplTraitContext<'a> {
     /// Treat `impl Trait` as shorthand for a new universal generic parameter.
     /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually
     /// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
@@ -274,14 +274,14 @@ enum ImplTraitContext {
         fn_kind: Option<FnDeclKind>,
     },
     /// `impl Trait` is unstably accepted in this position.
-    FeatureGated(ImplTraitPosition, Symbol),
+    FeatureGated(ImplTraitPosition<'a>, Symbol),
     /// `impl Trait` is not accepted in this position.
-    Disallowed(ImplTraitPosition),
+    Disallowed(ImplTraitPosition<'a>),
 }
 
 /// Position in which `impl Trait` is disallowed.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
-enum ImplTraitPosition {
+enum ImplTraitPosition<'a> {
     Path,
     Variable,
     Trait,
@@ -303,9 +303,10 @@ enum ImplTraitPosition {
     Cast,
     ImplSelf,
     OffsetOf,
+    ImplTrait { outer: &'a ImplTraitContext<'a> },
 }
 
-impl std::fmt::Display for ImplTraitPosition {
+impl std::fmt::Display for ImplTraitPosition<'_> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let name = match self {
             ImplTraitPosition::Path => "paths",
@@ -329,6 +330,7 @@ impl std::fmt::Display for ImplTraitPosition {
             ImplTraitPosition::Cast => "cast expression types",
             ImplTraitPosition::ImplSelf => "impl headers",
             ImplTraitPosition::OffsetOf => "`offset_of!` parameters",
+            ImplTraitPosition::ImplTrait { .. } => "`impl Trait`",
         };
 
         write!(f, "{name}")
@@ -979,7 +981,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_assoc_ty_constraint(
         &mut self,
         constraint: &AssocConstraint,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
         // lower generic arguments of identifier in constraint
@@ -1129,7 +1131,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_generic_arg(
         &mut self,
         arg: &ast::GenericArg,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
     ) -> hir::GenericArg<'hir> {
         match arg {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
@@ -1208,7 +1210,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
+    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext<'_>) -> &'hir hir::Ty<'hir> {
         self.arena.alloc(self.lower_ty_direct(t, itctx))
     }
 
@@ -1218,7 +1220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         qself: &Option<ptr::P<QSelf>>,
         path: &Path,
         param_mode: ParamMode,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
     ) -> hir::Ty<'hir> {
         // Check whether we should interpret this as a bare trait object.
         // This check mirrors the one in late resolution. We only introduce this special case in
@@ -1260,7 +1262,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.ty(span, hir::TyKind::Tup(tys))
     }
 
-    fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
+    fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext<'_>) -> hir::Ty<'hir> {
         let kind = match &t.kind {
             TyKind::Infer => hir::TyKind::Infer,
             TyKind::Err(guar) => hir::TyKind::Err(*guar),
@@ -1407,7 +1409,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         *def_node_id,
                         bounds,
                         fn_kind,
-                        itctx,
+                        ImplTraitContext::Disallowed(ImplTraitPosition::ImplTrait {
+                            outer: &itctx,
+                        }),
                     ),
                     ImplTraitContext::Universal => {
                         let span = t.span;
@@ -1516,7 +1520,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         opaque_ty_node_id: NodeId,
         bounds: &GenericBounds,
         fn_kind: Option<FnDeclKind>,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
@@ -1924,7 +1928,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         output: &FnRetTy,
         coro: CoroutineKind,
         opaque_ty_span: Span,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
     ) -> hir::GenericBound<'hir> {
         // Compute the `T` in `Future<Output = T>` from the return type.
         let output_ty = match output {
@@ -1972,7 +1976,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_param_bound(
         &mut self,
         tpb: &GenericBound,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
     ) -> hir::GenericBound<'hir> {
         match tpb {
             GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait(
@@ -2151,7 +2155,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         modifiers: ast::TraitBoundModifiers,
         p: &TraitRef,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
     ) -> hir::TraitRef<'hir> {
         let path = match self.lower_qpath(
             p.ref_id,
@@ -2171,7 +2175,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_poly_trait_ref(
         &mut self,
         p: &PolyTraitRef,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
         modifiers: ast::TraitBoundModifiers,
     ) -> hir::PolyTraitRef<'hir> {
         let bound_generic_params =
@@ -2180,7 +2184,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
     }
 
-    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
+    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext<'_>) -> hir::MutTy<'hir> {
         hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
     }
 
@@ -2188,16 +2192,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_param_bounds(
         &mut self,
         bounds: &[GenericBound],
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
     ) -> hir::GenericBounds<'hir> {
         self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
     }
 
-    fn lower_param_bounds_mut<'s>(
+    fn lower_param_bounds_mut<'s, 'c>(
         &'s mut self,
         bounds: &'s [GenericBound],
-        itctx: ImplTraitContext,
-    ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
+        itctx: ImplTraitContext<'c>,
+    ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'c> + Captures<'a>
+    {
         bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
     }
 
@@ -2232,7 +2237,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             bounds,
             /* colon_span */ None,
             span,
-            ImplTraitContext::Universal,
+            ImplTraitContext::Disallowed(ImplTraitPosition::ImplTrait {
+                outer: &ImplTraitContext::Universal,
+            }),
             hir::PredicateOrigin::ImplTrait,
         );
 
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index aeeb4bf9e763a..d22e88be1e4e2 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -27,12 +27,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         qself: &Option<ptr::P<QSelf>>,
         p: &Path,
         param_mode: ParamMode,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
         // modifiers of the impl/bound if this is a trait path
         modifiers: Option<ast::TraitBoundModifiers>,
     ) -> hir::QPath<'hir> {
         let qself_position = qself.as_ref().map(|q| q.position);
-        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
+        let qself = qself
+            .as_ref()
+            .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
 
         let partial_res =
             self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
@@ -71,14 +73,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             res,
             segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
                 |(i, segment)| {
-                    let param_mode = match (qself_position, param_mode) {
+                    let (param_mode, itctx) = match (qself_position, param_mode) {
                         (Some(j), ParamMode::Optional) if i < j => {
-                            // This segment is part of the trait path in a
-                            // qualified path - one of `a`, `b` or `Trait`
-                            // in `<X as a::b::Trait>::T::U::method`.
-                            ParamMode::Explicit
+                            // This segment is part of the trait path in a qualified path:
+                            // One of `a`, `b` or `Trait` in `<X as a::b::Trait>::T::U::method`.
+                            // `impl Trait` is unconditionally disallowed here.
+                            (
+                                ParamMode::Explicit,
+                                ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            )
                         }
-                        _ => param_mode,
+                        _ => (param_mode, itctx),
                     };
 
                     let parenthesized_generic_args = match base_res {
@@ -162,6 +167,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 segment,
                 param_mode,
                 ParenthesizedGenericArgs::Err,
+                // Whether `impl Trait` is allowed here depends on the context contrary to
+                // the self type and trait segment paths in qualified paths (see above).
                 itctx,
                 None,
                 None,
@@ -220,7 +227,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         segment: &PathSegment,
         param_mode: ParamMode,
         parenthesized_generic_args: ParenthesizedGenericArgs,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
         constness: Option<ast::BoundConstness>,
         // Additional features ungated with a bound modifier like `async`.
         // This is passed down to the implicit associated type binding in
@@ -374,7 +381,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         data: &AngleBracketedArgs,
         param_mode: ParamMode,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
     ) -> (GenericArgsCtor<'hir>, bool) {
         let has_non_lt_args = data.args.iter().any(|arg| match arg {
             AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
@@ -389,10 +396,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 AngleBracketedArg::Constraint(_) => None,
             })
             .collect();
-        let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
-            AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)),
-            AngleBracketedArg::Arg(_) => None,
-        }));
+        let bindings = {
+            // FIXME(fmease): explainer
+            let itctx = match itctx {
+                ImplTraitContext::Disallowed(ImplTraitPosition::ImplTrait { outer }) => *outer,
+                itctx => itctx,
+            };
+
+            self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
+                AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)),
+                AngleBracketedArg::Arg(_) => None,
+            }))
+        };
         let ctor = GenericArgsCtor {
             args,
             bindings,
@@ -405,7 +420,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_parenthesized_parameter_data(
         &mut self,
         data: &ParenthesizedArgs,
-        itctx: ImplTraitContext,
+        itctx: ImplTraitContext<'_>,
         bound_modifier_allowed_features: Option<Lrc<[Symbol]>>,
     ) -> (GenericArgsCtor<'hir>, bool) {
         // Switch to `PassThrough` mode for anonymous lifetimes; this
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 28a13d275a559..a6a0d80e45895 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -149,8 +149,6 @@ ast_passes_generic_before_constraints = generic arguments must come before the f
 
 ast_passes_generic_default_trailing = generic parameters with a default must be trailing
 
-ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
-
 ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
     .help = remove one of these features
 
@@ -191,10 +189,6 @@ ast_passes_negative_bound_not_supported =
 ast_passes_negative_bound_with_parenthetical_notation =
     parenthetical notation may not be used for negative bounds
 
-ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
-    .outer = outer `impl Trait`
-    .inner = nested `impl Trait` here
-
 ast_passes_nested_lifetimes = nested quantification of lifetimes
 
 ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 80c62d3fecf49..7c91b664c9c92 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -76,17 +76,8 @@ struct AstValidator<'a> {
 
     has_proc_macro_decls: bool,
 
-    /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
-    /// Nested `impl Trait` _is_ allowed in associated type position,
-    /// e.g., `impl Iterator<Item = impl Debug>`.
-    outer_impl_trait: Option<Span>,
-
     disallow_tilde_const: Option<DisallowTildeConstContext<'a>>,
 
-    /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
-    /// or `Foo::Bar<impl Trait>`
-    is_impl_trait_banned: bool,
-
     lint_buffer: &'a mut LintBuffer,
 }
 
@@ -117,12 +108,6 @@ impl<'a> AstValidator<'a> {
         self.outer_trait_or_trait_impl = old;
     }
 
-    fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_impl_trait_banned, true);
-        f(self);
-        self.is_impl_trait_banned = old;
-    }
-
     fn with_tilde_const(
         &mut self,
         disallowed: Option<DisallowTildeConstContext<'a>>,
@@ -175,53 +160,13 @@ impl<'a> AstValidator<'a> {
         Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
     }
 
-    fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.outer_impl_trait, outer);
-        f(self);
-        self.outer_impl_trait = old;
-    }
-
     // Mirrors `visit::walk_ty`, but tracks relevant state.
     fn walk_ty(&mut self, t: &'a Ty) {
         match &t.kind {
-            TyKind::ImplTrait(..) => {
-                self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
-            }
             TyKind::TraitObject(..) => self
                 .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| {
                     visit::walk_ty(this, t)
                 }),
-            TyKind::Path(qself, path) => {
-                // We allow these:
-                //  - `Option<impl Trait>`
-                //  - `option::Option<impl Trait>`
-                //  - `option::Option<T>::Foo<impl Trait>`
-                //
-                // But not these:
-                //  - `<impl Trait>::Foo`
-                //  - `option::Option<impl Trait>::Foo`.
-                //
-                // To implement this, we disallow `impl Trait` from `qself`
-                // (for cases like `<impl Trait>::Foo>`)
-                // but we allow `impl Trait` in `GenericArgs`
-                // iff there are no more PathSegments.
-                if let Some(qself) = qself {
-                    // `impl Trait` in `qself` is always illegal
-                    self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
-                }
-
-                // Note that there should be a call to visit_path here,
-                // so if any logic is added to process `Path`s a call to it should be
-                // added both in visit_path and here. This code mirrors visit::walk_path.
-                for (i, segment) in path.segments.iter().enumerate() {
-                    // Allow `impl Trait` iff we're on the final path segment
-                    if i == path.segments.len() - 1 {
-                        self.visit_path_segment(segment);
-                    } else {
-                        self.with_banned_impl_trait(|this| this.visit_path_segment(segment));
-                    }
-                }
-            }
             TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
                 walk_list!(self, visit_struct_field_def, fields)
             }
@@ -715,18 +660,6 @@ impl<'a> AstValidator<'a> {
                 }
             }
             TyKind::ImplTrait(_, bounds) => {
-                if self.is_impl_trait_banned {
-                    self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
-                }
-
-                if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
-                    self.dcx().emit_err(errors::NestedImplTrait {
-                        span: ty.span,
-                        outer: outer_impl_trait_sp,
-                        inner: ty.span,
-                    });
-                }
-
                 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
                     self.dcx().emit_err(errors::AtLeastOneTrait { span: ty.span });
                 }
@@ -1178,25 +1111,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             GenericArgs::AngleBracketed(data) => {
                 self.check_generic_args_before_constraints(data);
 
+                // FIXME: use walk method if available
                 for arg in &data.args {
                     match arg {
                         AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg),
-                        // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
-                        // are allowed to contain nested `impl Trait`.
                         AngleBracketedArg::Constraint(constraint) => {
-                            self.with_impl_trait(None, |this| {
-                                this.visit_assoc_constraint(constraint);
-                            });
+                            self.visit_assoc_constraint(constraint);
                         }
                     }
                 }
             }
+            // FIXME: use walk method if available
             GenericArgs::Parenthesized(data) => {
                 walk_list!(self, visit_ty, &data.inputs);
                 if let FnRetTy::Ty(ty) = &data.output {
-                    // `-> Foo` syntax is essentially an associated type binding,
-                    // so it is also allowed to contain nested `impl Trait`.
-                    self.with_impl_trait(None, |this| this.visit_ty(ty));
+                    self.visit_ty(ty);
                 }
             }
         }
@@ -1716,9 +1645,7 @@ pub fn check_crate(
         extern_mod: None,
         outer_trait_or_trait_impl: None,
         has_proc_macro_decls: false,
-        outer_impl_trait: None,
         disallow_tilde_const: Some(DisallowTildeConstContext::Item),
-        is_impl_trait_banned: false,
         lint_buffer: lints,
     };
     visit::walk_crate(&mut validator, krate);
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 9e8c1d7f5fd19..2cb5162853640 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -397,24 +397,6 @@ pub struct TraitObjectBound {
     pub span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(ast_passes_impl_trait_path, code = E0667)]
-pub struct ImplTraitPath {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(ast_passes_nested_impl_trait, code = E0666)]
-pub struct NestedImplTrait {
-    #[primary_span]
-    pub span: Span,
-    #[label(ast_passes_outer)]
-    pub outer: Span,
-    #[label(ast_passes_inner)]
-    pub inner: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(ast_passes_at_least_one_trait)]
 pub struct AtLeastOneTrait {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 8886a78c6ecdc..08ddd2bb0502b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1212,7 +1212,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     err.emit()
                 } else if let Err(reported) = qself_ty.error_reported() {
                     reported
-                } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
+                } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() { // FIXME: bug!
                     // `<impl Trait as OtherTrait>::Assoc` makes no sense.
                     struct_span_code_err!(
                         tcx.dcx(),
diff --git a/tests/rustdoc/rrustdoc/auxiliary/dep.rs b/tests/rustdoc/rrustdoc/auxiliary/dep.rs
new file mode 100644
index 0000000000000..ddd7ee5579374
--- /dev/null
+++ b/tests/rustdoc/rrustdoc/auxiliary/dep.rs
@@ -0,0 +1,2 @@
+pub struct X;
+
diff --git a/tests/rustdoc/rrustdoc/crazy.rs b/tests/rustdoc/rrustdoc/crazy.rs
new file mode 100644
index 0000000000000..4f6662026a14d
--- /dev/null
+++ b/tests/rustdoc/rrustdoc/crazy.rs
@@ -0,0 +1,9 @@
+//(@) aux-crate:dep=dep.rs
+//@ aux-crate:dep
+//(@) aux-build:../dep.rs
+
+extern crate dep;
+
+use dep::X;
+
+
diff --git a/tests/rustdoc/rrustdoc/dep.rs b/tests/rustdoc/rrustdoc/dep.rs
new file mode 100644
index 0000000000000..10ff0bd960d06
--- /dev/null
+++ b/tests/rustdoc/rrustdoc/dep.rs
@@ -0,0 +1 @@
+pub struct X;
diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs
index 365ac85e2f665..2c277aee06dad 100644
--- a/tests/ui/impl-trait/impl_trait_projections.rs
+++ b/tests/ui/impl-trait/impl_trait_projections.rs
@@ -10,30 +10,27 @@ fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> {
 }
 
 fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-//~^ ERROR `impl Trait` is not allowed in path parameters
-//~| ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
     x.next().unwrap()
 }
 
 fn projection_with_named_trait_is_disallowed(mut x: impl Iterator)
     -> <impl Iterator as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
 {
     x.next().unwrap()
 }
 
 fn projection_with_named_trait_inside_path_is_disallowed()
     -> <::std::ops::Range<impl Debug> as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
-//~| ERROR `impl Debug: Step` is not satisfied
+//~^ ERROR `impl Trait` is not allowed in paths
 {
-    //~^ ERROR `impl Debug: Step` is not satisfied
     (1i32..100).next().unwrap()
 }
 
 fn projection_from_impl_trait_inside_dyn_trait_is_disallowed()
     -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
 {
     panic!()
 }
diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr
index d62e3ac4183f5..5e0b80fcd5922 100644
--- a/tests/ui/impl-trait/impl_trait_projections.stderr
+++ b/tests/ui/impl-trait/impl_trait_projections.stderr
@@ -1,73 +1,35 @@
-error[E0667]: `impl Trait` is not allowed in path parameters
+error[E0562]: `impl Trait` is not allowed in paths
   --> $DIR/impl_trait_projections.rs:12:51
    |
 LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
    |                                                   ^^^^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:19:9
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/impl_trait_projections.rs:18:9
    |
 LL |     -> <impl Iterator as Iterator>::Item
    |         ^^^^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:26:27
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/impl_trait_projections.rs:25:27
    |
 LL |     -> <::std::ops::Range<impl Debug> as Iterator>::Item
    |                           ^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:35:29
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/impl_trait_projections.rs:32:29
    |
 LL |     -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
    |                             ^^^^^^^^^^
-
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:12:51
-   |
-LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-   |                                                   ^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `impl Debug: Step` is not satisfied
-  --> $DIR/impl_trait_projections.rs:26:8
-   |
-LL |     -> <::std::ops::Range<impl Debug> as Iterator>::Item
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
-   |
-   = help: the following other types implement trait `Step`:
-             Char
-             Ipv4Addr
-             Ipv6Addr
-             char
-             i128
-             i16
-             i32
-             i64
-           and 8 others
-   = note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
-
-error[E0277]: the trait bound `impl Debug: Step` is not satisfied
-  --> $DIR/impl_trait_projections.rs:29:1
-   |
-LL | / {
-LL | |
-LL | |     (1i32..100).next().unwrap()
-LL | | }
-   | |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
    |
-   = help: the following other types implement trait `Step`:
-             Char
-             Ipv4Addr
-             Ipv6Addr
-             char
-             i128
-             i16
-             i32
-             i64
-           and 8 others
-   = note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error: aborting due to 7 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0277, E0667.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs
index 0daec3305c0ae..dd8f7453aa127 100644
--- a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs
+++ b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs
@@ -12,6 +12,6 @@ pub trait Foo<T> { }
 pub trait Bar { }
 pub trait Quux { type Assoc; }
 pub fn demo(_: impl Quux<Assoc=Deeper<impl Foo<impl Bar>>>) { }
-//~^ ERROR nested `impl Trait` is not allowed
+//~^ ERROR `impl Trait` is not allowed in `impl Trait`
 
 fn main() { }
diff --git a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr
index 83d0d77657247..8145d4ab5e3de 100644
--- a/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr
+++ b/tests/ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr
@@ -1,12 +1,11 @@
-error[E0666]: nested `impl Trait` is not allowed
+error[E0562]: `impl Trait` is not allowed in `impl Trait`
   --> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:14:48
    |
 LL | pub fn demo(_: impl Quux<Assoc=Deeper<impl Foo<impl Bar>>>) { }
-   |                                       ---------^^^^^^^^-
-   |                                       |        |
-   |                                       |        nested `impl Trait` here
-   |                                       outer `impl Trait`
+   |                                                ^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0666`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
index c5ecd1caae1f9..718830589af6a 100644
--- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
+++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
@@ -3,10 +3,12 @@
 // Here we test behavior of occurrences of `impl Trait` within a path
 // component in that context.
 
+// FIXME(fmease): this is now check-pass :(
+
 pub trait Bar { }
 pub trait Quux<T> { type Assoc; }
 pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
 impl<T> Quux<T> for () { type Assoc = u32; }
 
 fn main() { }
diff --git a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs
index 5a444d3dfddfa..0c1ef2088963d 100644
--- a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs
+++ b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs
@@ -7,6 +7,6 @@ pub trait Foo<T> { }
 pub trait Bar { }
 pub trait Quux { type Assoc; }
 pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
-//~^ ERROR nested `impl Trait` is not allowed
+//~^ ERROR `impl Trait` is not allowed in `impl Trait`
 
 fn main() { }
diff --git a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr
index 0e105817b18af..f03bc62608341 100644
--- a/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr
+++ b/tests/ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.stderr
@@ -1,12 +1,11 @@
-error[E0666]: nested `impl Trait` is not allowed
+error[E0562]: `impl Trait` is not allowed in `impl Trait`
   --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:9:41
    |
 LL | pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
-   |                                ---------^^^^^^^^-
-   |                                |        |
-   |                                |        nested `impl Trait` here
-   |                                outer `impl Trait`
+   |                                         ^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0666`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs
index 760102794c34e..610159d0b4773 100644
--- a/tests/ui/impl-trait/nested_impl_trait.rs
+++ b/tests/ui/impl-trait/nested_impl_trait.rs
@@ -4,20 +4,20 @@ use std::fmt::Debug;
 fn fine(x: impl Into<u32>) -> impl Into<u32> { x }
 
 fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-//~^ ERROR nested `impl Trait` is not allowed
+//~^ ERROR `impl Trait` is not allowed in `impl Trait`
 //~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
 
 fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
-//~^ ERROR nested `impl Trait` is not allowed
+//~^ ERROR `impl Trait` is not allowed in `impl Trait`
 //~| `impl Trait` is not allowed in `fn` pointer
 
 fn bad_in_arg_position(_: impl Into<impl Debug>) { }
-//~^ ERROR nested `impl Trait` is not allowed
+//~^ ERROR `impl Trait` is not allowed in `impl Trait`
 
 struct X;
 impl X {
     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-    //~^ ERROR nested `impl Trait` is not allowed
+    //~^ ERROR `impl Trait` is not allowed in `impl Trait`
     //~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
 }
 
diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr
index 83d1347aff431..b2c66dd5f3981 100644
--- a/tests/ui/impl-trait/nested_impl_trait.stderr
+++ b/tests/ui/impl-trait/nested_impl_trait.stderr
@@ -1,38 +1,10 @@
-error[E0666]: nested `impl Trait` is not allowed
+error[E0562]: `impl Trait` is not allowed in `impl Trait`
   --> $DIR/nested_impl_trait.rs:6:56
    |
 LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                              ----------^^^^^^^^^^-
-   |                                              |         |
-   |                                              |         nested `impl Trait` here
-   |                                              outer `impl Trait`
-
-error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/nested_impl_trait.rs:10:42
-   |
-LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
-   |                                ----------^^^^^^^^^^-
-   |                                |         |
-   |                                |         nested `impl Trait` here
-   |                                outer `impl Trait`
-
-error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/nested_impl_trait.rs:14:37
+   |                                                        ^^^^^^^^^^
    |
-LL | fn bad_in_arg_position(_: impl Into<impl Debug>) { }
-   |                           ----------^^^^^^^^^^-
-   |                           |         |
-   |                           |         nested `impl Trait` here
-   |                           outer `impl Trait`
-
-error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/nested_impl_trait.rs:19:44
-   |
-LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                  ----------^^^^^^^^^^-
-   |                                  |         |
-   |                                  |         nested `impl Trait` here
-   |                                  outer `impl Trait`
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
 error[E0562]: `impl Trait` is not allowed in `fn` pointer return types
   --> $DIR/nested_impl_trait.rs:10:32
@@ -42,25 +14,30 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
-  --> $DIR/nested_impl_trait.rs:6:46
+error[E0562]: `impl Trait` is not allowed in `impl Trait`
+  --> $DIR/nested_impl_trait.rs:14:37
    |
-LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                              ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
+LL | fn bad_in_arg_position(_: impl Into<impl Debug>) { }
+   |                                     ^^^^^^^^^^
    |
-   = help: the trait `Into<U>` is implemented for `T`
-   = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
-  --> $DIR/nested_impl_trait.rs:19:34
+error[E0562]: `impl Trait` is not allowed in `impl Trait`
+  --> $DIR/nested_impl_trait.rs:19:44
    |
 LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                  ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
+   |                                            ^^^^^^^^^^
    |
-   = help: the trait `Into<U>` is implemented for `T`
-   = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+
+error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds
+  --> $DIR/nested_impl_trait.rs:28:42
+   |
+LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
+   |                                          ^^^^^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0277, E0562, E0666.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/where-allowed.rs b/tests/ui/impl-trait/where-allowed.rs
index 72ce617693e40..60fa3e5f95183 100644
--- a/tests/ui/impl-trait/where-allowed.rs
+++ b/tests/ui/impl-trait/where-allowed.rs
@@ -49,7 +49,7 @@ fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() }
 // Disallowed
 fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
 //~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds
-//~^^ ERROR nested `impl Trait` is not allowed
+//~| ERROR `impl Trait` is not allowed in `impl Trait`
 
 // Disallowed
 fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() }
@@ -58,7 +58,7 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() }
 // Disallowed
 fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
 //~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds
-//~| ERROR nested `impl Trait` is not allowed
+//~| ERROR `impl Trait` is not allowed in `impl Trait`
 
 // Allowed
 fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr
index bffe0447f8bb4..ec7898a1d11bf 100644
--- a/tests/ui/impl-trait/where-allowed.stderr
+++ b/tests/ui/impl-trait/where-allowed.stderr
@@ -1,21 +1,3 @@
-error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/where-allowed.rs:50:51
-   |
-LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
-   |                                           --------^^^^^^^^^^-
-   |                                           |       |
-   |                                           |       nested `impl Trait` here
-   |                                           outer `impl Trait`
-
-error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/where-allowed.rs:59:57
-   |
-LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
-   |                                                 --------^^^^^^^^^^-
-   |                                                 |       |
-   |                                                 |       nested `impl Trait` here
-   |                                                 outer `impl Trait`
-
 error[E0658]: `impl Trait` in associated types is unstable
   --> $DIR/where-allowed.rs:122:16
    |
@@ -126,6 +108,14 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
+error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds
+  --> $DIR/where-allowed.rs:64:59
+   |
+LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
+   |                                                           ^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+
 error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds
   --> $DIR/where-allowed.rs:68:38
    |
@@ -428,7 +418,7 @@ LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
 
-error: aborting due to 50 previous errors
+error: aborting due to 49 previous errors
 
-Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0599, E0658, E0666.
+Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0599, E0658.
 For more information about an error, try `rustc --explain E0053`.