diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index b5f42e98127..27dc088d5dd 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -94,15 +94,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             return false;
         };
         let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
+        let mut is_downgradable = true;
         let is_object_safe = match self_ty.kind {
             hir::TyKind::TraitObject(objects, ..) => {
                 objects.iter().all(|o| match o.trait_ref.path.res {
-                    Res::Def(DefKind::Trait, id) if Some(id) == owner => {
-                        // When we're dealing with a recursive trait, we don't want to downgrade
-                        // the error, so we consider them to be object safe always. (#119652)
-                        true
+                    Res::Def(DefKind::Trait, id) => {
+                        if Some(id) == owner {
+                            // For recursive traits, don't downgrade the error. (#119652)
+                            is_downgradable = false;
+                        }
+                        tcx.check_is_object_safe(id)
                     }
-                    Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
                     _ => false,
                 })
             }
@@ -130,7 +132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ],
                     Applicability::MachineApplicable,
                 );
-            } else if diag.is_error() {
+            } else if diag.is_error() && is_downgradable {
                 // We'll emit the object safety error already, with a structured suggestion.
                 diag.downgrade_to_delayed_bug();
             }
@@ -156,7 +158,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             if !is_object_safe {
                 diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
-                if diag.is_error() {
+                if diag.is_error() && is_downgradable {
                     // We'll emit the object safety error already, with a structured suggestion.
                     diag.downgrade_to_delayed_bug();
                 }
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
index f48c3d124dd..dbdfde6dd50 100644
--- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.rs
@@ -8,16 +8,18 @@ trait A: Sized {
     //~| ERROR the trait `A` cannot be made into an object
 }
 trait B {
-    fn f(a: B) -> B;
+    fn f(b: B) -> B;
     //~^ ERROR trait objects must include the `dyn` keyword
     //~| ERROR trait objects must include the `dyn` keyword
     //~| ERROR associated item referring to unboxed trait object for its own trait
     //~| ERROR the trait `B` cannot be made into an object
 }
 trait C {
-    fn f(&self, a: C) -> C;
+    fn f(&self, c: C) -> C;
     //~^ ERROR trait objects must include the `dyn` keyword
     //~| ERROR trait objects must include the `dyn` keyword
+    //~| ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `C` cannot be made into an object
 }
 
 fn main() {}
diff --git a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
index 73d5a24f831..60eb72ab4f7 100644
--- a/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
+++ b/tests/ui/suggestions/object-unsafe-trait-should-use-self-2021-without-dyn.stderr
@@ -30,18 +30,18 @@ error: associated item referring to unboxed trait object for its own trait
    |
 LL | trait B {
    |       - in this trait
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |             ^     ^
    |
 help: you might have meant to use `Self` to refer to the implementing type
    |
-LL |     fn f(a: Self) -> Self;
+LL |     fn f(b: Self) -> Self;
    |             ~~~~     ~~~~
 
 error[E0038]: the trait `B` cannot be made into an object
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
    |
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |             ^ `B` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
@@ -49,23 +49,53 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
    |
 LL | trait B {
    |       - this trait cannot be made into an object...
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |        ^ ...because associated function `f` has no `self` parameter
 help: consider turning `f` into a method by giving it a `&self` argument
    |
-LL |     fn f(&self, a: B) -> B;
+LL |     fn f(&self, b: B) -> B;
    |          ++++++
 help: alternatively, consider constraining `f` so it does not apply to trait objects
    |
-LL |     fn f(a: B) -> B where Self: Sized;
+LL |     fn f(b: B) -> B where Self: Sized;
    |                     +++++++++++++++++
 
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
+   |
+LL | trait C {
+   |       - in this trait
+LL |     fn f(&self, c: C) -> C;
+   |                    ^     ^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn f(&self, c: Self) -> Self;
+   |                    ~~~~     ~~~~
+
+error[E0038]: the trait `C` cannot be made into an object
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
+   |
+LL |     fn f(&self, c: C) -> C;
+   |          -----     ^ `C` cannot be made into an object
+   |          |
+   |          help: consider changing method `f`'s `self` parameter to be `&self` (notice the capitalization): `&Self`
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:10
+   |
+LL | trait C {
+   |       - this trait cannot be made into an object...
+LL |     fn f(&self, c: C) -> C;
+   |          ^^^^^ ...because method `f`'s `self` parameter cannot be dispatched on
+
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13
    |
 LL |     fn f(a: A) -> A;
    |             ^
    |
+   = note: `A` it is not object safe, so it can't be `dyn`
 help: use a new generic type parameter, constrained by `A`
    |
 LL |     fn f<T: A>(a: T) -> A;
@@ -74,10 +104,6 @@ help: you can also use an opaque type, but users won't be able to specify the ty
    |
 LL |     fn f(a: impl A) -> A;
    |             ++++
-help: alternatively, use a trait object to accept any type that implements `A`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn f(a: &dyn A) -> A;
-   |             ++++
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19
@@ -85,84 +111,66 @@ error[E0782]: trait objects must include the `dyn` keyword
 LL |     fn f(a: A) -> A;
    |                   ^
    |
-help: use `impl A` to return an opaque type, as long as you return a single underlying type
+help: `A` is not object safe, use `impl A` to return an opaque type, as long as you return a single underlying type
    |
 LL |     fn f(a: A) -> impl A;
    |                   ++++
-help: alternatively, you can return an owned trait object
-   |
-LL |     fn f(a: A) -> Box<dyn A>;
-   |                   +++++++  +
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
    |
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |             ^
    |
+   = note: `B` it is not object safe, so it can't be `dyn`
 help: use a new generic type parameter, constrained by `B`
    |
-LL |     fn f<T: B>(a: T) -> B;
+LL |     fn f<T: B>(b: T) -> B;
    |         ++++++    ~
 help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
    |
-LL |     fn f(a: impl B) -> B;
-   |             ++++
-help: alternatively, use a trait object to accept any type that implements `B`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn f(a: &dyn B) -> B;
+LL |     fn f(b: impl B) -> B;
    |             ++++
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:19
    |
-LL |     fn f(a: B) -> B;
+LL |     fn f(b: B) -> B;
    |                   ^
    |
-help: use `impl B` to return an opaque type, as long as you return a single underlying type
+help: `B` is not object safe, use `impl B` to return an opaque type, as long as you return a single underlying type
    |
-LL |     fn f(a: B) -> impl B;
+LL |     fn f(b: B) -> impl B;
    |                   ++++
-help: alternatively, you can return an owned trait object
-   |
-LL |     fn f(a: B) -> Box<dyn B>;
-   |                   +++++++  +
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
    |
-LL |     fn f(&self, a: C) -> C;
+LL |     fn f(&self, c: C) -> C;
    |                    ^
    |
+   = note: `C` it is not object safe, so it can't be `dyn`
 help: use a new generic type parameter, constrained by `C`
    |
-LL |     fn f<T: C>(&self, a: T) -> C;
+LL |     fn f<T: C>(&self, c: T) -> C;
    |         ++++++           ~
 help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
    |
-LL |     fn f(&self, a: impl C) -> C;
-   |                    ++++
-help: alternatively, use a trait object to accept any type that implements `C`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn f(&self, a: &dyn C) -> C;
+LL |     fn f(&self, c: impl C) -> C;
    |                    ++++
 
 error[E0782]: trait objects must include the `dyn` keyword
   --> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:26
    |
-LL |     fn f(&self, a: C) -> C;
+LL |     fn f(&self, c: C) -> C;
    |                          ^
    |
-help: use `impl C` to return an opaque type, as long as you return a single underlying type
+help: `C` is not object safe, use `impl C` to return an opaque type, as long as you return a single underlying type
    |
-LL |     fn f(&self, a: C) -> impl C;
+LL |     fn f(&self, c: C) -> impl C;
    |                          ++++
-help: alternatively, you can return an owned trait object
-   |
-LL |     fn f(&self, a: C) -> Box<dyn C>;
-   |                          +++++++  +
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
 Some errors have detailed explanations: E0038, E0782.
 For more information about an error, try `rustc --explain E0038`.