about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-07-25 20:02:55 +0000
committerbors <bors@rust-lang.org>2022-07-25 20:02:55 +0000
commit6dbae3ad19309bb541d9e76638e6aa4b5449f29a (patch)
treea35d361e27036633b9422e60fae27c050e298ec8
parentbdf520fd419cd4dea184332f57206f1cf5ca3e8f (diff)
parentb9bd65e2ca68342bdb8ab56134677ad330d786ba (diff)
downloadrust-6dbae3ad19309bb541d9e76638e6aa4b5449f29a.tar.gz
rust-6dbae3ad19309bb541d9e76638e6aa4b5449f29a.zip
Auto merge of #97313 - cjgillot:ast-lifetimes-anon, r=petrochenkov
Resolve function lifetime elision on the AST

~Based on https://github.com/rust-lang/rust/pull/97720~

Lifetime elision for functions is purely syntactic in nature, so can be resolved on the AST.
This PR replicates the elision logic and diagnostics on the AST, and replaces HIR-based resolution by a `delay_span_bug`.

This refactor allows for more consistent diagnostics, which don't have to guess the original code from HIR.

r? `@petrochenkov`
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs1
-rw-r--r--compiler/rustc_hir/src/def.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs660
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs851
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs235
-rw-r--r--compiler/rustc_resolve/src/lib.rs1
-rw-r--r--src/test/ui/associated-type-bounds/elision.rs9
-rw-r--r--src/test/ui/associated-type-bounds/elision.stderr28
-rw-r--r--src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr7
-rw-r--r--src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr7
-rw-r--r--src/test/ui/async-await/issues/issue-63388-2.rs1
-rw-r--r--src/test/ui/async-await/issues/issue-63388-2.stderr19
-rw-r--r--src/test/ui/c-variadic/variadic-ffi-6.stderr4
-rw-r--r--src/test/ui/error-codes/E0106.stderr22
-rw-r--r--src/test/ui/error-codes/E0637.stderr12
-rw-r--r--src/test/ui/foreign-fn-return-lifetime.stderr2
-rw-r--r--src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs3
-rw-r--r--src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr24
-rw-r--r--src/test/ui/generic-associated-types/issue-70304.rs1
-rw-r--r--src/test/ui/generic-associated-types/issue-70304.stderr17
-rw-r--r--src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs1
-rw-r--r--src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr42
-rw-r--r--src/test/ui/generics/wrong-number-of-args.rs9
-rw-r--r--src/test/ui/generics/wrong-number-of-args.stderr429
-rw-r--r--src/test/ui/impl-header-lifetime-elision/assoc-type.rs4
-rw-r--r--src/test/ui/impl-header-lifetime-elision/assoc-type.stderr20
-rw-r--r--src/test/ui/issues/issue-13497.stderr2
-rw-r--r--src/test/ui/issues/issue-19707.stderr1
-rw-r--r--src/test/ui/issues/issue-30255.stderr12
-rw-r--r--src/test/ui/lifetimes/issue-26638.rs3
-rw-r--r--src/test/ui/lifetimes/issue-26638.stderr52
-rw-r--r--src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr18
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs2
-rw-r--r--src/test/ui/lifetimes/missing-lifetime-in-alias.stderr6
-rw-r--r--src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs1
-rw-r--r--src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr22
-rw-r--r--src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs2
-rw-r--r--src/test/ui/rfc1623-2.rs1
-rw-r--r--src/test/ui/rfc1623-2.stderr12
-rw-r--r--src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr1
-rw-r--r--src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr36
-rw-r--r--src/test/ui/suggestions/impl-trait-missing-lifetime.rs5
-rw-r--r--src/test/ui/suggestions/impl-trait-missing-lifetime.stderr34
-rw-r--r--src/test/ui/suggestions/issue-86667.rs1
-rw-r--r--src/test/ui/suggestions/issue-86667.stderr13
-rw-r--r--src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr16
-rw-r--r--src/test/ui/suggestions/missing-lifetime-specifier.rs16
-rw-r--r--src/test/ui/suggestions/missing-lifetime-specifier.stderr158
-rw-r--r--src/test/ui/suggestions/missing-lt-for-hrtb.rs6
-rw-r--r--src/test/ui/suggestions/missing-lt-for-hrtb.stderr61
-rw-r--r--src/test/ui/suggestions/return-elided-lifetime.rs15
-rw-r--r--src/test/ui/suggestions/return-elided-lifetime.stderr155
-rw-r--r--src/test/ui/suggestions/return-without-lifetime.stderr6
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr5
-rw-r--r--src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs3
-rw-r--r--src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr11
-rw-r--r--src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr22
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs78
58 files changed, 1560 insertions, 1627 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 7cd360623ec..d4b41aad08c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1835,7 +1835,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         debug!(?self.captured_lifetimes);
         let name = match res {
             LifetimeRes::Param { mut param, binder } => {
-                debug_assert_ne!(ident.name, kw::UnderscoreLifetime);
                 let p_name = ParamName::Plain(ident);
                 if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
                     if !captured_lifetimes.binders_to_ignore.contains(&binder) {
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index d0893cd09d8..c0d5d2bc46d 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -713,7 +713,7 @@ impl<Id> Res<Id> {
 }
 
 /// Resolution for a lifetime appearing in a type.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum LifetimeRes {
     /// Successfully linked the lifetime to a generic parameter.
     Param {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index e739ed678d8..9b5fd4ea6d1 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -21,6 +21,7 @@ use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_middle::middle::resolve_lifetime::Set1;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -43,6 +44,10 @@ type IdentMap<T> = FxHashMap<Ident, T>;
 /// Map from the name in a pattern to its binding mode.
 type BindingMap = IdentMap<BindingInfo>;
 
+use diagnostics::{
+    ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind,
+};
+
 #[derive(Copy, Clone, Debug)]
 struct BindingInfo {
     span: Span,
@@ -258,7 +263,13 @@ enum LifetimeRibKind {
     AnonymousReportError,
 
     /// Pass responsibility to `resolve_lifetime` code for all cases.
-    AnonymousPassThrough(NodeId, /* in_fn_return */ bool),
+    AnonymousPassThrough(NodeId),
+
+    /// Replace all anonymous lifetimes by provided lifetime.
+    Elided(LifetimeRes),
+
+    /// Signal we cannot find which should be the anonymous lifetime.
+    ElisionFailure,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -522,6 +533,10 @@ struct DiagnosticMetadata<'ast> {
 
     /// When processing impl trait
     currently_processing_impl_trait: Option<(TraitRef, Ty)>,
+
+    /// Accumulate the errors due to missed lifetime elision,
+    /// and report them all at once for each function.
+    current_elision_failures: Vec<MissingLifetime>,
 }
 
 struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -540,6 +555,13 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
     /// The current set of local scopes for lifetimes.
     lifetime_ribs: Vec<LifetimeRib>,
 
+    /// We are looking for lifetimes in an elision context.
+    /// The set contains all the resolutions that we encountered so far.
+    /// They will be used to determine the correct lifetime for the fn return type.
+    /// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named
+    /// lifetimes.
+    lifetime_elision_candidates: Option<FxIndexMap<LifetimeRes, LifetimeElisionCandidate>>,
+
     /// The trait that the current context can refer to.
     current_trait_ref: Option<(Module<'a>, TraitRef)>,
 
@@ -580,7 +602,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
     fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
         // We deal with repeat expressions explicitly in `resolve_expr`.
         self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
-            this.resolve_anon_const(constant, IsRepeatExpr::No);
+            this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
+                this.resolve_anon_const(constant, IsRepeatExpr::No);
+            })
         })
     }
     fn visit_expr(&mut self, expr: &'ast Expr) {
@@ -607,8 +631,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             TyKind::Rptr(None, _) => {
                 // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
                 // NodeId `ty.id`.
+                // This span will be used in case of elision failure.
                 let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
                 self.resolve_elided_lifetime(ty.id, span);
+                visit::walk_ty(self, ty);
             }
             TyKind::Path(ref qself, ref path) => {
                 self.diagnostic_metadata.current_type_path = Some(ty);
@@ -634,8 +660,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                         },
                         |this| this.visit_path(&path, ty.id),
                     );
-                    self.diagnostic_metadata.current_type_path = prev_ty;
-                    return;
+                } else {
+                    visit::walk_ty(self, ty)
                 }
             }
             TyKind::ImplicitSelf => {
@@ -649,9 +675,16 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                     )
                     .map_or(Res::Err, |d| d.res());
                 self.r.record_partial_res(ty.id, PartialRes::new(res));
+                visit::walk_ty(self, ty)
+            }
+            TyKind::ImplTrait(..) => {
+                let candidates = self.lifetime_elision_candidates.take();
+                visit::walk_ty(self, ty);
+                self.lifetime_elision_candidates = candidates;
             }
             TyKind::TraitObject(ref bounds, ..) => {
                 self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
+                visit::walk_ty(self, ty)
             }
             TyKind::BareFn(ref bare_fn) => {
                 let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo());
@@ -665,25 +698,20 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                     },
                     |this| {
                         this.visit_generic_params(&bare_fn.generic_params, false);
-                        this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousCreateParameter {
-                                binder: ty.id,
-                                report_in_path: false,
-                            },
-                            |this| walk_list!(this, visit_param, &bare_fn.decl.inputs),
-                        );
-                        this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(ty.id, true),
-                            |this| this.visit_fn_ret_ty(&bare_fn.decl.output),
+                        this.resolve_fn_signature(
+                            ty.id,
+                            None,
+                            false,
+                            // We don't need to deal with patterns in parameters, because
+                            // they are not possible for foreign or bodiless functions.
+                            bare_fn.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
+                            &bare_fn.decl.output,
                         );
                     },
-                );
-                self.diagnostic_metadata.current_trait_object = prev;
-                return;
+                )
             }
-            _ => (),
+            _ => visit::walk_ty(self, ty),
         }
-        visit::walk_ty(self, ty);
         self.diagnostic_metadata.current_trait_object = prev;
         self.diagnostic_metadata.current_type_path = prev_ty;
     }
@@ -757,18 +785,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             | FnKind::Fn(_, _, sig, _, generics, None) => {
                 self.visit_fn_header(&sig.header);
                 self.visit_generics(generics);
-                // We don't need to deal with patterns in parameters, because
-                // they are not possible for foreign or bodiless functions.
-                self.with_lifetime_rib(
-                    LifetimeRibKind::AnonymousCreateParameter {
-                        binder: fn_id,
-                        report_in_path: false,
-                    },
-                    |this| walk_list!(this, visit_param, &sig.decl.inputs),
-                );
-                self.with_lifetime_rib(
-                    LifetimeRibKind::AnonymousPassThrough(fn_id, true),
-                    |this| this.visit_fn_ret_ty(&sig.decl.output),
+                self.resolve_fn_signature(
+                    fn_id,
+                    None,
+                    sig.decl.has_self(),
+                    sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
+                    &sig.decl.output,
                 );
                 return;
             }
@@ -793,19 +815,15 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                         let declaration = &sig.decl;
                         let async_node_id = sig.header.asyncness.opt_return_id();
 
-                        // Argument-position elided lifetimes must be transformed into fresh
-                        // generic parameters.  This is especially useful for `async fn`, where
-                        // these fresh generic parameters can be applied to the opaque `impl Trait`
-                        // return type.
-                        this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousCreateParameter {
-                                binder: fn_id,
-                                // Only emit a hard error for `async fn`, since this kind of
-                                // elision has always been allowed in regular `fn`s.
-                                report_in_path: async_node_id.is_some(),
-                            },
-                            // Add each argument to the rib.
-                            |this| this.resolve_params(&declaration.inputs),
+                        this.resolve_fn_signature(
+                            fn_id,
+                            async_node_id,
+                            declaration.has_self(),
+                            declaration
+                                .inputs
+                                .iter()
+                                .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)),
+                            &declaration.output,
                         );
 
                         // Construct the list of in-scope lifetime parameters for async lowering.
@@ -844,23 +862,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                                 .insert(async_node_id, extra_lifetime_params);
                         }
 
-                        this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(
-                                // For async fn, the return type appears inside a custom
-                                // `impl Future` RPIT, so we override the binder's id.
-                                async_node_id.unwrap_or(fn_id),
-                                true,
-                            ),
-                            |this| visit::walk_fn_ret_ty(this, &declaration.output),
-                        );
-
                         if let Some(body) = body {
                             // Ignore errors in function bodies if this is rustdoc
                             // Be sure not to set this until the function signature has been resolved.
                             let previous_state = replace(&mut this.in_func_body, true);
                             // Resolve the function body, potentially inside the body of an async closure
                             this.with_lifetime_rib(
-                                LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                                LifetimeRibKind::AnonymousPassThrough(fn_id),
                                 |this| this.visit_block(body),
                             );
 
@@ -888,7 +896,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                         this.with_lifetime_rib(
                             match binder {
                                 ClosureBinder::NotPresent => {
-                                    LifetimeRibKind::AnonymousPassThrough(fn_id, true)
+                                    LifetimeRibKind::AnonymousPassThrough(fn_id)
                                 }
                                 ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
                             },
@@ -900,7 +908,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                         let previous_state = replace(&mut this.in_func_body, true);
                         // Resolve the function body, potentially inside the body of an async closure
                         this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                            LifetimeRibKind::AnonymousPassThrough(fn_id),
                             |this| this.visit_expr(body),
                         );
 
@@ -1030,16 +1038,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                                 kind: LifetimeBinderKind::PolyTrait,
                                 ..
                             } => {
-                                self.with_lifetime_rib(
-                                    LifetimeRibKind::AnonymousCreateParameter {
-                                        binder,
-                                        report_in_path: false,
-                                    },
-                                    |this| walk_list!(this, visit_ty, &p_args.inputs),
-                                );
-                                self.with_lifetime_rib(
-                                    LifetimeRibKind::AnonymousPassThrough(binder, true),
-                                    |this| visit::walk_fn_ret_ty(this, &p_args.output),
+                                self.resolve_fn_signature(
+                                    binder,
+                                    None,
+                                    false,
+                                    p_args.inputs.iter().map(|ty| (None, &**ty)),
+                                    &p_args.output,
                                 );
                                 break;
                             }
@@ -1052,6 +1056,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                             LifetimeRibKind::AnonymousPassThrough(..)
                             | LifetimeRibKind::AnonymousCreateParameter { .. }
                             | LifetimeRibKind::AnonymousReportError
+                            | LifetimeRibKind::Elided(_)
+                            | LifetimeRibKind::ElisionFailure
                             | LifetimeRibKind::AnonConst
                             | LifetimeRibKind::ConstGeneric => {}
                         }
@@ -1156,6 +1162,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             },
             label_ribs: Vec::new(),
             lifetime_ribs: Vec::new(),
+            lifetime_elision_candidates: None,
             current_trait_ref: None,
             diagnostic_metadata: Box::new(DiagnosticMetadata::default()),
             // errors at module scope should always be reported
@@ -1362,7 +1369,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         work: impl FnOnce(&mut Self) -> T,
     ) -> T {
         self.lifetime_ribs.push(LifetimeRib::new(kind));
+        let outer_elision_candidates = self.lifetime_elision_candidates.take();
         let ret = work(self);
+        self.lifetime_elision_candidates = outer_elision_candidates;
         self.lifetime_ribs.pop();
         ret
     }
@@ -1372,7 +1381,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         let ident = lifetime.ident;
 
         if ident.name == kw::StaticLifetime {
-            self.record_lifetime_res(lifetime.id, LifetimeRes::Static);
+            self.record_lifetime_res(
+                lifetime.id,
+                LifetimeRes::Static,
+                LifetimeElisionCandidate::Named,
+            );
             return;
         }
 
@@ -1385,7 +1398,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             let rib = &self.lifetime_ribs[i];
             let normalized_ident = ident.normalize_to_macros_2_0();
             if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
-                self.record_lifetime_res(lifetime.id, res);
+                self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
 
                 if let LifetimeRes::Param { param, .. } = res {
                     match self.lifetime_uses.entry(param) {
@@ -1399,15 +1412,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                     // Do not suggest eliding a lifetime where an anonymous
                                     // lifetime would be illegal.
                                     LifetimeRibKind::Item
-                                    | LifetimeRibKind::AnonymousPassThrough(_, true)
-                                    | LifetimeRibKind::AnonymousReportError => {
-                                        Some(LifetimeUseSet::Many)
-                                    }
+                                    | LifetimeRibKind::AnonymousReportError
+                                    | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
                                     // An anonymous lifetime is legal here, go ahead.
-                                    LifetimeRibKind::AnonymousPassThrough(_, false)
+                                    LifetimeRibKind::AnonymousPassThrough(_)
                                     | LifetimeRibKind::AnonymousCreateParameter { .. } => {
                                         Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
                                     }
+                                    // Only report if eliding the lifetime would have the same
+                                    // semantics.
+                                    LifetimeRibKind::Elided(r) => Some(if res == r {
+                                        LifetimeUseSet::One { use_span: ident.span, use_ctxt }
+                                    } else {
+                                        LifetimeUseSet::Many
+                                    }),
                                     LifetimeRibKind::Generics { .. }
                                     | LifetimeRibKind::ConstGeneric
                                     | LifetimeRibKind::AnonConst => None,
@@ -1429,12 +1447,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 LifetimeRibKind::Item => break,
                 LifetimeRibKind::ConstGeneric => {
                     self.emit_non_static_lt_in_const_generic_error(lifetime);
-                    self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
+                    self.record_lifetime_res(
+                        lifetime.id,
+                        LifetimeRes::Error,
+                        LifetimeElisionCandidate::Ignore,
+                    );
                     return;
                 }
                 LifetimeRibKind::AnonConst => {
                     self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
-                    self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
+                    self.record_lifetime_res(
+                        lifetime.id,
+                        LifetimeRes::Error,
+                        LifetimeElisionCandidate::Ignore,
+                    );
                     return;
                 }
                 _ => {}
@@ -1452,19 +1478,31 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         }
 
         self.emit_undeclared_lifetime_error(lifetime, outer_res);
-        self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
+        self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named);
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
     fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
         debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
 
+        let missing_lifetime = MissingLifetime {
+            id: lifetime.id,
+            span: lifetime.ident.span,
+            kind: if elided {
+                MissingLifetimeKind::Ampersand
+            } else {
+                MissingLifetimeKind::Underscore
+            },
+            count: 1,
+        };
+        let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
         for i in (0..self.lifetime_ribs.len()).rev() {
             let rib = &mut self.lifetime_ribs[i];
+            debug!(?rib.kind);
             match rib.kind {
                 LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
                     let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder);
-                    self.record_lifetime_res(lifetime.id, res);
+                    self.record_lifetime_res(lifetime.id, res, elision_candidate);
                     return;
                 }
                 LifetimeRibKind::AnonymousReportError => {
@@ -1486,39 +1524,46 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     .span_label(lifetime.ident.span, note)
                     .emit();
 
-                    self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
+                    self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
                     return;
                 }
-                LifetimeRibKind::AnonymousPassThrough(node_id, _) => {
+                LifetimeRibKind::AnonymousPassThrough(node_id) => {
                     self.record_lifetime_res(
                         lifetime.id,
                         LifetimeRes::Anonymous { binder: node_id, elided },
+                        elision_candidate,
                     );
                     return;
                 }
+                LifetimeRibKind::Elided(res) => {
+                    self.record_lifetime_res(lifetime.id, res, elision_candidate);
+                    return;
+                }
+                LifetimeRibKind::ElisionFailure => {
+                    self.diagnostic_metadata.current_elision_failures.push(missing_lifetime);
+                    self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
+                    return;
+                }
                 LifetimeRibKind::Item => break,
                 LifetimeRibKind::Generics { .. }
                 | LifetimeRibKind::ConstGeneric
                 | LifetimeRibKind::AnonConst => {}
             }
         }
-        // This resolution is wrong, it passes the work to HIR lifetime resolution.
-        // We cannot use `LifetimeRes::Error` because we do not emit a diagnostic.
-        self.record_lifetime_res(
-            lifetime.id,
-            LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided },
-        );
+        self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
+        self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
     fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
         let id = self.r.next_node_id();
