about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-04-30 13:52:29 +0000
committerbors <bors@rust-lang.org>2022-04-30 13:52:29 +0000
commitd201c812d40932509b2b5307c0b20c1ce78d21da (patch)
treefebd00751fa6caa1f704cdcabe5249a7643643e7
parent76d4862fdd131b6f79dc0a31857f888d26bcdb27 (diff)
parentb4e3e62c9cde00637fc2e69b24581ba77494035b (diff)
downloadrust-d201c812d40932509b2b5307c0b20c1ce78d21da.tar.gz
rust-d201c812d40932509b2b5307c0b20c1ce78d21da.zip
Auto merge of #93803 - cjgillot:unify-bounds, r=oli-obk
Handle generic bounds in a uniform way in HIR

Generic bounds in HIR used to be split between bounds in the parameter definition and bounds in a where clause. This PR attempts to store all of those as where predicates.

This effectively desugars
```rust
fn foo<T: Default, U>(x: impl Copy) where U: Clone
```
into
```rust
fn foo<T, U, _V>(x: _V) where T: Default, U: Clone, _V: Copy
```
(where _V is actually hidden and called "impl Copy").

I managed to make compiler warnings more uniform.
About rustdoc: is making this desugaring user-visible acceptable?
About clippy: I don't understand the subtle logic in the `needless-lifetimes` lint.

r? `@estebank`
-rw-r--r--compiler/rustc_ast/src/ast.rs1
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs5
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs136
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs109
-rw-r--r--compiler/rustc_builtin_macros/src/derive.rs1
-rw-r--r--compiler/rustc_expand/src/build.rs1
-rw-r--r--compiler/rustc_expand/src/placeholders.rs1
-rw-r--r--compiler/rustc_hir/src/arena.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs273
-rw-r--r--compiler/rustc_hir/src/intravisit.rs5
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs53
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs71
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs4
-rw-r--r--compiler/rustc_lint/src/builtin.rs180
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs4
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs360
-rw-r--r--compiler/rustc_middle/src/ty/error.rs59
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs13
-rw-r--r--compiler/rustc_passes/src/dead.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs7
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs90
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs4
-rw-r--r--compiler/rustc_save_analysis/src/sig.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs33
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs5
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs20
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs19
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs14
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs66
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs11
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs17
-rw-r--r--compiler/rustc_typeck/src/collect.rs185
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs4
-rw-r--r--compiler/rustc_typeck/src/lib.rs4
-rw-r--r--src/etc/check_missing_items.py2
-rw-r--r--src/librustdoc/clean/mod.rs119
-rw-r--r--src/librustdoc/html/render/span_map.rs13
-rw-r--r--src/test/ui/async-await/issue-86507.stderr6
-rw-r--r--src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr9
-rw-r--r--src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr6
-rw-r--r--src/test/ui/generic-associated-types/issue-86483.stderr16
-rw-r--r--src/test/ui/generic-associated-types/issue-91139.migrate.stderr7
-rw-r--r--src/test/ui/generic-associated-types/issue-92096.migrate.stderr18
-rw-r--r--src/test/ui/generic-associated-types/missing-bounds.stderr6
-rw-r--r--src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr2
-rw-r--r--src/test/ui/impl-trait/equal-hidden-lifetimes.stderr2
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr8
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr9
-rw-r--r--src/test/ui/impl-trait/type_parameters_captured.nll.stderr8
-rw-r--r--src/test/ui/impl-trait/type_parameters_captured.stderr9
-rw-r--r--src/test/ui/issues/issue-30438-c.rs1
-rw-r--r--src/test/ui/issues/issue-30438-c.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr39
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr7
-rw-r--r--src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed16
-rw-r--r--src/test/ui/moves/use_of_moved_value_copy_suggestions.rs6
-rw-r--r--src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr16
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr8
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr16
-rw-r--r--src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr7
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr16
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr8
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr7
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr16
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr15
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr7
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-fn.stderr16
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-4.nll.stderr28
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-5.base.stderr53
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-5.nll.stderr32
-rw-r--r--src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr14
-rw-r--r--src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr14
-rw-r--r--src/test/ui/regions/regions-close-param-into-object.base.stderr32
-rw-r--r--src/test/ui/regions/regions-close-param-into-object.nll.stderr32
-rw-r--r--src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs2
-rw-r--r--src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr10
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr8
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr8
-rw-r--r--src/test/ui/regions/regions-infer-bound-from-trait.base.stderr12
-rw-r--r--src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr14
-rw-r--r--src/test/ui/regions/regions-static-bound-rpass.rs7
-rw-r--r--src/test/ui/regions/regions-static-bound-rpass.stderr26
-rw-r--r--src/test/ui/regions/regions-static-bound.base.stderr30
-rw-r--r--src/test/ui/regions/regions-static-bound.nll.stderr24
-rw-r--r--src/test/ui/regions/regions-static-bound.rs4
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr6
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr22
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr13
-rw-r--r--src/test/ui/static/static-lifetime-bound.stderr2
-rw-r--r--src/test/ui/suggestions/bound-suggestions.fixed2
-rw-r--r--src/test/ui/suggestions/bound-suggestions.stderr6
-rw-r--r--src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr2
-rw-r--r--src/test/ui/suggestions/issue-21673.stderr6
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr6
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr6
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr36
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr24
-rw-r--r--src/test/ui/suggestions/restrict-type-argument.stderr4
-rw-r--r--src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr8
-rw-r--r--src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr7
-rw-r--r--src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr4
-rw-r--r--src/test/ui/traits/issue-95898.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr7
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr7
-rw-r--r--src/test/ui/wf/wf-impl-associated-type-region.stderr7
-rw-r--r--src/test/ui/wf/wf-in-fn-type-static.stderr16
-rw-r--r--src/test/ui/wf/wf-in-obj-type-static.stderr8
-rw-r--r--src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr14
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/serde_api.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs4
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr8
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.stderr8
120 files changed, 1498 insertions, 1462 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index a310828b9fb..cdcd221e811 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -397,6 +397,7 @@ pub struct GenericParam {
     pub bounds: GenericBounds,
     pub is_placeholder: bool,
     pub kind: GenericParamKind,
+    pub colon_span: Option<Span>,
 }
 
 impl GenericParam {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index cba49835f69..d7b1bc6a7f5 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -867,9 +867,12 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
     mut param: GenericParam,
     vis: &mut T,
 ) -> SmallVec<[GenericParam; 1]> {
-    let GenericParam { id, ident, attrs, bounds, kind, is_placeholder: _ } = &mut param;
+    let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param;
     vis.visit_id(id);
     vis.visit_ident(ident);
+    if let Some(ref mut colon_span) = colon_span {
+        vis.visit_span(colon_span);
+    }
     visit_thin_attrs(attrs, vis);
     visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
     match kind {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 8ae07982f6f..125acdcc27d 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -267,9 +267,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
 
                     let (generics, decl) =
-                        this.add_implicit_generics(generics, id, |this, idty| {
+                        this.add_implicit_generics(generics, id, |this, idty, idpb| {
                             let ret_id = asyncness.opt_return_id();
-                            this.lower_fn_decl(&decl, Some((id, idty)), FnDeclKind::Fn, ret_id)
+                            this.lower_fn_decl(
+                                &decl,
+                                Some((id, idty, idpb)),
+                                FnDeclKind::Fn,
+                                ret_id,
+                            )
                         });
                     let sig = hir::FnSig {
                         decl,
@@ -384,7 +389,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // lifetime to be added, but rather a reference to a
                 // parent lifetime.
                 let (generics, (trait_ref, lowered_ty)) =
-                    self.add_implicit_generics(ast_generics, id, |this, _| {
+                    self.add_implicit_generics(ast_generics, id, |this, _, _| {
                         let trait_ref = trait_ref.as_ref().map(|trait_ref| {
                             this.lower_trait_ref(
                                 trait_ref,
@@ -410,7 +415,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     ImplPolarity::Positive => ImplPolarity::Positive,
                     ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
                 };
-                hir::ItemKind::Impl(hir::Impl {
+                hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
                     unsafety: self.lower_unsafety(unsafety),
                     polarity,
                     defaultness,
@@ -420,7 +425,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     of_trait: trait_ref,
                     self_ty: lowered_ty,
                     items: new_impl_items,
-                })
+                }))
             }
             ItemKind::Trait(box Trait {
                 is_auto,
@@ -649,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
                     let fdec = &sig.decl;
                     let (generics, (fn_dec, fn_args)) =
-                        self.add_implicit_generics(generics, i.id, |this, _| {
+                        self.add_implicit_generics(generics, i.id, |this, _, _| {
                             (
                                 // Disallow `impl Trait` in foreign items.
                                 this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
@@ -1226,10 +1231,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
         id: NodeId,
         kind: FnDeclKind,
         is_async: Option<NodeId>,
-    ) -> (hir::Generics<'hir>, hir::FnSig<'hir>) {
+    ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
         let header = self.lower_fn_header(sig.header);
-        let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty| {
-            this.lower_fn_decl(&sig.decl, Some((id, idty)), kind, is_async)
+        let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty, idpb| {
+            this.lower_fn_decl(&sig.decl, Some((id, idty, idpb)), kind, is_async)
         });
         (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
     }
@@ -1289,7 +1294,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     pub(super) fn lower_generics_mut(
         &mut self,
         generics: &Generics,
-        itctx: ImplTraitContext<'_, 'hir>,
+        mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> GenericsCtor<'hir> {
         // Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
         // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
@@ -1338,9 +1343,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
         }
 
+        let mut predicates = SmallVec::new();
+        predicates.extend(generics.params.iter().filter_map(|param| {
+            let bounds = self.lower_param_bounds(&param.bounds, itctx.reborrow());
+            self.lower_generic_bound_predicate(param.ident, param.id, &param.kind, bounds)
+        }));
+        predicates.extend(
+            generics
+                .where_clause
+                .predicates
+                .iter()
+                .map(|predicate| self.lower_where_predicate(predicate)),
+        );
+
         GenericsCtor {
-            params: self.lower_generic_params_mut(&generics.params, itctx).collect(),
-            where_clause: self.lower_where_clause(&generics.where_clause),
+            params: self.lower_generic_params_mut(&generics.params).collect(),
+            predicates,
+            has_where_clause: !generics.where_clause.predicates.is_empty(),
+            where_clause_span: self.lower_span(generics.where_clause.span),
             span: self.lower_span(generics.span),
         }
     }
@@ -1349,17 +1369,74 @@ impl<'hir> LoweringContext<'_, 'hir> {
         &mut self,
         generics: &Generics,
         itctx: ImplTraitContext<'_, 'hir>,
-    ) -> hir::Generics<'hir> {
+    ) -> &'hir hir::Generics<'hir> {
         let generics_ctor = self.lower_generics_mut(generics, itctx);
         generics_ctor.into_generics(self.arena)
     }
 
-    fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause<'hir> {
-        hir::WhereClause {
-            predicates: self.arena.alloc_from_iter(
-                wc.predicates.iter().map(|predicate| self.lower_where_predicate(predicate)),
-            ),
-            span: self.lower_span(wc.span),
+    pub(super) fn lower_generic_bound_predicate(
+        &mut self,
+        ident: Ident,
+        id: NodeId,
+        kind: &GenericParamKind,
+        bounds: &'hir [hir::GenericBound<'hir>],
+    ) -> Option<hir::WherePredicate<'hir>> {
+        // Do not create a clause if we do not have anything inside it.
+        if bounds.is_empty() {
+            return None;
+        }
+        let ident = self.lower_ident(ident);
+        let param_span = ident.span;
+        let span = bounds
+            .iter()
+            .fold(Some(param_span.shrink_to_hi()), |span: Option<Span>, bound| {
+                let bound_span = bound.span();
+                // We include bounds that come from a `#[derive(_)]` but point at the user's code,
+                // as we use this method to get a span appropriate for suggestions.
+                if !bound_span.can_be_used_for_suggestions() {
+                    None
+                } else if let Some(span) = span {
+                    Some(span.to(bound_span))
+                } else {
+                    Some(bound_span)
+                }
+            })
+            .unwrap_or(param_span.shrink_to_hi());
+        match kind {
+            GenericParamKind::Const { .. } => None,
+            GenericParamKind::Type { .. } => {
+                let def_id = self.resolver.local_def_id(id).to_def_id();
+                let ty_path = self.arena.alloc(hir::Path {
+                    span: param_span,
+                    res: Res::Def(DefKind::TyParam, def_id),
+                    segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]),
+                });
+                let ty_id = self.next_id();
+                let bounded_ty =
+                    self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path));
+                Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                    bounded_ty: self.arena.alloc(bounded_ty),
+                    bounds,
+                    span,
+                    bound_generic_params: &[],
+                    in_where_clause: false,
+                }))
+            }
+            GenericParamKind::Lifetime => {
+                let ident_span = self.lower_span(ident.span);
+                let ident = self.lower_ident(ident);
+                let res = self.resolver.get_lifetime_res(id).unwrap_or_else(|| {
+                    panic!("Missing resolution for lifetime {:?} at {:?}", id, ident.span)
+                });
+                let lt_id = self.resolver.next_node_id();
+                let lifetime = self.new_named_lifetime_with_res(lt_id, ident_span, ident, res);
+                Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+                    lifetime,
+                    span,
+                    bounds,
+                    in_where_clause: false,
+                }))
+            }
         }
     }
 
@@ -1371,10 +1448,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ref bounds,
                 span,
             }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
-                bound_generic_params: self.lower_generic_params(
-                    bound_generic_params,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                ),
+                bound_generic_params: self.lower_generic_params(bound_generic_params),
                 bounded_ty: self
                     .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
                 bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
@@ -1384,6 +1458,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     )
                 })),
                 span: self.lower_span(span),
+                in_where_clause: true,
             }),
             WherePredicate::RegionPredicate(WhereRegionPredicate {
                 ref lifetime,
@@ -1396,6 +1471,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     bounds,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                 ),
+                in_where_clause: true,
             }),
             WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
@@ -1414,16 +1490,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
 /// Helper struct for delayed construction of Generics.
 pub(super) struct GenericsCtor<'hir> {
     pub(super) params: SmallVec<[hir::GenericParam<'hir>; 4]>,
-    where_clause: hir::WhereClause<'hir>,
+    pub(super) predicates: SmallVec<[hir::WherePredicate<'hir>; 4]>,
+    has_where_clause: bool,
+    where_clause_span: Span,
     span: Span,
 }
 
 impl<'hir> GenericsCtor<'hir> {
-    pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> hir::Generics<'hir> {
-        hir::Generics {
+    pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> &'hir hir::Generics<'hir> {
+        arena.alloc(hir::Generics {
             params: arena.alloc_from_iter(self.params),
-            where_clause: self.where_clause,
+            predicates: arena.alloc_from_iter(self.predicates),
+            has_where_clause: self.has_where_clause,
+            where_clause_span: self.where_clause_span,
             span: self.span,
-        }
+        })
     }
 }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index de4f8e04b16..d433775f85c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -259,7 +259,7 @@ enum ImplTraitContext<'b, 'a> {
     /// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
     ///
     /// Newly generated parameters should be inserted into the given `Vec`.
-    Universal(&'b mut Vec<hir::GenericParam<'a>>, LocalDefId),
+    Universal(&'b mut Vec<hir::GenericParam<'a>>, &'b mut Vec<hir::WherePredicate<'a>>, LocalDefId),
 
     /// Treat `impl Trait` as shorthand for a new opaque type.
     /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
@@ -303,7 +303,7 @@ impl<'a> ImplTraitContext<'_, 'a> {
     fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
         use self::ImplTraitContext::*;
         match self {
-            Universal(params, parent) => Universal(params, *parent),
+            Universal(params, bounds, parent) => Universal(params, bounds, *parent),
             ReturnPositionOpaqueTy { origin } => ReturnPositionOpaqueTy { origin: *origin },
             TypeAliasesOpaqueTy => TypeAliasesOpaqueTy,
             Disallowed(pos) => Disallowed(*pos),
@@ -704,10 +704,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         Some(hir::GenericParam {
             hir_id,
             name,
-            bounds: &[],
             span: self.lower_span(ident.span),
             pure_wrt_drop: false,
             kind: hir::GenericParamKind::Lifetime { kind },
+            colon_span: None,
         })
     }
 
@@ -718,14 +718,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         generics: &Generics,
         parent_node_id: NodeId,
-        f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
-    ) -> (hir::Generics<'hir>, T) {
+        f: impl FnOnce(
+            &mut Self,
+            &mut Vec<hir::GenericParam<'hir>>,
+            &mut Vec<hir::WherePredicate<'hir>>,
+        ) -> T,
+    ) -> (&'hir hir::Generics<'hir>, T) {
         let mut impl_trait_defs = Vec::new();
+        let mut impl_trait_bounds = Vec::new();
         let mut lowered_generics = self.lower_generics_mut(
             generics,
-            ImplTraitContext::Universal(&mut impl_trait_defs, self.current_hir_id_owner),
+            ImplTraitContext::Universal(
+                &mut impl_trait_defs,
+                &mut impl_trait_bounds,
+                self.current_hir_id_owner,
+            ),
         );
-        let res = f(self, &mut impl_trait_defs);
+        let res = f(self, &mut impl_trait_defs, &mut impl_trait_bounds);
 
         let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
         lowered_generics.params.extend(
@@ -736,6 +745,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 })
                 .chain(impl_trait_defs),
         );
+        lowered_generics.predicates.extend(impl_trait_bounds);
 
         let lowered_generics = lowered_generics.into_generics(self.arena);
         (lowered_generics, res)
@@ -999,7 +1009,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // so desugar to
                     //
                     //     fn foo(x: dyn Iterator<Item = impl Debug>)
-                    ImplTraitContext::Universal(_, parent) if self.is_in_dyn_type => {
+                    ImplTraitContext::Universal(_, _, parent) if self.is_in_dyn_type => {
                         parent_def_id = parent;
                         (true, itctx)
                     }
@@ -1188,10 +1198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
             TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| {
                 hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
-                    generic_params: this.lower_generic_params(
-                        &f.generic_params,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
+                    generic_params: this.lower_generic_params(&f.generic_params),
                     unsafety: this.lower_unsafety(f.unsafety),
                     abi: this.lower_extern(f.ext),
                     decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
@@ -1274,13 +1281,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             |this| this.lower_param_bounds(bounds, nested_itctx),
                         )
                     }
-                    ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => {
+                    ImplTraitContext::Universal(
+                        in_band_ty_params,
+                        in_band_ty_bounds,
+                        parent_def_id,
+                    ) => {
                         // Add a definition for the in-band `Param`.
                         let def_id = self.resolver.local_def_id(def_node_id);
 
                         let hir_bounds = self.lower_param_bounds(
                             bounds,
-                            ImplTraitContext::Universal(in_band_ty_params, parent_def_id),
+                            ImplTraitContext::Universal(
+                                in_band_ty_params,
+                                in_band_ty_bounds,
+                                parent_def_id,
+                            ),
                         );
                         // Set the name to `impl Bound1 + Bound2`.
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
@@ -1288,10 +1303,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             hir_id: self.lower_node_id(def_node_id),
                             name: ParamName::Plain(self.lower_ident(ident)),
                             pure_wrt_drop: false,
-                            bounds: hir_bounds,
                             span: self.lower_span(span),
                             kind: hir::GenericParamKind::Type { default: None, synthetic: true },
+                            colon_span: None,
                         });
+                        if let Some(preds) = self.lower_generic_bound_predicate(
+                            ident,
+                            def_node_id,
+                            &GenericParamKind::Type { default: None },
+                            hir_bounds,
+                        ) {
+                            in_band_ty_bounds.push(preds)
+                        }
 
                         hir::TyKind::Path(hir::QPath::Resolved(
                             None,
@@ -1374,8 +1397,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         name: p_name,
                         span,
                         pure_wrt_drop: false,
-                        bounds: &[],
                         kind: hir::GenericParamKind::Lifetime { kind },
+                        colon_span: None,
                     }
                 },
             ));
@@ -1383,11 +1406,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs);
 
             let opaque_ty_item = hir::OpaqueTy {
-                generics: hir::Generics {
+                generics: self.arena.alloc(hir::Generics {
                     params: lifetime_defs,
-                    where_clause: hir::WhereClause { predicates: &[], span: lctx.lower_span(span) },
+                    predicates: &[],
+                    has_where_clause: false,
+                    where_clause_span: lctx.lower_span(span),
                     span: lctx.lower_span(span),
-                },
+                }),
                 bounds: hir_bounds,
                 origin,
             };
@@ -1462,7 +1487,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
-        mut in_band_ty_params: Option<(NodeId, &mut Vec<hir::GenericParam<'hir>>)>,
+        mut in_band_ty_params: Option<(
+            NodeId,
+            &mut Vec<hir::GenericParam<'hir>>,
+            &mut Vec<hir::WherePredicate<'hir>>,
+        )>,
         kind: FnDeclKind,
         make_ret_async: Option<NodeId>,
     ) -> &'hir hir::FnDecl<'hir> {
@@ -1485,10 +1514,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             inputs = &inputs[..inputs.len() - 1];
         }
         let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