+        let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
+
         self.record_lifetime_res(
             anchor_id,
             LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
+            LifetimeElisionCandidate::Ignore,
         );
-
-        let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
         self.resolve_anonymous_lifetime(&lt, true);
     }
 
@@ -1603,16 +1648,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             self.record_lifetime_res(
                 segment_id,
                 LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
+                LifetimeElisionCandidate::Ignore,
             );
 
             if !missing {
                 // Do not create a parameter for patterns and expressions.
                 for rib in self.lifetime_ribs.iter().rev() {
                     match rib.kind {
-                        LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+                        LifetimeRibKind::AnonymousPassThrough(binder) => {
                             let res = LifetimeRes::Anonymous { binder, elided: true };
                             for id in node_ids {
-                                self.record_lifetime_res(id, res);
+                                self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
                             }
                             break;
                         }
@@ -1627,11 +1673,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                             let res =
                                 LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
                             for id in node_ids {
-                                self.record_lifetime_res(id, res);
+                                self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
                             }
                             break;
                         }
                         LifetimeRibKind::AnonymousCreateParameter { .. }
+                        | LifetimeRibKind::Elided(_)
+                        | LifetimeRibKind::ElisionFailure
                         | LifetimeRibKind::Generics { .. }
                         | LifetimeRibKind::ConstGeneric
                         | LifetimeRibKind::AnonConst => {}
@@ -1640,6 +1688,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 continue;
             }
 
+            let missing_lifetime = MissingLifetime {
+                id: node_ids.start,
+                span: elided_lifetime_span,
+                kind: if segment.has_generic_args {
+                    MissingLifetimeKind::Comma
+                } else {
+                    MissingLifetimeKind::Brackets
+                },
+                count: expected_lifetimes,
+            };
             let mut should_lint = true;
             for rib in self.lifetime_ribs.iter().rev() {
                 match rib.kind {
@@ -1670,23 +1728,60 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         should_lint = false;
 
                         for id in node_ids {
-                            self.record_lifetime_res(id, LifetimeRes::Error);
+                            self.record_lifetime_res(
+                                id,
+                                LifetimeRes::Error,
+                                LifetimeElisionCandidate::Named,
+                            );
                         }
                         break;
                     }
                     // Do not create a parameter for patterns and expressions.
                     LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+                        // Group all suggestions into the first record.
+                        let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
                         for id in node_ids {
                             let res = self.create_fresh_lifetime(id, ident, binder);
-                            self.record_lifetime_res(id, res);
+                            self.record_lifetime_res(
+                                id,
+                                res,
+                                replace(&mut candidate, LifetimeElisionCandidate::Named),
+                            );
                         }
                         break;
                     }
                     // `PassThrough` is the normal case.
-                    LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+                    LifetimeRibKind::AnonymousPassThrough(binder) => {
                         let res = LifetimeRes::Anonymous { binder, elided: true };
+                        let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
                         for id in node_ids {
-                            self.record_lifetime_res(id, res);
+                            self.record_lifetime_res(
+                                id,
+                                res,
+                                replace(&mut candidate, LifetimeElisionCandidate::Ignore),
+                            );
+                        }
+                        break;
+                    }
+                    LifetimeRibKind::Elided(res) => {
+                        let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
+                        for id in node_ids {
+                            self.record_lifetime_res(
+                                id,
+                                res,
+                                replace(&mut candidate, LifetimeElisionCandidate::Ignore),
+                            );
+                        }
+                        break;
+                    }
+                    LifetimeRibKind::ElisionFailure => {
+                        self.diagnostic_metadata.current_elision_failures.push(missing_lifetime);
+                        for id in node_ids {
+                            self.record_lifetime_res(
+                                id,
+                                LifetimeRes::Error,
+                                LifetimeElisionCandidate::Ignore,
+                            );
                         }
                         break;
                     }
@@ -1695,13 +1790,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     // we simply resolve to an implicit lifetime, which will be checked later, at
                     // which point a suitable error will be emitted.
                     LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
-                        // FIXME(cjgillot) This resolution is wrong, but this does not matter
-                        // since these cases are erroneous anyway.  Lifetime resolution should
-                        // emit a "missing lifetime specifier" diagnostic.
-                        let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
                         for id in node_ids {
-                            self.record_lifetime_res(id, res);
+                            self.record_lifetime_res(
+                                id,
+                                LifetimeRes::Error,
+                                LifetimeElisionCandidate::Ignore,
+                            );
                         }
+                        self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
                         break;
                     }
                     LifetimeRibKind::Generics { .. }
@@ -1728,13 +1824,223 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
-    fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) {
+    fn record_lifetime_res(
+        &mut self,
+        id: NodeId,
+        res: LifetimeRes,
+        candidate: LifetimeElisionCandidate,
+    ) {
         if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
             panic!(
                 "lifetime {:?} resolved multiple times ({:?} before, {:?} now)",
                 id, prev_res, res
             )
         }
+        match res {
+            LifetimeRes::Param { .. }
+            | LifetimeRes::Fresh { .. }
+            | LifetimeRes::Anonymous { .. }
+            | LifetimeRes::Static => {
+                if let Some(ref mut candidates) = self.lifetime_elision_candidates {
+                    candidates.insert(res, candidate);
+                }
+            }
+            LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {}
+        }
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) {
+        if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
+            panic!(
+                "lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)",
+                id, prev_res, res
+            )
+        }
+    }
+
+    /// Perform resolution of a function signature, accounting for lifetime elision.
+    #[tracing::instrument(level = "debug", skip(self, inputs))]
+    fn resolve_fn_signature(
+        &mut self,
+        fn_id: NodeId,
+        async_node_id: Option<NodeId>,
+        has_self: bool,
+        inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)> + Clone,
+        output_ty: &'ast FnRetTy,
+    ) {
+        // Add each argument to the rib.
+        let parameter_rib = LifetimeRibKind::AnonymousCreateParameter {
+            binder: fn_id,
+            report_in_path: async_node_id.is_some(),
+        };
+        let elision_lifetime =
+            self.with_lifetime_rib(parameter_rib, |this| this.resolve_fn_params(has_self, inputs));
+        debug!(?elision_lifetime);
+
+        let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures);
+        let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
+            LifetimeRibKind::Elided(*res)
+        } else {
+            LifetimeRibKind::ElisionFailure
+        };
+        self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, &output_ty));
+        let elision_failures =
+            replace(&mut self.diagnostic_metadata.current_elision_failures, outer_failures);
+        if !elision_failures.is_empty() {
+            let Err(failure_info) = elision_lifetime else { bug!() };
+            self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info));
+        }
+    }
+
+    /// Resolve inside function parameters and parameter types.
+    /// Returns the lifetime for elision in fn return type,
+    /// or diagnostic information in case of elision failure.
+    fn resolve_fn_params(
+        &mut self,
+        has_self: bool,
+        inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)>,
+    ) -> Result<LifetimeRes, (Vec<MissingLifetime>, Vec<ElisionFnParameter>)> {
+        let outer_candidates =
+            replace(&mut self.lifetime_elision_candidates, Some(Default::default()));
+
+        let mut elision_lifetime = None;
+        let mut lifetime_count = 0;
+        let mut parameter_info = Vec::new();
+
+        let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
+        for (index, (pat, ty)) in inputs.enumerate() {
+            debug!(?pat, ?ty);
+            if let Some(pat) = pat {
+                self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+            }
+            self.visit_ty(ty);
+
+            if let Some(ref candidates) = self.lifetime_elision_candidates {
+                let new_count = candidates.len();
+                let local_count = new_count - lifetime_count;
+                if local_count != 0 {
+                    parameter_info.push(ElisionFnParameter {
+                        index,
+                        ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind {
+                            Some(ident)
+                        } else {
+                            None
+                        },
+                        lifetime_count: local_count,
+                        span: ty.span,
+                    });
+                }
+                lifetime_count = new_count;
+            }
+
+            // Handle `self` specially.
+            if index == 0 && has_self {
+                let self_lifetime = self.find_lifetime_for_self(ty);
+                if let Set1::One(lifetime) = self_lifetime {
+                    elision_lifetime = Some(lifetime);
+                    self.lifetime_elision_candidates = None;
+                } else {
+                    self.lifetime_elision_candidates = Some(Default::default());
+                    lifetime_count = 0;
+                }
+            }
+            debug!("(resolving function / closure) recorded parameter");
+        }
+
+        let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates);
+        debug!(?all_candidates);
+
+        if let Some(res) = elision_lifetime {
+            return Ok(res);
+        }
+
+        // We do not have a `self` candidate, look at the full list.
+        let all_candidates = all_candidates.unwrap();
+        if all_candidates.len() == 1 {
+            Ok(*all_candidates.first().unwrap().0)
+        } else {
+            let all_candidates = all_candidates
+                .into_iter()
+                .filter_map(|(_, candidate)| match candidate {
+                    LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None,
+                    LifetimeElisionCandidate::Missing(missing) => Some(missing),
+                })
+                .collect();
+            Err((all_candidates, parameter_info))
+        }
+    }
+
+    /// List all the lifetimes that appear in the provided type.
+    fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1<LifetimeRes> {
+        struct SelfVisitor<'r, 'a> {
+            r: &'r Resolver<'a>,
+            impl_self: Option<Res>,
+            lifetime: Set1<LifetimeRes>,
+        }
+
+        impl SelfVisitor<'_, '_> {
+            // Look for `self: &'a Self` - also desugared from `&'a self`,
+            // and if that matches, use it for elision and return early.
+            fn is_self_ty(&self, ty: &Ty) -> bool {
+                match ty.kind {
+                    TyKind::ImplicitSelf => true,
+                    TyKind::Path(None, _) => {
+                        let path_res = self.r.partial_res_map[&ty.id].base_res();
+                        if let Res::SelfTy { .. } = path_res {
+                            return true;
+                        }
+                        Some(path_res) == self.impl_self
+                    }
+                    _ => false,
+                }
+            }
+        }
+
+        impl<'a> Visitor<'a> for SelfVisitor<'_, '_> {
+            fn visit_ty(&mut self, ty: &'a Ty) {
+                trace!("SelfVisitor considering ty={:?}", ty);
+                if let TyKind::Rptr(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
+                    let lt_id = if let Some(lt) = lt {
+                        lt.id
+                    } else {
+                        let res = self.r.lifetimes_res_map[&ty.id];
+                        let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() };
+                        start
+                    };
+                    let lt_res = self.r.lifetimes_res_map[&lt_id];
+                    trace!("SelfVisitor inserting res={:?}", lt_res);
+                    self.lifetime.insert(lt_res);
+                }
+                visit::walk_ty(self, ty)
+            }
+        }
+
+        let impl_self = self
+            .diagnostic_metadata
+            .current_self_type
+            .as_ref()
+            .and_then(|ty| {
+                if let TyKind::Path(None, _) = ty.kind {
+                    self.r.partial_res_map.get(&ty.id)
+                } else {
+                    None
+                }
+            })
+            .map(|res| res.base_res())
+            .filter(|res| {
+                // Permit the types that unambiguously always
+                // result in the same type constructor being used
+                // (it can't differ between `Self` and `self`).
+                matches!(
+                    res,
+                    Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
+                )
+            });
+        let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
+        visitor.visit_ty(ty);
+        trace!("SelfVisitor found={:?}", visitor.lifetime);
+        visitor.lifetime
     }
 
     /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
@@ -1959,22 +2265,29 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
             ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
                 self.with_item_rib(|this| {
-                    this.visit_ty(ty);
-                    if let Some(expr) = expr {
-                        let constant_item_kind = match item.kind {
-                            ItemKind::Const(..) => ConstantItemKind::Const,
-                            ItemKind::Static(..) => ConstantItemKind::Static,
-                            _ => unreachable!(),
-                        };
-                        // We already forbid generic params because of the above item rib,
-                        // so it doesn't matter whether this is a trivial constant.
-                        this.with_constant_rib(
-                            IsRepeatExpr::No,
-                            HasGenericParams::Yes,
-                            Some((item.ident, constant_item_kind)),
-                            |this| this.visit_expr(expr),
-                        );
-                    }
+                    this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
+                        this.visit_ty(ty);
+                    });
+                    this.with_lifetime_rib(
+                        LifetimeRibKind::AnonymousPassThrough(item.id),
+                        |this| {
+                            if let Some(expr) = expr {
+                                let constant_item_kind = match item.kind {
+                                    ItemKind::Const(..) => ConstantItemKind::Const,
+                                    ItemKind::Static(..) => ConstantItemKind::Static,
+                                    _ => unreachable!(),
+                                };
+                                // We already forbid generic params because of the above item rib,
+                                // so it doesn't matter whether this is a trivial constant.
+                                this.with_constant_rib(
+                                    IsRepeatExpr::No,
+                                    HasGenericParams::Yes,
+                                    Some((item.ident, constant_item_kind)),
+                                    |this| this.visit_expr(expr),
+                                );
+                            }
+                        },
+                    );
                 });
             }
 
@@ -2045,7 +2358,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             {
                 diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident);
                 // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_res(param.id, LifetimeRes::Error);
+                self.record_lifetime_param(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -2056,7 +2369,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     self.report_error(param.ident.span, err);
                     if let GenericParamKind::Lifetime = param.kind {
                         // Record lifetime res, so lowering knows there is something fishy.
-                        self.record_lifetime_res(param.id, LifetimeRes::Error);
+                        self.record_lifetime_param(param.id, LifetimeRes::Error);
                         continue;
                     }
                 }
@@ -2075,7 +2388,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 .span_label(param.ident.span, "`'_` is a reserved lifetime name")
                 .emit();
                 // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_res(param.id, LifetimeRes::Error);
+                self.record_lifetime_param(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -2090,7 +2403,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 .span_label(param.ident.span, "'static is a reserved lifetime name")
                 .emit();
                 // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_res(param.id, LifetimeRes::Error);
+                self.record_lifetime_param(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -2102,7 +2415,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
                 GenericParamKind::Lifetime => {
                     let res = LifetimeRes::Param { param: def_id, binder };
-                    self.record_lifetime_res(param.id, res);
+                    self.record_lifetime_param(param.id, res);
                     function_lifetime_rib.bindings.insert(ident, (param.id, res));
                     continue;
                 }
@@ -2125,7 +2438,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
         self.ribs[TypeNS].pop();
         self.ribs[ValueNS].pop();
-        self.lifetime_ribs.pop();
+        let function_lifetime_rib = self.lifetime_ribs.pop().unwrap();
+
+        // Do not account for the parameters we just bound for function lifetime elision.
+        if let Some(ref mut candidates) = self.lifetime_elision_candidates {
+            for (_, res) in function_lifetime_rib.bindings.values() {
+                candidates.remove(res);
+            }
+        }
 
         if let LifetimeBinderKind::BareFnType
         | LifetimeBinderKind::WhereBound
@@ -2223,20 +2543,26 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         //
                         // Type parameters can already be used and as associated consts are
                         // not used as part of the type system, this is far less surprising.
-                        self.with_constant_rib(
-                            IsRepeatExpr::No,
-                            HasGenericParams::Yes,
-                            None,
-                            |this| this.visit_expr(expr),
+                        self.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(item.id),
+                            |this| {
+                                this.with_constant_rib(
+                                    IsRepeatExpr::No,
+                                    HasGenericParams::Yes,
+                                    None,
+                                    |this| this.visit_expr(expr),
+                                )
+                            },
                         );
                     }
                 }
                 AssocItemKind::Fn(box Fn { generics, .. }) => {
                     walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
                 }
-                AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
-                    walk_assoc_item(self, generics, LifetimeBinderKind::Item, item);
-                }
+                AssocItemKind::TyAlias(box TyAlias { generics, .. }) => self
+                    .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+                        walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
+                    }),
                 AssocItemKind::MacCall(_) => {
                     panic!("unexpanded macro in resolve!")
                 }
@@ -2307,7 +2633,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             LifetimeRibKind::Generics {
                 span: generics.span,
                 binder: item_id,
-                kind: LifetimeBinderKind::ImplBlock
+                kind: LifetimeBinderKind::ImplBlock,
             },
             |this| {
                 // Dummy self type for better errors if `Self` is used in the trait path.
@@ -2327,7 +2653,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
                                     // Register the trait definitions from here.
                                     if let Some(trait_id) = trait_id {
-                                        this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
+                                        this.r
+                                            .trait_impls
+                                            .entry(trait_id)
+                                            .or_default()
+                                            .push(item_def_id);
                                     }
 
                                     let item_def_id = item_def_id.to_def_id();
@@ -2346,21 +2676,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                         this.visit_generics(generics);
 
                                         // Resolve the items within the impl.
-                                        this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false),
-                                            |this| {
-                                                this.with_current_self_type(self_type, |this| {
-                                                    this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
-                                                        debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
-                                                        for item in impl_items {
-                                                            this.resolve_impl_item(&**item);
-                                                        }
-                                                    });
-                                                });
-                                            },
-                                        );
+                                        this.with_current_self_type(self_type, |this| {
+                                            this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
+                                                debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
+                                                for item in impl_items {
+                                                    this.resolve_impl_item(&**item);
+                                                }
+                                            });
+                                        });
                                     });
                                 },
-                            );
+                            )
                         },
                     );
                 });
@@ -2391,9 +2717,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     //
                     // Type parameters can already be used and as associated consts are
                     // not used as part of the type system, this is far less surprising.
-                    self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
-                        this.visit_expr(expr)
-                    });
+                    self.with_lifetime_rib(
+                        LifetimeRibKind::AnonymousPassThrough(item.id),
+                        |this| {
+                            this.with_constant_rib(
+                                IsRepeatExpr::No,
+                                HasGenericParams::Yes,
+                                None,
+                                |this| this.visit_expr(expr),
+                            )
+                        },
+                    );
                 }
             }
             AssocItemKind::Fn(box Fn { generics, .. }) => {
@@ -2435,18 +2769,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         kind: LifetimeBinderKind::Item,
                     },
                     |this| {
-                        // If this is a trait impl, ensure the type
-                        // exists in trait
-                        this.check_trait_item(
-                            item.id,
-                            item.ident,
-                            &item.kind,
-                            TypeNS,
-                            item.span,
-                            |i, s, c| TypeNotMemberOfTrait(i, s, c),
-                        );
+                        this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+                            // If this is a trait impl, ensure the type
+                            // exists in trait
+                            this.check_trait_item(
+                                item.id,
+                                item.ident,
+                                &item.kind,
+                                TypeNS,
+                                item.span,
+                                |i, s, c| TypeNotMemberOfTrait(i, s, c),
+                            );
 
-                        visit::walk_assoc_item(this, item, AssocCtxt::Impl)
+                            visit::walk_assoc_item(this, item, AssocCtxt::Impl)
+                        });
                     },
                 );
             }
@@ -3581,7 +3917,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             ExprKind::Repeat(ref elem, ref ct) => {
                 self.visit_expr(elem);
                 self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
-                    this.resolve_anon_const(ct, IsRepeatExpr::Yes)
+                    this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
+                        this.resolve_anon_const(ct, IsRepeatExpr::Yes)
+                    })
                 });
             }
             ExprKind::ConstBlock(ref ct) => {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index e428bae479b..f979403e097 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1,7 +1,6 @@
 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
-use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
-use crate::late::{LifetimeBinderKind, LifetimeRibKind, LifetimeUseSet};
+use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
 use crate::path_names_to_string;
 use crate::{Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
@@ -9,10 +8,10 @@ use crate::{PathResult, PathSource, Segment};
 use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt};
 use rustc_ast::{
     self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind,
-    NodeId, Path, Ty, TyKind,
+    NodeId, Path, Ty, TyKind, DUMMY_NODE_ID,
 };
 use rustc_ast_pretty::pprust::path_segment_to_string;
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
     MultiSpan,
@@ -20,7 +19,7 @@ use rustc_errors::{
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
@@ -29,7 +28,7 @@ use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, Span};
 
 use std::iter;
 use std::ops::Deref;
@@ -59,45 +58,6 @@ impl AssocSuggestion {
     }
 }
 
-pub(crate) enum MissingLifetimeSpot<'tcx> {
-    Generics(&'tcx hir::Generics<'tcx>),
-    HigherRanked { span: Span, span_type: ForLifetimeSpanType },
-    Static,
-}
-
-pub(crate) enum ForLifetimeSpanType {
-    BoundEmpty,
-    BoundTail,
-    TypeEmpty,
-    TypeTail,
-    ClosureEmpty,
-    ClosureTail,
-}
-
-impl ForLifetimeSpanType {
-    pub(crate) fn descr(&self) -> &'static str {
-        match self {
-            Self::BoundEmpty | Self::BoundTail => "bound",
-            Self::TypeEmpty | Self::TypeTail => "type",
-            Self::ClosureEmpty | Self::ClosureTail => "closure",
-        }
-    }
-
-    pub(crate) fn suggestion(&self, sugg: impl std::fmt::Display) -> String {
-        match self {
-            Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
-            Self::ClosureEmpty => format!("for<{}>", sugg),
-            Self::BoundTail | Self::TypeTail | Self::ClosureTail => format!(", {}", sugg),
-        }
-    }
-}
-
-impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &&'tcx hir::Generics<'tcx> {
-    fn into(self) -> MissingLifetimeSpot<'tcx> {
-        MissingLifetimeSpot::Generics(self)
-    }
-}
-
 fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
     namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
 }
@@ -122,6 +82,56 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str
     (variant_path_string, enum_path_string)
 }
 
+/// Description of an elided lifetime.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub(super) struct MissingLifetime {
+    /// Used to overwrite the resolution with the suggestion, to avoid cascasing errors.
+    pub id: NodeId,
+    /// Where to suggest adding the lifetime.
+    pub span: Span,
+    /// How the lifetime was introduced, to have the correct space and comma.
+    pub kind: MissingLifetimeKind,
+    /// Number of elided lifetimes, used for elision in path.
+    pub count: usize,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub(super) enum MissingLifetimeKind {
+    /// An explicit `'_`.
+    Underscore,
+    /// An elided lifetime `&' ty`.
+    Ampersand,
+    /// An elided lifetime in brackets with written brackets.
+    Comma,
+    /// An elided lifetime with elided brackets.
+    Brackets,
+}
+
+/// Description of the lifetimes appearing in a function parameter.
+/// This is used to provide a literal explanation to the elision failure.
+#[derive(Clone, Debug)]
+pub(super) struct ElisionFnParameter {
+    /// The index of the argument in the original definition.
+    pub index: usize,
+    /// The name of the argument if it's a simple ident.
+    pub ident: Option<Ident>,
+    /// The number of lifetimes in the parameter.
+    pub lifetime_count: usize,
+    /// The span of the parameter.
+    pub span: Span,
+}
+
+/// Description of lifetimes that appear as candidates for elision.
+/// This is used to suggest introducing an explicit lifetime.
+#[derive(Debug)]
+pub(super) enum LifetimeElisionCandidate {
+    /// This is not a real lifetime.
+    Ignore,
+    /// There is a named lifetime, we won't suggest anything.
+    Named,
+    Missing(MissingLifetime),
+}
+
 impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
     fn def_span(&self, def_id: DefId) -> Option<Span> {
         match def_id.krate {
@@ -2003,18 +2013,35 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
             err
         };
-        let mut suggest_note = true;
+        self.suggest_introducing_lifetime(
+            &mut err,
+            Some(lifetime_ref.ident.name.as_str()),
+            |err, _, span, message, suggestion| {
+                err.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect);
+                true
+            },
+        );
+        err.emit();
+    }
 
+    fn suggest_introducing_lifetime(
+        &self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        name: Option<&str>,
+        suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool,
+    ) {
+        let mut suggest_note = true;
         for rib in self.lifetime_ribs.iter().rev() {
+            let mut should_continue = true;
             match rib.kind {
                 LifetimeRibKind::Generics { binder: _, span, kind } => {
-                    if !span.can_be_used_for_suggestions() && suggest_note {
+                    if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name {
                         suggest_note = false; // Avoid displaying the same help multiple times.
                         err.span_label(
                             span,
                             &format!(
                                 "lifetime `{}` is missing in item created through this procedural macro",
-                                lifetime_ref.ident,
+                                name,
                             ),
                         );
                         continue;
@@ -2030,46 +2057,42 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                         let sugg = format!(
                             "{}<{}>{}",
                             if higher_ranked { "for" } else { "" },
-                            lifetime_ref.ident,
+                            name.unwrap_or("'a"),
                             if higher_ranked { " " } else { "" },
                         );
                         (span, sugg)
                     } else {
                         let span =
                             self.r.session.source_map().span_through_char(span, '<').shrink_to_hi();
-                        let sugg = format!("{}, ", lifetime_ref.ident);
+                        let sugg = format!("{}, ", name.unwrap_or("'a"));
                         (span, sugg)
                     };
                     if higher_ranked {
-                        err.span_suggestion(
-                            span,
-                            &format!(
-                                "consider making the {} lifetime-generic with a new `{}` lifetime",
-                                kind.descr(),
-                                lifetime_ref
-                            ),
-                            sugg,
-                            Applicability::MaybeIncorrect,
+                        let message = format!(
+                            "consider making the {} lifetime-generic with a new `{}` lifetime",
+                            kind.descr(),
+                            name.unwrap_or("'a"),
                         );
+                        should_continue = suggest(err, true, span, &message, sugg);
                         err.note_once(
                             "for more information on higher-ranked polymorphism, visit \
                              https://doc.rust-lang.org/nomicon/hrtb.html",
                         );
+                    } else if let Some(name) = name {
+                        let message = format!("consider introducing lifetime `{}` here", name);
+                        should_continue = suggest(err, false, span, &message, sugg);
                     } else {
-                        err.span_suggestion(
-                            span,
-                            &format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
-                            sugg,
-                            Applicability::MaybeIncorrect,
-                        );
+                        let message = format!("consider introducing a named lifetime parameter");
+                        should_continue = suggest(err, false, span, &message, sugg);
                     }
                 }
                 LifetimeRibKind::Item => break,
                 _ => {}
             }
+            if !should_continue {
+                break;
+            }
         }
-
-        err.emit();
     }
 
     pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) {
@@ -2105,552 +2128,209 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             .emit();
         }
     }
-}
 
-/// Report lifetime/lifetime shadowing as an error.
-pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
-    let mut err = struct_span_err!(
-        sess,
-        shadower.span,
-        E0496,
-        "lifetime name `{}` shadows a lifetime name that is already in scope",
-        orig.name,
-    );
-    err.span_label(orig.span, "first declared here");
-    err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
-    err.emit();
-}
-
-/// Shadowing involving a label is only a warning for historical reasons.
-//FIXME: make this a proper lint.
-pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
-    let name = shadower.name;
-    let shadower = shadower.span;
-    let mut err = sess.struct_span_warn(
-        shadower,
-        &format!("label name `{}` shadows a label name that is already in scope", name),
-    );
-    err.span_label(orig, "first declared here");
-    err.span_label(shadower, format!("label `{}` already in scope", name));
-    err.emit();
-}
-
-impl<'tcx> LifetimeContext<'_, 'tcx> {
     pub(crate) fn report_missing_lifetime_specifiers(
-        &self,
-        spans: Vec<Span>,
-        count: usize,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        struct_span_err!(
-            self.tcx.sess,
+        &mut self,
+        lifetime_refs: Vec<MissingLifetime>,
+        function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
+    ) -> ErrorGuaranteed {
+        let num_lifetimes: usize = lifetime_refs.iter().map(|lt| lt.count).sum();
+        let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
+
+        let mut err = struct_span_err!(
+            self.r.session,
             spans,
             E0106,
             "missing lifetime specifier{}",
-            pluralize!(count)
-        )
+            pluralize!(num_lifetimes)
+        );
+        self.add_missing_lifetime_specifiers_label(
+            &mut err,
+            lifetime_refs,
+            function_param_lifetimes,
+        );
+        err.emit()
     }
 
-    /// Returns whether to add `'static` lifetime to the suggested lifetime list.
-    pub(crate) fn report_elision_failure(
-        &self,
-        diag: &mut Diagnostic,
-        params: &[ElisionFailureInfo],
-    ) -> bool {
-        let mut m = String::new();
-        let len = params.len();
+    pub(crate) fn add_missing_lifetime_specifiers_label(
+        &mut self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        lifetime_refs: Vec<MissingLifetime>,
+        function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
+    ) {
+        for &lt in &lifetime_refs {
+            err.span_label(
+                lt.span,
+                format!(
+                    "expected {} lifetime parameter{}",
+                    if lt.count == 1 { "named".to_string() } else { lt.count.to_string() },
+                    pluralize!(lt.count),
+                ),
+            );
+        }
 
-        let elided_params: Vec<_> =
-            params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
+        let mut in_scope_lifetimes: Vec<_> = self
+            .lifetime_ribs
+            .iter()
+            .rev()
+            .take_while(|rib| !matches!(rib.kind, LifetimeRibKind::Item))
+            .flat_map(|rib| rib.bindings.iter())
+            .map(|(&ident, &res)| (ident, res))
+            .filter(|(ident, _)| ident.name != kw::UnderscoreLifetime)
+            .collect();
+        debug!(?in_scope_lifetimes);
 
-        let elided_len = elided_params.len();
+        debug!(?function_param_lifetimes);
+        if let Some((param_lifetimes, params)) = &function_param_lifetimes {
+            let elided_len = param_lifetimes.len();
+            let num_params = params.len();
 
-        for (i, info) in elided_params.into_iter().enumerate() {
-            let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
-                info;
+            let mut m = String::new();
 
-            diag.span_label(span, "");
-            let help_name = if let Some(ident) =
-                parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
-            {
-                format!("`{}`", ident)
-            } else {
-                format!("argument {}", index + 1)
-            };
+            for (i, info) in params.iter().enumerate() {
+                let ElisionFnParameter { ident, index, lifetime_count, span } = *info;
+                debug_assert_ne!(lifetime_count, 0);
 
-            m.push_str(
-                &(if n == 1 {
-                    help_name
+                err.span_label(span, "");
+
+                if i != 0 {
+                    if i + 1 < num_params {
+                        m.push_str(", ");
+                    } else if num_params == 2 {
+                        m.push_str(" or ");
+                    } else {
+                        m.push_str(", or ");
+                    }
+                }
+
+                let help_name = if let Some(ident) = ident {
+                    format!("`{}`", ident)
                 } else {
-                    format!(
-                        "one of {}'s {} {}lifetimes",
-                        help_name,
-                        n,
-                        if have_bound_regions { "free " } else { "" }
-                    )
-                })[..],
-            );
+                    format!("argument {}", index + 1)
+                };
 
-            if elided_len == 2 && i == 0 {
-                m.push_str(" or ");
-            } else if i + 2 == elided_len {
-                m.push_str(", or ");
-            } else if i != elided_len - 1 {
-                m.push_str(", ");
+                if lifetime_count == 1 {
+                    m.push_str(&help_name[..])
+                } else {
+                    m.push_str(&format!("one of {}'s {} lifetimes", help_name, lifetime_count)[..])
+                }
             }
-        }
 
-        if len == 0 {
-            diag.help(
-                "this function's return type contains a borrowed value, \
+            if num_params == 0 {
+                err.help(
+                    "this function's return type contains a borrowed value, \
                  but there is no value for it to be borrowed from",
-            );
-            true
-        } else if elided_len == 0 {
-            diag.help(
-                "this function's return type contains a borrowed value with \
+                );
+                if in_scope_lifetimes.is_empty() {
+                    in_scope_lifetimes = vec![(
+                        Ident::with_dummy_span(kw::StaticLifetime),
+                        (DUMMY_NODE_ID, LifetimeRes::Static),
+                    )];
+                }
+            } else if elided_len == 0 {
+                err.help(
+                    "this function's return type contains a borrowed value with \
                  an elided lifetime, but the lifetime cannot be derived from \
                  the arguments",
-            );
-            true
-        } else if elided_len == 1 {
-            diag.help(&format!(
-                "this function's return type contains a borrowed value, \
+                );
+                if in_scope_lifetimes.is_empty() {
+                    in_scope_lifetimes = vec![(
+                        Ident::with_dummy_span(kw::StaticLifetime),
+                        (DUMMY_NODE_ID, LifetimeRes::Static),
+                    )];
+                }
+            } else if num_params == 1 {
+                err.help(&format!(
+                    "this function's return type contains a borrowed value, \
                  but the signature does not say which {} it is borrowed from",
-                m
-            ));
-            false
-        } else {
-            diag.help(&format!(
-                "this function's return type contains a borrowed value, \
+                    m
+                ));
+            } else {
+                err.help(&format!(
+                    "this function's return type contains a borrowed value, \
                  but the signature does not say whether it is borrowed from {}",
-                m
-            ));
-            false
+                    m
+                ));
+            }
         }
-    }
 
-    pub(crate) fn is_trait_ref_fn_scope(
-        &mut self,
-        trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
-    ) -> bool {
-        if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
-            if [
-                self.tcx.lang_items().fn_once_trait(),
-                self.tcx.lang_items().fn_trait(),
-                self.tcx.lang_items().fn_mut_trait(),
-            ]
-            .contains(&Some(did))
-            {
-                let (span, span_type) = if let Some(bound) =
-                    trait_ref.bound_generic_params.iter().rfind(|param| {
-                        matches!(
-                            param.kind,
-                            hir::GenericParamKind::Lifetime {
-                                kind: hir::LifetimeParamKind::Explicit
-                            }
-                        )
-                    }) {
-                    (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail)
-                } else {
-                    (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty)
-                };
-                self.missing_named_lifetime_spots
-                    .push(MissingLifetimeSpot::HigherRanked { span, span_type });
-                return true;
-            }
+        let existing_name = match &in_scope_lifetimes[..] {
+            [] => Symbol::intern("'a"),
+            [(existing, _)] => existing.name,
+            _ => Symbol::intern("'lifetime"),
         };
-        false
-    }
-
-    pub(crate) fn add_missing_lifetime_specifiers_label(
-        &self,
-        err: &mut Diagnostic,
-        mut spans_with_counts: Vec<(Span, usize)>,
-        in_scope_lifetimes: FxIndexSet<LocalDefId>,
-        params: Option<&[ElisionFailureInfo]>,
-    ) {
-        let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes
-            .iter()
-            .filter_map(|def_id| {
-                let name = self.tcx.item_name(def_id.to_def_id());
-                let span = self.tcx.def_ident_span(def_id.to_def_id())?;
-                Some((name, span))
-            })
-            .filter(|&(n, _)| n != kw::UnderscoreLifetime)
-            .unzip();
 
-        if let Some(params) = params {
-            // If there's no lifetime available, suggest `'static`.
-            if self.report_elision_failure(err, params) && lifetime_names.is_empty() {
-                lifetime_names.insert(kw::StaticLifetime);
+        let mut spans_suggs: Vec<_> = Vec::new();
+        let build_sugg = |lt: MissingLifetime| match lt.kind {
+            MissingLifetimeKind::Underscore => {
+                debug_assert_eq!(lt.count, 1);
+                (lt.span, existing_name.to_string())
             }
-        }
-        let params = params.unwrap_or(&[]);
-
-        let snippets: Vec<Option<String>> = spans_with_counts
-            .iter()
-            .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
-            .collect();
-
-        // Empty generics are marked with a span of "<", but since from now on
-        // that information is in the snippets it can be removed from the spans.
-        for ((span, _), snippet) in spans_with_counts.iter_mut().zip(&snippets) {
-            if snippet.as_deref() == Some("<") {
-                *span = span.shrink_to_hi();
+            MissingLifetimeKind::Ampersand => {
+                debug_assert_eq!(lt.count, 1);
+                (lt.span.shrink_to_hi(), format!("{} ", existing_name))
             }
+            MissingLifetimeKind::Comma => {
+                let sugg: String = std::iter::repeat([existing_name.as_str(), ", "])
+                    .take(lt.count)
+                    .flatten()
+                    .collect();
+                (lt.span.shrink_to_hi(), sugg)
+            }
+            MissingLifetimeKind::Brackets => {
+                let sugg: String = std::iter::once("<")
+                    .chain(
+                        std::iter::repeat(existing_name.as_str()).take(lt.count).intersperse(", "),
+                    )
+                    .chain([">"])
+                    .collect();
+                (lt.span.shrink_to_hi(), sugg)
+            }
+        };
+        for &lt in &lifetime_refs {
+            spans_suggs.push(build_sugg(lt));
         }
-
-        for &(span, count) in &spans_with_counts {
-            err.span_label(
-                span,
-                format!(
-                    "expected {} lifetime parameter{}",
-                    if count == 1 { "named".to_string() } else { count.to_string() },
-                    pluralize!(count),
-                ),
-            );
-        }
-
-        let suggest_existing =
-            |err: &mut Diagnostic,
-             name: Symbol,
-             formatters: Vec<Option<Box<dyn Fn(Symbol) -> String>>>| {
-                if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) =
-                    self.missing_named_lifetime_spots.iter().rev().next()
-                {
-                    // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
-                    // using `'a`, but also introduce the concept of HRLTs by suggesting
-                    // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
-                    let mut introduce_suggestion = vec![];
-
-                    let a_to_z_repeat_n = |n| {
-                        (b'a'..=b'z').map(move |c| {
-                            let mut s = '\''.to_string();
-                            s.extend(std::iter::repeat(char::from(c)).take(n));
-                            s
-                        })
-                    };
-
-                    // If all single char lifetime names are present, we wrap around and double the chars.
-                    let lt_name = (1..)
-                        .flat_map(a_to_z_repeat_n)
-                        .map(|lt| Symbol::intern(&lt))
-                        .find(|lt| !lifetime_names.contains(lt))
-                        .unwrap();
-                    let msg = format!(
-                        "consider making the {} lifetime-generic with a new `{}` lifetime",
-                        span_type.descr(),
-                        lt_name,
-                    );
-                    err.note(
-                        "for more information on higher-ranked polymorphism, visit \
-                    https://doc.rust-lang.org/nomicon/hrtb.html",
-                    );
-                    let for_sugg = span_type.suggestion(&lt_name);
-                    for param in params {
-                        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span)
-                        {
-                            if snippet.starts_with('&') && !snippet.starts_with("&'") {
-                                introduce_suggestion
-                                    .push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
-                            } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
-                                introduce_suggestion
-                                    .push((param.span, format!("&{} {}", lt_name, stripped)));
-                            }
-                        }
+        debug!(?spans_suggs);
+        match in_scope_lifetimes.len() {
+            0 => {
+                if let Some((param_lifetimes, _)) = function_param_lifetimes {
+                    for lt in param_lifetimes {
+                        spans_suggs.push(build_sugg(lt))
                     }
-                    introduce_suggestion.push((*for_span, for_sugg));
-                    for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) {
-                        if let Some(formatter) = formatter {
-                            introduce_suggestion.push((*span, formatter(lt_name)));
-                        }
-                    }
-                    err.multipart_suggestion_verbose(
-                        &msg,
-                        introduce_suggestion,
-                        Applicability::MaybeIncorrect,
-                    );
                 }
-
-                let spans_suggs: Vec<_> = formatters
-                    .into_iter()
-                    .zip(spans_with_counts.iter())
-                    .filter_map(|(formatter, (span, _))| {
-                        if let Some(formatter) = formatter {
-                            Some((*span, formatter(name)))
-                        } else {
-                            None
-                        }
-                    })
-                    .collect();
-                if spans_suggs.is_empty() {
-                    // If all the spans come from macros, we cannot extract snippets and then
-                    // `formatters` only contains None and `spans_suggs` is empty.
-                    return;
-                }
-                err.multipart_suggestion_verbose(
-                    &format!(
-                        "consider using the `{}` lifetime",
-                        lifetime_names.iter().next().unwrap()
-                    ),
-                    spans_suggs,
-                    Applicability::MaybeIncorrect,
-                );
-            };
-        let suggest_new = |err: &mut Diagnostic, suggs: Vec<Option<String>>| {
-            for missing in self.missing_named_lifetime_spots.iter().rev() {
-                let mut introduce_suggestion = vec![];
-                let msg;
-                let should_break;
-                introduce_suggestion.push(match missing {
-                    MissingLifetimeSpot::Generics(generics) => {
-                        if generics.span == DUMMY_SP {
-                            // Account for malformed generics in the HIR. This shouldn't happen,
-                            // but if we make a mistake elsewhere, mainly by keeping something in
-                            // `missing_named_lifetime_spots` that we shouldn't, like associated
-                            // `const`s or making a mistake in the AST lowering we would provide
-                            // nonsensical suggestions. Guard against that by skipping these.
-                            // (#74264)
-                            continue;
-                        }
-                        msg = "consider introducing a named lifetime parameter".to_string();
-                        should_break = true;
-                        if let Some(param) = generics.params.iter().find(|p| {
-                            !matches!(
-                                p.kind,
-                                hir::GenericParamKind::Type { synthetic: true, .. }
-                                    | hir::GenericParamKind::Lifetime {
-                                        kind: hir::LifetimeParamKind::Elided
-                                    }
-                            )
-                        }) {
-                            (param.span.shrink_to_lo(), "'a, ".to_string())
-                        } else {
-                            (generics.span, "<'a>".to_string())
-                        }
-                    }
-                    MissingLifetimeSpot::HigherRanked { span, span_type } => {
-                        msg = format!(
-                            "consider making the {} lifetime-generic with a new `'a` lifetime",
-                            span_type.descr(),
-                        );
-                        should_break = false;
-                        err.note(
-                            "for more information on higher-ranked polymorphism, visit \
-                            https://doc.rust-lang.org/nomicon/hrtb.html",
-                        );
-                        (*span, span_type.suggestion("'a"))
-                    }
-                    MissingLifetimeSpot::Static => {
-                        let mut spans_suggs = Vec::new();
-                        for ((span, count), snippet) in
-                            spans_with_counts.iter().copied().zip(snippets.iter())
-                        {
-                            let (span, sugg) = match snippet.as_deref() {
-                                Some("&") => (span.shrink_to_hi(), "'static ".to_owned()),
-                                Some("'_") => (span, "'static".to_owned()),
-                                Some(snippet) if !snippet.ends_with('>') => {
-                                    if snippet == "" {
-                                        (
-                                            span,
-                                            std::iter::repeat("'static")
-                                                .take(count)
-                                                .collect::<Vec<_>>()
-                                                .join(", "),
-                                        )
-                                    } else if snippet == "<" || snippet == "(" {
-                                        (
-                                            span.shrink_to_hi(),
-                                            std::iter::repeat("'static")
-                                                .take(count)
-                                                .collect::<Vec<_>>()
-                                                .join(", "),
-                                        )
-                                    } else {
-                                        (
-                                            span.shrink_to_hi(),
-                                            format!(
-                                                "<{}>",
-                                                std::iter::repeat("'static")
-                                                    .take(count)
-                                                    .collect::<Vec<_>>()
-                                                    .join(", "),
-                                            ),
-                                        )
-                                    }
-                                }
-                                _ => continue,
-                            };
-                            spans_suggs.push((span, sugg.to_string()));
-                        }
+                self.suggest_introducing_lifetime(
+                    err,
+                    None,
+                    |err, higher_ranked, span, message, intro_sugg| {
                         err.multipart_suggestion_verbose(
-                            "consider using the `'static` lifetime",
-                            spans_suggs,
+                            message,
+                            std::iter::once((span, intro_sugg))
+                                .chain(spans_suggs.clone())
+                                .collect(),
                             Applicability::MaybeIncorrect,
                         );
-                        continue;
-                    }
-                });
-
-                struct Lifetime(Span, String);
-                impl Lifetime {
-                    fn is_unnamed(&self) -> bool {
-                        self.1.starts_with('&') && !self.1.starts_with("&'")
-                    }
-                    fn is_underscore(&self) -> bool {
-                        self.1.starts_with("&'_ ")
-                    }
-                    fn is_named(&self) -> bool {
-                        self.1.starts_with("&'")
-                    }
-                    fn suggestion(&self, sugg: String) -> Option<(Span, String)> {
-                        Some(
-                            match (
-                                self.is_unnamed(),
-                                self.is_underscore(),
-                                self.is_named(),
-                                sugg.starts_with('&'),
-                            ) {
-                                (true, _, _, false) => (self.span_unnamed_borrow(), sugg),
-                                (true, _, _, true) => {
-                                    (self.span_unnamed_borrow(), sugg[1..].to_string())
-                                }
-                                (_, true, _, false) => {
-                                    (self.span_underscore_borrow(), sugg.trim().to_string())
-                                }
-                                (_, true, _, true) => {
-                                    (self.span_underscore_borrow(), sugg[1..].trim().to_string())
-                                }
-                                (_, _, true, false) => {
-                                    (self.span_named_borrow(), sugg.trim().to_string())
-                                }
-                                (_, _, true, true) => {
-                                    (self.span_named_borrow(), sugg[1..].trim().to_string())
-                                }
-                                _ => return None,
-                            },
-                        )
-                    }
-                    fn span_unnamed_borrow(&self) -> Span {
-                        let lo = self.0.lo() + BytePos(1);
-                        self.0.with_lo(lo).with_hi(lo)
-                    }
-                    fn span_named_borrow(&self) -> Span {
-                        let lo = self.0.lo() + BytePos(1);
-                        self.0.with_lo(lo)
-                    }
-                    fn span_underscore_borrow(&self) -> Span {
-                        let lo = self.0.lo() + BytePos(1);
-                        let hi = lo + BytePos(2);
-                        self.0.with_lo(lo).with_hi(hi)
-                    }
-                }
-
-                for param in params {
-                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
-                        if let Some((span, sugg)) =
-                            Lifetime(param.span, snippet).suggestion("'a ".to_string())
-                        {
-                            introduce_suggestion.push((span, sugg));
-                        }
-                    }
-                }
-                for (span, sugg) in spans_with_counts.iter().copied().zip(suggs.iter()).filter_map(
-                    |((span, _), sugg)| match &sugg {
-                        Some(sugg) => Some((span, sugg.to_string())),
-                        _ => None,
+                        higher_ranked
                     },
-                ) {
-                    let (span, sugg) = self
-                        .tcx
-                        .sess
-                        .source_map()
-                        .span_to_snippet(span)
-                        .ok()
-                        .and_then(|snippet| Lifetime(span, snippet).suggestion(sugg.clone()))
-                        .unwrap_or((span, sugg));
-                    introduce_suggestion.push((span, sugg.to_string()));
-                }
+                );
+            }
+            1 => {
                 err.multipart_suggestion_verbose(
-                    &msg,
-                    introduce_suggestion,
+                    &format!("consider using the `{}` lifetime", existing_name),
+                    spans_suggs,
                     Applicability::MaybeIncorrect,
                 );
-                if should_break {
-                    break;
-                }
-            }
-        };
 
-        let lifetime_names: Vec<_> = lifetime_names.iter().collect();
-        match &lifetime_names[..] {
-            [name] => {
-                let mut suggs: Vec<Option<Box<dyn Fn(Symbol) -> String>>> = Vec::new();
-                for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied())
-                {
-                    suggs.push(match snippet.as_deref() {
-                        Some("&") => Some(Box::new(|name| format!("&{} ", name))),
-                        Some("'_") => Some(Box::new(|n| n.to_string())),
-                        Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))),
-                        Some("<") => Some(Box::new(move |n| {
-                            std::iter::repeat(n)
-                                .take(count)
-                                .map(|n| n.to_string())
-                                .collect::<Vec<_>>()
-                                .join(", ")
-                        })),
-                        Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| {
-                            format!(
-                                "{}<{}>",
-                                snippet,
-                                std::iter::repeat(name.to_string())
-                                    .take(count)
-                                    .collect::<Vec<_>>()
-                                    .join(", ")
-                            )
-                        })),
-                        _ => None,
-                    });
+                // Record as using the suggested resolution.
+                let (_, (_, res)) = in_scope_lifetimes[0];
+                for &lt in &lifetime_refs {
+                    self.r.lifetimes_res_map.insert(lt.id, res);
                 }
-                suggest_existing(err, **name, suggs);
             }
-            [] => {
-                let mut suggs = Vec::new();
-                for (snippet, (_, count)) in
-                    snippets.iter().cloned().zip(spans_with_counts.iter().copied())
-                {
-                    suggs.push(match snippet.as_deref() {
-                        Some("&") => Some("&'a ".to_string()),
-                        Some("'_") => Some("'a".to_string()),
-                        Some("") => {
-                            Some(std::iter::repeat("'a, ").take(count).collect::<Vec<_>>().join(""))
-                        }
-                        Some("<") => {
-                            Some(std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "))
-                        }
-                        Some(snippet) => Some(format!(
-                            "{}<{}>",
-                            snippet,
-                            std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "),
-                        )),
-                        None => None,
-                    });
-                }
-                suggest_new(err, suggs);
-            }
-            lts if lts.len() > 1 => {
+            _ => {
+                let lifetime_spans: Vec<_> =
+                    in_scope_lifetimes.iter().map(|(ident, _)| ident.span).collect();
                 err.span_note(lifetime_spans, "these named lifetimes are available to use");
 
-                let mut spans_suggs: Vec<_> = Vec::new();
-                for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) {
-                    match snippet.as_deref() {
-                        Some("") => spans_suggs.push((span, "'lifetime, ".to_string())),
-                        Some("&") => spans_suggs
-                            .push((span.with_lo(span.lo() + BytePos(1)), "'lifetime ".to_string())),
-                        _ => {}
-                    }
-                }
-
                 if spans_suggs.len() > 0 {
                     // This happens when we have `Foo<T>` where we point at the space before `T`,
                     // but this can be confusing so we give a suggestion with placeholders.
@@ -2661,7 +2341,34 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                     );
                 }
             }
-            _ => unreachable!(),
         }
     }
 }
+
+/// Report lifetime/lifetime shadowing as an error.
+pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
+    let mut err = struct_span_err!(
+        sess,
+        shadower.span,
+        E0496,
+        "lifetime name `{}` shadows a lifetime name that is already in scope",
+        orig.name,
+    );
+    err.span_label(orig.span, "first declared here");
+    err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
+    err.emit();
+}
+
+/// Shadowing involving a label is only a warning for historical reasons.
+//FIXME: make this a proper lint.
+pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
+    let name = shadower.name;
+    let shadower = shadower.span;
+    let mut err = sess.struct_span_warn(
+        shadower,
+        &format!("label name `{}` shadows a label name that is already in scope", name),
+    );
+    err.span_label(orig, "first declared here");
+    err.span_label(shadower, format!("label `{}` already in scope", name));
+    err.emit();
+}
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 0eb11cd3e9f..a7fd7c427c7 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -1,12 +1,12 @@
 // ignore-tidy-filelength