-            if let Some((_, ibty)) = &mut in_band_ty_params {
+            if let Some((_, ibty, ibpb)) = &mut in_band_ty_params {
                 self.lower_ty_direct(
                     &param.ty,
-                    ImplTraitContext::Universal(ibty, self.current_hir_id_owner),
+                    ImplTraitContext::Universal(ibty, ibpb, self.current_hir_id_owner),
                 )
             } else {
                 self.lower_ty_direct(
@@ -1517,7 +1546,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             match decl.output {
                 FnRetTy::Ty(ref ty) => {
                     let context = match in_band_ty_params {
-                        Some((node_id, _)) if kind.impl_trait_return_allowed() => {
+                        Some((node_id, _, _)) if kind.impl_trait_return_allowed() => {
                             let fn_def_id = self.resolver.local_def_id(node_id);
                             ImplTraitContext::ReturnPositionOpaqueTy {
                                 origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
@@ -1708,18 +1737,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         name: p_name,
                         span,
                         pure_wrt_drop: false,
-                        bounds: &[],
                         kind: hir::GenericParamKind::Lifetime { kind },
+                        colon_span: None,
                     }
                 }));
             debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
 
             let opaque_ty_item = hir::OpaqueTy {
-                generics: hir::Generics {
+                generics: this.arena.alloc(hir::Generics {
                     params: generic_params,
-                    where_clause: hir::WhereClause { predicates: &[], span: this.lower_span(span) },
+                    predicates: &[],
+                    has_where_clause: false,
+                    where_clause_span: this.lower_span(span),
                     span: this.lower_span(span),
-                },
+                }),
                 bounds: arena_vec![this; future_bound],
                 origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
             };
@@ -1923,26 +1954,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_generic_params_mut<'s>(
         &'s mut self,
         params: &'s [GenericParam],
-        mut itctx: ImplTraitContext<'s, 'hir>,
     ) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> {
-        params.iter().map(move |param| self.lower_generic_param(param, itctx.reborrow()))
+        params.iter().map(move |param| self.lower_generic_param(param))
     }
 
-    fn lower_generic_params(
-        &mut self,
-        params: &[GenericParam],
-        itctx: ImplTraitContext<'_, 'hir>,
-    ) -> &'hir [hir::GenericParam<'hir>] {
-        self.arena.alloc_from_iter(self.lower_generic_params_mut(params, itctx))
+    fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] {
+        self.arena.alloc_from_iter(self.lower_generic_params_mut(params))
     }
 
-    fn lower_generic_param(
-        &mut self,
-        param: &GenericParam,
-        mut itctx: ImplTraitContext<'_, 'hir>,
-    ) -> hir::GenericParam<'hir> {
-        let bounds: Vec<_> = self.lower_param_bounds_mut(&param.bounds, itctx.reborrow()).collect();
-
+    fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> {
         let (name, kind) = match param.kind {
             GenericParamKind::Lifetime => {
                 let param_name = if param.ident.name == kw::StaticLifetime
@@ -1989,8 +2009,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             name,
             span: self.lower_span(param.span()),
             pure_wrt_drop: self.sess.contains_name(&param.attrs, sym::may_dangle),
-            bounds: self.arena.alloc_from_iter(bounds),
             kind,
+            colon_span: param.colon_span.map(|s| self.lower_span(s)),
         }
     }
 
@@ -2012,8 +2032,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         p: &PolyTraitRef,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::PolyTraitRef<'hir> {
-        let bound_generic_params =
-            self.lower_generic_params(&p.bound_generic_params, itctx.reborrow());
+        let bound_generic_params = self.lower_generic_params(&p.bound_generic_params);
 
         let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| {
             this.lower_trait_ref(&p.trait_ref, itctx.reborrow())
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index 61681ec66a4..391c46d1813 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -95,6 +95,7 @@ fn dummy_annotatable() -> Annotatable {
         bounds: Default::default(),
         is_placeholder: false,
         kind: GenericParamKind::Lifetime,
+        colon_span: None,
     })
 }
 
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index b8ed75cb6bb..301c67f7026 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -113,6 +113,7 @@ impl<'a> ExtCtxt<'a> {
             bounds,
             kind: ast::GenericParamKind::Type { default },
             is_placeholder: false,
+            colon_span: None,
         }
     }
 
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 15af5fdc5f8..0d5d6ee0794 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -149,6 +149,7 @@ pub fn placeholder(
                 ident,
                 is_placeholder: true,
                 kind: ast::GenericParamKind::Lifetime,
+                colon_span: None,
             }
         }]),
         AstFragmentKind::Params => AstFragment::Params(smallvec![ast::Param {
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index 27ec4619064..5d1314ebb48 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -15,11 +15,13 @@ macro_rules! arena_types {
             [] block: rustc_hir::Block<'tcx>,
             [] bare_fn_ty: rustc_hir::BareFnTy<'tcx>,
             [] body: rustc_hir::Body<'tcx>,
+            [] generics: rustc_hir::Generics<'tcx>,
             [] generic_arg: rustc_hir::GenericArg<'tcx>,
             [] generic_args: rustc_hir::GenericArgs<'tcx>,
             [] generic_bound: rustc_hir::GenericBound<'tcx>,
             [] generic_param: rustc_hir::GenericParam<'tcx>,
             [] expr: rustc_hir::Expr<'tcx>,
+            [] impl_: rustc_hir::Impl<'tcx>,
             [] let_expr: rustc_hir::Let<'tcx>,
             [] expr_field: rustc_hir::ExprField<'tcx>,
             [] pat_field: rustc_hir::PatField<'tcx>,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 7d9203b70ab..dfeee3f356f 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -17,7 +17,7 @@ use rustc_error_messages::MultiSpan;
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable_Generic;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::source_map::{SourceMap, Spanned};
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP};
 use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -496,61 +496,25 @@ pub enum GenericParamKind<'hir> {
 pub struct GenericParam<'hir> {
     pub hir_id: HirId,
     pub name: ParamName,
-    pub bounds: GenericBounds<'hir>,
     pub span: Span,
     pub pure_wrt_drop: bool,
     pub kind: GenericParamKind<'hir>,
+    pub colon_span: Option<Span>,
 }
 
 impl<'hir> GenericParam<'hir> {
-    pub fn bounds_span_for_suggestions(&self) -> Option<Span> {
-        self.bounds
-            .iter()
-            .fold(None, |span: Option<Span>, bound| {
-                // We include bounds that come from a `#[derive(_)]` but point at the user's code,
-                // as we use this method to get a span appropriate for suggestions.
-                if !bound.span().can_be_used_for_suggestions() {
-                    None
-                } else {
-                    let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
-                    Some(span)
-                }
-            })
-            .map(|sp| sp.shrink_to_hi())
+    /// Synthetic type-parameters are inserted after normal ones.
+    /// In order for normal parameters to be able to refer to synthetic ones,
+    /// scans them first.
+    pub fn is_impl_trait(&self) -> bool {
+        matches!(self.kind, GenericParamKind::Type { synthetic: true, .. })
     }
 
-    /// Returns the span of `:` after a generic parameter.
+    /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
     ///
-    /// For example:
-    ///
-    /// ```text
-    /// fn a<T:>()
-    ///       ^
-    ///       |      here
-    ///       here   |
-    ///              v
-    /// fn b<T       :>()
-    ///
-    /// fn c<T
-    ///
-    /// :>()
-    /// ^
-    /// |
-    /// here
-    /// ```
-    pub fn colon_span_for_suggestions(&self, source_map: &SourceMap) -> Option<Span> {
-        let sp = source_map
-            .span_extend_while(self.span.shrink_to_hi(), |c| c.is_whitespace() || c == ':')
-            .ok()?;
-
-        let snippet = source_map.span_to_snippet(sp).ok()?;
-        let offset = snippet.find(':')?;
-
-        let colon_sp = sp
-            .with_lo(BytePos(sp.lo().0 + offset as u32))
-            .with_hi(BytePos(sp.lo().0 + (offset + ':'.len_utf8()) as u32));
-
-        Some(colon_sp)
+    /// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
+    pub fn is_elided_lifetime(&self) -> bool {
+        matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided })
     }
 }
 
@@ -567,17 +531,22 @@ pub struct GenericParamCount {
 #[derive(Debug, HashStable_Generic)]
 pub struct Generics<'hir> {
     pub params: &'hir [GenericParam<'hir>],
-    pub where_clause: WhereClause<'hir>,
+    pub predicates: &'hir [WherePredicate<'hir>],
+    pub has_where_clause: bool,
+    pub where_clause_span: Span,
     pub span: Span,
 }
 
 impl<'hir> Generics<'hir> {
-    pub const fn empty() -> Generics<'hir> {
-        Generics {
+    pub const fn empty() -> &'hir Generics<'hir> {
+        const NOPE: Generics<'_> = Generics {
             params: &[],
-            where_clause: WhereClause { predicates: &[], span: DUMMY_SP },
+            predicates: &[],
+            has_where_clause: false,
+            where_clause_span: DUMMY_SP,
             span: DUMMY_SP,
-        }
+        };
+        &NOPE
     }
 
     pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> {
@@ -596,32 +565,122 @@ impl<'hir> Generics<'hir> {
             self.params.iter().map(|p| p.span).collect::<Vec<Span>>().into()
         }
     }
-}
 
-/// A where-clause in a definition.
-#[derive(Debug, HashStable_Generic)]
-pub struct WhereClause<'hir> {
-    pub predicates: &'hir [WherePredicate<'hir>],
-    // Only valid if predicates aren't empty.
-    pub span: Span,
-}
+    /// If there are generic parameters, return where to introduce a new one.
+    pub fn span_for_param_suggestion(&self) -> Option<Span> {
+        if self.params.iter().any(|p| self.span.contains(p.span)) {
+            // `fn foo<A>(t: impl Trait)`
+            //          ^ suggest `, T: Trait` here
+            let span = self.span.with_lo(self.span.hi() - BytePos(1)).shrink_to_lo();
+            Some(span)
+        } else {
+            None
+        }
+    }
 
-impl WhereClause<'_> {
-    pub fn span(&self) -> Option<Span> {
-        if self.predicates.is_empty() { None } else { Some(self.span) }
+    pub fn where_clause_span(&self) -> Option<Span> {
+        if self.predicates.is_empty() { None } else { Some(self.where_clause_span) }
     }
 
-    /// The `WhereClause` under normal circumstances points at either the predicates or the empty
+    /// The `where_span` under normal circumstances points at either the predicates or the empty
     /// space where the `where` clause should be. Only of use for diagnostic suggestions.
     pub fn span_for_predicates_or_empty_place(&self) -> Span {
-        self.span
+        self.where_clause_span
     }
 
     /// `Span` where further predicates would be suggested, accounting for trailing commas, like
     ///  in `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas.
-    pub fn tail_span_for_suggestion(&self) -> Span {
+    pub fn tail_span_for_predicate_suggestion(&self) -> Span {
         let end = self.span_for_predicates_or_empty_place().shrink_to_hi();
-        self.predicates.last().map_or(end, |p| p.span()).shrink_to_hi().to(end)
+        if self.has_where_clause {
+            self.predicates
+                .iter()
+                .filter(|p| p.in_where_clause())
+                .last()
+                .map_or(end, |p| p.span())
+                .shrink_to_hi()
+                .to(end)
+        } else {
+            end
+        }
+    }
+
+    pub fn bounds_for_param(
+        &self,
+        param_def_id: LocalDefId,
+    ) -> impl Iterator<Item = &WhereBoundPredicate<'_>> {
+        self.predicates.iter().filter_map(move |pred| match pred {
+            WherePredicate::BoundPredicate(bp) if bp.is_param_bound(param_def_id.to_def_id()) => {
+                Some(bp)
+            }
+            _ => None,
+        })
+    }
+
+    pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option<Span> {
+        self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
+            |bound| {
+                // We include bounds that come from a `#[derive(_)]` but point at the user's code,
+                // as we use this method to get a span appropriate for suggestions.
+                let bs = bound.span();
+                if bs.can_be_used_for_suggestions() { Some(bs.shrink_to_hi()) } else { None }
+            },
+        )
+    }
+
+    pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
+        let predicate = &self.predicates[pos];
+        let span = predicate.span();
+
+        if !predicate.in_where_clause() {
+            // <T: ?Sized, U>
+            //   ^^^^^^^^
+            return span;
+        }
+
+        // We need to find out which comma to remove.
+        if pos < self.predicates.len() - 1 {
+            let next_pred = &self.predicates[pos + 1];
+            if next_pred.in_where_clause() {
+                // where T: ?Sized, Foo: Bar,
+                //       ^^^^^^^^^^^
+                return span.until(next_pred.span());
+            }
+        }
+
+        if pos > 0 {
+            let prev_pred = &self.predicates[pos - 1];
+            if prev_pred.in_where_clause() {
+                // where Foo: Bar, T: ?Sized,
+                //               ^^^^^^^^^^^
+                return prev_pred.span().shrink_to_hi().to(span);
+            }
+        }
+
+        // This is the only predicate in the where clause.
+        // where T: ?Sized
+        // ^^^^^^^^^^^^^^^
+        self.where_clause_span
+    }
+
+    pub fn span_for_bound_removal(&self, predicate_pos: usize, bound_pos: usize) -> Span {
+        let predicate = &self.predicates[predicate_pos];
+        let bounds = predicate.bounds();
+
+        if bounds.len() == 1 {
+            return self.span_for_predicate_removal(predicate_pos);
+        }
+
+        let span = bounds[bound_pos].span();
+        if bound_pos == 0 {
+            // where T: ?Sized + Bar, Foo: Bar,
+            //          ^^^^^^^^^
+            span.to(bounds[1].span().shrink_to_lo())
+        } else {
+            // where T: Bar + ?Sized, Foo: Bar,
+            //             ^^^^^^^^^
+            bounds[bound_pos - 1].span().shrink_to_hi().to(span)
+        }
     }
 }
 
@@ -644,12 +703,29 @@ impl<'hir> WherePredicate<'hir> {
             WherePredicate::EqPredicate(p) => p.span,
         }
     }
+
+    pub fn in_where_clause(&self) -> bool {
+        match self {
+            WherePredicate::BoundPredicate(p) => p.in_where_clause,
+            WherePredicate::RegionPredicate(p) => p.in_where_clause,
+            WherePredicate::EqPredicate(_) => false,
+        }
+    }
+
+    pub fn bounds(&self) -> GenericBounds<'hir> {
+        match self {
+            WherePredicate::BoundPredicate(p) => p.bounds,
+            WherePredicate::RegionPredicate(p) => p.bounds,
+            WherePredicate::EqPredicate(_) => &[],
+        }
+    }
 }
 
 /// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
 #[derive(Debug, HashStable_Generic)]
 pub struct WhereBoundPredicate<'hir> {
     pub span: Span,
+    pub in_where_clause: bool,
     /// Any generics from a `for` binding.
     pub bound_generic_params: &'hir [GenericParam<'hir>],
     /// The type being bounded.
@@ -661,14 +737,7 @@ pub struct WhereBoundPredicate<'hir> {
 impl<'hir> WhereBoundPredicate<'hir> {
     /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
     pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
-        let TyKind::Path(QPath::Resolved(None, path)) = self.bounded_ty.kind else {
-            return false;
-        };
-        match path.res {
-            Res::Def(DefKind::TyParam, def_id)
-            | Res::SelfTy { trait_: Some(def_id), alias_to: None } => def_id == param_def_id,
-            _ => false,
-        }
+        self.bounded_ty.as_generic_param().map_or(false, |(def_id, _)| def_id == param_def_id)
     }
 }
 
@@ -676,6 +745,7 @@ impl<'hir> WhereBoundPredicate<'hir> {
 #[derive(Debug, HashStable_Generic)]
 pub struct WhereRegionPredicate<'hir> {
     pub span: Span,
+    pub in_where_clause: bool,
     pub lifetime: Lifetime,
     pub bounds: GenericBounds<'hir>,
 }
@@ -2075,7 +2145,7 @@ impl TraitItemId {
 pub struct TraitItem<'hir> {
     pub ident: Ident,
     pub def_id: LocalDefId,
-    pub generics: Generics<'hir>,
+    pub generics: &'hir Generics<'hir>,
     pub kind: TraitItemKind<'hir>,
     pub span: Span,
 }
@@ -2135,7 +2205,7 @@ impl ImplItemId {
 pub struct ImplItem<'hir> {
     pub ident: Ident,
     pub def_id: LocalDefId,
-    pub generics: Generics<'hir>,
+    pub generics: &'hir Generics<'hir>,
     pub kind: ImplItemKind<'hir>,
     pub span: Span,
     pub vis_span: Span,
@@ -2241,6 +2311,23 @@ pub struct Ty<'hir> {
     pub span: Span,
 }
 
+impl<'hir> Ty<'hir> {
+    /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
+    pub fn as_generic_param(&self) -> Option<(DefId, Ident)> {
+        let TyKind::Path(QPath::Resolved(None, path)) = self.kind else {
+            return None;
+        };
+        let [segment] = &path.segments else {
+            return None;
+        };
+        match path.res {
+            Res::Def(DefKind::TyParam, def_id)
+            | Res::SelfTy { trait_: Some(def_id), alias_to: None } => Some((def_id, segment.ident)),
+            _ => None,
+        }
+    }
+}
+
 /// Not represented directly in the AST; referred to by name through a `ty_path`.
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
@@ -2340,7 +2427,7 @@ pub struct BareFnTy<'hir> {
 
 #[derive(Debug, HashStable_Generic)]
 pub struct OpaqueTy<'hir> {
-    pub generics: Generics<'hir>,
+    pub generics: &'hir Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
     pub origin: OpaqueTyOrigin,
 }
@@ -2814,7 +2901,7 @@ pub enum ItemKind<'hir> {
     /// A `const` item.
     Const(&'hir Ty<'hir>, BodyId),
     /// A function declaration.
-    Fn(FnSig<'hir>, Generics<'hir>, BodyId),
+    Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId),
     /// A MBE macro definition (`macro_rules!` or `macro`).
     Macro(ast::MacroDef, MacroKind),
     /// A module.
@@ -2824,22 +2911,22 @@ pub enum ItemKind<'hir> {
     /// Module-level inline assembly (from `global_asm!`).
     GlobalAsm(&'hir InlineAsm<'hir>),
     /// A type alias, e.g., `type Foo = Bar<u8>`.