-//! Name resolution for lifetimes.
+//! Resolution of early vs late bound lifetimes.
 //!
-//! Name resolution for lifetimes follows *much* simpler rules than the
-//! full resolve. For example, lifetime names are never exported or
-//! used between functions, and they operate in a purely top-down
-//! way. Therefore, we break lifetime name resolution into a separate pass.
+//! Name resolution for lifetimes is performed on the AST and embedded into HIR.  From this
+//! information, typechecking needs to transform the lifetime parameters into bound lifetimes.
+//! Lifetimes can be early-bound or late-bound.  Construction of typechecking terms needs to visit
+//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices.  This file
+//! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
 
-use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
 use rustc_ast::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::struct_span_err;
@@ -14,13 +14,12 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
-use rustc_hir::{GenericParamKind, HirIdMap, LifetimeParamKind};
+use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
+use rustc_middle::bug;
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
 use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
-use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
@@ -152,10 +151,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> {
 
     /// Cache for cross-crate per-definition object lifetime defaults.
     xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
-
-    /// When encountering an undefined named lifetime, we will suggest introducing it in these
-    /// places.
-    pub(crate) missing_named_lifetime_spots: Vec<MissingLifetimeSpot<'tcx>>,
 }
 
 #[derive(Debug)]
@@ -323,23 +318,12 @@ enum Elide {
     /// Always use this one lifetime.
     Exact(Region),
     /// Less or more than one lifetime were found, error on unspecified.
-    Error(Vec<ElisionFailureInfo>),
+    Error,
     /// Forbid lifetime elision inside of a larger scope where it would be
     /// permitted. For example, in let position impl trait.
     Forbid,
 }
 
-#[derive(Clone, Debug)]
-pub(crate) struct ElisionFailureInfo {
-    /// Where we can find the argument pattern.
-    pub(crate) parent: Option<hir::BodyId>,
-    /// The index of the argument in the original definition.
-    pub(crate) index: usize,
-    pub(crate) lifetime_count: usize,
-    pub(crate) have_bound_regions: bool,
-    pub(crate) span: Span,
-}
-
 type ScopeRef<'a> = &'a Scope<'a>;
 
 const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
@@ -421,7 +405,6 @@ fn do_resolve(
         scope: ROOT_SCOPE,
         trait_definition_only,
         xcrate_object_lifetime_defaults: Default::default(),
-        missing_named_lifetime_spots: vec![],
     };
     visitor.visit_item(item);
 
@@ -644,40 +627,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 where_bound_origin: None,
             };
 
-            if let &hir::ClosureBinder::For { span, .. } = binder {
-                let last_lt = bound_generic_params
-                    .iter()
-                    .filter(|p| {
-                        matches!(
-                            p,
-                            GenericParam {
-                                kind: GenericParamKind::Lifetime {
-                                    kind: LifetimeParamKind::Explicit
-                                },
-                                ..
-                            }
-                        )
-                    })
-                    .last();
-                let (span, span_type) = match last_lt {
-                    Some(GenericParam { span: last_sp, .. }) => {
-                        (last_sp.shrink_to_hi(), ForLifetimeSpanType::ClosureTail)
-                    }
-                    None => (span, ForLifetimeSpanType::ClosureEmpty),
-                };
-                self.missing_named_lifetime_spots
-                    .push(MissingLifetimeSpot::HigherRanked { span, span_type });
-            }
-
             self.with(scope, |this| {
                 // a closure has no bounds, so everything
                 // contained within is scoped within its binder.
                 intravisit::walk_expr(this, e)
             });
-
-            if let hir::ClosureBinder::For { .. } = binder {
-                self.missing_named_lifetime_spots.pop();
-            }
         } else {
             intravisit::walk_expr(self, e)
         }
@@ -694,11 +648,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         }
         match item.kind {
             hir::ItemKind::Fn(_, ref generics, _) => {
-                self.missing_named_lifetime_spots.push(generics.into());
                 self.visit_early_late(None, item.hir_id(), generics, |this| {
                     intravisit::walk_item(this, item);
                 });
-                self.missing_named_lifetime_spots.pop();
             }
 
             hir::ItemKind::ExternCrate(_)
@@ -761,8 +713,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             | hir::ItemKind::Trait(_, _, ref generics, ..)
             | hir::ItemKind::TraitAlias(ref generics, ..)
             | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
-                self.missing_named_lifetime_spots.push(generics.into());
-
                 // These kinds of items have only early-bound lifetime parameters.
                 let mut index = if sub_items_have_self_param(&item.kind) {
                     1 // Self comes before lifetimes
@@ -800,7 +750,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         intravisit::walk_item(this, item);
                     });
                 });
-                self.missing_named_lifetime_spots.pop();
             }
         }
     }
@@ -826,20 +775,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         match ty.kind {
             hir::TyKind::BareFn(ref c) => {
                 let next_early_index = self.next_early_index();
-                let lifetime_span: Option<Span> =
-                    c.generic_params.iter().rev().find_map(|param| match param.kind {
-                        GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
-                            Some(param.span)
-                        }
-                        _ => None,
-                    });
-                let (span, span_type) = if let Some(span) = lifetime_span {
-                    (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail)
-                } else {
-                    (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty)
-                };
-                self.missing_named_lifetime_spots
-                    .push(MissingLifetimeSpot::HigherRanked { span, span_type });
                 let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
                     .generic_params
                     .iter()
@@ -867,7 +802,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     // contained within is scoped within its binder.
                     intravisit::walk_ty(this, ty);
                 });
-                self.missing_named_lifetime_spots.pop();
             }
             hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
                 debug!(?bounds, ?lifetime, "TraitObject");
@@ -878,11 +812,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     }
                 });
                 match lifetime.name {
-                    LifetimeName::Implicit => {
-                        // For types like `dyn Foo`, we should
-                        // generate a special form of elided.
-                        span_bug!(ty.span, "object-lifetime-default expected, not implicit",);
-                    }
                     LifetimeName::ImplicitObjectLifetimeDefault => {
                         // If the user does not write *anything*, we
                         // use the object lifetime defaulting
@@ -890,7 +819,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         // `Box<dyn Debug + 'static>`.
                         self.resolve_object_lifetime_default(lifetime)
                     }
-                    LifetimeName::Underscore => {
+                    LifetimeName::Implicit | LifetimeName::Underscore => {
                         // If the user writes `'_`, we use the *ordinary* elision
                         // rules. So the `'_` in e.g., `Box<dyn Debug + '_>` will be
                         // resolved the same as the `'_` in `&'_ Foo`.
@@ -1010,10 +939,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let mut elision = None;
                 let mut lifetimes = FxIndexMap::default();
                 let mut non_lifetime_count = 0;
+                debug!(?generics.params);
                 for param in generics.params {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
                             let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, &param);
+                            lifetimes.insert(def_id, reg);
                             if let hir::ParamName::Plain(Ident {
                                 name: kw::UnderscoreLifetime,
                                 ..
@@ -1022,8 +953,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                                 // Pick the elided lifetime "definition" if one exists
                                 // and use it to make an elision scope.
                                 elision = Some(reg);
-                            } else {
-                                lifetimes.insert(def_id, reg);
                             }
                         }
                         GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
@@ -1088,7 +1017,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
             Fn(_, _) => {
-                self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(trait_item.hir_id())),
@@ -1096,10 +1024,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     &trait_item.generics,
                     |this| intravisit::walk_trait_item(this, trait_item),
                 );
-                self.missing_named_lifetime_spots.pop();
             }
             Type(bounds, ref ty) => {
-                self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let generics = &trait_item.generics;
                 let mut index = self.next_early_index();
                 debug!("visit_ty: index = {}", index);
@@ -1140,14 +1066,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         }
                     })
                 });
-                self.missing_named_lifetime_spots.pop();
             }
             Const(_, _) => {
                 // Only methods and types support generics.
                 assert!(trait_item.generics.params.is_empty());
-                self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
                 intravisit::walk_trait_item(self, trait_item);
-                self.missing_named_lifetime_spots.pop();
             }
         }
     }
@@ -1156,7 +1079,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         use self::hir::ImplItemKind::*;
         match impl_item.kind {
             Fn(..) => {
-                self.missing_named_lifetime_spots.push((&impl_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(impl_item.hir_id())),
@@ -1164,11 +1086,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     &impl_item.generics,
                     |this| intravisit::walk_impl_item(this, impl_item),
                 );
-                self.missing_named_lifetime_spots.pop();
             }
             TyAlias(ref ty) => {
                 let generics = &impl_item.generics;
-                self.missing_named_lifetime_spots.push(generics.into());
                 let mut index = self.next_early_index();
                 let mut non_lifetime_count = 0;
                 debug!("visit_ty: index = {}", index);
@@ -1203,14 +1123,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         this.visit_ty(ty);
                     })
                 });
-                self.missing_named_lifetime_spots.pop();
             }
             Const(_, _) => {
                 // Only methods and types support generics.
                 assert!(impl_item.generics.params.is_empty());
-                self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
                 intravisit::walk_impl_item(self, impl_item);
-                self.missing_named_lifetime_spots.pop();
             }
         }
     }
@@ -1393,8 +1310,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     ) {
         debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
 
-        let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref);
-
         let next_early_index = self.next_early_index();
         let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
 
@@ -1435,10 +1350,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
             this.visit_trait_ref(&trait_ref.trait_ref);
         });