-    TyAlias(&'hir Ty<'hir>, Generics<'hir>),
+    TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
     /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
     OpaqueTy(OpaqueTy<'hir>),
     /// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
-    Enum(EnumDef<'hir>, Generics<'hir>),
+    Enum(EnumDef<'hir>, &'hir Generics<'hir>),
     /// A struct definition, e.g., `struct Foo<A> {x: A}`.
-    Struct(VariantData<'hir>, Generics<'hir>),
+    Struct(VariantData<'hir>, &'hir Generics<'hir>),
     /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
-    Union(VariantData<'hir>, Generics<'hir>),
+    Union(VariantData<'hir>, &'hir Generics<'hir>),
     /// A trait definition.
-    Trait(IsAuto, Unsafety, Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
+    Trait(IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
     /// A trait alias.
-    TraitAlias(Generics<'hir>, GenericBounds<'hir>),
+    TraitAlias(&'hir Generics<'hir>, GenericBounds<'hir>),
 
     /// An implementation, e.g., `impl<A> Trait for Foo { .. }`.
-    Impl(Impl<'hir>),
+    Impl(&'hir Impl<'hir>),
 }
 
 #[derive(Debug, HashStable_Generic)]
@@ -2851,7 +2938,7 @@ pub struct Impl<'hir> {
     // decoding as `Span`s cannot be decoded when a `Session` is not available.
     pub defaultness_span: Option<Span>,
     pub constness: Constness,
-    pub generics: Generics<'hir>,
+    pub generics: &'hir Generics<'hir>,
 
     /// The trait being implemented, if any.
     pub of_trait: Option<TraitRef<'hir>>,
@@ -2993,7 +3080,7 @@ impl ForeignItem<'_> {
 #[derive(Debug, HashStable_Generic)]
 pub enum ForeignItemKind<'hir> {
     /// A foreign function.
-    Fn(&'hir FnDecl<'hir>, &'hir [Ident], Generics<'hir>),
+    Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>),
     /// A foreign static item (`static ext: u8`).
     Static(&'hir Ty<'hir>, Mutability),
     /// A foreign type.
@@ -3326,9 +3413,11 @@ mod size_asserts {
     rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
     rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
     rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48);
+    rustc_data_structures::static_assert_size!(super::Generics<'static>, 56);
+    rustc_data_structures::static_assert_size!(super::Impl<'static>, 80);
 
-    rustc_data_structures::static_assert_size!(super::Item<'static>, 160);
-    rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
-    rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 120);
-    rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 112);
+    rustc_data_structures::static_assert_size!(super::Item<'static>, 80);
+    rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 88);
+    rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 80);
+    rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 72);
 }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 59bd46ae353..d41b85fd20f 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -619,7 +619,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_trait_ref, of_trait);
             visitor.visit_ty(self_ty);
-            walk_list!(visitor, visit_impl_item_ref, items);
+            walk_list!(visitor, visit_impl_item_ref, *items);
         }
         ItemKind::Struct(ref struct_definition, ref generics)
         | ItemKind::Union(ref struct_definition, ref generics) => {
@@ -899,7 +899,6 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi
             }
         }
     }
-    walk_list!(visitor, visit_param_bound, param.bounds);
 }
 
 pub fn walk_const_param_default<'v, V: Visitor<'v>>(visitor: &mut V, ct: &'v AnonConst) {
@@ -908,7 +907,7 @@ pub fn walk_const_param_default<'v, V: Visitor<'v>>(visitor: &mut V, ct: &'v Ano
 
 pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) {
     walk_list!(visitor, visit_generic_param, generics.params);
-    walk_list!(visitor, visit_where_predicate, generics.where_clause.predicates);
+    walk_list!(visitor, visit_where_predicate, generics.predicates);
 }
 
 pub fn walk_where_predicate<'v, V: Visitor<'v>>(
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 87ff9457783..7af9622b2cf 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -445,7 +445,7 @@ impl<'a> State<'a> {
         if let Some(bounds) = bounds {
             self.print_bounds(":", bounds);
         }
-        self.print_where_clause(&generics.where_clause);
+        self.print_where_clause(generics);
         if let Some(ty) = ty {
             self.space();
             self.word_space("=");
@@ -465,7 +465,7 @@ impl<'a> State<'a> {
         self.print_generic_params(&generics.params);
         self.end(); // end the inner ibox
 
-        self.print_where_clause(&generics.where_clause);
+        self.print_where_clause(generics);
         self.space();
         inner(self);
         self.word(";");
@@ -626,8 +626,8 @@ impl<'a> State<'a> {
                 items,
             }) => {
                 self.head("");
-                self.print_defaultness(defaultness);
-                self.print_unsafety(unsafety);
+                self.print_defaultness(*defaultness);
+                self.print_unsafety(*unsafety);
                 self.word_nbsp("impl");
 
                 if !generics.params.is_empty() {
@@ -635,7 +635,7 @@ impl<'a> State<'a> {
                     self.space();
                 }
 
-                if constness == hir::Constness::Const {
+                if *constness == hir::Constness::Const {
                     self.word_nbsp("const");
                 }
 
@@ -650,12 +650,12 @@ impl<'a> State<'a> {
                 }
 
                 self.print_type(&self_ty);
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
 
                 self.space();
                 self.bopen();
                 self.print_inner_attributes(attrs);
-                for impl_item in items {
+                for impl_item in *items {
                     self.ann.nested(self, Nested::ImplItem(impl_item.id));
                 }
                 self.bclose(item.span);
@@ -678,7 +678,7 @@ impl<'a> State<'a> {
                     }
                 }
                 self.print_bounds(":", real_bounds);
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
                 self.word(" ");
                 self.bopen();
                 for trait_item in trait_items {
@@ -703,7 +703,7 @@ impl<'a> State<'a> {
                 }
                 self.nbsp();
                 self.print_bounds("=", real_bounds);
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
                 self.word(";");
                 self.end(); // end inner head-block
                 self.end(); // end outer head-block
@@ -739,7 +739,7 @@ impl<'a> State<'a> {
         self.head("enum");
         self.print_name(name);
         self.print_generic_params(&generics.params);
-        self.print_where_clause(&generics.where_clause);
+        self.print_where_clause(generics);
         self.space();
         self.print_variants(&enum_definition.variants, span)
     }
@@ -787,7 +787,7 @@ impl<'a> State<'a> {
                     });
                     self.pclose();
                 }
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
                 if print_finalizer {
                     self.word(";");
                 }
@@ -795,7 +795,7 @@ impl<'a> State<'a> {
                 self.end() // close the outer-box
             }
             hir::VariantData::Struct(..) => {
-                self.print_where_clause(&generics.where_clause);
+                self.print_where_clause(generics);
                 self.nbsp();
                 self.bopen();
                 self.hardbreak_if_not_bol();
@@ -1995,7 +1995,7 @@ impl<'a> State<'a> {
         self.pclose();
 
         self.print_fn_output(decl);
-        self.print_where_clause(&generics.where_clause)
+        self.print_where_clause(generics)
     }
 
     fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId) {
@@ -2096,21 +2096,8 @@ impl<'a> State<'a> {
         self.print_ident(param.name.ident());
 
         match param.kind {
-            GenericParamKind::Lifetime { .. } => {
-                let mut sep = ":";
-                for bound in param.bounds {
-                    match bound {
-                        GenericBound::Outlives(ref lt) => {
-                            self.word(sep);
-                            self.print_lifetime(lt);
-                            sep = "+";
-                        }
-                        _ => panic!(),
-                    }
-                }
-            }
+            GenericParamKind::Lifetime { .. } => {}
             GenericParamKind::Type { ref default, .. } => {
-                self.print_bounds(":", param.bounds);
                 if let Some(default) = default {
                     self.space();
                     self.word_space("=");
@@ -2133,15 +2120,15 @@ impl<'a> State<'a> {
         self.print_ident(lifetime.name.ident())
     }
 
-    pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause<'_>) {
-        if where_clause.predicates.is_empty() {
+    pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {
+        if generics.predicates.is_empty() {
             return;
         }
 
         self.space();
         self.word_space("where");
 
-        for (i, predicate) in where_clause.predicates.iter().enumerate() {
+        for (i, predicate) in generics.predicates.iter().enumerate() {
             if i != 0 {
                 self.word_space(",");
             }
@@ -2236,11 +2223,7 @@ impl<'a> State<'a> {
     ) {
         self.ibox(INDENT_UNIT);
         self.print_formal_generic_params(generic_params);
-        let generics = hir::Generics {
-            params: &[],
-            where_clause: hir::WhereClause { predicates: &[], span: rustc_span::DUMMY_SP },
-            span: rustc_span::DUMMY_SP,
-        };
+        let generics = hir::Generics::empty();
         self.print_fn(
             decl,
             hir::FnHeader {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 14555ad9255..2e50dbff510 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2327,6 +2327,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             _ => span,
         };
 
+        // type_param_span is (span, has_bounds)
         let type_param_span = match (generics, bound_kind) {
             (Some((_, ref generics, _)), GenericKind::Param(ref param)) => {
                 // Account for the case where `param` corresponds to `Self`,
@@ -2337,25 +2338,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         // Get the `hir::Param` to verify whether it already has any bounds.
                         // We do this to avoid suggesting code that ends up as `T: 'a'b`,
                         // instead we suggest `T: 'a + 'b` in that case.
-                        let id = hir.local_def_id_to_hir_id(def_id);
-                        let mut has_bounds = false;
-                        if let Node::GenericParam(param) = hir.get(id) {
-                            has_bounds = !param.bounds.is_empty();
-                        }
-                        let sp = self.tcx.def_span(def_id);
+                        let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                        let ast_generics = self.tcx.hir().get_generics(hir_id.owner);
+                        let bounds =
+                            ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
                         // `sp` only covers `T`, change it so that it covers
                         // `T:` when appropriate
-                        let is_impl_trait = bound_kind.to_string().starts_with("impl ");
-                        let sp = if has_bounds && !is_impl_trait {
-                            sp.to(self
-                                .tcx
-                                .sess
-                                .source_map()
-                                .next_point(self.tcx.sess.source_map().next_point(sp)))
+                        if let Some(span) = bounds {
+                            (span, true)
                         } else {
-                            sp
-                        };
-                        (sp, has_bounds, is_impl_trait)
+                            let sp = self.tcx.def_span(def_id);
+                            (sp.shrink_to_hi(), false)
+                        }
                     })
                 } else {
                     None
@@ -2411,52 +2405,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         fn binding_suggestion<'tcx, S: fmt::Display>(
             err: &mut Diagnostic,
-            type_param_span: Option<(Span, bool, bool)>,
+            type_param_span: Option<(Span, bool)>,
             bound_kind: GenericKind<'tcx>,
             sub: S,
         ) {
             let msg = "consider adding an explicit lifetime bound";
-            if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span {
-                let suggestion = if is_impl_trait {
-                    format!("{} + {}", bound_kind, sub)
-                } else {
-                    let tail = if has_lifetimes { " + " } else { "" };
-                    format!("{}: {}{}", bound_kind, sub, tail)
-                };
-                err.span_suggestion(
+            if let Some((sp, has_lifetimes)) = type_param_span {
+                let suggestion =
+                    if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
+                err.span_suggestion_verbose(
                     sp,
                     &format!("{}...", msg),
                     suggestion,
                     Applicability::MaybeIncorrect, // Issue #41966
                 );
             } else {
-                let consider = format!(
-                    "{} {}...",
-                    msg,
-                    if type_param_span.map_or(false, |(_, _, is_impl_trait)| is_impl_trait) {
-                        format!(" `{}` to `{}`", sub, bound_kind)
-                    } else {
-                        format!("`{}: {}`", bound_kind, sub)
-                    },
-                );
+                let consider = format!("{} `{}: {}`...", msg, bound_kind, sub,);
                 err.help(&consider);
             }
         }
 
         let new_binding_suggestion =
-            |err: &mut Diagnostic,
-             type_param_span: Option<(Span, bool, bool)>,
-             bound_kind: GenericKind<'tcx>| {
+            |err: &mut Diagnostic, type_param_span: Option<(Span, bool)>| {
                 let msg = "consider introducing an explicit lifetime bound";
-                if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span {
-                    let suggestion = if is_impl_trait {
-                        (sp.shrink_to_hi(), format!(" + {}", new_lt))
+                if let Some((sp, has_lifetimes)) = type_param_span {
+                    let suggestion = if has_lifetimes {
+                        format!(" + {}", new_lt)
                     } else {
-                        let tail = if has_lifetimes { " +" } else { "" };
-                        (sp, format!("{}: {}{}", bound_kind, new_lt, tail))
+                        format!(": {}", new_lt)
                     };
                     let mut sugg =
-                        vec![suggestion, (span.shrink_to_hi(), format!(" + {}", new_lt))];
+                        vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
                     if let Some(lt) = add_lt_sugg {
                         sugg.push(lt);
                         sugg.rotate_right(1);
@@ -2543,11 +2522,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 let pred = format!("{}: {}", bound_kind, sub);
                 let suggestion = format!(
                     "{} {}",
-                    if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
+                    if !generics.predicates.is_empty() { "," } else { " where" },
                     pred,
                 );
                 err.span_suggestion(
-                    generics.where_clause.tail_span_for_suggestion(),
+                    generics.tail_span_for_predicate_suggestion(),
                     "consider adding a where clause",
                     suggestion,
                     Applicability::MaybeIncorrect,
@@ -2615,7 +2594,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         // suggest:
                         // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
                         ty::Closure(_, _substs) | ty::Opaque(_, _substs) if return_impl_trait => {
-                            new_binding_suggestion(&mut err, type_param_span, bound_kind);
+                            new_binding_suggestion(&mut err, type_param_span);
                         }
                         _ => {
                             binding_suggestion(&mut err, type_param_span, bound_kind, new_lt);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index baea3e8285a..cbdcf013522 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -372,8 +372,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         .hir()
                         .get_generics(impl_item_def_id)
                         .unwrap()
-                        .where_clause
-                        .tail_span_for_suggestion();
+                        .where_clause_span
+                        .shrink_to_hi();
 
                     let suggestion = format!(
                         "{} {}",
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 68658e2616e..3564f15e210 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1199,8 +1199,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                     });
                 }
             }
-            hir::ItemKind::Impl(hir::Impl { ref generics, items, .. }) => {
-                for it in items {
+            hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
+                for it in *items {
                     if let hir::AssocItemKind::Fn { .. } = it.kind {
                         if let Some(no_mangle_attr) = cx
                             .sess()
@@ -1517,59 +1517,61 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
             // Bounds are respected for `type X = impl Trait`
             return;
         }
-        let mut suggested_changing_assoc_types = false;
         // There must not be a where clause
-        if !type_alias_generics.where_clause.predicates.is_empty() {
-            cx.lint(
-                TYPE_ALIAS_BOUNDS,
-                |lint| {
-                    let mut err = lint.build("where clauses are not enforced in type aliases");
-                    let spans: Vec<_> = type_alias_generics
-                        .where_clause
-                        .predicates
-                        .iter()
-                        .map(|pred| pred.span())
-                        .collect();
-                    err.set_span(spans);
-                    err.span_suggestion(
-                        type_alias_generics.where_clause.span_for_predicates_or_empty_place(),
-                        "the clause will not be checked when the type alias is used, and should be removed",
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
-                    if !suggested_changing_assoc_types {
-                        TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
-                        suggested_changing_assoc_types = true;
-                    }
-                    err.emit();
-                },
-            );
+        if type_alias_generics.predicates.is_empty() {
+            return;
         }
-        // The parameters must not have bounds
-        for param in type_alias_generics.params.iter() {
-            let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
-            let suggestion = spans
-                .iter()
-                .map(|sp| {
-                    let start = param.span.between(*sp); // Include the `:` in `T: Bound`.
-                    (start.to(*sp), String::new())
-                })
-                .collect();
-            if !spans.is_empty() {
-                cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans, |lint| {
-                    let mut err =
-                        lint.build("bounds on generic parameters are not enforced in type aliases");
-                    let msg = "the bound will not be checked when the type alias is used, \
-                                   and should be removed";
-                    err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);
-                    if !suggested_changing_assoc_types {
-                        TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
-                        suggested_changing_assoc_types = true;
-                    }
-                    err.emit();
-                });
+
+        let mut where_spans = Vec::new();
+        let mut inline_spans = Vec::new();
+        let mut inline_sugg = Vec::new();
+        for p in type_alias_generics.predicates {
+            let span = p.span();
+            if p.in_where_clause() {
+                where_spans.push(span);
+            } else {
+                for b in p.bounds() {
+                    inline_spans.push(b.span());
+                }
+                inline_sugg.push((span, String::new()));
             }
         }
+
+        let mut suggested_changing_assoc_types = false;
+        if !where_spans.is_empty() {
+            cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
+                let mut err = lint.build("where clauses are not enforced in type aliases");
+                err.set_span(where_spans);
+                err.span_suggestion(
+                    type_alias_generics.where_clause_span,
+                    "the clause will not be checked when the type alias is used, and should be removed",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+                if !suggested_changing_assoc_types {
+                    TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+                    suggested_changing_assoc_types = true;
+                }
+                err.emit();
+            });
+        }
+
+        if !inline_spans.is_empty() {
+            cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
+                let mut err =
+                    lint.build("bounds on generic parameters are not enforced in type aliases");
+                err.set_span(inline_spans);
+                err.multipart_suggestion(
+                    "the bound will not be checked when the type alias is used, and should be removed",
+                    inline_sugg,
+                    Applicability::MachineApplicable,
+                );
+                if !suggested_changing_assoc_types {
+                    TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+                }
+                err.emit();
+            });
+        }
     }
 }
 
@@ -2085,27 +2087,6 @@ impl ExplicitOutlivesRequirements {
             .collect()
     }
 
-    fn collect_outlived_lifetimes<'tcx>(
-        &self,
-        param: &'tcx hir::GenericParam<'tcx>,
-        tcx: TyCtxt<'tcx>,
-        inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
-        ty_generics: &'tcx ty::Generics,
-    ) -> Vec<ty::Region<'tcx>> {
-        let index =
-            ty_generics.param_def_id_to_index[&tcx.hir().local_def_id(param.hir_id).to_def_id()];
-
-        match param.kind {
-            hir::GenericParamKind::Lifetime { .. } => {
-                Self::lifetimes_outliving_lifetime(inferred_outlives, index)
-            }
-            hir::GenericParamKind::Type { .. } => {
-                Self::lifetimes_outliving_type(inferred_outlives, index)
-            }
-            hir::GenericParamKind::Const { .. } => Vec::new(),
-        }
-    }
-
     fn collect_outlives_bound_spans<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -2213,41 +2194,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
 
             let mut bound_count = 0;
             let mut lint_spans = Vec::new();
-
-            for param in hir_generics.params {
-                let has_lifetime_bounds = param
-                    .bounds
-                    .iter()
-                    .any(|bound| matches!(bound, hir::GenericBound::Outlives(_)));
-                if !has_lifetime_bounds {
-                    continue;
-                }
-
-                let relevant_lifetimes =
-                    self.collect_outlived_lifetimes(param, cx.tcx, inferred_outlives, ty_generics);
-                if relevant_lifetimes.is_empty() {
-                    continue;
-                }
-
-                let bound_spans = self.collect_outlives_bound_spans(
-                    cx.tcx,
-                    &param.bounds,
-                    &relevant_lifetimes,
-                    infer_static,
-                );
-                bound_count += bound_spans.len();
-                lint_spans.extend(self.consolidate_outlives_bound_spans(
-                    param.span.shrink_to_hi(),
-                    &param.bounds,
-                    bound_spans,
-                ));
-            }
-
             let mut where_lint_spans = Vec::new();
             let mut dropped_predicate_count = 0;
-            let num_predicates = hir_generics.where_clause.predicates.len();
-            for (i, where_predicate) in hir_generics.where_clause.predicates.iter().enumerate() {
-                let (relevant_lifetimes, bounds, span) = match where_predicate {
+            let num_predicates = hir_generics.predicates.len();
+            for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
+                let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
                     hir::WherePredicate::RegionPredicate(predicate) => {
                         if let Some(Region::EarlyBound(index, ..)) =
                             cx.tcx.named_region(predicate.lifetime.hir_id)
@@ -2256,6 +2207,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                                 Self::lifetimes_outliving_lifetime(inferred_outlives, index),
                                 &predicate.bounds,
                                 predicate.span,
+                                predicate.in_where_clause,
                             )
                         } else {
                             continue;
@@ -2274,6 +2226,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                                     Self::lifetimes_outliving_type(inferred_outlives, index),
                                     &predicate.bounds,
                                     predicate.span,
+                                    predicate.in_where_clause,
                                 )
                             }
                             _ => {
@@ -2300,10 +2253,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                     dropped_predicate_count += 1;
                 }
 
-                // If all the bounds on a predicate were inferable and there are
-                // further predicates, we want to eat the trailing comma.
-                if drop_predicate && i + 1 < num_predicates {
-                    let next_predicate_span = hir_generics.where_clause.predicates[i + 1].span();
+                if drop_predicate && !in_where_clause {
+                    lint_spans.push(span);
+                } else if drop_predicate && i + 1 < num_predicates {
+                    // If all the bounds on a predicate were inferable and there are
+                    // further predicates, we want to eat the trailing comma.
+                    let next_predicate_span = hir_generics.predicates[i + 1].span();
                     where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
                 } else {
                     where_lint_spans.extend(self.consolidate_outlives_bound_spans(
@@ -2316,10 +2271,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
 
             // If all predicates are inferable, drop the entire clause
             // (including the `where`)
-            if num_predicates > 0 && dropped_predicate_count == num_predicates {
+            if hir_generics.has_where_clause && dropped_predicate_count == num_predicates {
                 let where_span = hir_generics
-                    .where_clause
-                    .span()
+                    .where_clause_span()
                     .expect("span of (nonempty) where clause should exist");
                 // Extend the where clause back to the closing `>` of the
                 // generics, except for tuple struct, which have the `where`
@@ -2346,7 +2300,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
                             },
                             lint_spans
                                 .into_iter()
-                                .map(|span| (span, "".to_owned()))
+                                .map(|span| (span, String::new()))
                                 .collect::<Vec<_>>(),
                             Applicability::MachineApplicable,
                         )
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index ed49eebd16d..b46ea955a3a 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1462,8 +1462,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 }))
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
-                self.tables.impl_defaultness.set(def_id.index, defaultness);
-                self.tables.impl_constness.set(def_id.index, constness);
+                self.tables.impl_defaultness.set(def_id.index, *defaultness);
+                self.tables.impl_constness.set(def_id.index, *constness);
 
                 let trait_ref = self.tcx.impl_trait_ref(def_id);
                 if let Some(trait_ref) = trait_ref {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 8c8a2650fd6..f53dc0000ca 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
+use rustc_hir::WherePredicate;
 use rustc_span::Span;
 
 impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
@@ -156,13 +156,13 @@ pub fn suggest_arbitrary_trait_bound(
         _ => {}
     }
     // Suggest a where clause bound for a non-type parameter.
-    let (action, prefix) = if generics.where_clause.predicates.is_empty() {
-        ("introducing a", " where ")
-    } else {
+    let (action, prefix) = if generics.has_where_clause {
         ("extending the", ", ")
+    } else {
+        ("introducing a", " where ")
     };
     err.span_suggestion_verbose(
-        generics.where_clause.tail_span_for_suggestion(),
+        generics.tail_span_for_predicate_suggestion(),
         &format!(
             "consider {} `where` bound, but there might be an alternative better way to express \
              this requirement",
@@ -183,104 +183,37 @@ enum SuggestChangingConstraintsMessage<'a> {
 }
 
 fn suggest_removing_unsized_bound(
+    tcx: TyCtxt<'_>,
     generics: &hir::Generics<'_>,
     suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>,
-    param_name: &str,
     param: &hir::GenericParam<'_>,
     def_id: Option<DefId>,
 ) {
     // See if there's a `?Sized` bound that can be removed to suggest that.
     // First look at the `where` clause because we can have `where T: ?Sized`,
     // then look at params.
-    for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() {
-        match predicate {
-            WherePredicate::BoundPredicate(WhereBoundPredicate {
-                bounded_ty:
-                    hir::Ty {
-                        kind:
-                            hir::TyKind::Path(hir::QPath::Resolved(
-                                None,
-                                hir::Path {
-                                    segments: [segment],
-                                    res: hir::def::Res::Def(hir::def::DefKind::TyParam, _),
-                                    ..
-                                },
-                            )),
-                        ..
-                    },
-                bounds,
-                span,
-                ..
-            }) if segment.ident.as_str() == param_name => {
-                for (pos, bound) in bounds.iter().enumerate() {
-                    match bound {
-                        hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
-                            if poly.trait_ref.trait_def_id() == def_id => {}
-                        _ => continue,
-                    }
-                    let sp = match (
-                        bounds.len(),
-                        pos,
-                        generics.where_clause.predicates.len(),
-                        where_pos,
-                    ) {
-                        // where T: ?Sized
-                        // ^^^^^^^^^^^^^^^
-                        (1, _, 1, _) => generics.where_clause.span,
-                        // where Foo: Bar, T: ?Sized,
-                        //               ^^^^^^^^^^^
-                        (1, _, len, pos) if pos == len - 1 => generics.where_clause.predicates
-                            [pos - 1]
-                            .span()
-                            .shrink_to_hi()
-                            .to(*span),
-                        // where T: ?Sized, Foo: Bar,
-                        //       ^^^^^^^^^^^
-                        (1, _, _, pos) => {
-                            span.until(generics.where_clause.predicates[pos + 1].span())
-                        }
-                        // where T: ?Sized + Bar, Foo: Bar,
-                        //          ^^^^^^^^^
-                        (_, 0, _, _) => bound.span().to(bounds[1].span().shrink_to_lo()),
-                        // where T: Bar + ?Sized, Foo: Bar,
-                        //             ^^^^^^^^^
-                        (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
-                    };
+    let param_def_id = tcx.hir().local_def_id(param.hir_id);
+    for (where_pos, predicate) in generics.predicates.iter().enumerate() {
+        let WherePredicate::BoundPredicate(predicate) = predicate else {
+            continue;
+        };
+        if !predicate.is_param_bound(param_def_id.to_def_id()) {
+            continue;
+        };
 
-                    suggestions.push((
-                        sp,
-                        String::new(),
-                        SuggestChangingConstraintsMessage::RemovingQSized,
-                    ));
-                }
+        for (pos, bound) in predicate.bounds.iter().enumerate() {
+            let    hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else {
+                continue;
+            };
+            if poly.trait_ref.trait_def_id() != def_id {
+                continue;
             }
-            _ => {}
-        }
-    }
-    for (pos, bound) in param.bounds.iter().enumerate() {
-        match bound {
-            hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
-                if poly.trait_ref.trait_def_id() == def_id =>
-            {
-                let sp = match (param.bounds.len(), pos) {
-                    // T: ?Sized,
-                    //  ^^^^^^^^
-                    (1, _) => param.span.shrink_to_hi().to(bound.span()),
-                    // T: ?Sized + Bar,
-                    //    ^^^^^^^^^
-                    (_, 0) => bound.span().to(param.bounds[1].span().shrink_to_lo()),
-                    // T: Bar + ?Sized,
-                    //       ^^^^^^^^^
-                    (_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
-                };
-
-                suggestions.push((
-                    sp,
-                    String::new(),
-                    SuggestChangingConstraintsMessage::RemovingQSized,
-                ));
-            }
-            _ => {}
+            let sp = generics.span_for_bound_removal(where_pos, pos);
+            suggestions.push((
+                sp,
+                String::new(),
+                SuggestChangingConstraintsMessage::RemovingQSized,
+            ));
         }
     }
 }
@@ -331,13 +264,7 @@ pub fn suggest_constraining_type_params<'a>(
                     param.span,
                     &format!("this type parameter needs to be `{}`", constraint),
                 );
-                suggest_removing_unsized_bound(
-                    generics,
-                    &mut suggestions,
-                    param_name,
-                    param,
-                    def_id,
-                );
+                suggest_removing_unsized_bound(tcx, generics, &mut suggestions, param, def_id);
             }
         }
 
@@ -358,76 +285,45 @@ pub fn suggest_constraining_type_params<'a>(
             ))
         };
 
-        if param_name.starts_with("impl ") {
-            // If there's an `impl Trait` used in argument position, suggest
-            // restricting it:
-            //
-            //   fn foo(t: impl Foo) { ... }
-            //             --------
-            //             |
-            //             help: consider further restricting this bound with `+ Bar`
-            //
-            // Suggestion for tools in this case is:
-            //
-            //   fn foo(t: impl Foo) { ... }
-            //             --------
-            //             |
-            //             replace with: `impl Foo + Bar`
-
-            // `impl Trait` must have at least one trait in the list
-            let bound_list_non_empty = true;
-
-            suggest_restrict(param.span.shrink_to_hi(), bound_list_non_empty);
+        // When the type parameter has been provided bounds
+        //
+        //    Message:
+        //      fn foo<T>(t: T) where T: Foo { ... }
+        //                            ^^^^^^
+        //                            |
+        //                            help: consider further restricting this bound with `+ Bar`
+        //
+        //    Suggestion:
+        //      fn foo<T>(t: T) where T: Foo { ... }
+        //                                  ^
+        //                                  |
+        //                                  replace with: ` + Bar`
+        //
+        // Or, if user has provided some bounds, suggest restricting them:
+        //
+        //   fn foo<T: Foo>(t: T) { ... }
+        //             ---
+        //             |
+        //             help: consider further restricting this bound with `+ Bar`
+        //
+        // Suggestion for tools in this case is:
+        //
+        //   fn foo<T: Foo>(t: T) { ... }
+        //          --
+        //          |
+        //          replace with: `T: Bar +`
+        let param_def_id = tcx.hir().local_def_id(param.hir_id);
+        if let Some(span) = generics.bounds_span_for_suggestions(param_def_id) {
+            suggest_restrict(span, true);
             continue;
         }
 
-        if generics.where_clause.predicates.is_empty()
-        // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
-        // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
-        && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
-        {
-            if let Some(span) = param.bounds_span_for_suggestions() {
-                // If user has provided some bounds, suggest restricting them:
-                //
-                //   fn foo<T: Foo>(t: T) { ... }
-                //             ---
-                //             |
-                //             help: consider further restricting this bound with `+ Bar`
-                //
-                // Suggestion for tools in this case is:
-                //
-                //   fn foo<T: Foo>(t: T) { ... }
-                //          --
-                //          |
-                //          replace with: `T: Bar +`
-
-                // `bounds_span_for_suggestions` returns `None` if the list is empty
-                let bound_list_non_empty = true;
-
-                suggest_restrict(span, bound_list_non_empty);
-            } else {
-                let (colon, span) = match param.colon_span_for_suggestions(tcx.sess.source_map()) {
-                    // If there is already a colon after generic, do not suggest adding it again
-                    Some(sp) => ("", sp.shrink_to_hi()),
-                    None => (":", param.span.shrink_to_hi()),
-                };
-
-                // If user hasn't provided any bounds, suggest adding a new one:
-                //
-                //   fn foo<T>(t: T) { ... }
-                //          - help: consider restricting this type parameter with `T: Foo`
-                suggestions.push((
-                    span,
-                    format!("{colon} {constraint}"),
-                    SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
-                ));
-            }
-        } else {
+        if generics.has_where_clause {
             // This part is a bit tricky, because using the `where` clause user can
             // provide zero, one or many bounds for the same type parameter, so we
             // have following cases to consider:
             //
-            // 1) When the type parameter has been provided zero bounds
+            // When the type parameter has been provided zero bounds
             //
             //    Message:
             //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
@@ -436,95 +332,59 @@ pub fn suggest_constraining_type_params<'a>(
             //    Suggestion:
             //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
             //                                           - insert: `, X: Bar`
-            //
-            //
-            // 2) When the type parameter has been provided one bound
-            //
-            //    Message:
-            //      fn foo<T>(t: T) where T: Foo { ... }
-            //                            ^^^^^^
-            //                            |
-            //                            help: consider further restricting this bound with `+ Bar`
-            //
-            //    Suggestion:
-            //      fn foo<T>(t: T) where T: Foo { ... }
-            //                            ^^
-            //                            |
-            //                            replace with: `T: Bar +`
-            //
-            //
-            // 3) When the type parameter has been provided many bounds
-            //
-            //    Message:
-            //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
-            //             - help: consider further restricting this type parameter with `where T: Zar`
-            //
-            //    Suggestion:
-            //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
-            //                                          - insert: `, T: Zar`
-            //
-            // Additionally, there may be no `where` clause whatsoever in the case that this was
-            // reached because the generic parameter has a default:
-            //
-            //    Message:
-            //      trait Foo<T=()> {... }
-            //             - help: consider further restricting this type parameter with `where T: Zar`
-            //
-            //    Suggestion:
-            //      trait Foo<T=()> where T: Zar {... }
-            //                     - insert: `where T: Zar`
-
-            if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
-                && generics.where_clause.predicates.len() == 0
-            {
-                // Suggest a bound, but there is no existing `where` clause *and* the type param has a
-                // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
-                suggestions.push((
-                    generics.where_clause.tail_span_for_suggestion(),
-                    format!(" where {}: {}", param_name, constraint),
-                    SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
-                ));
-            } else {
-                let mut param_spans = Vec::new();
-                let mut non_empty = false;
-
-                for predicate in generics.where_clause.predicates {
-                    if let WherePredicate::BoundPredicate(WhereBoundPredicate {
-                        span,
-                        bounded_ty,
-                        bounds,
-                        ..
-                    }) = predicate
-                    {
-                        if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
-                            if let Some(segment) = path.segments.first() {
-                                if segment.ident.to_string() == param_name {
-                                    non_empty = !bounds.is_empty();
-
-                                    param_spans.push(span);
-                                }
-                            }
-                        }
-                    }
-                }
+            suggestions.push((
+                generics.tail_span_for_predicate_suggestion(),
+                constraints
+                    .iter()
+                    .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
+                    .collect::<String>(),
+                SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
+            ));
+            continue;
+        }
 
-                match param_spans[..] {
-                    [&param_span] => suggest_restrict(param_span.shrink_to_hi(), non_empty),
-                    _ => {
-                        suggestions.push((
-                            generics.where_clause.tail_span_for_suggestion(),
-                            constraints
-                                .iter()
-                                .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
-                                .collect::<String>(),
-                            SuggestChangingConstraintsMessage::RestrictTypeFurther {
-                                ty: param_name,
-                            },
-                        ));
-                    }
-                }
-            }
+        // Additionally, there may be no `where` clause but the generic parameter has a default:
+        //
+        //    Message:
+        //      trait Foo<T=()> {... }
+        //                - help: consider further restricting this type parameter with `where T: Zar`
+        //
+        //    Suggestion:
+        //      trait Foo<T=()> {... }
+        //                     - insert: `where T: Zar`
+        if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) {
+            // Suggest a bound, but there is no existing `where` clause *and* the type param has a
+            // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
+            suggestions.push((
+                generics.tail_span_for_predicate_suggestion(),
+                format!(" where {}: {}", param_name, constraint),
+                SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
+            ));
+            continue;
         }
+
+        // If user has provided a colon, don't suggest adding another:
+        //
+        //   fn foo<T:>(t: T) { ... }
+        //            - insert: consider restricting this type parameter with `T: Foo`
+        if let Some(colon_span) = param.colon_span {
+            suggestions.push((
+                colon_span.shrink_to_hi(),
+                format!(" {}", constraint),
+                SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
+            ));
+            continue;
+        }
+
+        // If user hasn't provided any bounds, suggest adding a new one:
+        //
+        //   fn foo<T>(t: T) { ... }
+        //          - help: consider restricting this type parameter with `T: Foo`
+        suggestions.push((
+            param.span.shrink_to_hi(),
+            format!(": {}", constraint),
+            SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
+        ));
     }
 
     if suggestions.len() == 1 {
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 07878defa8c..da0934b67c5 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -602,53 +602,24 @@ impl<T> Trait<T> for X {
                 } else {
                     return false;
                 };
+                let Some(def_id) = def_id.as_local() else {
+                    return false;
+                };
 
                 // First look in the `where` clause, as this might be
                 // `fn foo<T>(x: T) where T: Trait`.
-                for predicate in hir_generics.where_clause.predicates {
-                    if let hir::WherePredicate::BoundPredicate(pred) = predicate {
-                        if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) =
-                            pred.bounded_ty.kind
-                        {
-                            if path.res.opt_def_id() == Some(def_id) {
-                                // This predicate is binding type param `A` in `<A as T>::Foo` to
-                                // something, potentially `T`.
-                            } else {
-                                continue;
-                            }
-                        } else {
-                            continue;
-                        }
-
-                        if self.constrain_generic_bound_associated_type_structured_suggestion(
-                            diag,
-                            &trait_ref,
-                            pred.bounds,
-                            &assoc,
-                            assoc_substs,
-                            ty,
-                            msg,
-                            false,
-                        ) {
-                            return true;
-                        }
-                    }
-                }
-                for param in hir_generics.params {
-                    if self.hir().opt_local_def_id(param.hir_id).map(|id| id.to_def_id())
-                        == Some(def_id)
-                    {
-                        // This is type param `A` in `<A as T>::Foo`.
-                        return self.constrain_generic_bound_associated_type_structured_suggestion(
-                            diag,
-                            &trait_ref,
-                            param.bounds,
-                            &assoc,
-                            assoc_substs,
-                            ty,
-                            msg,
-                            false,
-                        );
+                for pred in hir_generics.bounds_for_param(def_id) {
+                    if self.constrain_generic_bound_associated_type_structured_suggestion(
+                        diag,
+                        &trait_ref,
+                        pred.bounds,
+                        &assoc,
+                        assoc_substs,
+                        ty,
+                        msg,
+                        false,
+                    ) {
+                        return true;
                     }
                 }
             }
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 29fe2b76101..8081bac7cfd 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -30,8 +30,10 @@ impl<'a> Parser<'a> {
         let ident = self.parse_ident()?;
 
         // Parse optional colon and param bounds.
+        let mut colon_span = None;
         let bounds = if self.eat(&token::Colon) {
-            self.parse_generic_bounds(Some(self.prev_token.span))?
+            colon_span = Some(self.prev_token.span);
+            self.parse_generic_bounds(colon_span)?
         } else {
             Vec::new()
         };
@@ -45,6 +47,7 @@ impl<'a> Parser<'a> {
             bounds,
             kind: GenericParamKind::Type { default },
             is_placeholder: false,
+            colon_span,
         })
     }
 
@@ -69,6 +72,7 @@ impl<'a> Parser<'a> {
             bounds: Vec::new(),
             kind: GenericParamKind::Const { ty, kw_span: const_span, default },
             is_placeholder: false,
+            colon_span: None,
         })
     }
 
@@ -97,10 +101,10 @@ impl<'a> Parser<'a> {
                     let param = if this.check_lifetime() {
                         let lifetime = this.expect_lifetime();
                         // Parse lifetime parameter.
-                        let bounds = if this.eat(&token::Colon) {
-                            this.parse_lt_param_bounds()
+                        let (colon_span, bounds) = if this.eat(&token::Colon) {
+                            (Some(this.prev_token.span), this.parse_lt_param_bounds())
                         } else {
-                            Vec::new()
+                            (None, Vec::new())
                         };
                         Some(ast::GenericParam {
                             ident: lifetime.ident,
@@ -109,6 +113,7 @@ impl<'a> Parser<'a> {
                             bounds,
                             kind: ast::GenericParamKind::Lifetime,
                             is_placeholder: false,
+                            colon_span,
                         })
                     } else if this.check_keyword(kw::Const) {
                         // Parse const parameter.
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index b661f6f9d72..3cd18390285 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -512,7 +512,7 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> {
                 if of_trait.is_some() {
                     self.worklist.push(item.def_id);
                 }
-                for impl_item_ref in items {
+                for impl_item_ref in *items {
                     let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                     if of_trait.is_some()
                         || has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id())
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 35a858cb86c..10dc587be6e 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -737,7 +737,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     }
                 }
 
-                for impl_item_ref in items {
+                for impl_item_ref in *items {
                     let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
 
                     if let Some(def_id) = impl_item.trait_item_def_id {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 5f9a0357557..619e0d0341f 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1585,12 +1585,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     }
 
     fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
-        for param in generics.params {
-            for bound in param.bounds {
-                self.check_generic_bound(bound);
-            }
-        }
-        for predicate in generics.where_clause.predicates {
+        for predicate in generics.predicates {
             match predicate {
                 hir::WherePredicate::BoundPredicate(bound_pred) => {
                     for bound in bound_pred.bounds.iter() {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 894ff0f17f8..a5243bf8ac3 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -86,7 +86,7 @@ impl ForLifetimeSpanType {
     }
 }
 
-impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> {
+impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &&'tcx hir::Generics<'tcx> {
     fn into(self) -> MissingLifetimeSpot<'tcx> {
         MissingLifetimeSpot::Generics(self)
     }
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 35a40a0a321..787536d2a38 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -1328,13 +1328,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 match param.kind {
                     GenericParamKind::Lifetime { .. } => {}
                     GenericParamKind::Type { ref default, .. } => {
-                        walk_list!(this, visit_param_bound, param.bounds);
                         if let Some(ref ty) = default {
                             this.visit_ty(&ty);
                         }
                     }
                     GenericParamKind::Const { ref ty, default } => {
-                        walk_list!(this, visit_param_bound, param.bounds);
                         this.visit_ty(&ty);
                         if let Some(default) = default {
                             this.visit_body(this.tcx.hir().body(default.body));
@@ -1342,7 +1340,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     }
                 }
             }
-            for predicate in generics.where_clause.predicates {
+            for predicate in generics.predicates {
                 match predicate {
                     &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                         ref bounded_ty,
@@ -1393,6 +1391,32 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     }) => {
                         this.visit_lifetime(lifetime);
                         walk_list!(this, visit_param_bound, bounds);
+
+                        if lifetime.name != hir::LifetimeName::Static {
+                            for bound in bounds {
+                                let hir::GenericBound::Outlives(ref lt) = bound else {
+                                    continue;
+                                };
+                                if lt.name != hir::LifetimeName::Static {
+                                    continue;
+                                }
+                                this.insert_lifetime(lt, Region::Static);
+                                this.tcx
+                                    .sess
+                                    .struct_span_warn(
+                                        lifetime.span,
+                                        &format!(
+                                            "unnecessary lifetime parameter `{}`",
+                                            lifetime.name.ident(),
+                                        ),
+                                    )
+                                    .help(&format!(
+                                        "you can use the `'static` lifetime directly, in place of `{}`",
+                                        lifetime.name.ident(),
+                                    ))
+                                    .emit();
+                            }
+                        }
                     }
                     &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                         ref lhs_ty,
@@ -1714,10 +1738,8 @@ fn object_lifetime_defaults_for_item<'tcx>(
         GenericParamKind::Type { .. } => {
             let mut set = Set1::Empty;
 
-            add_bounds(&mut set, &param.bounds);
-
             let param_def_id = tcx.hir().local_def_id(param.hir_id);
-            for predicate in generics.where_clause.predicates {
+            for predicate in generics.predicates {
                 // Look for `type: ...` where clauses.
                 let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue };
 
@@ -3124,50 +3146,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
             // It is a soft error to shadow a lifetime within a parent scope.
             self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i);
-
-            for bound in lifetime_i.bounds {
-                match bound {
-                    hir::GenericBound::Outlives(ref lt) => match lt.name {
-                        hir::LifetimeName::Underscore => {
-                            self.tcx.sess.delay_span_bug(
-                                lt.span,
-                                "use of `'_` in illegal place, but not caught by lowering",
-                            );
-                        }
-                        hir::LifetimeName::Static => {
-                            self.insert_lifetime(lt, Region::Static);
-                            self.tcx
-                                .sess
-                                .struct_span_warn(
-                                    lifetime_i.span.to(lt.span),
-                                    &format!(
-                                        "unnecessary lifetime parameter `{}`",
-                                        lifetime_i.name.ident(),
-                                    ),
-                                )
-                                .help(&format!(
-                                    "you can use the `'static` lifetime directly, in place of `{}`",
-                                    lifetime_i.name.ident(),
-                                ))
-                                .emit();
-                        }
-                        hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
-                            self.resolve_lifetime_ref(lt);
-                        }
-                        hir::LifetimeName::ImplicitObjectLifetimeDefault => {
-                            self.tcx.sess.delay_span_bug(
-                                lt.span,
-                                "lowering generated `ImplicitObjectLifetimeDefault` \
-                                 outside of an object type",
-                            );
-                        }
-                        hir::LifetimeName::Error => {
-                            // No need to do anything, error already reported.
-                        }
-                    },
-                    _ => bug!(),
-                }
-            }
         }
     }
 
@@ -3326,18 +3304,6 @@ fn insert_late_bound_lifetimes(
     // ignore binders here and scrape up all names we see.
     let mut appears_in_where_clause = AllCollector::default();
     appears_in_where_clause.visit_generics(generics);
-
-    for param in generics.params {
-        if let hir::GenericParamKind::Lifetime { .. } = param.kind {
-            if !param.bounds.is_empty() {
-                // `'a: 'b` means both `'a` and `'b` are referenced
-                appears_in_where_clause
-                    .regions
-                    .insert(hir::LifetimeName::Param(param.name.normalize_to_macros_2_0()));
-            }
-        }
-    }
-
     debug!(?appears_in_where_clause.regions);
 
     // Late bound regions are those that:
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 6681ea9d299..b4230a144f8 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -1267,13 +1267,11 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
             match param.kind {
                 hir::GenericParamKind::Lifetime { .. } => {}
                 hir::GenericParamKind::Type { ref default, .. } => {
-                    self.process_bounds(param.bounds);
                     if let Some(ref ty) = default {
                         self.visit_ty(ty);
                     }
                 }
                 hir::GenericParamKind::Const { ref ty, ref default } => {
-                    self.process_bounds(param.bounds);
                     self.visit_ty(ty);
                     if let Some(default) = default {
                         self.visit_anon_const(default);
@@ -1281,7 +1279,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 }
             }
         }
-        for pred in generics.where_clause.predicates {
+        for pred in generics.predicates {
             if let hir::WherePredicate::BoundPredicate(ref wbp) = *pred {
                 self.process_bounds(wbp.bounds);
                 self.visit_ty(wbp.bounded_ty);
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index 8f50f445719..d1286c9b8b0 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -630,31 +630,6 @@ impl<'hir> Sig for hir::Generics<'hir> {
                     param_text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id));
                 }
             }
-            if !param.bounds.is_empty() {
-                param_text.push_str(": ");
-                match param.kind {
-                    hir::GenericParamKind::Lifetime { .. } => {
-                        let bounds = param
-                            .bounds
-                            .iter()
-                            .map(|bound| match bound {
-                                hir::GenericBound::Outlives(lt) => lt.name.ident().to_string(),
-                                _ => panic!(),
-                            })
-                            .collect::<Vec<_>>()
-                            .join(" + ");
-                        param_text.push_str(&bounds);
-                        // FIXME add lifetime bounds refs.
-                    }
-                    hir::GenericParamKind::Type { .. } => {
-                        param_text.push_str(&bounds_to_string(param.bounds));
-                        // FIXME descend properly into bounds.
-                    }
-                    hir::GenericParamKind::Const { .. } => {
-                        // Const generics cannot contain bounds.
-                    }
-                }
-            }
             text.push_str(&param_text);
             text.push(',');
         }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 082402a38e3..7a3579eb1cc 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2419,26 +2419,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
         };
         let sized_trait = self.tcx.lang_items().sized_trait();
         debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params);
-        debug!("maybe_suggest_unsized_generics: generics.where_clause={:?}", generics.where_clause);
-        let param = generics.params.iter().filter(|param| param.span == span).find(|param| {
-            // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
-            // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
-            param
-                .bounds
-                .iter()
-                .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait)
-        });
-        let Some(param) = param else {
+        debug!("maybe_suggest_unsized_generics: generics.predicates={:?}", generics.predicates);
+        let Some(param) = generics.params.iter().find(|param| param.span == span) else {
             return;
         };
-        let param_def_id = self.tcx.hir().local_def_id(param.hir_id).to_def_id();
-        let preds = generics.where_clause.predicates.iter();
-        let explicitly_sized = preds
-            .filter_map(|pred| match pred {
-                hir::WherePredicate::BoundPredicate(bp) => Some(bp),
-                _ => None,
-            })
-            .filter(|bp| bp.is_param_bound(param_def_id))
+        let param_def_id = self.tcx.hir().local_def_id(param.hir_id);
+        // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
+        // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
+        let explicitly_sized = generics
+            .bounds_for_param(param_def_id)
             .flat_map(|bp| bp.bounds)
             .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
         if explicitly_sized {
@@ -2461,9 +2450,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
             _ => {}
         };
         // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
-        let (span, separator) = match param.bounds {
-            [] => (span.shrink_to_hi(), ":"),
-            [.., bound] => (bound.span().shrink_to_hi(), " +"),
+        let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param_def_id)
+        {
+            (s, " +")
+        } else {
+            (span.shrink_to_hi(), ":")
         };
         err.span_suggestion_verbose(
             span,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 187df6f7de0..446b14a17ae 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -319,12 +319,8 @@ pub trait InferCtxtExt<'tcx> {
 
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
     (
-        generics.where_clause.tail_span_for_suggestion(),
-        format!(
-            "{} {}",
-            if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
-            pred,
-        ),
+        generics.tail_span_for_predicate_suggestion(),
+        format!("{} {}", if generics.has_where_clause { "," } else { " where" }, pred,),
     )
 }
 
@@ -346,7 +342,7 @@ fn suggest_restriction<'tcx>(
     //              -  ^^^^^^^^^ GenericBounds
     //              |
     //              &Ident
-    let span = generics.where_clause.span_for_predicates_or_empty_place();
+    let span = generics.span_for_predicates_or_empty_place();
     if span.from_expansion() || span.desugaring_kind().is_some() {
         return;
     }
@@ -396,21 +392,10 @@ fn suggest_restriction<'tcx>(
         let pred = trait_pred.to_predicate(tcx).to_string();
         let pred = pred.replace(&impl_trait_str, &type_param_name);
         let mut sugg = vec![
-            // Find the last of the generic parameters contained within the span of
-            // the generics
-            match generics
-                .params
-                .iter()
-                .map(|p| p.bounds_span_for_suggestions().unwrap_or(p.span.shrink_to_hi()))
-                .filter(|&span| generics.span.contains(span) && span.can_be_used_for_suggestions())
-                .max_by_key(|span| span.hi())
-            {
-                // `fn foo(t: impl Trait)`
-                //        ^ suggest `<T: Trait>` here
-                None => (generics.span, format!("<{}>", type_param)),
-                // `fn foo<A>(t: impl Trait)`
-                //        ^^^ suggest `<A, T: Trait>` here
-                Some(span) => (span, format!(", {}", type_param)),
+            if let Some(span) = generics.span_for_param_suggestion() {
+                (span, format!(", {}", type_param))
+            } else {
+                (generics.span, format!("<{}>", type_param))
             },
             // `fn foo(t: impl Trait)`
             //                       ^ suggest `where <T as Trait>::A: Bound`
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 84958136cac..b39310d1294 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -221,7 +221,6 @@ fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]>
                 ..
             }) => Some(
                 generics
-                    .where_clause
                     .predicates
                     .iter()
                     .filter_map(|pred| {
@@ -399,8 +398,8 @@ fn virtual_call_violation_for_method<'tcx>(
         // We'll attempt to provide a structured suggestion for `Self: Sized`.
         let sugg =
             tcx.hir().get_if_local(method.def_id).as_ref().and_then(|node| node.generics()).map(
-                |generics| match generics.where_clause.predicates {
-                    [] => (" where Self: Sized", generics.where_clause.span),
+                |generics| match generics.predicates {
+                    [] => (" where Self: Sized", generics.where_clause_span),
                     [.., pred] => (", Self: Sized", pred.span().shrink_to_hi()),
                 },
             );
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 3e36ffa7fe0..b8422ce3208 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -924,14 +924,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let self_ty_def_id = tcx.hir().local_def_id(self_ty).to_def_id();
             for clause in where_clause {
                 if let hir::WherePredicate::BoundPredicate(pred) = clause {
-                    match pred.bounded_ty.kind {
-                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => match path.res {
-                            Res::Def(DefKind::TyParam, def_id) if def_id == self_ty_def_id => {}
-                            _ => continue,
-                        },
-                        _ => continue,
+                    if pred.is_param_bound(self_ty_def_id) {
+                        search_bounds(pred.bounds);
                     }
-                    search_bounds(pred.bounds);
                 }
             }
         }
@@ -2389,7 +2384,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     bf.unsafety,
                     bf.abi,
                     bf.decl,
-                    &hir::Generics::empty(),
                     None,
                     Some(ast_ty),
                 ))
@@ -2551,8 +2545,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         unsafety: hir::Unsafety,
         abi: abi::Abi,
         decl: &hir::FnDecl<'_>,
-        generics: &hir::Generics<'_>,
-        ident_span: Option<Span>,
+        generics: Option<&hir::Generics<'_>>,
         hir_ty: Option<&hir::Ty<'_>>,
     ) -> ty::PolyFnSig<'tcx> {
         debug!("ty_of_fn");
@@ -2565,7 +2558,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let mut visitor = HirPlaceholderCollector::default();
         let mut infer_replacements = vec![];
 
-        walk_generics(&mut visitor, generics);
+        if let Some(generics) = generics {
+            walk_generics(&mut visitor, generics);
+        }
 
         let input_tys: Vec<_> = decl
             .inputs
@@ -2617,8 +2612,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
             let mut diag = crate::collect::placeholder_type_error_diag(
                 tcx,
-                ident_span.map(|sp| sp.shrink_to_hi()),
-                generics.params,
+                generics,
                 visitor.0,
                 infer_replacements.iter().map(|(s, _)| *s).collect(),
                 true,
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 4ab6f2cdafb..6d78a863d54 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -804,7 +804,8 @@ fn compare_synthetic_generics<'tcx>(
         iter::zip(impl_m_type_params, trait_m_type_params)
     {
         if impl_synthetic != trait_synthetic {
-            let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id.expect_local());
+            let impl_def_id = impl_def_id.expect_local();
+            let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id);
             let impl_span = tcx.hir().span(impl_hir_id);
             let trait_span = tcx.def_span(trait_def_id);
             let mut err = struct_span_err!(
@@ -868,14 +869,14 @@ fn compare_synthetic_generics<'tcx>(
                             hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
                             _ => unreachable!(),
                         };
-                        struct Visitor(Option<Span>, hir::def_id::DefId);
+                        struct Visitor(Option<Span>, hir::def_id::LocalDefId);
                         impl<'v> intravisit::Visitor<'v> for Visitor {
                             fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                                 intravisit::walk_ty(self, ty);
                                 if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
                                     ty.kind
                                     && let Res::Def(DefKind::TyParam, def_id) = path.res
-                                    && def_id == self.1
+                                    && def_id == self.1.to_def_id()
                                 {
                                     self.0 = Some(ty.span);
                                 }
@@ -887,17 +888,7 @@ fn compare_synthetic_generics<'tcx>(
                         }
                         let span = visitor.0?;
 
-                        let bounds =
-                            impl_m.generics.params.iter().find_map(|param| match param.kind {
-                                GenericParamKind::Lifetime { .. } => None,
-                                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                                    if param.hir_id == impl_hir_id {
-                                        Some(&param.bounds)
-                                    } else {
-                                        None
-                                    }
-                                }
-                            })?;
+                        let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
                         let bounds = bounds.first()?.span().to(bounds.last()?.span());
                         let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
 
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index a92c288cac9..681d1e37f86 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -599,17 +599,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             kind:
                 hir::ItemKind::Fn(
                     hir::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }, .. },
-                    hir::Generics { params, where_clause, .. },
+                    hir::Generics { params, predicates, .. },
                     _body_id,
                 ),
             ..
         })) = fn_node else { return };
 
-        let Some(expected_generic_param) = params.get(expected_ty_as_param.index as usize) else { return };
+        if params.get(expected_ty_as_param.index as usize).is_none() {
+            return;
+        };
 
         // get all where BoundPredicates here, because they are used in to cases below
-        let where_predicates = where_clause
-            .predicates
+        let where_predicates = predicates
             .iter()
             .filter_map(|p| match p {
                 WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
@@ -640,10 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             where_predicates.iter().flatten().flat_map(|bounds| bounds.iter());
 
         // extract all bounds from the source code using their spans
-        let all_matching_bounds_strs = expected_generic_param
-            .bounds
-            .iter()
-            .chain(predicates_from_where)
+        let all_matching_bounds_strs = predicates_from_where
             .filter_map(|bound| match bound {
                 GenericBound::Trait(_, _) => {
                     self.tcx.sess.source_map().span_to_snippet(bound.span()).ok()
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 80c31355fe7..640dccf66b0 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -533,12 +533,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 };
                                 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
                                     if let Some(g) = kind.generics() {
-                                        let key = match g.where_clause.predicates {
+                                        let key = match g.predicates {
                                             [.., pred] => (pred.span().shrink_to_hi(), false),
-                                            [] => (
-                                                g.where_clause.span_for_predicates_or_empty_place(),
-                                                true,
-                                            ),
+                                            [] => (g.span_for_predicates_or_empty_place(), true),
                                         };
                                         type_params
                                             .entry(key)
@@ -1871,37 +1868,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // instead we suggest `T: Foo + Bar` in that case.
                     match hir.get(id) {
                         Node::GenericParam(param) => {
-                            let mut impl_trait = false;
-                            let has_bounds =
-                                if let hir::GenericParamKind::Type { synthetic: true, .. } =
-                                    &param.kind
-                                {
-                                    // We've found `fn foo(x: impl Trait)` instead of
-                                    // `fn foo<T>(x: T)`. We want to suggest the correct
-                                    // `fn foo(x: impl Trait + TraitBound)` instead of
-                                    // `fn foo<T: TraitBound>(x: T)`. (#63706)
-                                    impl_trait = true;
-                                    param.bounds.get(1)
-                                } else {
-                                    param.bounds.get(0)
-                                };
-                            let sp = hir.span(id);
-                            let sp = if let Some(first_bound) = has_bounds {
-                                sp.until(first_bound.span())
-                            } else if let Some(colon_sp) =
-                                // If the generic param is declared with a colon but without bounds:
-                                // fn foo<T:>(t: T) { ... }
-                                param.colon_span_for_suggestions(
-                                    self.inh.tcx.sess.source_map(),
-                                )
+                            enum Introducer {
+                                Plus,
+                                Colon,
+                                Nothing,
+                            }
+                            let ast_generics = hir.get_generics(id.owner).unwrap();
+                            let (sp, mut introducer) = if let Some(span) =
+                                ast_generics.bounds_span_for_suggestions(def_id)
                             {
-                                sp.to(colon_sp)
+                                (span, Introducer::Plus)
+                            } else if let Some(colon_span) = param.colon_span {
+                                (colon_span.shrink_to_hi(), Introducer::Nothing)
                             } else {
-                                sp
+                                (param.span.shrink_to_hi(), Introducer::Colon)
                             };
-                            let trait_def_ids: FxHashSet<DefId> = param
-                                .bounds
-                                .iter()
+                            if matches!(
+                                param.kind,
+                                hir::GenericParamKind::Type { synthetic: true, .. },
+                            ) {
+                                introducer = Introducer::Plus
+                            }
+                            let trait_def_ids: FxHashSet<DefId> = ast_generics
+                                .bounds_for_param(def_id)
+                                .flat_map(|bp| bp.bounds.iter())
                                 .filter_map(|bound| bound.trait_ref()?.trait_def_id())
                                 .collect();
                             if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
@@ -1913,11 +1903,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     )),
                                     candidates.iter().map(|t| {
                                         format!(
-                                            "{}{} {}{}",
-                                            param.name.ident(),
-                                            if impl_trait { " +" } else { ":" },
+                                            "{} {}",
+                                            match introducer {
+                                                Introducer::Plus => " +",
+                                                Introducer::Colon => ":",
+                                                Introducer::Nothing => "",
+                                            },
                                             self.tcx.def_path_str(t.def_id),
-                                            if has_bounds.is_some() { " + " } else { "" },
                                         )
                                     }),
                                     Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index f7bb30cd13e..76c955d6f69 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -373,16 +373,7 @@ fn typeck_with_fallback<'tcx>(
         let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
             let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
                 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
-                <dyn AstConv<'_>>::ty_of_fn(
-                    &fcx,
-                    id,
-                    header.unsafety,
-                    header.abi,
-                    decl,
-                    &hir::Generics::empty(),
-                    None,
-                    None,
-                )
+                <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
             } else {
                 tcx.fn_sig(def_id)
             };
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 4e3e32670e9..ec2b7c13ff3 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -420,15 +420,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
 
             let suggestion = format!(
                 "{} {}",
-                if !gat_item_hir.generics.where_clause.predicates.is_empty() {
-                    ","
-                } else {
-                    " where"
-                },
+                if !gat_item_hir.generics.predicates.is_empty() { "," } else { " where" },
                 unsatisfied_bounds.join(", "),
             );
             err.span_suggestion(
-                gat_item_hir.generics.where_clause.tail_span_for_suggestion(),
+                gat_item_hir.generics.tail_span_for_predicate_suggestion(),
                 &format!("add the required where clause{plural}"),
                 suggestion,
                 Applicability::MachineApplicable,
@@ -1733,7 +1729,6 @@ fn check_variances_for_type_defn<'tcx>(
     let explicitly_bounded_params = Lazy::new(|| {
         let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
         hir_generics
-            .where_clause
             .predicates
             .iter()
             .filter_map(|predicate| match predicate {
@@ -1760,8 +1755,7 @@ fn check_variances_for_type_defn<'tcx>(
         match param.name {
             hir::ParamName::Error => {}
             _ => {
-                let has_explicit_bounds =
-                    !param.bounds.is_empty() || explicitly_bounded_params.contains(&parameter);
+                let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
                 report_bivariance(tcx, param, has_explicit_bounds);
             }
         }
@@ -1819,13 +1813,12 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirI
 
             // only use the span of the predicate clause (#90869)
 
-            if let Some(hir::Generics { where_clause, .. }) =
+            if let Some(hir::Generics { predicates, .. }) =
                 hir_node.and_then(|node| node.generics())
             {
                 let obligation_span = obligation.cause.span(fcx.tcx);
 
-                span = where_clause
-                    .predicates
+                span = predicates
                     .iter()
                     // There seems to be no better way to find out which predicate we are in
                     .find(|pred| pred.span().contains(obligation_span))
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 0ccc2b6b182..f85735ec57b 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1,4 +1,3 @@
-// ignore-tidy-filelength
 //! "Collection" is the process of determining the type and other external
 //! details of each item in Rust. Collection is specifically concerned
 //! with *inter-procedural* things -- for example, for a function
@@ -149,8 +148,7 @@ struct CollectItemTypesVisitor<'tcx> {
 /// all already existing generic type parameters to avoid suggesting a name that is already in use.
 crate fn placeholder_type_error<'tcx>(
     tcx: TyCtxt<'tcx>,
-    span: Option<Span>,
-    generics: &[hir::GenericParam<'_>],
+    generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
     suggest: bool,
     hir_ty: Option<&hir::Ty<'_>>,
@@ -160,23 +158,13 @@ crate fn placeholder_type_error<'tcx>(
         return;
     }
 
-    placeholder_type_error_diag(
-        tcx,
-        span,
-        generics,
-        placeholder_types,
-        vec![],
-        suggest,
-        hir_ty,
-        kind,
-    )
-    .emit();
+    placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
+        .emit();
 }
 
 crate fn placeholder_type_error_diag<'tcx>(
     tcx: TyCtxt<'tcx>,
-    span: Option<Span>,
-    generics: &[hir::GenericParam<'_>],
+    generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
     additional_spans: Vec<Span>,
     suggest: bool,
@@ -187,26 +175,24 @@ crate fn placeholder_type_error_diag<'tcx>(
         return bad_placeholder(tcx, additional_spans, kind);
     }
 
-    let type_name = generics.next_type_param_name(None);
+    let params = generics.map(|g| g.params).unwrap_or_default();
+    let type_name = params.next_type_param_name(None);
     let mut sugg: Vec<_> =
         placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
 
-    if generics.is_empty() {
-        if let Some(span) = span {
-            sugg.push((span, format!("<{}>", type_name)));
+    if let Some(generics) = generics {
+        if let Some(arg) = params.iter().find(|arg| {
+            matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. }))
+        }) {
+            // Account for `_` already present in cases like `struct S<_>(_);` and suggest
+            // `struct S<T>(T);` instead of `struct S<_, T>(T);`.
+            sugg.push((arg.span, (*type_name).to_string()));
+        } else if let Some(span) = generics.span_for_param_suggestion() {
+            // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
+            sugg.push((span, format!(", {}", type_name)));
+        } else {
+            sugg.push((generics.span, format!("<{}>", type_name)));
         }
-    } else if let Some(arg) = generics
-        .iter()
-        .find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. })))
-    {
-        // Account for `_` already present in cases like `struct S<_>(_);` and suggest
-        // `struct S<T>(T);` instead of `struct S<_, T>(T);`.
-        sugg.push((arg.span, (*type_name).to_string()));
-    } else {
-        let last = generics.iter().last().unwrap();
-        // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
-        let span = last.bounds_span_for_suggestions().unwrap_or(last.span.shrink_to_hi());
-        sugg.push((span, format!(", {}", type_name)));
     }
 
     let mut err =
@@ -270,15 +256,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
     let mut visitor = HirPlaceholderCollector::default();
     visitor.visit_item(item);
 
-    placeholder_type_error(
-        tcx,
-        Some(generics.span),
-        generics.params,
-        visitor.0,
-        suggest,
-        None,
-        item.kind.descr(),
-    );
+    placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr());
 }
 
 impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
@@ -680,27 +658,8 @@ impl<'tcx> ItemCtxt<'tcx> {
         only_self_bounds: OnlySelfBounds,
         assoc_name: Option<Ident>,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
-        let from_ty_params = ast_generics
-            .params
-            .iter()
-            .filter_map(|param| match param.kind {
-                GenericParamKind::Type { .. } | GenericParamKind::Const { .. }
-                    if param.hir_id == param_id =>
-                {
-                    Some(&param.bounds)
-                }
-                _ => None,
-            })
-            .flat_map(|bounds| bounds.iter())
-            .filter(|b| match assoc_name {
-                Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
-                None => true,
-            })
-            .flat_map(|b| predicates_from_bound(self, ty, b, ty::List::empty()));
-
         let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
-        let from_where_clauses = ast_generics
-            .where_clause
+        ast_generics
             .predicates
             .iter()
             .filter_map(|wp| match *wp {
@@ -725,9 +684,8 @@ impl<'tcx> ItemCtxt<'tcx> {
                     })
                     .filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
             })
-            .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars));
-
-        from_ty_params.chain(from_where_clauses).collect()
+            .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
+            .collect()
     }
 
     fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
@@ -773,7 +731,6 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                         placeholder_type_error(
                             tcx,
                             None,
-                            &[],
                             visitor.0,
                             false,
                             None,
@@ -853,15 +810,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                     if let hir::TyKind::TraitObject(..) = ty.kind {
                         let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_item(it);
-                        placeholder_type_error(
-                            tcx,
-                            None,
-                            &[],
-                            visitor.0,
-                            false,
-                            None,
-                            it.kind.descr(),
-                        );
+                        placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
                     }
                 }
                 _ => (),
@@ -889,7 +838,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             // Account for `const C: _;`.
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, None, &[], visitor.0, false, None, "constant");
+            placeholder_type_error(tcx, None, visitor.0, false, None, "constant");
         }
 
         hir::TraitItemKind::Type(_, Some(_)) => {
@@ -898,7 +847,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             // Account for `type T = _;`.
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
+            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
         }
 
         hir::TraitItemKind::Type(_, None) => {
@@ -908,7 +857,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
 
-            placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
+            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
         }
     };
 
@@ -930,7 +879,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
             let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_impl_item(impl_item);
 
-            placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
+            placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
         }
         hir::ImplItemKind::Const(..) => {}
     }
@@ -1893,15 +1842,14 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
     match tcx.hir().get(hir_id) {
         TraitItem(hir::TraitItem {
             kind: TraitItemKind::Fn(sig, TraitFn::Provided(_)),
-            ident,
             generics,
             ..
         })
-        | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), ident, .. }) => {
-            infer_return_ty_for_fn_sig(tcx, sig, *ident, generics, def_id, &icx)
+        | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
+            infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
         }
 
-        ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), ident, generics, .. }) => {
+        ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
             // Do not try to inference the return type for a impl method coming from a trait
             if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
                 tcx.hir().get(tcx.hir().get_parent_node(hir_id))
@@ -1913,18 +1861,16 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                     sig.header.unsafety,
                     sig.header.abi,
                     sig.decl,
-                    generics,
-                    Some(ident.span),
+                    Some(generics),
                     None,
                 )
             } else {
-                infer_return_ty_for_fn_sig(tcx, sig, *ident, generics, def_id, &icx)
+                infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
             }
         }
 
         TraitItem(hir::TraitItem {
             kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
-            ident,
             generics,
             ..
         }) => <dyn AstConv<'_>>::ty_of_fn(
@@ -1933,16 +1879,13 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
             header.unsafety,
             header.abi,
             decl,
-            generics,
-            Some(ident.span),
+            Some(generics),
             None,
         ),
 
-        ForeignItem(&hir::ForeignItem {
-            kind: ForeignItemKind::Fn(fn_decl, _, _), ident, ..
-        }) => {
+        ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
-            compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi, ident)
+            compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi)
         }
 
         Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor_hir_id().is_some() => {
@@ -1983,7 +1926,6 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
 fn infer_return_ty_for_fn_sig<'tcx>(
     tcx: TyCtxt<'tcx>,
     sig: &hir::FnSig<'_>,
-    ident: Ident,
     generics: &hir::Generics<'_>,
     def_id: LocalDefId,
     icx: &ItemCtxt<'tcx>,
@@ -2038,8 +1980,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             sig.header.unsafety,
             sig.header.abi,
             sig.decl,
-            generics,
-            Some(ident.span),
+            Some(generics),
             None,
         ),
     }
@@ -2200,16 +2141,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
 
     let icx = ItemCtxt::new(tcx, def_id);
 
-    const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
+    const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
 
     // We use an `IndexSet` to preserves order of insertion.
     // Preserving the order of insertion is important here so as not to break UI tests.
     let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
 
     let ast_generics = match node {
-        Node::TraitItem(item) => &item.generics,
+        Node::TraitItem(item) => item.generics,
 
-        Node::ImplItem(item) => &item.generics,
+        Node::ImplItem(item) => item.generics,
 
         Node::Item(item) => {
             match item.kind {
@@ -2223,15 +2164,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                 | ItemKind::TyAlias(_, ref generics)
                 | ItemKind::Enum(_, ref generics)
                 | ItemKind::Struct(_, ref generics)
-                | ItemKind::Union(_, ref generics) => generics,
+                | ItemKind::Union(_, ref generics) => *generics,
 
                 ItemKind::Trait(_, _, ref generics, ..) => {
                     is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    generics
+                    *generics
                 }
                 ItemKind::TraitAlias(ref generics, _) => {
                     is_trait = Some(ty::TraitRef::identity(tcx, def_id));
-                    generics
+                    *generics
                 }
                 ItemKind::OpaqueTy(OpaqueTy {
                     origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
@@ -2268,7 +2209,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
 
         Node::ForeignItem(item) => match item.kind {
             ForeignItemKind::Static(..) => NO_GENERICS,
-            ForeignItemKind::Fn(_, _, ref generics) => generics,
+            ForeignItemKind::Fn(_, _, ref generics) => *generics,
             ForeignItemKind::Type => NO_GENERICS,
         },
 
@@ -2302,29 +2243,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
     // Collect the region predicates that were declared inline as
     // well. In the case of parameters declared on a fn or method, we
     // have to be careful to only iterate over early-bound regions.
-    let mut index = parent_count + has_own_self as u32;
-    for param in early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics) {
-        let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
-            def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
-            index,
-            name: param.name.ident().name,
-        }));
-        index += 1;
-
-        match param.kind {
-            GenericParamKind::Lifetime { .. } => {
-                param.bounds.iter().for_each(|bound| match bound {
-                    hir::GenericBound::Outlives(lt) => {
-                        let bound = <dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None);
-                        let outlives = ty::Binder::dummy(ty::OutlivesPredicate(region, bound));
-                        predicates.insert((outlives.to_predicate(tcx), lt.span));
-                    }
-                    _ => bug!(),
-                });
-            }
-            _ => bug!(),
-        }
-    }
+    let mut index = parent_count
+        + has_own_self as u32
+        + early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics).count() as u32;
 
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T: Foo>`).
@@ -2337,28 +2258,26 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                 let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
                 index += 1;
 
-                let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, param_ty, param.bounds);
+                let mut bounds = Bounds::default();
                 // Params are implicitly sized unless a `?Sized` bound is found
                 <dyn AstConv<'_>>::add_implicitly_sized(
                     &icx,
                     &mut bounds,
-                    param.bounds,
-                    Some((param.hir_id, ast_generics.where_clause.predicates)),
+                    &[],
+                    Some((param.hir_id, ast_generics.predicates)),
                     param.span,
                 );
                 predicates.extend(bounds.predicates(tcx, param_ty));
             }
             GenericParamKind::Const { .. } => {
                 // Bounds on const parameters are currently not possible.
-                debug_assert!(param.bounds.is_empty());
                 index += 1;
             }
         }
     }
 
     // Add in the bounds that appear in the where-clause.
-    let where_clause = &ast_generics.where_clause;
-    for predicate in where_clause.predicates {
+    for predicate in ast_generics.predicates {
         match predicate {
             hir::WherePredicate::BoundPredicate(bound_pred) => {
                 let ty = icx.to_ty(bound_pred.bounded_ty);
@@ -2616,7 +2535,6 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     def_id: DefId,
     decl: &'tcx hir::FnDecl<'tcx>,
     abi: abi::Abi,
-    ident: Ident,
 ) -> ty::PolyFnSig<'tcx> {
     let unsafety = if abi == abi::Abi::RustIntrinsic {
         intrinsic_operation_unsafety(tcx.item_name(def_id))
@@ -2630,8 +2548,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
         unsafety,
         abi,
         decl,
-        &hir::Generics::empty(),
-        Some(ident.span),
+        None,
         None,
     );
 
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index fa06ec09fce..495b8d3b4ee 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -337,8 +337,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         icx.to_ty(ty)
                     }
                 }
-                ItemKind::TyAlias(self_ty, _)
-                | ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(self_ty),
+                ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
+                ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(*self_ty),
                 ItemKind::Fn(..) => {
                     let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
                     tcx.mk_fn_def(def_id.to_def_id(), substs)
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 9fb9652b849..03b3d68d59f 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -213,7 +213,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
         match tcx.hir().find(hir_id) {
             Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
-                generics.where_clause.span()
+                generics.where_clause_span()
             }
             _ => {
                 span_bug!(tcx.def_span(def_id), "main has a non-function type");
@@ -408,7 +408,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                         .emit();
                         error = true;
                     }
-                    if let Some(sp) = generics.where_clause.span() {
+                    if let Some(sp) = generics.where_clause_span() {
                         struct_span_err!(
                             tcx.sess,
                             sp,
diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py
index 89696f39262..343dd0387f4 100644
--- a/src/etc/check_missing_items.py
+++ b/src/etc/check_missing_items.py
@@ -49,8 +49,6 @@ def check_generic_param(param):
         ty = param["kind"]["type"]
         if ty["default"]:
             check_type(ty["default"])
-        for bound in ty["bounds"]:
-            check_generic_bound(bound)
     elif "const" in param["kind"]:
         check_type(param["kind"]["const"])
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 476a89523a5..d458deddae3 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -238,9 +238,12 @@ impl Clean<Option<Lifetime>> for ty::Region<'_> {
     }
 }
 
-impl Clean<WherePredicate> for hir::WherePredicate<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
-        match *self {
+impl Clean<Option<WherePredicate>> for hir::WherePredicate<'_> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
+        if !self.in_where_clause() {
+            return None;
+        }
+        Some(match *self {
             hir::WherePredicate::BoundPredicate(ref wbp) => {
                 let bound_params = wbp
                     .bound_generic_params
@@ -250,11 +253,7 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
                         // Higher-ranked lifetimes can't have bounds.
                         assert_matches!(
                             param,
-                            hir::GenericParam {
-                                kind: hir::GenericParamKind::Lifetime { .. },
-                                bounds: [],
-                                ..
-                            }
+                            hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
                         );
                         Lifetime(param.name.ident().name)
                     })
@@ -275,7 +274,7 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
                 lhs: wrp.lhs_ty.clean(cx),
                 rhs: wrp.rhs_ty.clean(cx).into(),
             },
-        }
+        })
     }
 }
 
@@ -456,44 +455,75 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
     }
 }
 
-impl Clean<GenericParamDef> for hir::GenericParam<'_> {
-    fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
-        let (name, kind) = match self.kind {
-            hir::GenericParamKind::Lifetime { .. } => {
-                let outlives = self
-                    .bounds
+fn clean_generic_param(
+    cx: &mut DocContext<'_>,
+    generics: Option<&hir::Generics<'_>>,
+    param: &hir::GenericParam<'_>,
+) -> GenericParamDef {
+    let (name, kind) = match param.kind {
+        hir::GenericParamKind::Lifetime { .. } => {
+            let outlives = if let Some(generics) = generics {
+                generics
+                    .predicates
                     .iter()
+                    .flat_map(|pred| {
+                        match pred {
+                            hir::WherePredicate::RegionPredicate(rp)
+                                if rp.lifetime.name == hir::LifetimeName::Param(param.name)
+                                    && !rp.in_where_clause =>
+                            {
+                                rp.bounds
+                            }
+                            _ => &[],
+                        }
+                        .iter()
+                    })
                     .map(|bound| match bound {
                         hir::GenericBound::Outlives(lt) => lt.clean(cx),
                         _ => panic!(),
                     })
-                    .collect();
-                (self.name.ident().name, GenericParamDefKind::Lifetime { outlives })
-            }
-            hir::GenericParamKind::Type { ref default, synthetic } => (
-                self.name.ident().name,
+                    .collect()
+            } else {
+                Vec::new()
+            };
+            (param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
+        }
+        hir::GenericParamKind::Type { ref default, synthetic } => {
+            let did = cx.tcx.hir().local_def_id(param.hir_id);
+            let bounds = if let Some(generics) = generics {
+                generics
+                    .bounds_for_param(did)
+                    .filter(|bp| !bp.in_where_clause)
+                    .flat_map(|bp| bp.bounds)
+                    .filter_map(|x| x.clean(cx))
+                    .collect()
+            } else {
+                Vec::new()
+            };
+            (
+                param.name.ident().name,
                 GenericParamDefKind::Type {
-                    did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
-                    bounds: self.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                    did: did.to_def_id(),
+                    bounds,
                     default: default.map(|t| t.clean(cx)).map(Box::new),
                     synthetic,
                 },
-            ),
-            hir::GenericParamKind::Const { ref ty, default } => (
-                self.name.ident().name,
-                GenericParamDefKind::Const {
-                    did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
-                    ty: Box::new(ty.clean(cx)),
-                    default: default.map(|ct| {
-                        let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
-                        Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
-                    }),
-                },
-            ),
-        };
+            )
+        }
+        hir::GenericParamKind::Const { ref ty, default } => (
+            param.name.ident().name,
+            GenericParamDefKind::Const {
+                did: cx.tcx.hir().local_def_id(param.hir_id).to_def_id(),
+                ty: Box::new(ty.clean(cx)),
+                default: default.map(|ct| {
+                    let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
+                    Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
+                }),
+            },
+        ),
+    };
 
-        GenericParamDef { name, kind }
-    }
+    GenericParamDef { name, kind }
 }
 
 impl Clean<Generics> for hir::Generics<'_> {
@@ -524,7 +554,7 @@ impl Clean<Generics> for hir::Generics<'_> {
             .iter()
             .filter(|param| is_impl_trait(param))
             .map(|param| {
-                let param: GenericParamDef = param.clean(cx);
+                let param = clean_generic_param(cx, Some(self), param);
                 match param.kind {
                     GenericParamDefKind::Lifetime { .. } => unreachable!(),
                     GenericParamDefKind::Type { did, ref bounds, .. } => {
@@ -538,14 +568,14 @@ impl Clean<Generics> for hir::Generics<'_> {
 
         let mut params = Vec::with_capacity(self.params.len());
         for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
-            let p = p.clean(cx);
+            let p = clean_generic_param(cx, Some(self), p);
             params.push(p);
         }
         params.extend(impl_trait_params);
 
         let mut generics = Generics {
             params,
-            where_predicates: self.where_clause.predicates.iter().map(|x| x.clean(cx)).collect(),
+            where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(),
         };
 
         // Some duplicates are generated for ?Sized bounds between type params and where
@@ -954,7 +984,11 @@ impl Clean<PolyTrait> for hir::PolyTraitRef<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait {
         PolyTrait {
             trait_: self.trait_ref.clean(cx),
-            generic_params: self.bound_generic_params.iter().map(|x| x.clean(cx)).collect(),
+            generic_params: self
+                .bound_generic_params
+                .iter()
+                .map(|x| clean_generic_param(cx, None, x))
+                .collect(),
         }
     }
 }
@@ -1823,7 +1857,8 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
         let (generic_params, decl) = enter_impl_trait(cx, |cx| {
             // NOTE: generics must be cleaned before args
-            let generic_params = self.generic_params.iter().map(|x| x.clean(cx)).collect();
+            let generic_params =
+                self.generic_params.iter().map(|x| clean_generic_param(cx, None, x)).collect();
             let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
             let decl = clean_fn_decl_with_args(cx, self.decl, args);
             (generic_params, decl)
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 06c63ec97d7..b5502309560 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{ExprKind, GenericParam, GenericParamKind, HirId, Mod, Node};
+use rustc_hir::{ExprKind, GenericParam, HirId, Mod, Node};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
@@ -100,16 +100,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
         self.tcx.hir()
     }
 
-    fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
-        if !matches!(p.kind, GenericParamKind::Type { .. }) {
-            return;
-        }
-        for bound in p.bounds {
-            if let Some(trait_ref) = bound.trait_ref() {
-                self.handle_path(trait_ref.path, None);
-            }
-        }
-    }
+    fn visit_generic_param(&mut self, _: &'tcx GenericParam<'tcx>) {}
 
     fn visit_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) {
         self.handle_path(path, None);
diff --git a/src/test/ui/async-await/issue-86507.stderr b/src/test/ui/async-await/issue-86507.stderr
index ad0a3592241..5bbc20359c6 100644
--- a/src/test/ui/async-await/issue-86507.stderr
+++ b/src/test/ui/async-await/issue-86507.stderr
@@ -14,10 +14,10 @@ note: captured value is not `Send` because `&` references cannot be sent unless
 LL |                     let x = x;
    |                             ^ has type `&T` which is not `Send`, because `T` is not `Sync`
    = note: required for the cast to the object type `dyn Future<Output = ()> + Send`
-help: consider further restricting type parameter `T`
+help: consider further restricting this bound
    |
-LL |         where 'me:'async_trait, T: std::marker::Sync {
-   |                               ++++++++++++++++++++++
+LL |     fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
+   |                                       +++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr
index 2dac4a22ae7..b1e59e9d5de 100644
--- a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr
+++ b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/builtin-superkinds-self-type.rs:10:16
    |
 LL | impl <T: Sync> Foo for T { }
-   |       --       ^^^ ...so that the type `T` will meet its required lifetime bounds
-   |       |
-   |       help: consider adding an explicit lifetime bound...: `T: 'static +`
+   |                ^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl <T: Sync + 'static> Foo for T { }
+   |               +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr
index 2bccec45894..7ffebab4153 100644
--- a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr
+++ b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr
@@ -1,8 +1,6 @@
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:10
    |
-LL | struct Foo<U> {
-   |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
    |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds...
    |
@@ -11,6 +9,10 @@ note: ...that is required by this bound
    |
 LL | struct Bar<T: 'static> {
    |               ^^^^^^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<U: 'static> {
+   |             +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/issue-86483.stderr b/src/test/ui/generic-associated-types/issue-86483.stderr
index 2f29cd5d9e9..a13dc043dc5 100644
--- a/src/test/ui/generic-associated-types/issue-86483.stderr
+++ b/src/test/ui/generic-associated-types/issue-86483.stderr
@@ -1,10 +1,7 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/issue-86483.rs:5:1
    |
-LL |   pub trait IceIce<T>
-   |   ^                - help: consider adding an explicit lifetime bound...: `T: 'a`
-   |  _|
-   | |
+LL | / pub trait IceIce<T>
 LL | | where
 LL | |     for<'a> T: 'a,
 LL | | {
@@ -19,13 +16,14 @@ note: ...that is required by this bound
    |
 LL |     for<'a> T: 'a,
    |                ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL |     for<'a> T: 'a + 'a,
+   |                   ++++
 
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/issue-86483.rs:9:5
    |
-LL | pub trait IceIce<T>
-   |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     type Ice<'v>: IntoIterator<Item = &'v T>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
@@ -34,6 +32,10 @@ note: ...that is required by this bound
    |
 LL |     for<'a> T: 'a,
    |                ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL |     for<'a> T: 'a + 'a,
+   |                   ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/issue-86483.rs:9:32
diff --git a/src/test/ui/generic-associated-types/issue-91139.migrate.stderr b/src/test/ui/generic-associated-types/issue-91139.migrate.stderr
index a27d8110238..b424d9a2fdb 100644
--- a/src/test/ui/generic-associated-types/issue-91139.migrate.stderr
+++ b/src/test/ui/generic-associated-types/issue-91139.migrate.stderr
@@ -1,10 +1,13 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/issue-91139.rs:27:12
    |
-LL | fn foo<T>() {
-   |        - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo<T: 'a>() {
+   |         ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr
index 72ade5774d7..c74161cd3e0 100644
--- a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr
+++ b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr
@@ -2,17 +2,23 @@ error[E0311]: the parameter type `C` may not live long enough
   --> $DIR/issue-92096.rs:20:33
    |
 LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
-   |                 -               ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
-   |                 |
-   |                 help: consider adding an explicit lifetime bound...: `C: 'a`
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     C: Client + Send + Sync + 'a,
+   |                             ++++
 
 error[E0311]: the parameter type `C` may not live long enough
   --> $DIR/issue-92096.rs:20:33
    |
 LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
-   |                 -               ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
-   |                 |
-   |                 help: consider adding an explicit lifetime bound...: `C: 'a`
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     C: Client + Send + Sync + 'a,
+   |                             ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr
index aaeec920527..5323ee17226 100644
--- a/src/test/ui/generic-associated-types/missing-bounds.stderr
+++ b/src/test/ui/generic-associated-types/missing-bounds.stderr
@@ -87,10 +87,10 @@ note: tuple struct defined here
    |
 LL | struct E<B>(B);
    |        ^
-help: consider further restricting type parameter `B`
+help: consider further restricting this bound
    |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: Add<Output = B> {
-   |                                                       ++++++++++++++++++++
+LL | impl<B: Add + Add<Output = B>> Add for E<B> where <B as Add>::Output = B {
+   |             +++++++++++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr
index 4f0a023ee39..ae52010cc50 100644
--- a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr
+++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr
@@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a`
   --> $DIR/unsatified-item-lifetime-bound.rs:4:12
    |
 LL |     type Y<'a: 'static>;
-   |            ^^^^^^^^^^^
+   |            ^^
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
diff --git a/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr b/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr
index 51247f1d7b0..3e48aef553b 100644
--- a/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr
+++ b/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr
@@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a`
   --> $DIR/equal-hidden-lifetimes.rs:7:25
    |
 LL | fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized {
-   |                         ^^^^^^^^^^^
+   |                         ^^
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
index 2681241bbad..db737a9c544 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
@@ -112,11 +112,13 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/must_outlive_least_region_or_bound.rs:40:5
    |
-LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
-   |                                 -- help: consider adding an explicit lifetime bound...: `T: 'static +`
-LL |
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn ty_param_wont_outlive_static<T:Debug + 'static>(x: T) -> impl Debug + 'static {
+   |                                         +++++++++
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index 6bcfb27ce16..dade2b91fe0 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -128,9 +128,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/must_outlive_least_region_or_bound.rs:38:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
-   |                                 --                ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-   |                                 |
-   |                                 help: consider adding an explicit lifetime bound...: `T: 'static +`
+   |                                                   ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn ty_param_wont_outlive_static<T:Debug + 'static>(x: T) -> impl Debug + 'static {
+   |                                         +++++++++
 
 error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/must_outlive_least_region_or_bound.rs:16:50
diff --git a/src/test/ui/impl-trait/type_parameters_captured.nll.stderr b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr
index 1cd5b65b974..3050f10b205 100644
--- a/src/test/ui/impl-trait/type_parameters_captured.nll.stderr
+++ b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr
@@ -1,11 +1,13 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/type_parameters_captured.rs:9:5
    |
-LL | fn foo<T>(x: T) -> impl Any + 'static {
-   |        - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo<T: 'static>(x: T) -> impl Any + 'static {
+   |         +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/type_parameters_captured.stderr b/src/test/ui/impl-trait/type_parameters_captured.stderr
index 40e50b9922f..9f28a8d44a7 100644
--- a/src/test/ui/impl-trait/type_parameters_captured.stderr
+++ b/src/test/ui/impl-trait/type_parameters_captured.stderr
@@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/type_parameters_captured.rs:7:20
    |
 LL | fn foo<T>(x: T) -> impl Any + 'static {
-   |        -           ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
-   |        |
-   |        help: consider adding an explicit lifetime bound...: `T: 'static`
+   |                    ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo<T: 'static>(x: T) -> impl Any + 'static {
+   |         +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-30438-c.rs b/src/test/ui/issues/issue-30438-c.rs
index 813c1d3e2cc..4cf634245be 100644
--- a/src/test/ui/issues/issue-30438-c.rs
+++ b/src/test/ui/issues/issue-30438-c.rs
@@ -5,6 +5,7 @@ trait Trait { type Out; }
 struct Test<'a> { s: &'a str }
 
 fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y <Test<'z> as Trait>::Out where 'z: 'static {
+    //~^ WARN unnecessary lifetime parameter `'z`
     let x = Test { s: "this cannot last" };
     &x
     //~^ ERROR: cannot return reference to local variable `x`
diff --git a/src/test/ui/issues/issue-30438-c.stderr b/src/test/ui/issues/issue-30438-c.stderr
index 7c001088097..a7a5c0500fd 100644
--- a/src/test/ui/issues/issue-30438-c.stderr
+++ b/src/test/ui/issues/issue-30438-c.stderr
@@ -1,9 +1,17 @@
+warning: unnecessary lifetime parameter `'z`
+  --> $DIR/issue-30438-c.rs:7:74
+   |
+LL | fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y <Test<'z> as Trait>::Out where 'z: 'static {
+   |                                                                          ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'z`
+
 error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/issue-30438-c.rs:9:5
+  --> $DIR/issue-30438-c.rs:10:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0515`.
diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
index e5083e3a088..33f6c498b6f 100644
--- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
+++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
@@ -1,18 +1,24 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:19:10
    |
-LL | struct Foo<T> {
-   |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     foo: &'static T
    |          ^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<T: 'static> {
+   |             +++++++++
 
 error[E0309]: the parameter type `K` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19
    |
-LL | trait X<K>: Sized {
-   |         - help: consider adding an explicit lifetime bound...: `K: 'a`
 LL |     fn foo<'a, L: X<&'a Nested<K>>>();
    |                   ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | trait X<K: 'a>: Sized {
+   |          ++++
 
 error[E0309]: the parameter type `Self` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:28:19
@@ -27,25 +33,34 @@ error[E0309]: the parameter type `L` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:32:22
    |
 LL |     fn baz<'a, L, M: X<&'a Nested<L>>>() {
-   |                -     ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<L>` does not outlive the data it points at
-   |                |
-   |                help: consider adding an explicit lifetime bound...: `L: 'a`
+   |                      ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<L>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     fn baz<'a, L: 'a, M: X<&'a Nested<L>>>() {
+   |                 ++++
 
 error[E0309]: the parameter type `K` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33
    |
-LL | impl<K> Nested<K> {
-   |      - help: consider adding an explicit lifetime bound...: `K: 'a`
 LL |     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
    |                                 ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<K: 'a> Nested<K> {
+   |       ++++
 
 error[E0309]: the parameter type `M` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36
    |
 LL |     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
-   |                                    ^^^^^^^^^^^^^^^^  -- help: consider adding an explicit lifetime bound...: `M: 'a +`
-   |                                    |
-   |                                    ...so that the reference type `&'a Nested<M>` does not outlive the data it points at
+   |                                    ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested<M>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b + 'a>() {
+   |                                                            ++++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr
index 422673b361a..2906c05864b 100644
--- a/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr
@@ -1,10 +1,13 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/issue_74400.rs:12:5
    |
-LL | fn g<T>(data: &[T]) {
-   |      - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     f(data, identity)
    |     ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn g<T: 'static>(data: &[T]) {
+   |       +++++++++
 
 error[E0308]: mismatched types
   --> $DIR/issue_74400.rs:12:5
diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
index fb6cf7e8996..ba1b745ba84 100644
--- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
+++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
@@ -54,17 +54,17 @@ where
 
 fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
 where
-    T: A,
-    T: B, T: Trait, T: Copy
-    //~^ HELP consider further restricting type parameter `T`
+    T: A + Trait + Copy,
+    //~^ HELP consider further restricting this bound
+    T: B,
 {
     (t, t) //~ use of moved value: `t`
 }
 
-fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
+fn duplicate_custom_4<T: A + Trait + Copy>(t: S<T>) -> (S<T>, S<T>)
+//~^ HELP consider further restricting this bound
 where
-    T: B + Trait + Copy,
-    //~^ HELP consider further restricting this bound
+    T: B,
 {
     (t, t) //~ use of moved value: `t`
 }
@@ -77,8 +77,8 @@ fn existing_colon<T: Copy>(t: T) {
 
 fn existing_colon_in_where<T>(t: T)
 where
-    T: Copy,
-    //~^ HELP consider further restricting this bound
+    T:, T: Copy
+    //~^ HELP consider further restricting type parameter `T`
 {
     [t, t]; //~ use of moved value: `t`
 }
diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs
index cadbf2a54cc..0a43dd1a9a3 100644
--- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs
+++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs
@@ -55,16 +55,16 @@ where
 fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
 where
     T: A,
+    //~^ HELP consider further restricting this bound
     T: B,
-    //~^ HELP consider further restricting type parameter `T`
 {
     (t, t) //~ use of moved value: `t`
 }
 
 fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
+//~^ HELP consider further restricting this bound
 where
     T: B,
-    //~^ HELP consider further restricting this bound
 {
     (t, t) //~ use of moved value: `t`
 }
@@ -78,7 +78,7 @@ fn existing_colon<T:>(t: T) {
 fn existing_colon_in_where<T>(t: T)
 where
     T:,
-    //~^ HELP consider further restricting this bound
+    //~^ HELP consider further restricting type parameter `T`
 {
     [t, t]; //~ use of moved value: `t`
 }
diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
index f5252084d68..2353cd079a3 100644
--- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
+++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
@@ -121,10 +121,10 @@ LL |     (t, t)
    |      |
    |      value moved here
    |
-help: consider further restricting type parameter `T`
+help: consider further restricting this bound
    |
-LL |     T: B, T: Trait, T: Copy
-   |         ~~~~~~~~~~~~~~~~~~~
+LL |     T: A + Trait + Copy,
+   |          ++++++++++++++
 
 error[E0382]: use of moved value: `t`
   --> $DIR/use_of_moved_value_copy_suggestions.rs:69:9
@@ -139,8 +139,8 @@ LL |     (t, t)
    |
 help: consider further restricting this bound
    |
-LL |     T: B + Trait + Copy,
-   |          ++++++++++++++
+LL | fn duplicate_custom_4<T: A + Trait + Copy>(t: S<T>) -> (S<T>, S<T>)
+   |                            ++++++++++++++
 
 error[E0382]: use of moved value: `t`
   --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9
@@ -153,10 +153,10 @@ LL |     [t, t];
    |      |
    |      value moved here
    |
-help: consider further restricting this bound
+help: consider further restricting type parameter `T`
    |
-LL |     T: Copy,
-   |        ++++
+LL |     T:, T: Copy
+   |       ~~~~~~~~~
 
 error[E0382]: use of moved value: `t`
   --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9
diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
index b6856089a84..08605efa2ea 100644
--- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
@@ -36,9 +36,6 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/propagate-from-trait-match.rs:32:36
    |
-LL |   fn supply<'a, T>(value: T)
-   |                 - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |       establish_relationships(value, |value| {
    |  ____________________________________^
 LL | |
@@ -48,6 +45,11 @@ LL | |         // This function call requires that
 LL | |         require(value);
 LL | |     });
    | |_____^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: Trait<'a> + 'a,
+   |                  ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
index 3d4cfc1610a..64b08a9b32f 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
+++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr
@@ -1,20 +1,24 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/impl-trait-outlives.rs:11:5
    |
-LL | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
-   |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: Debug + 'a,
+   |              ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/impl-trait-outlives.rs:26:5
    |
-LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
-   |                         - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: 'b + Debug + 'a,
+   |                   ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr b/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
index cc5aa1eb11e..3b9b2956c51 100644
--- a/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
@@ -1,10 +1,13 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/projection-implied-bounds.rs:30:18
    |
-LL | fn generic2<T: Iterator>(value: T) {
-   |             -- help: consider adding an explicit lifetime bound...: `T: 'static +`
 LL |     twice(value, |value_ref, item| invoke2(value_ref, item));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn generic2<T: Iterator + 'static>(value: T) {
+   |                         +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
index 62db6dd845a..caf2e3c4747 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -31,11 +31,13 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:45:29
    |
-LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
-   |                                  - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: Anything<'b> + 'a,
+   |                     ++++
 
 error: lifetime may not live long enough
   --> $DIR/projection-one-region-closure.rs:45:39
@@ -82,11 +84,13 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-one-region-closure.rs:56:29
    |
-LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
-   |                                   - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: Anything<'b> + 'a,
+   |                     ++++
 
 error: lifetime may not live long enough
   --> $DIR/projection-one-region-closure.rs:56:39
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr
index c51edb7868d..e28b89580bc 100644
--- a/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr
@@ -1,11 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-where-clause-none.rs:16:5
    |
-LL | fn foo<'a, T>() -> &'a ()
-   |            - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     bar::<T::Output>()
    |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: MyTrait<'a> + 'a,
+   |                    ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index 3e5e4868341..a4588730b3f 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -52,10 +52,13 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
    |
-LL | fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
-   |                     - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     twice(cell, value, |a, b| invoke(a, b));
    |                        ^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn generic_fail<'a, T: 'a>(cell: Cell<&'a ()>, value: T) {
+   |                      ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
index dc2f23b4fc8..084dd93cb86 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
@@ -29,20 +29,24 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
    |
-LL | fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
-   |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     with_signature(x, |y| y)
    |                       ^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: Debug + 'a,
+   |              ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:41:5
    |
-LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
-   |                         - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: 'b + Debug + 'a,
+   |                   ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
index e9f728c77b3..11a737ba291 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
@@ -37,8 +37,6 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26
    |
-LL |   fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
-   |                    - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |       with_signature(a, b, |x, y| {
    |  __________________________^
 LL | |
@@ -48,6 +46,11 @@ LL | |         // See `correct_region`, which explains the point of this
 LL | |         require(&x, &y)
 LL | |     })
    | |_____^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn no_region<'a, T: 'a>(a: Cell<&'a ()>, b: T) {
+   |                   ++++
 
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26
@@ -121,9 +124,6 @@ LL | | }
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
    |
-LL |   fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
-   |                           - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |       with_signature(a, b, |x, y| {
    |  __________________________^
 LL | |
@@ -131,6 +131,11 @@ LL | |         // See `correct_region`
 LL | |         require(&x, &y)
 LL | |     })
    | |_____^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: 'b + 'a,
+   |           ++++
 
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26
diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr
index a2e6a5d57cd..ba79137d18d 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn-body.rs:19:5
    |
-LL | fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
-   |                      - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     outlives(cell, t)
    |     ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn region_static<'a, T: 'a>(cell: Cell<&'a usize>, t: T) {
+   |                       ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr
index fce360dd54b..729f14d84ad 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr
@@ -1,20 +1,24 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn.rs:11:5
    |
-LL | fn no_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
-   |                  - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: Debug + 'a,
+   |              ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/ty-param-fn.rs:26:5
    |
-LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
-   |                         - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     x
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     T: 'b + Debug + 'a,
+   |                   ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
index 05ddc09b2d0..66d3102225e 100644
--- a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
@@ -1,26 +1,35 @@
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:13:5
    |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-   |             - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |              +++++++++
 
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:13:5
    |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-   |             - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |              +++++++++
 
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:13:5
    |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-   |             - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |              +++++++++
 
 error: lifetime may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:13:5
@@ -51,10 +60,13 @@ LL |     Box::new(B(&*v)) as Box<dyn X>
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/regions-close-object-into-object-4.rs:13:14
    |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-   |             - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |              ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn i<'a, T, U: 'static>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |              +++++++++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/regions/regions-close-object-into-object-5.base.stderr b/src/test/ui/regions/regions-close-object-into-object-5.base.stderr
index 8b5a06bab71..1a78079b638 100644
--- a/src/test/ui/regions/regions-close-object-into-object-5.base.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-5.base.stderr
@@ -1,9 +1,6 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:5
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
@@ -12,22 +9,25 @@ note: ...that is required by this bound
    |
 LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
    |                 ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:5
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:14
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |              ^ ...so that the type `T` will meet its required lifetime bounds...
    |
@@ -36,13 +36,14 @@ note: ...that is required by this bound
    |
 LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
    |                 ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:14
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |              ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
@@ -51,33 +52,43 @@ note: ...that is required by this bound
    |
 LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
    |                 ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:16
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |                ^^^ ...so that the reference type `&dyn A<T>` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:16
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |                ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:16
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |                ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr
index f4e3809e916..cb06326130e 100644
--- a/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr
@@ -1,29 +1,35 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:5
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:5
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:5
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |     ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error[E0515]: cannot return value referencing local data `*v`
   --> $DIR/regions-close-object-into-object-5.rs:21:5
@@ -37,11 +43,13 @@ LL |     Box::new(B(&*v)) as Box<dyn X>
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:21:14
    |
-LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // oh dear!
 LL |     Box::new(B(&*v)) as Box<dyn X>
    |              ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn f<'a, T: 'static, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |           +++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr
index 41dc03e86dd..d8f77ad85c9 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr
@@ -1,18 +1,24 @@
 error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:15:5
    |
-LL | fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
-   |                 -- help: consider adding an explicit lifetime bound...: `A: 'static +`
 LL |     Box::new(v) as Box<dyn SomeTrait + 'static>
    |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn make_object1<A: SomeTrait + 'static>(v: A) -> Box<dyn SomeTrait + 'static> {
+   |                              +++++++++
 
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:24:5
    |
-LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
-   |                         -- help: consider adding an explicit lifetime bound...: `A: 'b +`
 LL |     Box::new(v) as Box<dyn SomeTrait + 'b>
    |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn make_object3<'a, 'b, A: SomeTrait + 'a + 'b>(v: A) -> Box<dyn SomeTrait + 'b> {
+   |                                           ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
index 41dc03e86dd..d8f77ad85c9 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
@@ -1,18 +1,24 @@
 error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:15:5
    |
-LL | fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
-   |                 -- help: consider adding an explicit lifetime bound...: `A: 'static +`
 LL |     Box::new(v) as Box<dyn SomeTrait + 'static>
    |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn make_object1<A: SomeTrait + 'static>(v: A) -> Box<dyn SomeTrait + 'static> {
+   |                              +++++++++
 
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:24:5
    |
-LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
-   |                         -- help: consider adding an explicit lifetime bound...: `A: 'b +`
 LL |     Box::new(v) as Box<dyn SomeTrait + 'b>
    |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn make_object3<'a, 'b, A: SomeTrait + 'a + 'b>(v: A) -> Box<dyn SomeTrait + 'b> {
+   |                                           ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/regions/regions-close-param-into-object.base.stderr b/src/test/ui/regions/regions-close-param-into-object.base.stderr
index 7e135c65450..79a5d34dea8 100644
--- a/src/test/ui/regions/regions-close-param-into-object.base.stderr
+++ b/src/test/ui/regions/regions-close-param-into-object.base.stderr
@@ -1,38 +1,46 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:10:5
    |
-LL | fn p1<T>(v: T) -> Box<dyn X + 'static>
-   |       - help: consider adding an explicit lifetime bound...: `T: 'static`
-...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     where T : X + 'static
+   |                 +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:16:5
    |
-LL | fn p2<T>(v: Box<T>) -> Box<dyn X + 'static>
-   |       - help: consider adding an explicit lifetime bound...: `T: 'static`
-...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn p2<T: 'static>(v: Box<T>) -> Box<dyn X + 'static>
+   |        +++++++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:22:5
    |
-LL | fn p3<'a,T>(v: T) -> Box<dyn X + 'a>
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     where T : X + 'a
+   |                 ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:28:5
    |
-LL | fn p4<'a,T>(v: Box<T>) -> Box<dyn X + 'a>
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `Box<T>` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn p4<'a,T: 'a>(v: Box<T>) -> Box<dyn X + 'a>
+   |           ++++
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/regions/regions-close-param-into-object.nll.stderr b/src/test/ui/regions/regions-close-param-into-object.nll.stderr
index 3fbc1022631..6ee12d5b82c 100644
--- a/src/test/ui/regions/regions-close-param-into-object.nll.stderr
+++ b/src/test/ui/regions/regions-close-param-into-object.nll.stderr
@@ -1,38 +1,46 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:10:5
    |
-LL | fn p1<T>(v: T) -> Box<dyn X + 'static>
-   |       - help: consider adding an explicit lifetime bound...: `T: 'static`
-...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     where T : X + 'static
+   |                 +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:16:5
    |
-LL | fn p2<T>(v: Box<T>) -> Box<dyn X + 'static>
-   |       - help: consider adding an explicit lifetime bound...: `T: 'static`
-...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn p2<T: 'static>(v: Box<T>) -> Box<dyn X + 'static>
+   |        +++++++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:22:5
    |
-LL | fn p3<'a,T>(v: T) -> Box<dyn X + 'a>
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     where T : X + 'a
+   |                 ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-param-into-object.rs:28:5
    |
-LL | fn p4<'a,T>(v: Box<T>) -> Box<dyn X + 'a>
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
-...
 LL |     Box::new(v)
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn p4<'a,T: 'a>(v: Box<T>) -> Box<dyn X + 'a>
+   |           ++++
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs
index f464cab7554..7c2e1aeeea6 100644
--- a/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs
+++ b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs
@@ -9,7 +9,7 @@
 //     'a : 'b
 
 fn test<'a,'b>(x: &'a i32) -> &'b i32
-    where 'a: 'static
+    where 'a: 'static //~ WARN unnecessary lifetime parameter `'a`
 {
     x
 }
diff --git a/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr
new file mode 100644
index 00000000000..70ed418d5cb
--- /dev/null
+++ b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr
@@ -0,0 +1,10 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:12:11
+   |
+LL |     where 'a: 'static
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr
index ef68674a18f..85ced4b5241 100644
--- a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr
@@ -1,11 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-implied-bounds-projection-gap-1.rs:20:10
    |
-LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
-   |             -- help: consider adding an explicit lifetime bound...: `T: 'x +`
-LL | {
 LL |     wf::<&'x T>();
    |          ^^^^^ ...so that the reference type `&'x T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn func<'x, T:Trait1<'x> + 'x>(t: &'x T::Foo)
+   |                          ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr
index 6d63de6d6bd..1a428eb25d7 100644
--- a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr
@@ -1,11 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-implied-bounds-projection-gap-1.rs:20:5
    |
-LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo)
-   |             -- help: consider adding an explicit lifetime bound...: `T: 'x +`
-LL | {
 LL |     wf::<&'x T>();
    |     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn func<'x, T:Trait1<'x> + 'x>(t: &'x T::Foo)
+   |                          ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr
index 6a7e8ba1347..658740f3f87 100644
--- a/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr
+++ b/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr
@@ -1,8 +1,6 @@
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-infer-bound-from-trait.rs:37:5
    |
-LL | fn bar1<'a,A>(x: Inv<'a>, a: A) {
-   |            - help: consider adding an explicit lifetime bound...: `A: 'a`
 LL |     check_bound(x, a)
    |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
    |
@@ -11,12 +9,14 @@ note: ...that is required by this bound
    |
 LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
    |                     ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bar1<'a,A: 'a>(x: Inv<'a>, a: A) {
+   |             ++++
 
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-infer-bound-from-trait.rs:41:5
    |
-LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) {
-   |               -- help: consider adding an explicit lifetime bound...: `A: 'a +`
 LL |     check_bound(x, a)
    |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds...
    |
@@ -25,6 +25,10 @@ note: ...that is required by this bound
    |
 LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { }
    |                     ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bar2<'a,'b,A:Is<'b> + 'a>(x: Inv<'a>, y: Inv<'b>, a: A) {
+   |                        ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr
index 4aa4b468eaa..5cc2d20c2e0 100644
--- a/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr
+++ b/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr
@@ -1,18 +1,24 @@
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-infer-bound-from-trait.rs:37:5
    |
-LL | fn bar1<'a,A>(x: Inv<'a>, a: A) {
-   |            - help: consider adding an explicit lifetime bound...: `A: 'a`
 LL |     check_bound(x, a)
    |     ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bar1<'a,A: 'a>(x: Inv<'a>, a: A) {
+   |             ++++
 
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-infer-bound-from-trait.rs:41:5
    |
-LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) {
-   |               -- help: consider adding an explicit lifetime bound...: `A: 'a +`
 LL |     check_bound(x, a)
    |     ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bar2<'a,'b,A:Is<'b> + 'a>(x: Inv<'a>, y: Inv<'b>, a: A) {
+   |                        ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/regions/regions-static-bound-rpass.rs b/src/test/ui/regions/regions-static-bound-rpass.rs
index c91c6f87493..25232b455b6 100644
--- a/src/test/ui/regions/regions-static-bound-rpass.rs
+++ b/src/test/ui/regions/regions-static-bound-rpass.rs
@@ -1,10 +1,17 @@
 // run-pass
+
 fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a ()
     where 'a: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'a`
+
 fn static_id<'a>(t: &'a ()) -> &'static ()
     where 'a: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'a`
+
 fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
     where 'a: 'b, 'b: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'b`
+
 fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t }
 
 static UNIT: () = ();
diff --git a/src/test/ui/regions/regions-static-bound-rpass.stderr b/src/test/ui/regions/regions-static-bound-rpass.stderr
new file mode 100644
index 00000000000..9355a409d50
--- /dev/null
+++ b/src/test/ui/regions/regions-static-bound-rpass.stderr
@@ -0,0 +1,26 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-static-bound-rpass.rs:4:11
+   |
+LL |     where 'a: 'static { t }
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-static-bound-rpass.rs:8:11
+   |
+LL |     where 'a: 'static { t }
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'b`
+  --> $DIR/regions-static-bound-rpass.rs:12:19
+   |
+LL |     where 'a: 'b, 'b: 'static { t }
+   |                   ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'b`
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/regions/regions-static-bound.base.stderr b/src/test/ui/regions/regions-static-bound.base.stderr
index b37ce1e76bd..6b8120444d0 100644
--- a/src/test/ui/regions/regions-static-bound.base.stderr
+++ b/src/test/ui/regions/regions-static-bound.base.stderr
@@ -1,18 +1,34 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-static-bound.rs:6:11
+   |
+LL |     where 'a: 'static { t }
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'b`
+  --> $DIR/regions-static-bound.rs:10:19
+   |
+LL |     where 'a: 'b, 'b: 'static { t }
+   |                   ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'b`
+
 error[E0312]: lifetime of reference outlives lifetime of borrowed content...
-  --> $DIR/regions-static-bound.rs:10:5
+  --> $DIR/regions-static-bound.rs:14:5
    |
 LL |     t
    |     ^
    |
    = note: ...the reference is valid for the static lifetime...
 note: ...but the borrowed content is only valid for the lifetime `'a` as defined here
-  --> $DIR/regions-static-bound.rs:9:24
+  --> $DIR/regions-static-bound.rs:13:24
    |
 LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
    |                        ^^
 
 error[E0759]: `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-static-bound.rs:16:5
+  --> $DIR/regions-static-bound.rs:20:5
    |
 LL | fn error(u: &(), v: &()) {
    |             --- this data with an anonymous lifetime `'_`...
@@ -20,13 +36,13 @@ LL |     static_id(&u);
    |     ^^^^^^^^^ -- ...is used here...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/regions-static-bound.rs:16:5
+  --> $DIR/regions-static-bound.rs:20:5
    |
 LL |     static_id(&u);
    |     ^^^^^^^^^
 
 error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-static-bound.rs:19:5
+  --> $DIR/regions-static-bound.rs:23:5
    |
 LL | fn error(u: &(), v: &()) {
    |                     --- this data with an anonymous lifetime `'_`...
@@ -35,12 +51,12 @@ LL |     static_id_indirect(&v);
    |     ^^^^^^^^^^^^^^^^^^ -- ...is used here...
    |
 note: ...and is required to live as long as `'static` here
-  --> $DIR/regions-static-bound.rs:19:5
+  --> $DIR/regions-static-bound.rs:23:5
    |
 LL |     static_id_indirect(&v);
    |     ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 3 previous errors; 2 warnings emitted
 
 Some errors have detailed explanations: E0312, E0759.
 For more information about an error, try `rustc --explain E0312`.
diff --git a/src/test/ui/regions/regions-static-bound.nll.stderr b/src/test/ui/regions/regions-static-bound.nll.stderr
index d228c42f995..68e36f3aeea 100644
--- a/src/test/ui/regions/regions-static-bound.nll.stderr
+++ b/src/test/ui/regions/regions-static-bound.nll.stderr
@@ -1,5 +1,21 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/regions-static-bound.rs:6:11
+   |
+LL |     where 'a: 'static { t }
+   |           ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+warning: unnecessary lifetime parameter `'b`
+  --> $DIR/regions-static-bound.rs:10:19
+   |
+LL |     where 'a: 'b, 'b: 'static { t }
+   |                   ^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'b`
+
 error: lifetime may not live long enough
-  --> $DIR/regions-static-bound.rs:10:5
+  --> $DIR/regions-static-bound.rs:14:5
    |
 LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
    |                        -- lifetime `'a` defined here
@@ -7,7 +23,7 @@ LL |     t
    |     ^ returning this value requires that `'a` must outlive `'static`
 
 error[E0521]: borrowed data escapes outside of function
-  --> $DIR/regions-static-bound.rs:16:5
+  --> $DIR/regions-static-bound.rs:20:5
    |
 LL | fn error(u: &(), v: &()) {
    |          -  - let's call the lifetime of this reference `'1`
@@ -20,7 +36,7 @@ LL |     static_id(&u);
    |     argument requires that `'1` must outlive `'static`
 
 error[E0521]: borrowed data escapes outside of function
-  --> $DIR/regions-static-bound.rs:19:5
+  --> $DIR/regions-static-bound.rs:23:5
    |
 LL | fn error(u: &(), v: &()) {
    |                  -  - let's call the lifetime of this reference `'2`
@@ -33,6 +49,6 @@ LL |     static_id_indirect(&v);
    |     `v` escapes the function body here
    |     argument requires that `'2` must outlive `'static`
 
-error: aborting due to 3 previous errors
+error: aborting due to 3 previous errors; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/regions/regions-static-bound.rs b/src/test/ui/regions/regions-static-bound.rs
index 058b717c95d..1eed7e71745 100644
--- a/src/test/ui/regions/regions-static-bound.rs
+++ b/src/test/ui/regions/regions-static-bound.rs
@@ -4,8 +4,12 @@
 
 fn static_id<'a,'b>(t: &'a ()) -> &'static ()
     where 'a: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'a`
+
 fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
     where 'a: 'b, 'b: 'static { t }
+//~^ WARN unnecessary lifetime parameter `'b`
+
 fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
     t
     //[base]~^ ERROR E0312
diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr
index 1f387a042e6..950ffd6c89b 100644
--- a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr
@@ -1,8 +1,6 @@
 error[E0310]: the parameter type `U` may not live long enough
   --> $DIR/dont-infer-static.rs:8:10
    |
-LL | struct Foo<U> {
-   |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
    |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds...
    |
@@ -11,6 +9,10 @@ note: ...that is required by this bound
    |
 LL | struct Bar<T: 'static> {
    |               ^^^^^^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<U: 'static> {
+   |             +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
index 553a3e71c16..2c660b28500 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
@@ -1,27 +1,35 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:17:18
    |
-LL | enum Ref1<'a, T> {
-   |               - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     Ref1Variant1(RequireOutlives<'a, T>),
    |                  ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | enum Ref1<'a, T: 'a> {
+   |                ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:22:25
    |
-LL | enum Ref2<'a, T> {
-   |               - help: consider adding an explicit lifetime bound...: `T: 'a`
-LL |     Ref2Variant1,
 LL |     Ref2Variant2(isize, RequireOutlives<'a, T>),
    |                         ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | enum Ref2<'a, T: 'a> {
+   |                ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-enum-not-wf.rs:35:23
    |
-LL | enum RefDouble<'a, 'b, T> {
-   |                        - help: consider adding an explicit lifetime bound...: `T: 'b`
 LL |     RefDoubleVariant1(&'a RequireOutlives<'b, T>),
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | enum RefDouble<'a, 'b, T: 'b> {
+   |                         ++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
index f8861262991..34ff1362cf3 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
@@ -1,16 +1,17 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-struct-not-wf.rs:13:16
    |
-LL | impl<'a, T> Trait<'a, T> for usize {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Out = &'a T;
    |                ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a, T> for usize {
+   |           ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/regions-struct-not-wf.rs:21:16
    |
-LL | impl<'a, T> Trait<'a, T> for u32 {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Out = RefOk<'a, T>;
    |                ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
@@ -19,6 +20,10 @@ note: ...that is required by this bound
    |
 LL | struct RefOk<'a, T:'a> {
    |                    ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a, T> for u32 {
+   |           ++++
 
 error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references
   --> $DIR/regions-struct-not-wf.rs:25:16
diff --git a/src/test/ui/static/static-lifetime-bound.stderr b/src/test/ui/static/static-lifetime-bound.stderr
index 79d9506619e..ef07a89315f 100644
--- a/src/test/ui/static/static-lifetime-bound.stderr
+++ b/src/test/ui/static/static-lifetime-bound.stderr
@@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a`
   --> $DIR/static-lifetime-bound.rs:1:6
    |
 LL | fn f<'a: 'static>(_: &'a i32) {}
-   |      ^^^^^^^^^^^
+   |      ^^
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
diff --git a/src/test/ui/suggestions/bound-suggestions.fixed b/src/test/ui/suggestions/bound-suggestions.fixed
index 31fdd2b67e2..17a019c6984 100644
--- a/src/test/ui/suggestions/bound-suggestions.fixed
+++ b/src/test/ui/suggestions/bound-suggestions.fixed
@@ -35,7 +35,7 @@ fn test_one_bound_where<X>(x: X) where X: Sized + std::fmt::Debug {
 }
 
 #[allow(dead_code)]
-fn test_many_bounds_where<X>(x: X) where X: Sized, X: Sized, X: std::fmt::Debug {
+fn test_many_bounds_where<X>(x: X) where X: Sized + std::fmt::Debug, X: Sized {
     println!("{:?}", x);
     //~^ ERROR doesn't implement
 }
diff --git a/src/test/ui/suggestions/bound-suggestions.stderr b/src/test/ui/suggestions/bound-suggestions.stderr
index 04f233a1e87..e5e19444d24 100644
--- a/src/test/ui/suggestions/bound-suggestions.stderr
+++ b/src/test/ui/suggestions/bound-suggestions.stderr
@@ -65,10 +65,10 @@ LL |     println!("{:?}", x);
    |                      ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider further restricting type parameter `X`
+help: consider further restricting this bound
    |
-LL | fn test_many_bounds_where<X>(x: X) where X: Sized, X: Sized, X: std::fmt::Debug {
-   |                                                            ++++++++++++++++++++
+LL | fn test_many_bounds_where<X>(x: X) where X: Sized + std::fmt::Debug, X: Sized {
+   |                                                   +++++++++++++++++
 
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
   --> $DIR/bound-suggestions.rs:44:46
diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
index 6255df06efb..8ec7b7bf496 100644
--- a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
+++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
@@ -8,7 +8,7 @@ LL |     foo.hello();
 help: the following trait defines an item `hello`, perhaps you need to restrict type parameter `impl Foo` with it:
    |
 LL | fn test(foo: impl Foo + Bar) {
-   |              ~~~~~~~~~~~~~~
+   |                       +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/issue-21673.stderr b/src/test/ui/suggestions/issue-21673.stderr
index eda29f876d8..0a4aaa61bc7 100644
--- a/src/test/ui/suggestions/issue-21673.stderr
+++ b/src/test/ui/suggestions/issue-21673.stderr
@@ -7,8 +7,8 @@ LL |     x.method()
    = help: items from traits can only be used if the type parameter is bounded by the trait
 help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it:
    |
-LL | fn call_method<T: Foo + std::fmt::Debug>(x: &T) {
-   |                ~~~~~~~~
+LL | fn call_method<T: std::fmt::Debug + Foo>(x: &T) {
+   |                                   +++++
 
 error[E0599]: no method named `method` found for type parameter `T` in the current scope
   --> $DIR/issue-21673.rs:10:7
@@ -20,7 +20,7 @@ LL |     x.method()
 help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it:
    |
 LL | fn call_method_2<T: Foo>(x: T) {
-   |                  ~~~~~~
+   |                   +++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr
index d38d66c0885..0212c2d712c 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr
@@ -1,8 +1,6 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/missing-lifetimes-in-signature-2.rs:20:5
    |
-LL |   fn func<T: Test>(foo: &Foo, t: T) {
-   |           -- help: consider adding an explicit lifetime bound...: `T: 'a +`
 LL | /     foo.bar(move |_| {
 LL | |
 LL | |         t.test();
@@ -22,6 +20,10 @@ LL | |
 LL | |         t.test();
 LL | |     });
    | |______^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn func<T: Test + 'a>(foo: &Foo, t: T) {
+   |                 ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
index adb928aa8a3..5d195e5ff32 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
@@ -1,8 +1,6 @@
 error[E0311]: the parameter type `T` may not live long enough
   --> $DIR/missing-lifetimes-in-signature-2.rs:20:9
    |
-LL | fn func<T: Test>(foo: &Foo, t: T) {
-   |         -- help: consider adding an explicit lifetime bound...: `T: 'a +`
 LL |     foo.bar(move |_| {
    |         ^^^
    |
@@ -21,6 +19,10 @@ note: ...that is required by this bound
    |
 LL |         F: 'a,
    |            ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn func<T: Test + 'a>(foo: &Foo, t: T) {
+   |                 ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr
index e47f7dc3566..24eac64d334 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr
@@ -26,9 +26,6 @@ LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:31:5
    |
-LL |   fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
-   |          - help: consider adding an explicit lifetime bound...: `G: 'a`
-...
 LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
@@ -46,13 +43,14 @@ LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
    | |_____^
+help: consider adding an explicit lifetime bound...
+   |
+LL |     G: Get<T> + 'a,
+   |               ++++
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:53:5
    |
-LL |   fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
-   |              -- help: consider adding an explicit lifetime bound...: `G: 'b +`
-...
 LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
@@ -70,13 +68,14 @@ LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
    | |_____^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn qux<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                  ++++
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:62:9
    |
-LL |       fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
-   |                  -- help: consider adding an explicit lifetime bound...: `G: 'c +`
-LL |
 LL | /         move || {
 LL | |             *dest = g.get();
 LL | |         }
@@ -94,13 +93,14 @@ LL | /         move || {
 LL | |             *dest = g.get();
 LL | |         }
    | |_________^
+help: consider adding an explicit lifetime bound...
+   |
+LL |     fn qux<'b, G: Get<T> + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                               ++++
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:74:5
    |
-LL |   fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
-   |              -- help: consider adding an explicit lifetime bound...: `G: 'b +`
-...
 LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
@@ -118,6 +118,10 @@ LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
    | |_____^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn bat<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |                  ++++
 
 error[E0621]: explicit lifetime required in the type of `dest`
   --> $DIR/missing-lifetimes-in-signature.rs:74:5
@@ -133,13 +137,15 @@ LL | |     }
 error[E0309]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:85:5
    |
-LL |   fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
-   |              - help: consider adding an explicit lifetime bound...: `G: 'a`
-...
 LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
    | |_____^ ...so that the type `G` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     G: Get<T> + 'a,
+   |               ++++
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index 7526aadb38c..ae9a020a099 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -41,8 +41,11 @@ LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                     ^^^^^^^^^^^^^^^^^^
 help: consider introducing an explicit lifetime bound
    |
-LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
-   |        ~~~~~                                                   ++++
+LL ~ fn bar<'a, G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+LL |
+LL | where
+LL ~     G: Get<T> + 'a,
+   |
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:48:45
@@ -62,8 +65,8 @@ LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                             ^^^^^^^^^^^^^^^^^^
 help: consider introducing an explicit lifetime bound
    |
-LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b
-   |        +++     ~~~~~~~                                                  ++++
+LL | fn qux<'b, 'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b
+   |        +++           ++++                                               ++++
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:60:58
@@ -83,8 +86,8 @@ LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                                          ^^^^^^^^^^^^^^^^^^
 help: consider introducing an explicit lifetime bound
    |
-LL |     fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c {
-   |            +++     ~~~~~~~                                                           ++++
+LL |     fn qux<'c, 'b, G: Get<T> + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c {
+   |            +++                    ++++                                               ++++
 
 error[E0621]: explicit lifetime required in the type of `dest`
   --> $DIR/missing-lifetimes-in-signature.rs:69:45
@@ -98,9 +101,12 @@ error[E0309]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:80:44
    |
 LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
-   |            -                               ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:85:5: 87:6]` will meet its required lifetime bounds
-   |            |
-   |            help: consider adding an explicit lifetime bound...: `G: 'a`
+   |                                            ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:85:5: 87:6]` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL |     G: Get<T> + 'a,
+   |               ++++
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr
index 551a7c5060f..01c2de79864 100644
--- a/src/test/ui/suggestions/restrict-type-argument.stderr
+++ b/src/test/ui/suggestions/restrict-type-argument.stderr
@@ -85,8 +85,8 @@ LL | fn is_send<T: Send>(val: T) {}
    |               ^^^^ required by this bound in `is_send`
 help: consider further restricting this bound
    |
-LL | fn use_bound_and_where<S: Sync>(val: S) where S: std::fmt::Debug + std::marker::Send {
-   |                                                                  +++++++++++++++++++
+LL | fn use_bound_and_where<S: Sync + std::marker::Send>(val: S) where S: std::fmt::Debug {
+   |                                +++++++++++++++++++
 
 error[E0277]: `S` cannot be sent between threads safely
   --> $DIR/restrict-type-argument.rs:28:13
diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr b/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr
index 72354eaaee1..cf912f4aac2 100644
--- a/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr
+++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr
@@ -1,11 +1,13 @@
 error[E0310]: the parameter type `impl Debug` may not live long enough
   --> $DIR/suggest-impl-trait-lifetime.rs:7:5
    |
-LL | fn foo(d: impl Debug) {
-   |           ---------- help: consider adding an explicit lifetime bound...: `impl Debug + 'static`
-LL |
 LL |     bar(d);
    |     ^^^^^^ ...so that the type `impl Debug` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo(d: impl Debug + 'static) {
+   |                      +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr b/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr
index e4a247993c2..4a99c3a14d7 100644
--- a/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr
+++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr
@@ -1,9 +1,6 @@
 error[E0310]: the parameter type `impl Debug` may not live long enough
   --> $DIR/suggest-impl-trait-lifetime.rs:7:5
    |
-LL | fn foo(d: impl Debug) {
-   |           ---------- help: consider adding an explicit lifetime bound...: `impl Debug + 'static`
-LL |
 LL |     bar(d);
    |     ^^^ ...so that the type `impl Debug` will meet its required lifetime bounds...
    |
@@ -12,6 +9,10 @@ note: ...that is required by this bound
    |
 LL | fn bar(d: impl Debug + 'static) {
    |                        ^^^^^^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo(d: impl Debug + 'static) {
+   |                      +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr b/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr
index cb1128fe5c6..35d41c62667 100644
--- a/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr
+++ b/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr
@@ -7,8 +7,8 @@ LL |     t.foo()
    = help: items from traits can only be used if the type parameter is bounded by the trait
 help: the following trait defines an item `foo`, perhaps you need to restrict type parameter `T` with it:
    |
-LL | fn do_stuff<T: Foo + Bar>(t : T) {
-   |             ~~~~~~~~
+LL | fn do_stuff<T : Bar + Foo>(t : T) {
+   |                     +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/issue-95898.stderr b/src/test/ui/traits/issue-95898.stderr
index d7d47905396..0a58ad4b663 100644
--- a/src/test/ui/traits/issue-95898.stderr
+++ b/src/test/ui/traits/issue-95898.stderr
@@ -8,7 +8,7 @@ LL |     t.clone();
 help: the following trait defines an item `clone`, perhaps you need to restrict type parameter `T` with it:
    |
 LL | fn foo<T: Clone>(t: T) {
-   |        ~~~~~~~~
+   |           +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
index d87ef2ec79c..920eef11da4 100644
--- a/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
+++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
@@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a`
   --> $DIR/bounds-are-checked.rs:8:6
    |
 LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
-   |      ^^^^^^^^^^^
+   |      ^^
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr
index a3b410c2cfb..593fb8af32f 100644
--- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr
@@ -19,10 +19,13 @@ LL | type WrongGeneric<T> = impl 'static;
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/generic_type_does_not_live_long_enough.rs:18:5
    |
-LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
-   |                  - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     t
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn wrong_generic<T: 'static>(t: T) -> WrongGeneric<T> {
+   |                   +++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
index a3b410c2cfb..593fb8af32f 100644
--- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
@@ -19,10 +19,13 @@ LL | type WrongGeneric<T> = impl 'static;
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/generic_type_does_not_live_long_enough.rs:18:5
    |
-LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
-   |                  - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     t
    |     ^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn wrong_generic<T: 'static>(t: T) -> WrongGeneric<T> {
+   |                   +++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/wf/wf-impl-associated-type-region.stderr b/src/test/ui/wf/wf-impl-associated-type-region.stderr
index 3f324190b7b..b9d4857a3ef 100644
--- a/src/test/ui/wf/wf-impl-associated-type-region.stderr
+++ b/src/test/ui/wf/wf-impl-associated-type-region.stderr
@@ -1,10 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-impl-associated-type-region.rs:10:16
    |
-LL | impl<'a, T> Foo<'a> for T {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Bar = &'a T;
    |                ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Foo<'a> for T {
+   |           ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-in-fn-type-static.stderr b/src/test/ui/wf/wf-in-fn-type-static.stderr
index 44cacf4ef4d..73fbb9ca670 100644
--- a/src/test/ui/wf/wf-in-fn-type-static.stderr
+++ b/src/test/ui/wf/wf-in-fn-type-static.stderr
@@ -1,20 +1,24 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-fn-type-static.rs:13:8
    |
-LL | struct Foo<T> {
-   |            - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // needs T: 'static
 LL |     x: fn() -> &'static T
    |        ^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<T: 'static> {
+   |             +++++++++
 
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-fn-type-static.rs:18:8
    |
-LL | struct Bar<T> {
-   |            - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // needs T: Copy
 LL |     x: fn(&'static T)
    |        ^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Bar<T: 'static> {
+   |             +++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/wf/wf-in-obj-type-static.stderr b/src/test/ui/wf/wf-in-obj-type-static.stderr
index c50a6bb6e4d..c3ad42dd5d5 100644
--- a/src/test/ui/wf/wf-in-obj-type-static.stderr
+++ b/src/test/ui/wf/wf-in-obj-type-static.stderr
@@ -1,11 +1,13 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/wf-in-obj-type-static.rs:14:8
    |
-LL | struct Foo<T> {
-   |            - help: consider adding an explicit lifetime bound...: `T: 'static`
-LL |     // needs T: 'static
 LL |     x: dyn Object<&'static T>
    |        ^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | struct Foo<T: 'static> {
+   |             +++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr
index 68c1e9091d7..4d4d8b2ab4d 100644
--- a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr
+++ b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr
@@ -1,18 +1,24 @@
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:9:16
    |
-LL | impl<'a, T> Trait<'a, T> for usize {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Out = &'a fn(T);
    |                ^^^^^^^^^ ...so that the reference type `&'a fn(T)` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a, T> for usize {
+   |           ++++
 
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:19:16
    |
-LL | impl<'a, T> Trait<'a, T> for u32 {
-   |          - help: consider adding an explicit lifetime bound...: `T: 'a`
 LL |     type Out = &'a dyn Baz<T>;
    |                ^^^^^^^^^^^^^^ ...so that the reference type `&'a (dyn Baz<T> + 'a)` does not outlive the data it points at
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a, T> for u32 {
+   |           ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index b09c23f31e9..662a561f171 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -8,7 +8,7 @@ use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
     BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
     ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier,
-    TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
+    TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -130,7 +130,7 @@ fn check_fn_inner<'tcx>(
     span: Span,
     report_extra_lifetimes: bool,
 ) {
-    if span.from_expansion() || has_where_lifetimes(cx, &generics.where_clause) {
+    if span.from_expansion() || has_where_lifetimes(cx, generics) {
         return;
     }
 
@@ -139,28 +139,35 @@ fn check_fn_inner<'tcx>(
         .iter()
         .filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
     for typ in types {
-        for bound in typ.bounds {
-            let mut visitor = RefVisitor::new(cx);
-            walk_param_bound(&mut visitor, bound);
-            if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
-                return;
+        for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
+            if pred.in_where_clause {
+                // has_where_lifetimes checked that this predicate contains no lifetime.
+                continue;
             }
-            if let GenericBound::Trait(ref trait_ref, _) = *bound {
-                let params = &trait_ref
-                    .trait_ref
-                    .path
-                    .segments
-                    .last()
-                    .expect("a path must have at least one segment")
-                    .args;
-                if let Some(params) = *params {
-                    let lifetimes = params.args.iter().filter_map(|arg| match arg {
-                        GenericArg::Lifetime(lt) => Some(lt),
-                        _ => None,
-                    });
-                    for bound in lifetimes {
-                        if bound.name != LifetimeName::Static && !bound.is_elided() {
-                            return;
+
+            for bound in pred.bounds {
+                let mut visitor = RefVisitor::new(cx);
+                walk_param_bound(&mut visitor, bound);
+                if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
+                    return;
+                }
+                if let GenericBound::Trait(ref trait_ref, _) = *bound {
+                    let params = &trait_ref
+                        .trait_ref
+                        .path
+                        .segments
+                        .last()
+                        .expect("a path must have at least one segment")
+                        .args;
+                    if let Some(params) = *params {
+                        let lifetimes = params.args.iter().filter_map(|arg| match arg {
+                            GenericArg::Lifetime(lt) => Some(lt),
+                            _ => None,
+                        });
+                        for bound in lifetimes {
+                            if bound.name != LifetimeName::Static && !bound.is_elided() {
+                                return;
+                            }
                         }
                     }
                 }
@@ -322,9 +329,7 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
     let mut allowed_lts = FxHashSet::default();
     for par in named_generics.iter() {
         if let GenericParamKind::Lifetime { .. } = par.kind {
-            if par.bounds.is_empty() {
-                allowed_lts.insert(RefLt::Named(par.name.ident().name));
-            }
+            allowed_lts.insert(RefLt::Named(par.name.ident().name));
         }
     }
     allowed_lts.insert(RefLt::Unnamed);
@@ -445,8 +450,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
 
 /// Are any lifetimes mentioned in the `where` clause? If so, we don't try to
 /// reason about elision.
-fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereClause<'_>) -> bool {
-    for predicate in where_clause.predicates {
+fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) -> bool {
+    for predicate in generics.predicates {
         match *predicate {
             WherePredicate::RegionPredicate(..) => return true,
             WherePredicate::BoundPredicate(ref pred) => {
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 9419056be14..96c00c205ff 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
             ..
         }) = item.kind
         {
-            for assoc_item in items {
+            for assoc_item in *items {
                 if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) {
                     let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
                     if in_external_macro(cx.sess(), impl_item.span) {
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index e827cdaae87..1469cb434c0 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
             if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
             if trait_ref.path.res.def_id() == eq_trait;
             then {
-                for impl_item in impl_items {
+                for impl_item in *impl_items {
                     if impl_item.ident.name == sym::ne {
                         span_lint_hir(
                             cx,
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index 398e2c200de..fc1c2af9257 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for SerdeApi {
                 if did == visit_did {
                     let mut seen_str = None;
                     let mut seen_string = None;
-                    for item in items {
+                    for item in *items {
                         match item.ident.as_str() {
                             "visit_str" => seen_str = Some(item.span),
                             "visit_string" => seen_string = Some(item.span),
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 43e0132a7ec..3d1b2ee925b 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -8,8 +8,7 @@ use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty, TyKind,
-    WherePredicate,
+    GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, QPath, TraitItem, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -90,10 +89,9 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
-        let Generics { where_clause, .. } = &item.generics;
         let mut self_bounds_map = FxHashMap::default();
 
-        for predicate in where_clause.predicates {
+        for predicate in item.generics.predicates {
             if_chain! {
                 if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
                 if !bound_predicate.span.from_expansion();
@@ -166,7 +164,7 @@ impl TraitBounds {
         }
         let mut map: UnhashMap<SpanlessTy<'_, '_>, Vec<&GenericBound<'_>>> = UnhashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
-        for bound in gen.where_clause.predicates {
+        for bound in gen.predicates {
             if_chain! {
                 if let WherePredicate::BoundPredicate(ref p) = bound;
                 if p.bounds.len() as u64 <= self.max_trait_bounds;
@@ -216,34 +214,23 @@ impl TraitBounds {
 }
 
 fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
-    if gen.span.from_expansion() || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
+    if gen.span.from_expansion() || gen.params.is_empty() || gen.predicates.is_empty() {
         return;
     }
 
-    let mut map = FxHashMap::default();
-    for param in gen.params {
-        if let ParamName::Plain(ref ident) = param.name {
-            let res = param
-                .bounds
-                .iter()
-                .filter_map(get_trait_info_from_bound)
-                .collect::<Vec<_>>();
-            map.insert(*ident, res);
-        }
-    }
-
-    for predicate in gen.where_clause.predicates {
+    let mut map = FxHashMap::<_, Vec<_>>::default();
+    for predicate in gen.predicates {
         if_chain! {
             if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
             if !bound_predicate.span.from_expansion();
             if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
             if let Some(segment) = segments.first();
-            if let Some(trait_resolutions_direct) = map.get(&segment.ident);
             then {
-                for (res_where, _,  _) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
-                    if let Some((_, _, span_direct)) = trait_resolutions_direct
+                for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
+                    let trait_resolutions_direct = map.entry(segment.ident).or_default();
+                    if let Some((_, span_direct)) = trait_resolutions_direct
                                                 .iter()
-                                                .find(|(res_direct, _, _)| *res_direct == res_where) {
+                                                .find(|(res_direct, _)| *res_direct == res_where) {
                         span_lint_and_help(
                             cx,
                             TRAIT_DUPLICATION_IN_BOUNDS,
@@ -253,6 +240,9 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
                             "consider removing this trait bound",
                         );
                     }
+                    else {
+                        trait_resolutions_direct.push((res_where, span_where))
+                    }
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index 7c06906293b..f35f44eda56 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -104,8 +104,10 @@ fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id:
         if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
         if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
         if synthetic;
+        if let Some(generics) = cx.tcx.hir().get_generics(id.owner);
+        if let Some(pred) = generics.bounds_for_param(did.expect_local()).next();
         then {
-            Some(generic_param.bounds)
+            Some(pred.bounds)
         } else {
             None
         }
diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
index ebdb8e74952..9143fb2c208 100644
--- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr
@@ -7,12 +7,6 @@ LL | fn unused_lt<'a>(x: u8) {}
    = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings`
 
 error: this lifetime isn't used in the function definition
-  --> $DIR/extra_unused_lifetimes.rs:16:25
-   |
-LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) {
-   |                         ^^
-
-error: this lifetime isn't used in the function definition
   --> $DIR/extra_unused_lifetimes.rs:41:10
    |
 LL |     fn x<'a>(&self) {}
@@ -24,5 +18,5 @@ error: this lifetime isn't used in the function definition
 LL |         fn unused_lt<'a>(x: u8) {}
    |                      ^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
index ffa152427a9..a488bc01fff 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
@@ -109,12 +109,6 @@ LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:307:5
-   |
-LL |     fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
   --> $DIR/needless_lifetimes.rs:310:5
    |
 LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
@@ -192,5 +186,5 @@ error: explicit lifetimes given in parameter types where they could be elided (o
 LL |         fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 32 previous errors
+error: aborting due to 31 previous errors