-
-        if should_pop_missing_lt {
-            self.missing_named_lifetime_spots.pop();
-        }
     }
 }
 
@@ -1584,14 +1495,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     {
         let LifetimeContext { tcx, map, .. } = self;
         let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
-        let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
         let mut this = LifetimeContext {
             tcx: *tcx,
             map,
             scope: &wrap_scope,
             trait_definition_only: self.trait_definition_only,
             xcrate_object_lifetime_defaults,
-            missing_named_lifetime_spots,
         };
         let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
         {
@@ -1599,7 +1508,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             f(&mut this);
         }
         self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
-        self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
     }
 
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
@@ -2202,24 +2110,20 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let mut assoc_item_kind = None;
         let mut impl_self = None;
         let parent = self.tcx.hir().get_parent_node(output.hir_id);
-        let body = match self.tcx.hir().get(parent) {
+        match self.tcx.hir().get(parent) {
             // `fn` definitions and methods.
-            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body),
+            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) => {}
 
-            Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => {
+            Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
                 if let hir::ItemKind::Trait(.., ref trait_items) =
                     self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
                 {
                     assoc_item_kind =
                         trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
                 }
-                match *m {
-                    hir::TraitFn::Required(_) => None,
-                    hir::TraitFn::Provided(body) => Some(body),
-                }
             }
 
-            Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => {
+            Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, _), .. }) => {
                 if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
                     self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
                 {
@@ -2227,13 +2131,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     assoc_item_kind =
                         items.iter().find(|ii| ii.id.hir_id() == parent).map(|ii| ii.kind);
                 }
-                Some(body)
             }
 
             // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
-            Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None,
+            Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => {},
 
-            Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None,
+            Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => {},
 
             // Everything else (only closures?) doesn't
             // actually enjoy elision in return types.
@@ -2320,42 +2223,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         // have that lifetime.
         let mut possible_implied_output_region = None;
         let mut lifetime_count = 0;
-        let arg_lifetimes = inputs
-            .iter()
-            .enumerate()
-            .skip(has_self as usize)
-            .map(|(i, input)| {
-                let mut gather = GatherLifetimes {
-                    map: self.map,
-                    outer_index: ty::INNERMOST,
-                    have_bound_regions: false,
-                    lifetimes: Default::default(),
-                };
-                gather.visit_ty(input);
-
-                lifetime_count += gather.lifetimes.len();
+        for input in inputs.iter().skip(has_self as usize) {
+            let mut gather = GatherLifetimes {
+                map: self.map,
+                outer_index: ty::INNERMOST,
+                have_bound_regions: false,
+                lifetimes: Default::default(),
+            };
+            gather.visit_ty(input);
 
-                if lifetime_count == 1 && gather.lifetimes.len() == 1 {
-                    // there's a chance that the unique lifetime of this
-                    // iteration will be the appropriate lifetime for output
-                    // parameters, so lets store it.
-                    possible_implied_output_region = gather.lifetimes.iter().cloned().next();
-                }
+            lifetime_count += gather.lifetimes.len();
 
-                ElisionFailureInfo {
-                    parent: body,
-                    index: i,
-                    lifetime_count: gather.lifetimes.len(),
-                    have_bound_regions: gather.have_bound_regions,
-                    span: input.span,
-                }
-            })
-            .collect();
+            if lifetime_count == 1 && gather.lifetimes.len() == 1 {
+                // there's a chance that the unique lifetime of this
+                // iteration will be the appropriate lifetime for output
+                // parameters, so lets store it.
+                possible_implied_output_region = gather.lifetimes.iter().cloned().next();
+            }
+        }
 
         let elide = if lifetime_count == 1 {
             Elide::Exact(possible_implied_output_region.unwrap())
         } else {
-            Elide::Error(arg_lifetimes)
+            Elide::Error
         };
 
         debug!(?elide);
@@ -2487,17 +2377,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
         let mut late_depth = 0;
         let mut scope = self.scope;
-        let mut in_scope_lifetimes = FxIndexSet::default();
-        let error = loop {
+        loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
                 Scope::Body { .. } => return,
 
-                Scope::Root => break None,
+                Scope::Root => break,
 
-                Scope::Binder { s, ref lifetimes, scope_type, .. } => {
-                    // collect named lifetimes for suggestions
-                    in_scope_lifetimes.extend(lifetimes.keys().copied());
+                Scope::Binder { s, scope_type, .. } => {
                     match scope_type {
                         BinderScopeType::Normal => late_depth += 1,
                         BinderScopeType::Concatenating => {}
@@ -2526,27 +2413,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     return;
                 }
 
-                Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
-                    let mut scope = s;
-                    loop {
-                        match scope {
-                            Scope::Binder { ref lifetimes, s, .. } => {
-                                // Collect named lifetimes for suggestions.
-                                in_scope_lifetimes.extend(lifetimes.keys().copied());
-                                scope = s;
-                            }
-                            Scope::ObjectLifetimeDefault { ref s, .. }
-                            | Scope::Elision { ref s, .. }
-                            | Scope::TraitRefBoundary { ref s, .. } => {
-                                scope = s;
-                            }
-                            _ => break,
-                        }
-                    }
-                    break Some(&e[..]);
-                }
-
-                Scope::Elision { elide: Elide::Forbid, .. } => break None,
+                Scope::Elision { elide: Elide::Error, .. }
+                | Scope::Elision { elide: Elide::Forbid, .. } => break,
 
                 Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
@@ -2554,26 +2422,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     scope = s;
                 }
             }
-        };
-
-        let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
-        spans.sort();
-        let mut spans_dedup = spans.clone();
-        spans_dedup.dedup();
-        let spans_with_counts: Vec<_> = spans_dedup
-            .into_iter()
-            .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count()))
-            .collect();
-
-        let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len());
+        }
 
-        self.add_missing_lifetime_specifiers_label(
-            &mut err,
-            spans_with_counts,
-            in_scope_lifetimes,
-            error,
-        );
-        err.emit();
+        for lt in lifetime_refs {
+            self.tcx.sess.delay_span_bug(lt.span, "Missing lifetime specifier");
+        }
     }
 
     fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 2fcbe1d4c14..6945306a691 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -11,6 +11,7 @@
 #![feature(drain_filter)]
 #![feature(if_let_guard)]
 #![cfg_attr(bootstrap, feature(let_chains))]
+#![feature(iter_intersperse)]
 #![feature(let_else)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
diff --git a/src/test/ui/associated-type-bounds/elision.rs b/src/test/ui/associated-type-bounds/elision.rs
new file mode 100644
index 00000000000..4a533939931
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/elision.rs
@@ -0,0 +1,9 @@
+#![feature(associated_type_bounds)]
+#![feature(anonymous_lifetime_in_impl_trait)]
+
+// The same thing should happen for constaints in dyn trait.
+fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
+//~^ ERROR missing lifetime specifier
+//~| ERROR mismatched types
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/elision.stderr b/src/test/ui/associated-type-bounds/elision.stderr
new file mode 100644
index 00000000000..ea302462749
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/elision.stderr
@@ -0,0 +1,28 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/elision.rs:5:70
+   |
+LL | fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
+   |         ------------------------------------------------             ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of `x`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+   |
+LL | fn f<'a>(x: &'a mut dyn Iterator<Item: Iterator<Item = &'a ()>>) -> Option<&'a ()> { x.next() }
+   |     ++++     ++                                         ~~                  ~~
+
+error[E0308]: mismatched types
+  --> $DIR/elision.rs:5:79
+   |
+LL | fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
+   |                           -----------------------------      --------------   ^^^^^^^^ expected `&()`, found type parameter `impl Iterator<Item = &'_ ()>`
+   |                           |                                  |
+   |                           |                                  expected `Option<&'static ()>` because of return type
+   |                           this type parameter
+   |
+   = note: expected enum `Option<&'static ()>`
+              found enum `Option<impl Iterator<Item = &'_ ()>>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0106, E0308.
+For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
index e8e07997c72..4de4afb6e92 100644
--- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
+++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
@@ -5,15 +5,10 @@ LL | fn elision<T: Fn() -> &i32>() {
    |                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider making the bound lifetime-generic with a new `'a` lifetime
-   |
-LL | fn elision<T: for<'a> Fn() -> &'a i32>() {
-   |               +++++++         ~~~
 help: consider using the `'static` lifetime
    |
 LL | fn elision<T: Fn() -> &'static i32>() {
-   |                       ~~~~~~~~
+   |                        +++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
index c75e732b7ca..7753d186504 100644
--- a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
+++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
@@ -5,15 +5,10 @@ LL | fn elision(_: fn() -> &i32) {
    |                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider making the type lifetime-generic with a new `'a` lifetime
-   |
-LL | fn elision(_: for<'a> fn() -> &'a i32) {
-   |               +++++++         ~~~
 help: consider using the `'static` lifetime
    |
 LL | fn elision(_: fn() -> &'static i32) {
-   |                       ~~~~~~~~
+   |                        +++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/issues/issue-63388-2.rs b/src/test/ui/async-await/issues/issue-63388-2.rs
index 458bc9faeaf..90b59f96e5f 100644
--- a/src/test/ui/async-await/issues/issue-63388-2.rs
+++ b/src/test/ui/async-await/issues/issue-63388-2.rs
@@ -11,6 +11,7 @@ impl Xyz {
         foo: &dyn Foo, bar: &'a dyn Foo
     ) -> &dyn Foo //~ ERROR missing lifetime specifier
     {
+        //~^ ERROR explicit lifetime required in the type of `foo` [E0621]
         foo
     }
 }
diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr
index 24fd3845b4e..e515f227c7e 100644
--- a/src/test/ui/async-await/issues/issue-63388-2.stderr
+++ b/src/test/ui/async-await/issues/issue-63388-2.stderr
@@ -10,8 +10,21 @@ LL |     ) -> &dyn Foo
 help: consider using the `'a` lifetime
    |
 LL |     ) -> &'a dyn Foo
-   |          ~~~
+   |           ++
 
-error: aborting due to previous error
+error[E0621]: explicit lifetime required in the type of `foo`
+  --> $DIR/issue-63388-2.rs:13:5
+   |
+LL |           foo: &dyn Foo, bar: &'a dyn Foo
+   |                -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
+LL |       ) -> &dyn Foo
+LL | /     {
+LL | |
+LL | |         foo
+LL | |     }
+   | |_____^ lifetime `'a` required
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0106, E0621.
+For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/c-variadic/variadic-ffi-6.stderr b/src/test/ui/c-variadic/variadic-ffi-6.stderr
index bb15cc000a4..4c7792d9650 100644
--- a/src/test/ui/c-variadic/variadic-ffi-6.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-6.stderr
@@ -4,11 +4,11 @@ error[E0106]: missing lifetime specifier
 LL | ) -> &usize {
    |      ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | ) -> &'static usize {
-   |      ~~~~~~~~
+   |       +++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr
index fbd77d96700..d11a24f7768 100644
--- a/src/test/ui/error-codes/E0106.stderr
+++ b/src/test/ui/error-codes/E0106.stderr
@@ -24,6 +24,17 @@ LL ~     B(&'a bool),
    |
 
 error[E0106]: missing lifetime specifier
+  --> $DIR/E0106.rs:10:14
+   |
+LL | type MyStr = &str;
+   |              ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | type MyStr<'a> = &'a str;
+   |           ++++    ++
+
+error[E0106]: missing lifetime specifier
   --> $DIR/E0106.rs:17:10
    |
 LL |     baz: Baz,
@@ -50,17 +61,6 @@ LL |
 LL ~     buzz: Buzz<'a, 'a>,
    |
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/E0106.rs:10:14
-   |
-LL | type MyStr = &str;
-   |              ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL | type MyStr<'a> = &'a str;
-   |           ++++    ++
-
 error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/error-codes/E0637.stderr b/src/test/ui/error-codes/E0637.stderr
index 87aaba65a73..35a4b34fb0a 100644
--- a/src/test/ui/error-codes/E0637.stderr
+++ b/src/test/ui/error-codes/E0637.stderr
@@ -4,12 +4,6 @@ error[E0637]: `'_` cannot be used here
 LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
    |                        ^^ `'_` is a reserved lifetime name
 
-error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/E0637.rs:13:13
-   |
-LL |     T: Into<&u32>,
-   |             ^ explicit lifetime name needed here
-
 error[E0106]: missing lifetime specifier
   --> $DIR/E0637.rs:1:62
    |
@@ -22,6 +16,12 @@ help: consider introducing a named lifetime parameter
 LL | fn underscore_lifetime<'a, '_>(str1: &'a str, str2: &'a str) -> &'a str {
    |                        +++            ~~             ~~          ~~
 
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/E0637.rs:13:13
+   |
+LL |     T: Into<&u32>,
+   |             ^ explicit lifetime name needed here
+
 error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0106, E0637.
diff --git a/src/test/ui/foreign-fn-return-lifetime.stderr b/src/test/ui/foreign-fn-return-lifetime.stderr
index b174766cd3d..df1a23a19ed 100644
--- a/src/test/ui/foreign-fn-return-lifetime.stderr
+++ b/src/test/ui/foreign-fn-return-lifetime.stderr
@@ -8,7 +8,7 @@ LL |     pub fn f() -> &u8;
 help: consider using the `'static` lifetime
    |
 LL |     pub fn f() -> &'static u8;
-   |                   ~~~~~~~~
+   |                    +++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs
index 246659a268a..dbf7e02aeaf 100644
--- a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs
+++ b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs
@@ -7,9 +7,10 @@ trait Foo {
 }
 
 impl <T, T1> Foo for T {
+    //~^ ERROR: the type parameter `T1` is not constrained
     type F<T1> = &[u8];
       //~^ ERROR: the name `T1` is already used for
-      //~| ERROR: missing lifetime specifier
+      //~| ERROR: `&` without an explicit lifetime name cannot be used here
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr
index e82cbf7e8e5..dad0dae6a44 100644
--- a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr
+++ b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr
@@ -1,23 +1,25 @@
 error[E0403]: the name `T1` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/gat-trait-path-generic-type-arg.rs:10:12
+  --> $DIR/gat-trait-path-generic-type-arg.rs:11:12
    |
 LL | impl <T, T1> Foo for T {
    |          -- first use of `T1`
+LL |
 LL |     type F<T1> = &[u8];
    |            ^^ already used
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/gat-trait-path-generic-type-arg.rs:10:18
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/gat-trait-path-generic-type-arg.rs:11:18
    |
 LL |     type F<T1> = &[u8];
-   |                  ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
+   |                  ^ explicit lifetime name needed here
+
+error[E0207]: the type parameter `T1` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/gat-trait-path-generic-type-arg.rs:9:10
    |
-LL |     type F<'a, T1> = &'a [u8];
-   |            +++        ++
+LL | impl <T, T1> Foo for T {
+   |          ^^ unconstrained type parameter
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0106, E0403.
-For more information about an error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0207, E0403, E0637.
+For more information about an error, try `rustc --explain E0207`.
diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs
index c9fd7248a80..f778f985cf0 100644
--- a/src/test/ui/generic-associated-types/issue-70304.rs
+++ b/src/test/ui/generic-associated-types/issue-70304.rs
@@ -2,6 +2,7 @@
 
 trait Document {
     type Cursor<'a>: DocCursor<'a>;
+    //~^ ERROR: missing required bound on `Cursor`
 
     fn cursor(&self) -> Self::Cursor<'_>;
 }
diff --git a/src/test/ui/generic-associated-types/issue-70304.stderr b/src/test/ui/generic-associated-types/issue-70304.stderr
index b3881ccb099..bba7cab7093 100644
--- a/src/test/ui/generic-associated-types/issue-70304.stderr
+++ b/src/test/ui/generic-associated-types/issue-70304.stderr
@@ -1,11 +1,11 @@
 error[E0637]: `'_` cannot be used here
-  --> $DIR/issue-70304.rs:47:41
+  --> $DIR/issue-70304.rs:48:41
    |
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
    |                                         ^^ `'_` is a reserved lifetime name
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-70304.rs:47:61
+  --> $DIR/issue-70304.rs:48:61
    |
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
    |                                                             ^^ expected named lifetime parameter
@@ -16,7 +16,18 @@ help: consider using the `'static` lifetime
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'static>> {
    |                                                             ~~~~~~~
 
-error: aborting due to 2 previous errors
+error: missing required bound on `Cursor`
+  --> $DIR/issue-70304.rs:4:5
+   |
+LL |     type Cursor<'a>: DocCursor<'a>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                   |
+   |                                   help: add the required where clause: `where Self: 'a`
+   |
+   = note: this bound is currently required to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0106, E0637.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs
index 54b483f53d4..9ea9fc71b55 100644
--- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs
+++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs
@@ -8,6 +8,7 @@ fn should_error<T>() where T : Into<&u32> {}
 trait X<'a, K: 'a> {
     fn foo<'b, L: X<&'b Nested<K>>>();
     //~^ ERROR missing lifetime specifier [E0106]
+    //~| ERROR the type `&'b Nested<K>` does not fulfill the required lifetime
 }
 
 fn bar<'b, L: X<&'b Nested<i32>>>(){}
diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
index 270d6b8e18e..e45387acaf3 100644
--- a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
+++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
@@ -5,21 +5,10 @@ LL | fn should_error<T>() where T : Into<&u32> {}
    |                                     ^ explicit lifetime name needed here
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17
-   |
-LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
-   |                 ^ expected named lifetime parameter
-   |
-help: consider using the `'b` lifetime
-   |
-LL | fn bar<'b, L: X<'b, &'b Nested<i32>>>(){}
-   |                 +++
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:21
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20
    |
 LL |     fn foo<'b, L: X<&'b Nested<K>>>();
-   |                     ^ expected named lifetime parameter
+   |                    ^ expected named lifetime parameter
    |
 note: these named lifetimes are available to use
   --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:9
@@ -33,7 +22,30 @@ help: consider using one of the available lifetimes here
 LL |     fn foo<'b, L: X<'lifetime, &'b Nested<K>>>();
    |                     ++++++++++
 
-error: aborting due to 3 previous errors
+error[E0106]: missing lifetime specifier
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:14:16
+   |
+LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
+   |                ^ expected named lifetime parameter
+   |
+help: consider using the `'b` lifetime
+   |
+LL | fn bar<'b, L: X<'b, &'b Nested<i32>>>(){}
+   |                 +++
+
+error[E0477]: the type `&'b Nested<K>` does not fulfill the required lifetime
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19
+   |
+LL |     fn foo<'b, L: X<&'b Nested<K>>>();
+   |                   ^^^^^^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:16
+   |
+LL | trait X<'a, K: 'a> {
+   |                ^^
+
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0106, E0637.
+Some errors have detailed explanations: E0106, E0477, E0637.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/generics/wrong-number-of-args.rs b/src/test/ui/generics/wrong-number-of-args.rs
index 272cd361968..cd2f96a1819 100644
--- a/src/test/ui/generics/wrong-number-of-args.rs
+++ b/src/test/ui/generics/wrong-number-of-args.rs
@@ -120,6 +120,7 @@ mod r#trait {
     type B = Box<dyn GenericLifetime>;
     //~^ ERROR missing lifetime specifier
     //~| HELP consider introducing
+    //~| HELP consider making the bound lifetime-generic
 
     type C = Box<dyn GenericLifetime<'static, 'static>>;
     //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
@@ -136,6 +137,7 @@ mod r#trait {
     type F = Box<dyn GenericLifetime<>>;
     //~^ ERROR missing lifetime specifier
     //~| HELP consider introducing
+    //~| HELP consider making the bound lifetime-generic
 
     type G = Box<dyn GenericType<>>;
     //~^ ERROR this trait takes 1 generic argument but 0 generic arguments
@@ -161,6 +163,7 @@ mod associated_item {
         type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
 
         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
         //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
@@ -169,6 +172,7 @@ mod associated_item {
         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
         //~| ERROR this trait takes 0 generic arguments but 1 generic argument
         //~| HELP remove
     }
@@ -203,6 +207,7 @@ mod associated_item {
         //~| HELP add missing
         //~| ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
 
         type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
         //~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
@@ -217,10 +222,12 @@ mod associated_item {
         type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
 
         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
         //~| ERROR this trait takes 1 generic argument but 2 generic arguments
         //~| HELP remove
 
@@ -265,6 +272,7 @@ mod associated_item {
         type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
 
         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
         //~^ ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
@@ -279,6 +287,7 @@ mod associated_item {
         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
         //~| ERROR this trait takes 1 generic argument but 0 generic arguments
         //~| HELP add missing
 
diff --git a/src/test/ui/generics/wrong-number-of-args.stderr b/src/test/ui/generics/wrong-number-of-args.stderr
index 3b0834a5f51..388c23fc24f 100644
--- a/src/test/ui/generics/wrong-number-of-args.stderr
+++ b/src/test/ui/generics/wrong-number-of-args.stderr
@@ -1,3 +1,172 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:48:14
+   |
+LL |     type A = Ty;
+   |              ^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL |     type A<'a> = Ty<'a>;
+   |           ++++     ++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:58:16
+   |
+LL |     type C = Ty<usize>;
+   |                ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL |     type C<'a> = Ty<'a, usize>;
+   |           ++++      +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:64:16
+   |
+LL |     type E = Ty<>;
+   |                ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL |     type E<'a> = Ty<'a, >;
+   |           ++++      +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:120:22
+   |
+LL |     type B = Box<dyn GenericLifetime>;
+   |                      ^^^^^^^^^^^^^^^ expected named lifetime parameter
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |     type B = Box<dyn for<'a> GenericLifetime<'a>>;
+   |                      +++++++                ++++
+help: consider introducing a named lifetime parameter
+   |
+LL |     type B<'a> = Box<dyn GenericLifetime<'a>>;
+   |           ++++                          ++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:137:37
+   |
+LL |     type F = Box<dyn GenericLifetime<>>;
+   |                                     ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |     type F = Box<dyn for<'a> GenericLifetime<'a, >>;
+   |                      +++++++                 +++
+help: consider introducing a named lifetime parameter
+   |
+LL |     type F<'a> = Box<dyn GenericLifetime<'a, >>;
+   |           ++++                           +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:163:43
+   |
+LL |         type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
+   |                                           ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type A = Box<dyn for<'a> GenericLifetimeAT<'a, AssocTy=()>>;
+   |                          +++++++                   +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>;
+   |               ++++                             +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:172:43
+   |
+LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
+   |                                           ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type C = Box<dyn for<'a> GenericLifetimeAT<'a, (), AssocTy=()>>;
+   |                          +++++++                   +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>;
+   |               ++++                             +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:205:47
+   |
+LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
+   |                                               ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type A = Box<dyn for<'a> GenericLifetimeTypeAT<'a, AssocTy=()>>;
+   |                          +++++++                       +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>;
+   |               ++++                                 +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:222:47
+   |
+LL |         type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
+   |                                               ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type D = Box<dyn for<'a> GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
+   |                          +++++++                       +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
+   |               ++++                                 +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:227:47
+   |
+LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
+   |                                               ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type E = Box<dyn for<'a> GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>;
+   |                          +++++++                       +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>;
+   |               ++++                                 +++
+
+error[E0106]: missing lifetime specifiers
+  --> $DIR/wrong-number-of-args.rs:272:51
+   |
+LL |         type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
+   |                                                   ^ expected 2 lifetime parameters
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type A = Box<dyn for<'a> GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>;
+   |                          +++++++                           +++++++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>;
+   |               ++++                                     +++++++
+
+error[E0106]: missing lifetime specifiers
+  --> $DIR/wrong-number-of-args.rs:287:55
+   |
+LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
+   |                                                       ^ expected 2 lifetime parameters
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type A = Box<dyn for<'a> GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
+   |                          +++++++                               +++++++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
+   |               ++++                                         +++++++
+
 error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:6:14
    |
@@ -148,17 +317,6 @@ help: add missing generic argument
 LL |     type A = Ty<T>;
    |              ~~~~~
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:48:14
-   |
-LL |     type A = Ty;
-   |              ^^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type A<'a> = Ty<'a>;
-   |           ++++   ~~~~~~
-
 error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:54:14
    |
@@ -175,17 +333,6 @@ help: add missing generic argument
 LL |     type B = Ty<'static, T>;
    |                        +++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:58:17
-   |
-LL |     type C = Ty<usize>;
-   |                 ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type C<'a> = Ty<'a, usize>;
-   |           ++++      +++
-
 error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:64:14
    |
@@ -202,17 +349,6 @@ help: add missing generic argument
 LL |     type E = Ty<T>;
    |                 +
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:64:16
-   |
-LL |     type E = Ty<>;
-   |                ^- expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type E<'a> = Ty<'a>;
-   |           ++++      ++
-
 error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/wrong-number-of-args.rs:70:14
    |
@@ -319,19 +455,8 @@ note: trait defined here, with 0 generic parameters
 LL |     trait NonGeneric {
    |           ^^^^^^^^^^
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:120:22
-   |
-LL |     type B = Box<dyn GenericLifetime>;
-   |                      ^^^^^^^^^^^^^^^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type B<'a> = Box<dyn GenericLifetime<'a>>;
-   |           ++++           ~~~~~~~~~~~~~~~~~~~
-
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:124:22
+  --> $DIR/wrong-number-of-args.rs:125:22
    |
 LL |     type C = Box<dyn GenericLifetime<'static, 'static>>;
    |                      ^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -345,7 +470,7 @@ LL |     trait GenericLifetime<'a> {
    |           ^^^^^^^^^^^^^^^ --
 
 error[E0107]: missing generics for trait `GenericType`
-  --> $DIR/wrong-number-of-args.rs:128:22
+  --> $DIR/wrong-number-of-args.rs:129:22
    |
 LL |     type D = Box<dyn GenericType>;
    |                      ^^^^^^^^^^^ expected 1 generic argument
@@ -361,7 +486,7 @@ LL |     type D = Box<dyn GenericType<A>>;
    |                      ~~~~~~~~~~~~~~
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:132:22
+  --> $DIR/wrong-number-of-args.rs:133:22
    |
 LL |     type E = Box<dyn GenericType<String, usize>>;
    |                      ^^^^^^^^^^^         ----- help: remove this generic argument
@@ -374,19 +499,8 @@ note: trait defined here, with 1 generic parameter: `A`
 LL |     trait GenericType<A> {
    |           ^^^^^^^^^^^ -
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:136:37
-   |
-LL |     type F = Box<dyn GenericLifetime<>>;
-   |                                     ^- expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type F<'a> = Box<dyn GenericLifetime<'a>>;
-   |           ++++                           ++
-
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:140:22
+  --> $DIR/wrong-number-of-args.rs:142:22
    |
 LL |     type G = Box<dyn GenericType<>>;
    |                      ^^^^^^^^^^^ expected 1 generic argument
@@ -402,7 +516,7 @@ LL |     type G = Box<dyn GenericType<A>>;
    |                                  +
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:151:26
+  --> $DIR/wrong-number-of-args.rs:153:26
    |
 LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
    |                          ^^^^^^^^^^^^------------------- help: remove these generics
@@ -410,24 +524,13 @@ LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
    |                          expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:147:15
+  --> $DIR/wrong-number-of-args.rs:149:15
    |
 LL |         trait NonGenericAT {
    |               ^^^^^^^^^^^^
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:161:44
-   |
-LL |         type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
-   |                                            ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>;
-   |               ++++                             +++
-
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:165:26
+  --> $DIR/wrong-number-of-args.rs:168:26
    |
 LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -435,13 +538,13 @@ LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:157:15
+  --> $DIR/wrong-number-of-args.rs:159:15
    |
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:169:26
+  --> $DIR/wrong-number-of-args.rs:172:26
    |
 LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
@@ -449,30 +552,19 @@ LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                          expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:157:15
+  --> $DIR/wrong-number-of-args.rs:159:15
    |
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:169:44
-   |
-LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
-   |                                            ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>;
-   |               ++++                             +++
-
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:181:26
+  --> $DIR/wrong-number-of-args.rs:185:26
    |
 LL |         type A = Box<dyn GenericTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:177:15
+  --> $DIR/wrong-number-of-args.rs:181:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
@@ -482,7 +574,7 @@ LL |         type A = Box<dyn GenericTypeAT<A, AssocTy=()>>;
    |                                        ++
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:185:26
+  --> $DIR/wrong-number-of-args.rs:189:26
    |
 LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^     -- help: remove this generic argument
@@ -490,13 +582,13 @@ LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:177:15
+  --> $DIR/wrong-number-of-args.rs:181:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
 
 error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:189:26
+  --> $DIR/wrong-number-of-args.rs:193:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^--------------------- help: remove these generics
@@ -504,19 +596,19 @@ LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          expected 0 lifetime arguments
    |
 note: trait defined here, with 0 lifetime parameters
-  --> $DIR/wrong-number-of-args.rs:177:15
+  --> $DIR/wrong-number-of-args.rs:181:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:189:26
+  --> $DIR/wrong-number-of-args.rs:193:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:177:15
+  --> $DIR/wrong-number-of-args.rs:181:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
@@ -526,13 +618,13 @@ LL |         type C = Box<dyn GenericTypeAT<'static, A, AssocTy=()>>;
    |                                               +++
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:201:26
+  --> $DIR/wrong-number-of-args.rs:205:26
    |
 LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -541,25 +633,14 @@ help: add missing generic argument
 LL |         type A = Box<dyn GenericLifetimeTypeAT<A, AssocTy=()>>;
    |                                                ++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:201:48
-   |
-LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
-   |                                                ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>;
-   |               ++++                                 +++
-
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:207:26
+  --> $DIR/wrong-number-of-args.rs:212:26
    |
 LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -569,7 +650,7 @@ LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, A, AssocTy=()>>;
    |                                                       +++
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:211:26
+  --> $DIR/wrong-number-of-args.rs:216:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -577,19 +658,19 @@ LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:211:26
+  --> $DIR/wrong-number-of-args.rs:216:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -598,19 +679,8 @@ help: add missing generic argument
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, A, AssocTy=()>>;
    |                                                                +++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:217:48
-   |
-LL |         type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
-   |                                                ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
-   |               ++++                                 +++
-
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:221:26
+  --> $DIR/wrong-number-of-args.rs:227:26
    |
 LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^     -- help: remove this generic argument
@@ -618,24 +688,13 @@ LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:221:48
-   |
-LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
-   |                                                ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>;
-   |               ++++                                 +++
-
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:227:26
+  --> $DIR/wrong-number-of-args.rs:234:26
    |
 LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -643,13 +702,13 @@ LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocT
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:231:26
+  --> $DIR/wrong-number-of-args.rs:238:26
    |
 LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^              -- help: remove this generic argument
@@ -657,13 +716,13 @@ LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:235:26
+  --> $DIR/wrong-number-of-args.rs:242:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -671,13 +730,13 @@ LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:235:26
+  --> $DIR/wrong-number-of-args.rs:242:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^                       -- help: remove this generic argument
@@ -685,19 +744,19 @@ LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:247:26
+  --> $DIR/wrong-number-of-args.rs:254:26
    |
 LL |         type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:243:15
+  --> $DIR/wrong-number-of-args.rs:250:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
@@ -707,7 +766,7 @@ LL |         type A = Box<dyn GenericTypeTypeAT<A, B, AssocTy=()>>;
    |                                            +++++
 
 error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:251:26
+  --> $DIR/wrong-number-of-args.rs:258:26
    |
 LL |         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument
@@ -715,7 +774,7 @@ LL |         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
    |                          expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:243:15
+  --> $DIR/wrong-number-of-args.rs:250:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
@@ -725,7 +784,7 @@ LL |         type B = Box<dyn GenericTypeTypeAT<(), B, AssocTy=()>>;
    |                                              +++
 
 error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:255:26
+  --> $DIR/wrong-number-of-args.rs:262:26
    |
 LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^         -- help: remove this generic argument
@@ -733,24 +792,13 @@ LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
    |                          expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:243:15
+  --> $DIR/wrong-number-of-args.rs:250:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
 
-error[E0106]: missing lifetime specifiers
-  --> $DIR/wrong-number-of-args.rs:265:52
-   |
-LL |         type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
-   |                                                    ^ expected 2 lifetime parameters
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>;
-   |               ++++                                     +++++++
-
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:269:26
+  --> $DIR/wrong-number-of-args.rs:277:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -758,7 +806,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:261:15
+  --> $DIR/wrong-number-of-args.rs:268:15
    |
 LL |         trait GenericLifetimeLifetimeAT<'a, 'b> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -768,13 +816,13 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, 'b, AssocTy=()>
    |                                                           ++++
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:279:26
+  --> $DIR/wrong-number-of-args.rs:287:26
    |
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:275:15
+  --> $DIR/wrong-number-of-args.rs:283:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -
@@ -783,19 +831,8 @@ help: add missing generic argument
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<A, AssocTy=()>>;
    |                                                        ++
 
-error[E0106]: missing lifetime specifiers
-  --> $DIR/wrong-number-of-args.rs:279:56
-   |
-LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
-   |                                                        ^ expected 2 lifetime parameters
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
-   |               ++++                                         +++++++
-
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:285:26
+  --> $DIR/wrong-number-of-args.rs:294:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -803,7 +840,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:275:15
+  --> $DIR/wrong-number-of-args.rs:283:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -813,13 +850,13 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, AssocTy
    |                                                               ++++
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:285:26
+  --> $DIR/wrong-number-of-args.rs:294:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:275:15
+  --> $DIR/wrong-number-of-args.rs:283:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -
@@ -829,7 +866,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, A, AssocTy=
    |                                                               +++
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:291:26
+  --> $DIR/wrong-number-of-args.rs:300:26
    |
 LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -837,7 +874,7 @@ LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:275:15
+  --> $DIR/wrong-number-of-args.rs:283:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -847,7 +884,7 @@ LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, (), Ass
    |                                                               ++++
 
 error[E0107]: missing generics for struct `HashMap`
-  --> $DIR/wrong-number-of-args.rs:301:18
+  --> $DIR/wrong-number-of-args.rs:310:18
    |
 LL |         type A = HashMap;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -863,7 +900,7 @@ LL |         type A = HashMap<K, V>;
    |                  ~~~~~~~~~~~~~
 
 error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:305:18
+  --> $DIR/wrong-number-of-args.rs:314:18
    |
 LL |         type B = HashMap<String>;
    |                  ^^^^^^^ ------ supplied 1 generic argument
@@ -881,7 +918,7 @@ LL |         type B = HashMap<String, V>;
    |                                +++
 
 error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:309:18
+  --> $DIR/wrong-number-of-args.rs:318:18
    |
 LL |         type C = HashMap<'static>;
    |                  ^^^^^^^--------- help: remove these generics
@@ -895,7 +932,7 @@ LL | pub struct HashMap<K, V, S = RandomState> {
    |            ^^^^^^^
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:309:18
+  --> $DIR/wrong-number-of-args.rs:318:18
    |
 LL |         type C = HashMap<'static>;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -911,7 +948,7 @@ LL |         type C = HashMap<'static, K, V>;
    |                                 ++++++
 
 error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:315:18
+  --> $DIR/wrong-number-of-args.rs:324:18
    |
 LL |         type D = HashMap<usize, String, char, f64>;
    |                  ^^^^^^^                      --- help: remove this generic argument
@@ -925,7 +962,7 @@ LL | pub struct HashMap<K, V, S = RandomState> {
    |            ^^^^^^^ -  -  ---------------
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:319:18
+  --> $DIR/wrong-number-of-args.rs:328:18
    |
 LL |         type E = HashMap<>;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -941,7 +978,7 @@ LL |         type E = HashMap<K, V>;
    |                          ++++
 
 error[E0107]: missing generics for enum `Result`
-  --> $DIR/wrong-number-of-args.rs:325:18
+  --> $DIR/wrong-number-of-args.rs:334:18
    |
 LL |         type A = Result;
    |                  ^^^^^^ expected 2 generic arguments
@@ -957,7 +994,7 @@ LL |         type A = Result<T, E>;
    |                  ~~~~~~~~~~~~
 
 error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:329:18
+  --> $DIR/wrong-number-of-args.rs:338:18
    |
 LL |         type B = Result<String>;
    |                  ^^^^^^ ------ supplied 1 generic argument
@@ -975,7 +1012,7 @@ LL |         type B = Result<String, E>;
    |                               +++
 
 error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:333:18
+  --> $DIR/wrong-number-of-args.rs:342:18
    |
 LL |         type C = Result<'static>;
    |                  ^^^^^^--------- help: remove these generics
@@ -989,7 +1026,7 @@ LL | pub enum Result<T, E> {
    |          ^^^^^^
 
 error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:333:18
+  --> $DIR/wrong-number-of-args.rs:342:18
    |
 LL |         type C = Result<'static>;
    |                  ^^^^^^ expected 2 generic arguments
@@ -1005,7 +1042,7 @@ LL |         type C = Result<'static, T, E>;
    |                                ++++++
 
 error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:339:18
+  --> $DIR/wrong-number-of-args.rs:348:18
    |
 LL |         type D = Result<usize, String, char>;
    |                  ^^^^^^                ---- help: remove this generic argument
@@ -1019,7 +1056,7 @@ LL | pub enum Result<T, E> {
    |          ^^^^^^ -  -
 
 error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:343:18
+  --> $DIR/wrong-number-of-args.rs:352:18
    |
 LL |         type E = Result<>;
    |                  ^^^^^^ expected 2 generic arguments
diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.rs b/src/test/ui/impl-header-lifetime-elision/assoc-type.rs
index 44c46e444d6..b0089a37aa0 100644
--- a/src/test/ui/impl-header-lifetime-elision/assoc-type.rs
+++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.rs
@@ -9,12 +9,12 @@ trait MyTrait {
 
 impl MyTrait for &i32 {
     type Output = &i32;
-    //~^ ERROR missing lifetime specifier
+    //~^ ERROR `&` without an explicit lifetime name cannot be used here
 }
 
 impl MyTrait for &u32 {
     type Output = &'_ i32;
-    //~^ ERROR missing lifetime specifier
+    //~^ ERROR `'_` cannot be used here
 }
 
 // This is what you have to do:
diff --git a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr
index 44955c58889..c4f27e0b80e 100644
--- a/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/assoc-type.stderr
@@ -1,25 +1,15 @@
-error[E0106]: missing lifetime specifier
+error[E0637]: `&` without an explicit lifetime name cannot be used here
   --> $DIR/assoc-type.rs:11:19
    |
 LL |     type Output = &i32;
-   |                   ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type Output<'a> = &'a i32;
-   |                ++++    ++
+   |                   ^ explicit lifetime name needed here
 
-error[E0106]: missing lifetime specifier
+error[E0637]: `'_` cannot be used here
   --> $DIR/assoc-type.rs:16:20
    |
 LL |     type Output = &'_ i32;
-   |                    ^^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type Output<'a> = &'a i32;
-   |                ++++    ~~
+   |                    ^^ `'_` is a reserved lifetime name
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+For more information about this error, try `rustc --explain E0637`.
diff --git a/src/test/ui/issues/issue-13497.stderr b/src/test/ui/issues/issue-13497.stderr
index 6521a67428e..4b1d979da36 100644
--- a/src/test/ui/issues/issue-13497.stderr
+++ b/src/test/ui/issues/issue-13497.stderr
@@ -8,7 +8,7 @@ LL |     &str
 help: consider using the `'static` lifetime
    |
 LL |     &'static str
-   |     ~~~~~~~~
+   |      +++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-19707.stderr b/src/test/ui/issues/issue-19707.stderr
index 18f69bb5775..3e1bb32c19b 100644
--- a/src/test/ui/issues/issue-19707.stderr
+++ b/src/test/ui/issues/issue-19707.stderr
@@ -22,7 +22,6 @@ LL | fn bar<F: Fn(&u8, &u8) -> &u8>(f: &F) {}
    |              ---  ---     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
-   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
 help: consider making the bound lifetime-generic with a new `'a` lifetime
    |
 LL | fn bar<F: for<'a> Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {}
diff --git a/src/test/ui/issues/issue-30255.stderr b/src/test/ui/issues/issue-30255.stderr
index e5f492af5b3..adb721a1cba 100644
--- a/src/test/ui/issues/issue-30255.stderr
+++ b/src/test/ui/issues/issue-30255.stderr
@@ -7,8 +7,8 @@ LL | fn f(a: &S, b: i32) -> &i32 {
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from
 help: consider introducing a named lifetime parameter
    |
-LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 {
-   |     ++++     ++                ++
+LL | fn f<'a>(a: &'a S<'a>, b: i32) -> &'a i32 {
+   |     ++++     ++  ++++              ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-30255.rs:14:34
@@ -19,8 +19,8 @@ LL | fn g(a: &S, b: bool, c: &i32) -> &i32 {
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c`
 help: consider introducing a named lifetime parameter
    |
-LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 {
-   |     ++++     ++                 ++          ++
+LL | fn g<'a>(a: &'a S<'a>, b: bool, c: &'a i32) -> &'a i32 {
+   |     ++++     ++  ++++               ++          ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-30255.rs:19:44
@@ -31,8 +31,8 @@ LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 {
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d`
 help: consider introducing a named lifetime parameter
    |
-LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a i32 {
-   |     ++++     ++                    ++        ++          ++
+LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S<'a>, d: &'a i32) -> &'a i32 {
+   |     ++++     ++                    ++  ++++      ++          ++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/lifetimes/issue-26638.rs b/src/test/ui/lifetimes/issue-26638.rs
index 72fe4286a06..000ab6492bb 100644
--- a/src/test/ui/lifetimes/issue-26638.rs
+++ b/src/test/ui/lifetimes/issue-26638.rs
@@ -1,8 +1,11 @@
 fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
 //~^ ERROR missing lifetime specifier [E0106]
+//~| ERROR mismatched types
 
 fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
 //~^ ERROR missing lifetime specifier [E0106]
+//~| ERROR mismatched types
+//~| ERROR this function takes 1 argument but 0 arguments were supplied
 
 fn parse_type_3() -> &str { unimplemented!() }
 //~^ ERROR missing lifetime specifier [E0106]
diff --git a/src/test/ui/lifetimes/issue-26638.stderr b/src/test/ui/lifetimes/issue-26638.stderr
index bb7cdcbb100..f3af5cf5a35 100644
--- a/src/test/ui/lifetimes/issue-26638.stderr
+++ b/src/test/ui/lifetimes/issue-26638.stderr
@@ -7,23 +7,23 @@ LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.ne
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from
 help: consider introducing a named lifetime parameter
    |
-LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }
-   |              ++++                                                 ++
+LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&'a str>+'static>) -> &'a str { iter.next() }
+   |              ++++                              ++                    ++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-26638.rs:4:40
+  --> $DIR/issue-26638.rs:5:40
    |
 LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
    |                                        ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() }
-   |                                        ~~~~~~~~
+   |                                         +++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-26638.rs:7:22
+  --> $DIR/issue-26638.rs:10:22
    |
 LL | fn parse_type_3() -> &str { unimplemented!() }
    |                      ^ expected named lifetime parameter
@@ -32,8 +32,42 @@ LL | fn parse_type_3() -> &str { unimplemented!() }
 help: consider using the `'static` lifetime
    |
 LL | fn parse_type_3() -> &'static str { unimplemented!() }
-   |                      ~~~~~~~~
+   |                       +++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-26638.rs:1:69
+   |
+LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
+   |                                                              ----   ^^^^^^^^^^^ expected `&str`, found enum `Option`
+   |                                                              |
+   |                                                              expected `&'static str` because of return type
+   |
+   = note: expected reference `&'static str`
+                   found enum `Option<&str>`
+
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+  --> $DIR/issue-26638.rs:5:47
+   |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+   |                                               ^^^^-- an argument of type `&u8` is missing
+   |
+help: provide the argument
+   |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter(/* &u8 */) }
+   |                                               ~~~~~~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/issue-26638.rs:5:47
+   |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+   |                                        ----   ^^^^^^ expected `str`, found `u8`
+   |                                        |
+   |                                        expected `&'static str` because of return type
+   |
+   = note: expected reference `&'static str`
+              found reference `&u8`
 
-error: aborting due to 3 previous errors
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0061, E0106, E0308.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
index 0e69cd50f6a..d0775487955 100644
--- a/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
+++ b/src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
@@ -8,7 +8,7 @@ LL | fn f() -> &isize {
 help: consider using the `'static` lifetime
    |
 LL | fn f() -> &'static isize {
-   |           ~~~~~~~~
+   |            +++++++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33
@@ -31,8 +31,8 @@ LL | fn h(_x: &Foo) -> &isize {
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from
 help: consider introducing a named lifetime parameter
    |
-LL | fn h<'a>(_x: &'a Foo) -> &'a isize {
-   |     ++++      ++          ++
+LL | fn h<'a>(_x: &'a Foo<'a>) -> &'a isize {
+   |     ++++      ++    ++++      ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20
@@ -40,11 +40,11 @@ error[E0106]: missing lifetime specifier
 LL | fn i(_x: isize) -> &isize {
    |                    ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn i(_x: isize) -> &'static isize {
-   |                    ~~~~~~~~
+   |                     +++++++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:34:24
@@ -52,11 +52,11 @@ error[E0106]: missing lifetime specifier
 LL | fn j(_x: StaticStr) -> &isize {
    |                        ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn j(_x: StaticStr) -> &'static isize {
-   |                        ~~~~~~~~
+   |                         +++++++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:40:49
@@ -64,11 +64,11 @@ error[E0106]: missing lifetime specifier
 LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize {
    |                                                 ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'a` lifetime
    |
 LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &'a isize {
-   |                                                 ~~~
+   |                                                  ++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs
index d1263a4acb2..d6c918843c7 100644
--- a/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs
+++ b/src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs
@@ -2,4 +2,4 @@ fn foo(x: &i32, y: &i32) -> &i32 { //~ ERROR missing lifetime
     if x > y { x } else { y }
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr
index b16b792aefe..b8c68a4607d 100644
--- a/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr
+++ b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr
@@ -7,7 +7,7 @@ LL | type B<'a> = <A<'a> as Trait>::Foo;
 help: consider using the `'a` lifetime
    |
 LL | type B<'a> = <A<'a> as Trait<'a>>::Foo;
-   |                        ~~~~~~~~~
+   |                             ++++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/missing-lifetime-in-alias.rs:26:28
@@ -20,6 +20,10 @@ note: these named lifetimes are available to use
    |
 LL | type C<'a, 'b> = <A<'a> as Trait>::Bar;
    |        ^^  ^^
+help: consider using one of the available lifetimes here
+   |
+LL | type C<'a, 'b> = <A<'a> as Trait<'lifetime>>::Bar;
+   |                                 +++++++++++
 
 error[E0107]: missing generics for associated type `Trait::Bar`
   --> $DIR/missing-lifetime-in-alias.rs:26:36
diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs
index 6aa34354a7a..c7842667dc6 100644
--- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs
+++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs
@@ -9,6 +9,7 @@ impl<T, S: Iterator<Item = T>> Iterator for ChunkingIterator<T, S> {
     type Item = IteratorChunk<T, S>; //~ ERROR missing lifetime
 
     fn next(&mut self) -> Option<IteratorChunk<T, S>> {
+        //~^ ERROR `impl` item signature doesn't match `trait` item signature
         todo!()
     }
 }
diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr
index c7e1f87f2d4..94a9c97576f 100644
--- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr
+++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr
@@ -1,14 +1,30 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-74918-missing-lifetime.rs:9:31
+  --> $DIR/issue-74918-missing-lifetime.rs:9:30
    |
 LL |     type Item = IteratorChunk<T, S>;
-   |                               ^ expected named lifetime parameter
+   |                              ^ expected named lifetime parameter
    |
 help: consider introducing a named lifetime parameter
    |
 LL |     type Item<'a> = IteratorChunk<'a, T, S>;
    |              ++++                 +++
 
-error: aborting due to previous error
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/issue-74918-missing-lifetime.rs:11:5
+   |
+LL |     fn next(&mut self) -> Option<IteratorChunk<T, S>> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
+   |
+  ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |     fn next(&mut self) -> Option<Self::Item>;
+   |     ----------------------------------------- expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+   |
+   = note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+              found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs
index 4397baea4a9..c377ecea94d 100644
--- a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs
+++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs
@@ -2,5 +2,5 @@ fn main() {}
 
 trait Foo {
     fn fn_with_type_named_same_as_local_in_param(b: b);
-    //~^ ERROR cannot find type `b` in this scope
+    //~^ ERROR cannot find type `b` in this scope [E0412]
 }
diff --git a/src/test/ui/rfc1623-2.rs b/src/test/ui/rfc1623-2.rs
index 35a2ef10c2e..26fa6fdb57f 100644
--- a/src/test/ui/rfc1623-2.rs
+++ b/src/test/ui/rfc1623-2.rs
@@ -9,5 +9,6 @@ static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
 //~^ ERROR missing lifetime specifier [E0106]
     &(non_elidable as fn(&u8, &u8) -> &u8);
     //~^ ERROR missing lifetime specifier [E0106]
+    //~| ERROR non-primitive cast
 
 fn main() {}
diff --git a/src/test/ui/rfc1623-2.stderr b/src/test/ui/rfc1623-2.stderr
index 65b9f68817a..495d45e2234 100644
--- a/src/test/ui/rfc1623-2.stderr
+++ b/src/test/ui/rfc1623-2.stderr
@@ -18,12 +18,18 @@ LL |     &(non_elidable as fn(&u8, &u8) -> &u8);
    |                          ---  ---     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
-   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
 help: consider making the type lifetime-generic with a new `'a` lifetime
    |
 LL |     &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
    |                       +++++++     ++      ++         ++
 
-error: aborting due to 2 previous errors
+error[E0605]: non-primitive cast: `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {non_elidable}` as `for<'r, 's> fn(&'r u8, &'s u8) -> &u8`
+  --> $DIR/rfc1623-2.rs:10:6
+   |
+LL |     &(non_elidable as fn(&u8, &u8) -> &u8);
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0106, E0605.
+For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr
index a761ec59167..6d7c3d73097 100644
--- a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr
+++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr
@@ -21,7 +21,6 @@ LL | struct S2<F: Fn(&i32, &i32) -> &i32>(F);
    |                 ----  ----     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
-   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
 help: consider making the bound lifetime-generic with a new `'a` lifetime
    |
 LL | struct S2<F: for<'a> Fn(&'a i32, &'a i32) -> &'a i32>(F);
diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
index 9adc9679eee..e82a6f769e0 100644
--- a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
+++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
@@ -1,43 +1,43 @@
-error[E0658]: anonymous lifetimes in `impl Trait` are unstable
-  --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31
-   |
-LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
-   |                               ^^
-   |
-   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
-
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime-gated.rs:8:50
    |
 LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
    |                                                  ^^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
    |                                                  ~~~~~~~
 
-error[E0658]: anonymous lifetimes in `impl Trait` are unstable
-  --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31
-   |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-   |                               ^^
-   |
-   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
-
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime-gated.rs:18:56
    |
 LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
    |                                                        ^^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
    |                                                        ~~~~~~~
 
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31
+   |
+LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
+   |                               ^^
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31
+   |
+LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                               ^^
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+
 error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0106, E0658.
diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs
index dcc716f56b7..6f7c912d707 100644
--- a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs
+++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs
@@ -6,14 +6,15 @@
 fn f(_: impl Iterator<Item = &'_ ()>) {}
 
 // But that lifetime does not participate in resolution.
-fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
 //~^ ERROR missing lifetime specifier
 
 // This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
 async fn h(_: impl Iterator<Item = &'_ ()>) {}
 
 // But that lifetime does not participate in resolution.
-async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
 //~^ ERROR missing lifetime specifier
+//~| ERROR lifetime may not live long enough
 
 fn main() {}
diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr
index d3c64cb466d..b476d61017f 100644
--- a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr
+++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr
@@ -1,27 +1,35 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/impl-trait-missing-lifetime.rs:9:50
+  --> $DIR/impl-trait-missing-lifetime.rs:9:54
    |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-   |                                                  ^^ expected named lifetime parameter
+LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                      ^^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
-   |                                                  ~~~~~~~
+LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                      ~~~~~~~
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/impl-trait-missing-lifetime.rs:16:56
+  --> $DIR/impl-trait-missing-lifetime.rs:16:60
    |
-LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-   |                                                        ^^ expected named lifetime parameter
+LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                            ^^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
-   |                                                        ~~~~~~~
+LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                            ~~~~~~~
 
-error: aborting due to 2 previous errors
+error: lifetime may not live long enough
+  --> $DIR/impl-trait-missing-lifetime.rs:16:69
+   |
+LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                    --------------   ^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+   |                                                    |
+   |                                                    return type `impl Future<Output = Option<&'static ()>>` contains a lifetime `'1`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/suggestions/issue-86667.rs b/src/test/ui/suggestions/issue-86667.rs
index 6aceb137469..366787df1b4 100644
--- a/src/test/ui/suggestions/issue-86667.rs
+++ b/src/test/ui/suggestions/issue-86667.rs
@@ -6,6 +6,7 @@
 async fn a(s1: &str, s2: &str) -> &str {
 //~^ ERROR: missing lifetime specifier [E0106]
     s1
+//~^ ERROR: lifetime may not live long enough
 }
 
 fn b(s1: &str, s2: &str) -> &str {
diff --git a/src/test/ui/suggestions/issue-86667.stderr b/src/test/ui/suggestions/issue-86667.stderr
index 14dbbfffb0e..8d611641626 100644
--- a/src/test/ui/suggestions/issue-86667.stderr
+++ b/src/test/ui/suggestions/issue-86667.stderr
@@ -11,7 +11,7 @@ LL | async fn a<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    |           ++++      ++           ++          ++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-86667.rs:11:29
+  --> $DIR/issue-86667.rs:12:29
    |
 LL | fn b(s1: &str, s2: &str) -> &str {
    |          ----      ----     ^ expected named lifetime parameter
@@ -22,6 +22,15 @@ help: consider introducing a named lifetime parameter
 LL | fn b<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    |     ++++      ++           ++          ++
 
-error: aborting due to 2 previous errors
+error: lifetime may not live long enough
+  --> $DIR/issue-86667.rs:8:5
+   |
+LL | async fn a(s1: &str, s2: &str) -> &str {
+   |                - let's call the lifetime of this reference `'1`
+LL |
+LL |     s1
+   |     ^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr
index 1ecaade93c8..233f1bc5a86 100644
--- a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr
+++ b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr
@@ -4,10 +4,6 @@ error[E0106]: missing lifetime specifier
 LL |     const A: &str = "";
    |              ^ expected named lifetime parameter
    |
-help: consider using the `'static` lifetime
-   |
-LL |     const A: &'static str = "";
-   |               +++++++
 help: consider introducing a named lifetime parameter
    |
 LL ~ trait ZstAssert<'a>: Sized {
@@ -20,10 +16,6 @@ error[E0106]: missing lifetime specifier
 LL |     const B: S = S { s: &() };
    |              ^ expected named lifetime parameter
    |
-help: consider using the `'static` lifetime
-   |
-LL |     const B: S<'static> = S { s: &() };
-   |               +++++++++
 help: consider introducing a named lifetime parameter
    |
 LL ~ trait ZstAssert<'a>: Sized {
@@ -37,10 +29,6 @@ error[E0106]: missing lifetime specifier
 LL |     const C: &'_ str = "";
    |               ^^ expected named lifetime parameter
    |
-help: consider using the `'static` lifetime
-   |
-LL |     const C: &'static str = "";
-   |               ~~~~~~~
 help: consider introducing a named lifetime parameter
    |
 LL ~ trait ZstAssert<'a>: Sized {
@@ -55,10 +43,6 @@ error[E0106]: missing lifetime specifiers
 LL |     const D: T = T { a: &(), b: &() };
    |              ^ expected 2 lifetime parameters
    |
-help: consider using the `'static` lifetime
-   |
-LL |     const D: T<'static, 'static> = T { a: &(), b: &() };
-   |               ++++++++++++++++++
 help: consider introducing a named lifetime parameter
    |
 LL ~ trait ZstAssert<'a>: Sized {
diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.rs b/src/test/ui/suggestions/missing-lifetime-specifier.rs
index ce847c86bed..24f5f782f35 100644
--- a/src/test/ui/suggestions/missing-lifetime-specifier.rs
+++ b/src/test/ui/suggestions/missing-lifetime-specifier.rs
@@ -21,22 +21,18 @@ thread_local! {
 }
 thread_local! {
     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-      //~^ ERROR missing lifetime specifier
-      //~| ERROR missing lifetime specifier
-      //~| ERROR missing lifetime specifier
-      //~| ERROR missing lifetime specifier
+      //~^ ERROR missing lifetime specifiers
+      //~| ERROR missing lifetime specifiers
 }
 thread_local! {
     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
-    //~^ ERROR missing lifetime
-    //~| ERROR missing lifetime
+    //~^ ERROR missing lifetime specifiers
+    //~| ERROR missing lifetime specifiers
 }
 thread_local! {
     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-    //~^ ERROR missing lifetime
-    //~| ERROR missing lifetime
-    //~| ERROR missing lifetime
-    //~| ERROR missing lifetime
+    //~^ ERROR missing lifetime specifiers
+    //~| ERROR missing lifetime specifiers
 }
 
 thread_local! {
diff --git a/src/test/ui/suggestions/missing-lifetime-specifier.stderr b/src/test/ui/suggestions/missing-lifetime-specifier.stderr
index 1498337549d..10fb28c1891 100644
--- a/src/test/ui/suggestions/missing-lifetime-specifier.stderr
+++ b/src/test/ui/suggestions/missing-lifetime-specifier.stderr
@@ -8,7 +8,7 @@ LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::
 help: consider using the `'static` lifetime
    |
 LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefCell::new(HashMap::new());
-   |                                            ~~~~~~~~~~~~~~~~~~~~~
+   |                                               ++++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
   --> $DIR/missing-lifetime-specifier.rs:18:44
@@ -23,38 +23,28 @@ LL | | }
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
-error[E0106]: missing lifetime specifier
+error[E0106]: missing lifetime specifiers
   --> $DIR/missing-lifetime-specifier.rs:23:44
    |
 LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   |                                            ^ expected named lifetime parameter
+   |                                            ^^^^ expected 2 lifetime parameters
+   |                                            |
+   |                                            expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar>>>> = RefCell::new(HashMap::new());
-   |                                            ~~~~~~~~
+LL |     static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
+   |                                             +++++++    ++++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:23:45
-   |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   |                                             ^^^ expected 2 lifetime parameters
-   |
-   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
-   |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
-   |                                             ~~~~~~~~~~~~~~~~~~~~~
-
-error[E0106]: missing lifetime specifier
   --> $DIR/missing-lifetime-specifier.rs:23:44
    |
 LL | / thread_local! {
 LL | |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   | |                                            ^ expected named lifetime parameter
-LL | |
-LL | |
+   | |                                            ^^^^ expected 2 lifetime parameters
+   | |                                            |
+   | |                                            expected named lifetime parameter
 LL | |
 LL | |
 LL | | }
@@ -63,25 +53,10 @@ LL | | }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:23:45
-   |
-LL | / thread_local! {
-LL | |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   | |                                             ^^^ expected 2 lifetime parameters
-LL | |
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_-
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
-
-error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:30:48
+  --> $DIR/missing-lifetime-specifier.rs:28:47
    |
 LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
-   |                                                ^ expected 2 lifetime parameters
+   |                                               ^ expected 2 lifetime parameters
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
@@ -90,11 +65,11 @@ LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                +++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:30:48
+  --> $DIR/missing-lifetime-specifier.rs:28:47
    |
 LL | / thread_local! {
 LL | |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
-   | |                                                ^ expected 2 lifetime parameters
+   | |                                               ^ expected 2 lifetime parameters
 LL | |
 LL | |
 LL | | }
@@ -102,38 +77,28 @@ LL | | }
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:35:44
-   |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   |                                            ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
-   |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<i32>>>>> = RefCell::new(HashMap::new());
-   |                                            ~~~~~~~~
-
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:35:49
+  --> $DIR/missing-lifetime-specifier.rs:33:44
    |
 LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   |                                                 ^ expected 2 lifetime parameters
+   |                                            ^   ^ expected 2 lifetime parameters
+   |                                            |
+   |                                            expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                                 +++++++++++++++++
+LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                             +++++++     +++++++++++++++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:35:44
+error[E0106]: missing lifetime specifiers
+  --> $DIR/missing-lifetime-specifier.rs:33:44
    |
 LL | / thread_local! {
 LL | |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   | |                                            ^ expected named lifetime parameter
-LL | |
-LL | |
+   | |                                            ^   ^ expected 2 lifetime parameters
+   | |                                            |
+   | |                                            expected named lifetime parameter
 LL | |
 LL | |
 LL | | }
@@ -141,23 +106,35 @@ LL | | }
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
 
-error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:35:49
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lifetime-specifier.rs:47:44
+   |
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                            ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+   |
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                             +++++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lifetime-specifier.rs:47:44
    |
 LL | / thread_local! {
-LL | |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   | |                                                 ^ expected 2 lifetime parameters
-LL | |
+LL | |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+   | |                                            ^ expected named lifetime parameter
 LL | |
 LL | |
+...  |
 LL | |
 LL | | }
    | |_-
    |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -175,7 +152,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                       +++++++++
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -193,7 +170,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefC
    |                                                       ++++
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -211,7 +188,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefC
    |                                                       ++++
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -229,7 +206,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefC
    |                                                       ++++
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -247,7 +224,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                       +++++++++
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -264,20 +241,8 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        +++++++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:51:44
-   |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                            ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
-   |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                            ~~~~~~~~
-
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -294,23 +259,8 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        ++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:51:44
-   |
-LL | / thread_local! {
-LL | |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-   | |                                            ^ expected named lifetime parameter
-LL | |
-LL | |
-...  |
-LL | |
-LL | | }
-   | |_-
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
-
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -328,7 +278,7 @@ LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = Ref
    |                                                        ++++
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -346,7 +296,7 @@ LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = Ref
    |                                                        ++++
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -363,7 +313,7 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        +++++++++
 
-error: aborting due to 24 previous errors
+error: aborting due to 20 previous errors
 
 Some errors have detailed explanations: E0106, E0107.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.rs b/src/test/ui/suggestions/missing-lt-for-hrtb.rs
index a90a90122ad..04ea3d831c9 100644
--- a/src/test/ui/suggestions/missing-lt-for-hrtb.rs
+++ b/src/test/ui/suggestions/missing-lt-for-hrtb.rs
@@ -1,10 +1,8 @@
 struct X<'a>(&'a ());
 struct S<'a>(&'a dyn Fn(&X) -> &X);
-//~^ ERROR missing lifetime specifier
-//~| ERROR missing lifetime specifier
+//~^ ERROR missing lifetime specifiers
 struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
-//~^ ERROR missing lifetime specifier
-//~| ERROR missing lifetime specifier
+//~^ ERROR missing lifetime specifiers
 
 fn main() {
     let x = S(&|x| {
diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.stderr b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr
index 33f9d092e6e..fa515644431 100644
--- a/src/test/ui/suggestions/missing-lt-for-hrtb.stderr
+++ b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr
@@ -1,67 +1,36 @@
-error[E0106]: missing lifetime specifier
+error[E0106]: missing lifetime specifiers
   --> $DIR/missing-lt-for-hrtb.rs:2:32
    |
 LL | struct S<'a>(&'a dyn Fn(&X) -> &X);
-   |                         --     ^ expected named lifetime parameter
+   |                         --     ^^ expected named lifetime parameter
+   |                                |
+   |                                expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
-   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider making the bound lifetime-generic with a new `'b` lifetime
-   |
-LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &'b X);
-   |                      +++++++    ~~~~~     ~~~
-help: consider using the `'a` lifetime
-   |
-LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X);
-   |                                ~~~
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lt-for-hrtb.rs:2:33
-   |
-LL | struct S<'a>(&'a dyn Fn(&X) -> &X);
-   |                         --      ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
-   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider making the bound lifetime-generic with a new `'b` lifetime
-   |
-LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &X<'b>);
-   |                      +++++++    ~~~~~      ~~~~~
 help: consider using the `'a` lifetime
    |
-LL | struct S<'a>(&'a dyn Fn(&X) -> &X<'a>);
-   |                                 ~~~~~
+LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X<'a>);
+   |                                 ++  ++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lt-for-hrtb.rs:5:40
+error[E0106]: missing lifetime specifiers
+  --> $DIR/missing-lt-for-hrtb.rs:4:40
    |
 LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
-   |                                 --     ^ expected named lifetime parameter
+   |                                 --     ^^ expected named lifetime parameter
+   |                                        |
+   |                                        expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
 note: these named lifetimes are available to use
-  --> $DIR/missing-lt-for-hrtb.rs:5:10
+  --> $DIR/missing-lt-for-hrtb.rs:4:10
    |
 LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
    |          ^^              ^^
 help: consider using one of the available lifetimes here
    |
-LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X);
-   |                                         +++++++++
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lt-for-hrtb.rs:5:41
-   |
-LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
-   |                                 --      ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
-note: these named lifetimes are available to use
-  --> $DIR/missing-lt-for-hrtb.rs:5:10
-   |
-LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
-   |          ^^              ^^
+LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X<'lifetime>);
+   |                                         +++++++++  +++++++++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/suggestions/return-elided-lifetime.rs b/src/test/ui/suggestions/return-elided-lifetime.rs
index ca336bbb056..012d5492a04 100644
--- a/src/test/ui/suggestions/return-elided-lifetime.rs
+++ b/src/test/ui/suggestions/return-elided-lifetime.rs
@@ -6,32 +6,27 @@
 fn f1() -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f1_() -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 fn f2(a: i32, b: i32) -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 struct S<'a, 'b> { a: &'a i32, b: &'b i32 }
 fn f3(s: &S) -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 fn main() {}
diff --git a/src/test/ui/suggestions/return-elided-lifetime.stderr b/src/test/ui/suggestions/return-elided-lifetime.stderr
index f147b4463e2..273d95bc747 100644
--- a/src/test/ui/suggestions/return-elided-lifetime.stderr
+++ b/src/test/ui/suggestions/return-elided-lifetime.stderr
@@ -8,70 +8,50 @@ LL | fn f1() -> &i32 { loop {} }
 help: consider using the `'static` lifetime
    |
 LL | fn f1() -> &'static i32 { loop {} }
-   |            ~~~~~~~~
+   |             +++++++
 
-error[E0106]: missing lifetime specifier
+error[E0106]: missing lifetime specifiers
   --> $DIR/return-elided-lifetime.rs:8:14
    |
 LL | fn f1_() -> (&i32, &i32) { loop {} }
-   |              ^ expected named lifetime parameter
+   |              ^     ^ expected named lifetime parameter
+   |              |
+   |              expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | fn f1_() -> (&'static i32, &i32) { loop {} }
-   |              ~~~~~~~~
+LL | fn f1_() -> (&'static i32, &'static i32) { loop {} }
+   |               +++++++       +++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:8:20
-   |
-LL | fn f1_() -> (&i32, &i32) { loop {} }
-   |                    ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
-   |
-LL | fn f1_() -> (&i32, &'static i32) { loop {} }
-   |                    ~~~~~~~~
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:12:26
+  --> $DIR/return-elided-lifetime.rs:11:26
    |
 LL | fn f2(a: i32, b: i32) -> &i32 { loop {} }
    |                          ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn f2(a: i32, b: i32) -> &'static i32 { loop {} }
-   |                          ~~~~~~~~
+   |                           +++++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:14:28
+error[E0106]: missing lifetime specifiers
+  --> $DIR/return-elided-lifetime.rs:13:28
    |
 LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
-   |                            ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
-help: consider using the `'static` lifetime
+   |                            ^     ^ expected named lifetime parameter
+   |                            |
+   |                            expected named lifetime parameter
    |
-LL | fn f2_(a: i32, b: i32) -> (&'static i32, &i32) { loop {} }
-   |                            ~~~~~~~~
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:14:34
-   |
-LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
-   |                                  ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | fn f2_(a: i32, b: i32) -> (&i32, &'static i32) { loop {} }
-   |                                  ~~~~~~~~
+LL | fn f2_(a: i32, b: i32) -> (&'static i32, &'static i32) { loop {} }
+   |                             +++++++       +++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:19:17
+  --> $DIR/return-elided-lifetime.rs:17:17
    |
 LL | fn f3(s: &S) -> &i32 { loop {} }
    |          --     ^ expected named lifetime parameter
@@ -79,42 +59,32 @@ LL | fn f3(s: &S) -> &i32 { loop {} }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `s`'s 3 lifetimes it is borrowed from
 help: consider introducing a named lifetime parameter
    |
-LL | fn f3<'a>(s: &'a S) -> &'a i32 { loop {} }
-   |      ++++     ++        ++
+LL | fn f3<'a>(s: &'a S<'a, 'a>) -> &'a i32 { loop {} }
+   |      ++++     ++  ++++++++      ++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:21:26
+error[E0106]: missing lifetime specifiers
+  --> $DIR/return-elided-lifetime.rs:19:26
    |
 LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
-   |           --     --      ^ expected named lifetime parameter
+   |           --     --      ^     ^ expected named lifetime parameter
+   |                          |
+   |                          expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes
 help: consider introducing a named lifetime parameter
    |
-LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&'a i32, &i32) { loop {} }
-   |       ++++     ++        ++         ++
+LL | fn f3_<'a>(s: &'a S<'a, 'a>, t: &'a S<'a, 'a>) -> (&'a i32, &'a i32) { loop {} }
+   |       ++++     ++  ++++++++      ++  ++++++++       ++       ++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:21:32
-   |
-LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
-   |           --     --            ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes
-help: consider introducing a named lifetime parameter
-   |
-LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&i32, &'a i32) { loop {} }
-   |       ++++     ++        ++               ++
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:25:42
+  --> $DIR/return-elided-lifetime.rs:22:42
    |
 LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
    |                  -------     -------     ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
+   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
 note: these named lifetimes are available to use
-  --> $DIR/return-elided-lifetime.rs:25:7
+  --> $DIR/return-elided-lifetime.rs:22:7
    |
 LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
    |       ^^  ^^
@@ -123,42 +93,27 @@ help: consider using one of the available lifetimes here
 LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &'lifetime i32 { loop {} }
    |                                           +++++++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:27:44
-   |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
-   |                   -------     -------      ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
-note: these named lifetimes are available to use
-  --> $DIR/return-elided-lifetime.rs:27:8
-   |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
-   |        ^^  ^^
-help: consider using one of the available lifetimes here
-   |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &i32) { loop {} }
-   |                                             +++++++++
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:27:50
+error[E0106]: missing lifetime specifiers
+  --> $DIR/return-elided-lifetime.rs:24:44
    |
 LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
-   |                   -------     -------            ^ expected named lifetime parameter
+   |                   -------     -------      ^     ^ expected named lifetime parameter
+   |                                            |
+   |                                            expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
+   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
 note: these named lifetimes are available to use
-  --> $DIR/return-elided-lifetime.rs:27:8
+  --> $DIR/return-elided-lifetime.rs:24:8
    |
 LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
    |        ^^  ^^
 help: consider using one of the available lifetimes here
    |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &'lifetime i32) { loop {} }
-   |                                                   +++++++++
+LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &'lifetime i32) { loop {} }
+   |                                             +++++++++       +++++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:31:35
+  --> $DIR/return-elided-lifetime.rs:27:35
    |
 LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
    |              -------     ----     ^ expected named lifetime parameter
@@ -167,32 +122,22 @@ LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
 help: consider using the `'a` lifetime
    |
 LL | fn f5<'a>(a: &'a i32, b: &i32) -> &'a i32 { loop {} }
-   |                                   ~~~
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:33:37
-   |
-LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
-   |               -------     ----      ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
-help: consider using the `'a` lifetime
-   |
-LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &i32) { loop {} }
-   |                                     ~~~
+   |                                    ++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:33:43
+error[E0106]: missing lifetime specifiers
+  --> $DIR/return-elided-lifetime.rs:29:37
    |
 LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
-   |               -------     ----            ^ expected named lifetime parameter
+   |               -------     ----      ^     ^ expected named lifetime parameter
+   |                                     |
+   |                                     expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
 help: consider using the `'a` lifetime
    |
-LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &'a i32) { loop {} }
-   |                                           ~~~
+LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &'a i32) { loop {} }
+   |                                      ++       ++
 
-error: aborting due to 15 previous errors
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr
index 449a61d4809..5028e8d628f 100644
--- a/src/test/ui/suggestions/return-without-lifetime.stderr
+++ b/src/test/ui/suggestions/return-without-lifetime.stderr
@@ -7,7 +7,7 @@ LL | struct Foo<'a>(&usize);
 help: consider using the `'a` lifetime
    |
 LL | struct Foo<'a>(&'a usize);
-   |                ~~~
+   |                 ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/return-without-lifetime.rs:5:34
@@ -19,7 +19,7 @@ LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
 help: consider using the `'a` lifetime
    |
 LL | fn func1<'a>(_arg: &'a Thing) -> &'a () { unimplemented!() }
-   |                                  ~~~
+   |                                   ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/return-without-lifetime.rs:7:35
@@ -31,7 +31,7 @@ LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
 help: consider using the `'a` lifetime
    |
 LL | fn func2<'a>(_arg: &Thing<'a>) -> &'a () { unimplemented!() }
-   |                                   ~~~
+   |                                    ++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr
index d25452456bb..2b8fec86c8a 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr
@@ -5,6 +5,11 @@ LL |     let _: dyn Foo(&isize, &usize) -> &usize;
    |                    ------  ------     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |     let _: dyn for<'a> Foo(&'a isize, &'a usize) -> &'a usize;
+   |                +++++++      ++         ++            ++
 help: consider introducing a named lifetime parameter
    |
 LL ~ fn main<'a>() {
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs
index 37c87dbeaa9..e1deab736cf 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs
@@ -7,7 +7,6 @@ use std::fmt::Debug;
 
 struct Foo {
     x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier
-    //~^ ERROR E0228
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
index b865278e25f..fd086002803 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
@@ -10,13 +10,6 @@ LL ~ struct Foo<'a> {
 LL ~     x: Box<dyn Debug + 'a>,
    |
 
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
-  --> $DIR/dyn-trait-underscore-in-struct.rs:9:12
-   |
-LL |     x: Box<dyn Debug + '_>,
-   |            ^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0106, E0228.
-For more information about an error, try `rustc --explain E0106`.
+For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr
index 22bf1fdba32..50401791eff 100644
--- a/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr
+++ b/src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr
@@ -1,3 +1,14 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/underscore-lifetime-binders.rs:2:17
+   |
+LL | struct Baz<'a>(&'_ &'a u8);
+   |                 ^^ expected named lifetime parameter
+   |
+help: consider using the `'a` lifetime
+   |
+LL | struct Baz<'a>(&'a &'a u8);
+   |                 ~~
+
 error[E0637]: `'_` cannot be used here
   --> $DIR/underscore-lifetime-binders.rs:4:8
    |
@@ -11,17 +22,6 @@ LL | fn meh() -> Box<dyn for<'_> Meh<'_>>
    |                         ^^ `'_` is a reserved lifetime name
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/underscore-lifetime-binders.rs:2:17
-   |
-LL | struct Baz<'a>(&'_ &'a u8);
-   |                 ^^ expected named lifetime parameter
-   |
-help: consider using the `'a` lifetime
-   |
-LL | struct Baz<'a>(&'a &'a u8);
-   |                 ~~
-
-error[E0106]: missing lifetime specifier
   --> $DIR/underscore-lifetime-binders.rs:10:33
    |
 LL | fn meh() -> Box<dyn for<'_> Meh<'_>>
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 083c437a293..826353aafc0 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -9,12 +9,14 @@ use rustc_hir::intravisit::{
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
     BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
-    ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef,
-    PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+    ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
+    TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter as middle_nested_filter;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, Ident, Symbol};
 
@@ -129,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 enum RefLt {
     Unnamed,
     Static,
-    Named(Symbol),
+    Named(LocalDefId),
 }
 
 fn check_fn_inner<'tcx>(
@@ -232,7 +234,7 @@ fn could_use_elision<'tcx>(
     // level of the current item.
 
     // check named LTs
-    let allowed_lts = allowed_lts_from(named_generics);
+    let allowed_lts = allowed_lts_from(cx.tcx, named_generics);
 
     // these will collect all the lifetimes for references in arg/return types
     let mut input_visitor = RefVisitor::new(cx);
@@ -254,22 +256,6 @@ fn could_use_elision<'tcx>(
         return false;
     }
 
-    if allowed_lts
-        .intersection(
-            &input_visitor
-                .nested_elision_site_lts
-                .iter()
-                .chain(output_visitor.nested_elision_site_lts.iter())
-                .cloned()
-                .filter(|v| matches!(v, RefLt::Named(_)))
-                .collect(),
-        )
-        .next()
-        .is_some()
-    {
-        return false;
-    }
-
     let input_lts = input_visitor.lts;
     let output_lts = output_visitor.lts;
 
@@ -303,6 +289,31 @@ fn could_use_elision<'tcx>(
         }
     }
 
+    // check for higher-ranked trait bounds
+    if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() {
+        let allowed_lts: FxHashSet<_> = allowed_lts
+            .iter()
+            .filter_map(|lt| match lt {
+                RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())),
+                _ => None,
+            })
+            .collect();
+        for lt in input_visitor.nested_elision_site_lts {
+            if let RefLt::Named(def_id) = lt {
+                if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
+                    return false;
+                }
+            }
+        }
+        for lt in output_visitor.nested_elision_site_lts {
+            if let RefLt::Named(def_id) = lt {
+                if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
+                    return false;
+                }
+            }
+        }
+    }
+
     // no input lifetimes? easy case!
     if input_lts.is_empty() {
         false
@@ -335,14 +346,11 @@ fn could_use_elision<'tcx>(
     }
 }
 
-fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
+fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
     let mut allowed_lts = FxHashSet::default();
     for par in named_generics.iter() {
-        if let GenericParamKind::Lifetime {
-            kind: LifetimeParamKind::Explicit,
-        } = par.kind
-        {
-            allowed_lts.insert(RefLt::Named(par.name.ident().name));
+        if let GenericParamKind::Lifetime { .. } = par.kind {
+            allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id)));
         }
     }
     allowed_lts.insert(RefLt::Unnamed);
@@ -385,8 +393,10 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
                 self.lts.push(RefLt::Unnamed);
             } else if lt.is_elided() {
                 self.lts.push(RefLt::Unnamed);
+            } else if let LifetimeName::Param(def_id, _) = lt.name {
+                self.lts.push(RefLt::Named(def_id));
             } else {
-                self.lts.push(RefLt::Named(lt.name.ident().name));
+                self.lts.push(RefLt::Unnamed);
             }
         } else {
             self.lts.push(RefLt::Unnamed);
@@ -434,10 +444,15 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
             TyKind::OpaqueDef(item, bounds) => {
                 let map = self.cx.tcx.hir();
                 let item = map.item(item);
+                let len = self.lts.len();
                 walk_item(self, item);
-                walk_ty(self, ty);
+                self.lts.truncate(len);
                 self.lts.extend(bounds.iter().filter_map(|bound| match bound {
-                    GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
+                    GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id, _) = l.name {
+                        RefLt::Named(def_id)
+                    } else {
+                        RefLt::Unnamed
+                    }),
                     _ => None,
                 }));
             },
@@ -456,9 +471,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
                 }
                 return;
             },
-            _ => (),
+            _ => walk_ty(self, ty),
         }
-        walk_ty(self, ty);
     }
 }
 
@@ -477,7 +491,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
                     return true;
                 }
                 // if the bounds define new lifetimes, they are fine to occur
-                let allowed_lts = allowed_lts_from(pred.bound_generic_params);
+                let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params);
                 // now walk the bounds
                 for bound in pred.bounds.iter() {
                     walk_param_bound(&mut visitor, bound);