about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-04-17 12:56:19 +0000
committerbors <bors@rust-lang.org>2022-04-17 12:56:19 +0000
commit1ec2c136b35bd4660cba778346f8df7daf2ab173 (patch)
tree3a0923df3630bd8753561b81e704834eb3b9da88
parentaf68f7182e11de7eced78078313e9ba0436db84e (diff)
parente628df9b0b0310fb293c75e75ad19c72f92381f8 (diff)
downloadrust-1ec2c136b35bd4660cba778346f8df7daf2ab173.tar.gz
rust-1ec2c136b35bd4660cba778346f8df7daf2ab173.zip
Auto merge of #95779 - cjgillot:ast-lifetimes-undeclared, r=petrochenkov
Report undeclared lifetimes during late resolution.

First step in https://github.com/rust-lang/rust/pull/91557

We reuse the rib design of the current resolution framework. Specific `LifetimeRib` and `LifetimeRibKind` types are introduced. The most important variant is `LifetimeRibKind::Generics`, which happens each time we encounter something which may introduce generic lifetime parameters. It can be an item or a `for<...>` binder. The `LifetimeBinderKind` specifies how this rib behaves with respect to in-band lifetimes.

r? `@petrochenkov`
-rw-r--r--compiler/rustc_ast/src/visit.rs19
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs42
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs39
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs40
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs38
-rw-r--r--compiler/rustc_hir/src/hir.rs6
-rw-r--r--compiler/rustc_hir/src/intravisit.rs2
-rw-r--r--compiler/rustc_lint/src/builtin.rs1
-rw-r--r--compiler/rustc_lint/src/context.rs18
-rw-r--r--compiler/rustc_lint/src/early.rs7
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs1
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs9
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs4
-rw-r--r--compiler/rustc_resolve/src/ident.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs1214
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs192
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs52
-rw-r--r--compiler/rustc_resolve/src/lib.rs61
-rw-r--r--src/test/ui/async-await/async-fn-path-elision.stderr6
-rw-r--r--src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr14
-rw-r--r--src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr19
-rw-r--r--src/test/ui/generic-associated-types/issue-67510.rs8
-rw-r--r--src/test/ui/generic-associated-types/issue-67510.stderr53
-rw-r--r--src/test/ui/generic-associated-types/issue-70304.rs13
-rw-r--r--src/test/ui/generic-associated-types/issue-70304.stderr2
-rw-r--r--src/test/ui/generics/generic-extern-lifetime.stderr21
-rw-r--r--src/test/ui/impl-header-lifetime-elision/path-elided.stderr6
-rw-r--r--src/test/ui/impl-header-lifetime-elision/trait-elided.rs7
-rw-r--r--src/test/ui/impl-header-lifetime-elision/trait-elided.stderr8
-rw-r--r--src/test/ui/issues/issue-10412.rs18
-rw-r--r--src/test/ui/issues/issue-10412.stderr34
-rw-r--r--src/test/ui/lifetimes/issue-91763.stderr6
-rw-r--r--src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr10
-rw-r--r--src/test/ui/lint/force-warn/allowed-by-default-lint.stderr6
-rw-r--r--src/test/ui/lint/reasons.rs4
-rw-r--r--src/test/ui/lint/reasons.stderr8
-rw-r--r--src/test/ui/methods/method-call-lifetime-args-unresolved.rs5
-rw-r--r--src/test/ui/methods/method-call-lifetime-args-unresolved.stderr17
-rw-r--r--src/test/ui/regions/regions-name-static.rs5
-rw-r--r--src/test/ui/regions/regions-name-undeclared.rs8
-rw-r--r--src/test/ui/regions/regions-name-undeclared.stderr104
-rw-r--r--src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr8
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr106
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs31
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr229
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr40
-rw-r--r--src/test/ui/underscore-lifetime/in-binder.rs8
-rw-r--r--src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr6
-rw-r--r--src/test/ui/where-clauses/where-lifetime-resolution.stderr33
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.stderr16
-rw-r--r--src/tools/rustfmt/src/items.rs13
-rw-r--r--src/tools/rustfmt/src/visitor.rs18
54 files changed, 1859 insertions, 782 deletions
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 3183612597d..d925c6dd354 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -35,7 +35,7 @@ pub enum FnCtxt {
 #[derive(Copy, Clone, Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),
+    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
 
     /// E.g., `|x, y| body`.
     Closure(&'a FnDecl, &'a Expr),
@@ -44,7 +44,7 @@ pub enum FnKind<'a> {
 impl<'a> FnKind<'a> {
     pub fn header(&self) -> Option<&'a FnHeader> {
         match *self {
-            FnKind::Fn(_, _, sig, _, _) => Some(&sig.header),
+            FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
             FnKind::Closure(_, _) => None,
         }
     }
@@ -58,7 +58,7 @@ impl<'a> FnKind<'a> {
 
     pub fn decl(&self) -> &'a FnDecl {
         match self {
-            FnKind::Fn(_, _, sig, _, _) => &sig.decl,
+            FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
             FnKind::Closure(decl, _) => decl,
         }
     }
@@ -295,8 +295,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             walk_list!(visitor, visit_expr, expr);
         }
         ItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
-            visitor.visit_generics(generics);
-            let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+            let kind =
+                FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
             visitor.visit_fn(kind, item.span, item.id)
         }
         ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind {
@@ -561,8 +561,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
             walk_list!(visitor, visit_expr, expr);
         }
         ForeignItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
-            visitor.visit_generics(generics);
-            let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
+            let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
             visitor.visit_fn(kind, span, id);
         }
         ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
@@ -644,7 +643,8 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &
 
 pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) {
     match kind {
-        FnKind::Fn(_, _, sig, _, body) => {
+        FnKind::Fn(_, _, sig, _, generics, body) => {
+            visitor.visit_generics(generics);
             visitor.visit_fn_header(&sig.header);
             walk_fn_decl(visitor, &sig.decl);
             walk_list!(visitor, visit_block, body);
@@ -667,8 +667,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
             walk_list!(visitor, visit_expr, expr);
         }
         AssocItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
-            visitor.visit_generics(generics);
-            let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
+            let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
             visitor.visit_fn(kind, span, id);
         }
         AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e7e82e651bb..9cb205074e7 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -484,7 +484,7 @@ enum ParenthesizedGenericArgs {
 /// an "elided" or "underscore" lifetime name. In the future, we probably want to move
 /// everything into HIR lowering.
 #[derive(Copy, Clone, Debug)]
-enum AnonymousLifetimeMode {
+pub enum AnonymousLifetimeMode {
     /// For **Modern** cases, create a new anonymous region parameter
     /// and reference that.
     ///
@@ -1835,7 +1835,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // Output lifetime like `'_`:
             for (span, node_id) in lifetimes_to_define {
                 let param = this.fresh_lifetime_to_generic_param(span, node_id);
-                lifetime_params.push((span, hir::LifetimeName::Implicit(false)));
+                lifetime_params.push((span, hir::LifetimeName::Implicit));
                 generic_params.push(param);
             }
             let generic_params = this.arena.alloc_from_iter(generic_params);
@@ -2017,16 +2017,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     });
                 let param_name = match lt.name {
                     hir::LifetimeName::Param(param_name) => param_name,
-                    hir::LifetimeName::Implicit(_)
-                    | hir::LifetimeName::Underscore
-                    | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
+                    hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
+                        hir::ParamName::Plain(lt.name.ident())
+                    }
                     hir::LifetimeName::ImplicitObjectLifetimeDefault => {
                         self.sess.diagnostic().span_bug(
                             param.ident.span,
                             "object-lifetime-default should not occur here",
                         );
                     }
-                    hir::LifetimeName::Error => ParamName::Error,
+                    hir::LifetimeName::Static | hir::LifetimeName::Error => ParamName::Error,
                 };
 
                 let kind =
@@ -2397,27 +2397,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
             AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
 
-            AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false),
+            AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
         }
     }
 
     /// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime;
     /// return an "error lifetime".
     fn new_error_lifetime(&mut self, id: Option<NodeId>, span: Span) -> hir::Lifetime {
-        let (id, msg, label) = match id {
-            Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"),
-
-            None => (
-                self.resolver.next_node_id(),
-                "`&` without an explicit lifetime name cannot be used here",
-                "explicit lifetime name needed here",
-            ),
-        };
-
-        let mut err = struct_span_err!(self.sess, span, E0637, "{}", msg,);
-        err.span_label(span, label);
-        err.emit();
-
+        let id = id.unwrap_or_else(|| self.resolver.next_node_id());
         self.new_named_lifetime(id, span, hir::LifetimeName::Error)
     }
 
@@ -2429,12 +2416,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &'s mut self,
         span: Span,
         count: usize,
-        param_mode: ParamMode,
     ) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
-        (0..count).map(move |_| self.elided_path_lifetime(span, param_mode))
+        (0..count).map(move |_| self.elided_path_lifetime(span))
     }
 
-    fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime {
+    fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
         match self.anonymous_lifetime_mode {
             AnonymousLifetimeMode::CreateParameter => {
                 // We should have emitted E0726 when processing this path above
@@ -2450,7 +2436,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // lifetime. Instead, we simply create an implicit lifetime, which will be checked
             // later, at which point a suitable error will be emitted.
             AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
-                self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit)
+                self.new_implicit_lifetime(span)
             }
         }
     }
@@ -2493,11 +2479,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         r
     }
 
-    fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime {
+    fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
         hir::Lifetime {
             hir_id: self.next_id(),
             span: self.lower_span(span),
-            name: hir::LifetimeName::Implicit(missing),
+            name: hir::LifetimeName::Implicit,
         }
     }
 }
@@ -2600,7 +2586,7 @@ fn lifetimes_from_impl_trait_bounds(
 
         fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
             let name = match lifetime.name {
-                hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
+                hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
                     if self.collect_elided_lifetimes {
                         // Use `'_` for both implicit and underscore lifetimes in
                         // `type Foo<'_> = impl SomeTrait<'_>;`.
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index b35e3a07161..8bf4b8fcc39 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -290,47 +290,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
             };
             generic_args.args = self
-                .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode)
+                .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
                 .map(GenericArg::Lifetime)
                 .chain(generic_args.args.into_iter())
                 .collect();
-            // In create-parameter mode we error here because we don't want to support
-            // deprecated impl elision in new features like impl elision and `async fn`,
-            // both of which work using the `CreateParameter` mode:
-            //
-            //     impl Foo for std::cell::Ref<u32> // note lack of '_
-            //     async fn foo(_: std::cell::Ref<u32>) { ... }
             if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
                 (param_mode, self.anonymous_lifetime_mode)
             {
-                let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
-                let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
-                let no_bindings = generic_args.bindings.is_empty();
-                let (incl_angl_brckt, suggestion) = if no_non_lt_args && no_bindings {
-                    // If there are no generic args, our suggestion can include the angle brackets.
-                    (true, format!("<{}>", anon_lt_suggestion))
-                } else {
-                    // Otherwise we'll insert a `'_, ` right after the opening bracket.
-                    (false, format!("{}, ", anon_lt_suggestion))
-                };
-                let insertion_sp = elided_lifetime_span.shrink_to_hi();
-                let mut err = struct_span_err!(
-                    self.sess,
-                    path_span,
-                    E0726,
-                    "implicit elided lifetime not allowed here"
-                );
-                rustc_errors::add_elided_lifetime_in_path_suggestion(
-                    &self.sess.source_map(),
-                    &mut err,
-                    expected_lifetimes,
-                    path_span,
-                    incl_angl_brckt,
-                    insertion_sp,
-                    suggestion,
-                );
-                err.note("assuming a `'static` lifetime...");
-                err.emit();
+                // Late resolver should have issued the error.
+                self.sess
+                    .delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here");
             }
         }
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 33727084ccf..8d815e95528 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -91,16 +91,18 @@ impl<'a> AstValidator<'a> {
         self.is_impl_trait_banned = old;
     }
 
-    fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_tilde_const_allowed, true);
+    fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
         f(self);
         self.is_tilde_const_allowed = old;
     }
 
+    fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
+        self.with_tilde_const(true, f)
+    }
+
     fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_tilde_const_allowed, false);
-        f(self);
-        self.is_tilde_const_allowed = old;
+        self.with_tilde_const(false, f)
     }
 
     fn with_let_management(
@@ -1202,12 +1204,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
-                if let Const::Yes(_) = sig.header.constness {
-                    self.with_tilde_const_allowed(|this| this.visit_generics(generics));
-                } else {
-                    self.visit_generics(generics);
-                }
-                let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+                let kind =
+                    FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
                 self.visit_fn(kind, item.span, item.id);
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
@@ -1555,13 +1553,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
             _,
             _,
+            _,
         ) = fk
         {
             self.maybe_lint_missing_abi(*sig_span, id);
         }
 
         // Functions without bodies cannot have patterns.
-        if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
+        if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
             Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
                 let (code, msg, label) = match ctxt {
                     FnCtxt::Foreign => (
@@ -1596,7 +1595,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             });
         }
 
-        visit::walk_fn(self, fk, span);
+        let tilde_const_allowed =
+            matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
+                || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+
+        self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
     }
 
     fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
@@ -1670,9 +1673,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             {
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
-                self.with_tilde_const_allowed(|this| this.visit_generics(generics));
-                let kind =
-                    FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
+                let kind = FnKind::Fn(
+                    FnCtxt::Assoc(ctxt),
+                    item.ident,
+                    sig,
+                    &item.vis,
+                    generics,
+                    body.as_deref(),
+                );
                 self.visit_fn(kind, item.span, item.id);
             }
             _ => self
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 7742813888e..459d4a783e4 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -575,7 +575,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
             }
 
-            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => {
+            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
                 // In this case, the user left off the lifetime; so
                 // they wrote something like:
                 //
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 416bc4e2e3b..d7c5df7d8e2 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -1511,35 +1511,17 @@ pub fn add_elided_lifetime_in_path_suggestion(
     path_span: Span,
     incl_angl_brckt: bool,
     insertion_span: Span,
-    anon_lts: String,
 ) {
-    let (replace_span, suggestion) = if incl_angl_brckt {
-        (insertion_span, anon_lts)
-    } else {
-        // When possible, prefer a suggestion that replaces the whole
-        // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
-        // at a point (which makes for an ugly/confusing label)
-        if let Ok(snippet) = source_map.span_to_snippet(path_span) {
-            // But our spans can get out of whack due to macros; if the place we think
-            // we want to insert `'_` isn't even within the path expression's span, we
-            // should bail out of making any suggestion rather than panicking on a
-            // subtract-with-overflow or string-slice-out-out-bounds (!)
-            // FIXME: can we do better?
-            if insertion_span.lo().0 < path_span.lo().0 {
-                return;
-            }
-            let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
-            if insertion_index > snippet.len() {
-                return;
-            }
-            let (before, after) = snippet.split_at(insertion_index);
-            (path_span, format!("{}{}{}", before, anon_lts, after))
-        } else {
-            (insertion_span, anon_lts)
-        }
-    };
-    diag.span_suggestion(
-        replace_span,
+    diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n)));
+    if source_map.span_to_snippet(insertion_span).is_err() {
+        // Do not try to suggest anything if generated by a proc-macro.
+        return;
+    }
+    let anon_lts = vec!["'_"; n].join(", ");
+    let suggestion =
+        if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
+    diag.span_suggestion_verbose(
+        insertion_span.shrink_to_hi(),
         &format!("indicate the anonymous lifetime{}", pluralize!(n)),
         suggestion,
         Applicability::MachineApplicable,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 83193746432..b3de86662eb 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -95,7 +95,7 @@ pub enum LifetimeName {
     /// User wrote nothing (e.g., the lifetime in `&u32`).
     ///
     /// The bool indicates whether the user should have written something.
-    Implicit(bool),
+    Implicit,
 
     /// Implicit lifetime in a context like `dyn Foo`. This is
     /// distinguished from implicit lifetimes elsewhere because the
@@ -125,7 +125,7 @@ impl LifetimeName {
     pub fn ident(&self) -> Ident {
         match *self {
             LifetimeName::ImplicitObjectLifetimeDefault
-            | LifetimeName::Implicit(_)
+            | LifetimeName::Implicit
             | LifetimeName::Error => Ident::empty(),
             LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
             LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
@@ -136,7 +136,7 @@ impl LifetimeName {
     pub fn is_elided(&self) -> bool {
         match self {
             LifetimeName::ImplicitObjectLifetimeDefault
-            | LifetimeName::Implicit(_)
+            | LifetimeName::Implicit
             | LifetimeName::Underscore => true,
 
             // It might seem surprising that `Fresh(_)` counts as
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 445b856e513..8689e2c2afa 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -528,7 +528,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
         | LifetimeName::Param(ParamName::Error)
         | LifetimeName::Static
         | LifetimeName::Error
-        | LifetimeName::Implicit(_)
+        | LifetimeName::Implicit
         | LifetimeName::ImplicitObjectLifetimeDefault
         | LifetimeName::Underscore => {}
     }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index e6f9246d732..77fe76af2de 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -441,6 +441,7 @@ impl EarlyLintPass for UnsafeCode {
             _,
             ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
             _,
+            _,
             body,
         ) = fk
         {
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 3600b6ad212..152c53dac7f 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -21,7 +21,8 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject};
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
-use rustc_errors::{struct_span_err, Applicability, MultiSpan, SuggestionStyle};
+use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err};
+use rustc_errors::{Applicability, MultiSpan, SuggestionStyle};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
@@ -665,6 +666,21 @@ pub trait LintContext: Sized {
                 ) => {
                     db.span_note(span_def, "the macro is defined here");
                 }
+                BuiltinLintDiagnostics::ElidedLifetimesInPaths(
+                    n,
+                    path_span,
+                    incl_angl_brckt,
+                    insertion_span,
+                ) => {
+                    add_elided_lifetime_in_path_suggestion(
+                        sess.source_map(),
+                        &mut db,
+                        n,
+                        path_span,
+                        incl_angl_brckt,
+                        insertion_span,
+                    );
+                }
                 BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
                     db.span_suggestion(span, &note, sugg, Applicability::MaybeIncorrect);
                 }
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 7447f9f64b7..b4262f184c8 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -158,7 +158,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
 
         // Explicitly check for lints associated with 'closure_id', since
         // it does not have a corresponding AST node
-        if let ast_visit::FnKind::Fn(_, _, sig, _, _) = fk {
+        if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
             if let ast::Async::Yes { closure_id, .. } = sig.header.asyncness {
                 self.check_id(closure_id);
             }
@@ -284,6 +284,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         ast_visit::walk_path(self, p);
     }
 
+    fn visit_path_segment(&mut self, path_span: Span, s: &'a ast::PathSegment) {
+        self.check_id(s.id);
+        ast_visit::walk_path_segment(self, path_span, s);
+    }
+
     fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
         run_early_pass!(self, check_attribute, attr);
     }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 031b01af5dd..4debbf26be6 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -418,6 +418,7 @@ pub enum BuiltinLintDiagnostics {
     AbsPathWithModule(Span),
     ProcMacroDeriveResolutionFallback(Span),
     MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
+    ElidedLifetimesInPaths(usize, Span, bool, Span),
     UnknownCrateTypes(Span, String, String),
     UnusedImports(String, Vec<(Span, String)>, Option<Span>),
     RedundantImport(Vec<(Span, bool)>, Ident),
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 54e8c03156d..063b15e643d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -521,11 +521,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         // while the current crate doesn't have a valid `crate_name`.
                         if crate_name != kw::Empty {
                             // `crate_name` should not be interpreted as relative.
-                            module_path.push(Segment {
-                                ident: Ident { name: kw::PathRoot, span: source.ident.span },
-                                id: Some(self.r.next_node_id()),
-                                has_generic_args: false,
-                            });
+                            module_path.push(Segment::from_ident_and_id(
+                                Ident { name: kw::PathRoot, span: source.ident.span },
+                                self.r.next_node_id(),
+                            ));
                             source.ident.name = crate_name;
                         }
                         if rename.is_none() {
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 8ea5dca6f10..1e8cca6122c 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -133,8 +133,10 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
     }
 
     fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
-        if let FnKind::Fn(_, _, sig, _, body) = fn_kind {
+        if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
             if let Async::Yes { closure_id, return_impl_trait_id, .. } = sig.header.asyncness {
+                self.visit_generics(generics);
+
                 let return_impl_trait_id =
                     self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span);
 
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 24b6d656981..84fe0ec83d2 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1402,7 +1402,7 @@ impl<'a> Resolver<'a> {
         let mut allow_super = true;
         let mut second_binding = None;
 
-        for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
+        for (i, &Segment { ident, id, .. }) in path.iter().enumerate() {
             debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
             let record_segment_res = |this: &mut Self, res| {
                 if finalize.is_some() {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 763f31622bc..9bc5d63ca17 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -21,10 +21,11 @@ use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
 use smallvec::{smallvec, SmallVec};
 
 use rustc_span::source_map::{respan, Spanned};
@@ -188,6 +189,68 @@ impl<'a, R> Rib<'a, R> {
     }
 }
 
+#[derive(Copy, Clone, Debug)]
+enum LifetimeRibKind {
+    /// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
+    Item,
+
+    /// This rib declares generic parameters.
+    Generics { span: Span, kind: LifetimeBinderKind },
+
+    /// For **Modern** cases, create a new anonymous region parameter
+    /// and reference that.
+    ///
+    /// For **Dyn Bound** cases, pass responsibility to
+    /// `resolve_lifetime` code.
+    ///
+    /// For **Deprecated** cases, report an error.
+    AnonymousCreateParameter,
+
+    /// Give a hard error when either `&` or `'_` is written. Used to
+    /// rule out things like `where T: Foo<'_>`. Does not imply an
+    /// error on default object bounds (e.g., `Box<dyn Foo>`).
+    AnonymousReportError,
+
+    /// Pass responsibility to `resolve_lifetime` code for all cases.
+    AnonymousPassThrough,
+}
+
+#[derive(Copy, Clone, Debug)]
+enum LifetimeBinderKind {
+    BareFnType,
+    PolyTrait,
+    WhereBound,
+    Item,
+    Function,
+    ImplBlock,
+}
+
+impl LifetimeBinderKind {
+    fn descr(self) -> &'static str {
+        use LifetimeBinderKind::*;
+        match self {
+            BareFnType => "type",
+            PolyTrait => "bound",
+            WhereBound => "bound",
+            Item => "item",
+            ImplBlock => "impl block",
+            Function => "function",
+        }
+    }
+}
+
+#[derive(Debug)]
+struct LifetimeRib {
+    kind: LifetimeRibKind,
+    bindings: IdentMap<()>,
+}
+
+impl LifetimeRib {
+    fn new(kind: LifetimeRibKind) -> LifetimeRib {
+        LifetimeRib { bindings: Default::default(), kind }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 crate enum AliasPossibility {
     No,
@@ -422,6 +485,9 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
     /// The current set of local scopes, for labels.
     label_ribs: Vec<Rib<'a, NodeId>>,
 
+    /// The current set of local scopes for lifetimes.
+    lifetime_ribs: Vec<LifetimeRib>,
+
     /// The trait that the current context can refer to.
     current_trait_ref: Option<(Module<'a>, TraitRef)>,
 
@@ -446,7 +512,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
         // Always report errors in items we just entered.
         let old_ignore = replace(&mut self.in_func_body, false);
-        self.resolve_item(item);
+        self.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item));
         self.in_func_body = old_ignore;
         self.diagnostic_metadata.current_item = prev;
     }
@@ -481,6 +547,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         let prev = self.diagnostic_metadata.current_trait_object;
         let prev_ty = self.diagnostic_metadata.current_type_path;
         match ty.kind {
+            TyKind::Rptr(None, _) => {
+                // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
+                // NodeId `ty.id`.
+                let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
+                self.resolve_elided_lifetime(ty.id, span);
+            }
             TyKind::Path(ref qself, ref path) => {
                 self.diagnostic_metadata.current_type_path = Some(ty);
                 self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
@@ -500,36 +572,86 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             TyKind::TraitObject(ref bounds, ..) => {
                 self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
             }
+            TyKind::BareFn(ref bare_fn) => {
+                let span = if bare_fn.generic_params.is_empty() {
+                    ty.span.shrink_to_lo()
+                } else {
+                    ty.span
+                };
+                self.with_generic_param_rib(
+                    &bare_fn.generic_params,
+                    NormalRibKind,
+                    LifetimeRibKind::Generics { kind: LifetimeBinderKind::BareFnType, span },
+                    |this| {
+                        this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                            this.visit_generic_param_vec(&bare_fn.generic_params, false);
+                            visit::walk_fn_decl(this, &bare_fn.decl);
+                        });
+                    },
+                );
+                self.diagnostic_metadata.current_trait_object = prev;
+                return;
+            }
             _ => (),
         }
         visit::walk_ty(self, ty);
         self.diagnostic_metadata.current_trait_object = prev;
         self.diagnostic_metadata.current_type_path = prev_ty;
     }
-    fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
-        self.smart_resolve_path(
-            tref.trait_ref.ref_id,
-            None,
-            &tref.trait_ref.path,
-            PathSource::Trait(AliasPossibility::Maybe),
+    fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) {
+        let span =
+            if tref.bound_generic_params.is_empty() { tref.span.shrink_to_lo() } else { tref.span };
+        self.with_generic_param_rib(
+            &tref.bound_generic_params,
+            NormalRibKind,
+            LifetimeRibKind::Generics { kind: LifetimeBinderKind::PolyTrait, span },
+            |this| {
+                this.visit_generic_param_vec(&tref.bound_generic_params, false);
+                this.smart_resolve_path(
+                    tref.trait_ref.ref_id,
+                    None,
+                    &tref.trait_ref.path,
+                    PathSource::Trait(AliasPossibility::Maybe),
+                );
+                this.visit_trait_ref(&tref.trait_ref);
+            },
         );
-        visit::walk_poly_trait_ref(self, tref, m);
     }
     fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
         match foreign_item.kind {
-            ForeignItemKind::Fn(box Fn { ref generics, .. })
-            | ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
-                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    visit::walk_foreign_item(this, foreign_item);
+            ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
+                self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
+                    this.with_generic_param_rib(
+                        &generics.params,
+                        ItemRibKind(HasGenericParams::Yes),
+                        LifetimeRibKind::Generics {
+                            kind: LifetimeBinderKind::Item,
+                            span: generics.span,
+                        },
+                        |this| visit::walk_foreign_item(this, foreign_item),
+                    )
+                });
+            }
+            ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
+                self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
+                    this.with_generic_param_rib(
+                        &generics.params,
+                        ItemRibKind(HasGenericParams::Yes),
+                        LifetimeRibKind::Generics {
+                            kind: LifetimeBinderKind::Function,
+                            span: generics.span,
+                        },
+                        |this| visit::walk_foreign_item(this, foreign_item),
+                    )
                 });
             }
             ForeignItemKind::Static(..) => {
-                self.with_item_rib(HasGenericParams::No, |this| {
+                self.with_item_rib(|this| {
                     visit::walk_foreign_item(this, foreign_item);
                 });
             }
             ForeignItemKind::MacCall(..) => {
-                visit::walk_foreign_item(self, foreign_item);
+                panic!("unexpanded macro in resolve!")
             }
         }
     }
@@ -537,11 +659,15 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         let rib_kind = match fn_kind {
             // Bail if the function is foreign, and thus cannot validly have
             // a body, or if there's no body for some other reason.
-            FnKind::Fn(FnCtxt::Foreign, _, sig, ..) | FnKind::Fn(_, _, sig, .., None) => {
-                // We don't need to deal with patterns in parameters, because
-                // they are not possible for foreign or bodiless functions.
-                self.visit_fn_header(&sig.header);
-                visit::walk_fn_decl(self, &sig.decl);
+            FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
+            | FnKind::Fn(_, _, sig, _, generics, None) => {
+                self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                    // We don't need to deal with patterns in parameters, because
+                    // they are not possible for foreign or bodiless functions.
+                    this.visit_fn_header(&sig.header);
+                    this.visit_generics(generics);
+                    visit::walk_fn_decl(this, &sig.decl);
+                });
                 return;
             }
             FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
@@ -559,19 +685,44 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         self.with_rib(ValueNS, rib_kind, |this| {
             // Create a label rib for the function.
             this.with_label_rib(rib_kind, |this| {
-                // Add each argument to the rib.
-                this.resolve_params(&declaration.inputs);
+                let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
 
-                visit::walk_fn_ret_ty(this, &declaration.output);
+                if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
+                    this.visit_generics(generics);
+                }
+
+                if async_node_id.is_some() {
+                    // In `async fn`, argument-position elided lifetimes
+                    // must be transformed into fresh generic parameters so that
+                    // they can be applied to the opaque `impl Trait` return type.
+                    this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
+                        // Add each argument to the rib.
+                        this.resolve_params(&declaration.inputs)
+                    });
+
+                    this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                        visit::walk_fn_ret_ty(this, &declaration.output)
+                    });
+                } else {
+                    this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                        // Add each argument to the rib.
+                        this.resolve_params(&declaration.inputs);
+
+                        visit::walk_fn_ret_ty(this, &declaration.output);
+                    });
+                };
 
                 // 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
-                match fn_kind {
-                    FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
-                    FnKind::Closure(_, body) => this.visit_expr(body),
-                };
+                this.with_lifetime_rib(
+                    LifetimeRibKind::AnonymousPassThrough,
+                    |this| match fn_kind {
+                        FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
+                        FnKind::Closure(_, body) => this.visit_expr(body),
+                    },
+                );
 
                 debug!("(resolving function) leaving function");
                 this.in_func_body = previous_state;
@@ -579,89 +730,15 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         });
         self.diagnostic_metadata.current_function = previous_value;
     }
+    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
+        self.resolve_lifetime(lifetime)
+    }
 
     fn visit_generics(&mut self, generics: &'ast Generics) {
-        // For type parameter defaults, we have to ban access
-        // to following type parameters, as the InternalSubsts can only
-        // provide previous type parameters as they're built. We
-        // put all the parameters on the ban list and then remove
-        // them one by one as they are processed and become available.
-        let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
-        let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
-        for param in generics.params.iter() {
-            match param.kind {
-                GenericParamKind::Type { .. } => {
-                    forward_ty_ban_rib
-                        .bindings
-                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
-                }
-                GenericParamKind::Const { .. } => {
-                    forward_const_ban_rib
-                        .bindings
-                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
-                }
-                GenericParamKind::Lifetime => {}
-            }
-        }
-
-        // rust-lang/rust#61631: The type `Self` is essentially
-        // another type parameter. For ADTs, we consider it
-        // well-defined only after all of the ADT type parameters have
-        // been provided. Therefore, we do not allow use of `Self`
-        // anywhere in ADT type parameter defaults.
-        //
-        // (We however cannot ban `Self` for defaults on *all* generic
-        // lists; e.g. trait generics can usefully refer to `Self`,
-        // such as in the case of `trait Add<Rhs = Self>`.)
-        if self.diagnostic_metadata.current_self_item.is_some() {
-            // (`Some` if + only if we are in ADT's generics.)
-            forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
-        }
-
-        for param in &generics.params {
-            match param.kind {
-                GenericParamKind::Lifetime => self.visit_generic_param(param),
-                GenericParamKind::Type { ref default } => {
-                    for bound in &param.bounds {
-                        self.visit_param_bound(bound);
-                    }
-
-                    if let Some(ref ty) = default {
-                        self.ribs[TypeNS].push(forward_ty_ban_rib);
-                        self.ribs[ValueNS].push(forward_const_ban_rib);
-                        self.visit_ty(ty);
-                        forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
-                        forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
-                    }
-
-                    // Allow all following defaults to refer to this type parameter.
-                    forward_ty_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
-                }
-                GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
-                    // Const parameters can't have param bounds.
-                    assert!(param.bounds.is_empty());
-
-                    self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
-                    self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
-                    self.visit_ty(ty);
-                    self.ribs[TypeNS].pop().unwrap();
-                    self.ribs[ValueNS].pop().unwrap();
-
-                    if let Some(ref expr) = default {
-                        self.ribs[TypeNS].push(forward_ty_ban_rib);
-                        self.ribs[ValueNS].push(forward_const_ban_rib);
-                        self.visit_anon_const(expr);
-                        forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
-                        forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
-                    }
-
-                    // Allow all following defaults to refer to this const parameter.
-                    forward_const_ban_rib
-                        .bindings
-                        .remove(&Ident::with_dummy_span(param.ident.name));
-                }
-            }
-        }
+        self.visit_generic_param_vec(
+            &generics.params,
+            self.diagnostic_metadata.current_self_item.is_some(),
+        );
         for p in &generics.where_clause.predicates {
             self.visit_where_predicate(p);
         }
@@ -720,11 +797,52 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         self.diagnostic_metadata.currently_processing_generics = prev;
     }
 
+    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
+        if let Some(ref args) = path_segment.args {
+            match &**args {
+                GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args),
+                GenericArgs::Parenthesized(..) => self
+                    .with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                        visit::walk_generic_args(this, path_span, args)
+                    }),
+            }
+        }
+    }
+
     fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
         debug!("visit_where_predicate {:?}", p);
         let previous_value =
             replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p));
-        visit::walk_where_predicate(self, p);
+        self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+            if let WherePredicate::BoundPredicate(WhereBoundPredicate {
+                ref bounded_ty,
+                ref bounds,
+                ref bound_generic_params,
+                span: predicate_span,
+                ..
+            }) = p
+            {
+                let span = if bound_generic_params.is_empty() {
+                    predicate_span.shrink_to_lo()
+                } else {
+                    *predicate_span
+                };
+                this.with_generic_param_rib(
+                    &bound_generic_params,
+                    NormalRibKind,
+                    LifetimeRibKind::Generics { kind: LifetimeBinderKind::WhereBound, span },
+                    |this| {
+                        this.visit_generic_param_vec(&bound_generic_params, false);
+                        this.visit_ty(bounded_ty);
+                        for bound in bounds {
+                            this.visit_param_bound(bound)
+                        }
+                    },
+                );
+            } else {
+                visit::walk_where_predicate(this, p);
+            }
+        });
         self.diagnostic_metadata.current_where_predicate = previous_value;
     }
 
@@ -762,6 +880,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 macro_ns: vec![Rib::new(start_rib_kind)],
             },
             label_ribs: Vec::new(),
+            lifetime_ribs: Vec::new(),
             current_trait_ref: None,
             diagnostic_metadata: DiagnosticMetadata::default(),
             // errors at module scope should always be reported
@@ -864,6 +983,319 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         }
     }
 
+    fn visit_generic_param_vec(&mut self, params: &'ast Vec<GenericParam>, add_self_upper: bool) {
+        // For type parameter defaults, we have to ban access
+        // to following type parameters, as the InternalSubsts can only
+        // provide previous type parameters as they're built. We
+        // put all the parameters on the ban list and then remove
+        // them one by one as they are processed and become available.
+        let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
+        let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
+        for param in params.iter() {
+            match param.kind {
+                GenericParamKind::Type { .. } => {
+                    forward_ty_ban_rib
+                        .bindings
+                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
+                }
+                GenericParamKind::Const { .. } => {
+                    forward_const_ban_rib
+                        .bindings
+                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
+                }
+                GenericParamKind::Lifetime => {}
+            }
+        }
+
+        // rust-lang/rust#61631: The type `Self` is essentially
+        // another type parameter. For ADTs, we consider it
+        // well-defined only after all of the ADT type parameters have
+        // been provided. Therefore, we do not allow use of `Self`
+        // anywhere in ADT type parameter defaults.
+        //
+        // (We however cannot ban `Self` for defaults on *all* generic
+        // lists; e.g. trait generics can usefully refer to `Self`,
+        // such as in the case of `trait Add<Rhs = Self>`.)
+        if add_self_upper {
+            // (`Some` if + only if we are in ADT's generics.)
+            forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
+        }
+
+        self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+            for param in params {
+                match param.kind {
+                    GenericParamKind::Lifetime => {
+                        for bound in &param.bounds {
+                            this.visit_param_bound(bound);
+                        }
+                    }
+                    GenericParamKind::Type { ref default } => {
+                        for bound in &param.bounds {
+                            this.visit_param_bound(bound);
+                        }
+
+                        if let Some(ref ty) = default {
+                            this.ribs[TypeNS].push(forward_ty_ban_rib);
+                            this.ribs[ValueNS].push(forward_const_ban_rib);
+                            this.visit_ty(ty);
+                            forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
+                            forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
+                        }
+
+                        // Allow all following defaults to refer to this type parameter.
+                        forward_ty_ban_rib
+                            .bindings
+                            .remove(&Ident::with_dummy_span(param.ident.name));
+                    }
+                    GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
+                        // Const parameters can't have param bounds.
+                        assert!(param.bounds.is_empty());
+
+                        this.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
+                        this.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
+                        this.visit_ty(ty);
+                        this.ribs[TypeNS].pop().unwrap();
+                        this.ribs[ValueNS].pop().unwrap();
+
+                        if let Some(ref expr) = default {
+                            this.ribs[TypeNS].push(forward_ty_ban_rib);
+                            this.ribs[ValueNS].push(forward_const_ban_rib);
+                            this.visit_anon_const(expr);
+                            forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
+                            forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
+                        }
+
+                        // Allow all following defaults to refer to this const parameter.
+                        forward_const_ban_rib
+                            .bindings
+                            .remove(&Ident::with_dummy_span(param.ident.name));
+                    }
+                }
+            }
+        })
+    }
+
+    #[tracing::instrument(level = "debug", skip(self, work))]
+    fn with_lifetime_rib<T>(
+        &mut self,
+        kind: LifetimeRibKind,
+        work: impl FnOnce(&mut Self) -> T,
+    ) -> T {
+        self.lifetime_ribs.push(LifetimeRib::new(kind));
+        let ret = work(self);
+        self.lifetime_ribs.pop();
+        ret
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime) {
+        let ident = lifetime.ident;
+
+        if ident.name == kw::StaticLifetime {
+            return;
+        }
+
+        if ident.name == kw::UnderscoreLifetime {
+            return self.resolve_anonymous_lifetime(lifetime, false);
+        }
+
+        let mut indices = (0..self.lifetime_ribs.len()).rev();
+        for i in &mut indices {
+            let rib = &self.lifetime_ribs[i];
+            let normalized_ident = ident.normalize_to_macros_2_0();
+            if let Some(_) = rib.bindings.get_key_value(&normalized_ident) {
+                return;
+            }
+
+            if let LifetimeRibKind::Item = rib.kind {
+                break;
+            }
+        }
+
+        let mut outer_res = None;
+        for i in indices {
+            let rib = &self.lifetime_ribs[i];
+            let normalized_ident = ident.normalize_to_macros_2_0();
+            if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
+                outer_res = Some(outer);
+                break;
+            }
+        }
+
+        self.emit_undeclared_lifetime_error(lifetime, outer_res);
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
+        debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
+
+        for i in (0..self.lifetime_ribs.len()).rev() {
+            let rib = &mut self.lifetime_ribs[i];
+            match rib.kind {
+                LifetimeRibKind::AnonymousReportError => {
+                    let (msg, note) = if elided {
+                        (
+                            "`&` without an explicit lifetime name cannot be used here",
+                            "explicit lifetime name needed here",
+                        )
+                    } else {
+                        ("`'_` cannot be used here", "`'_` is a reserved lifetime name")
+                    };
+                    rustc_errors::struct_span_err!(
+                        self.r.session,
+                        lifetime.ident.span,
+                        E0637,
+                        "{}",
+                        msg,
+                    )
+                    .span_label(lifetime.ident.span, note)
+                    .emit();
+
+                    return;
+                }
+                LifetimeRibKind::AnonymousCreateParameter
+                | LifetimeRibKind::AnonymousPassThrough
+                | LifetimeRibKind::Item => return,
+                _ => {}
+            }
+        }
+    }
+
+    #[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.resolve_anonymous_lifetime(&lt, true);
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_elided_lifetimes_in_path(
+        &mut self,
+        path_id: NodeId,
+        partial_res: PartialRes,
+        path: &[Segment],
+        source: PathSource<'_>,
+        finalize: Finalize,
+    ) {
+        let Some(path_span) = finalize.path_span() else {
+            return;
+        };
+        let proj_start = path.len() - partial_res.unresolved_segments();
+        for (i, segment) in path.iter().enumerate() {
+            if segment.has_lifetime_args {
+                continue;
+            }
+            let Some(segment_id) = segment.id else {
+                continue;
+            };
+
+            // Figure out if this is a type/trait segment,
+            // which may need lifetime elision performed.
+            let type_def_id = match partial_res.base_res() {
+                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
+                    self.r.parent(def_id).unwrap()
+                }
+                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
+                    self.r.parent(def_id).unwrap()
+                }
+                Res::Def(DefKind::Struct, def_id)
+                | Res::Def(DefKind::Union, def_id)
+                | Res::Def(DefKind::Enum, def_id)
+                | Res::Def(DefKind::TyAlias, def_id)
+                | Res::Def(DefKind::Trait, def_id)
+                    if i + 1 == proj_start =>
+                {
+                    def_id
+                }
+                _ => continue,
+            };
+
+            let expected_lifetimes = self.r.item_generics_num_lifetimes(type_def_id);
+            if expected_lifetimes == 0 {
+                continue;
+            }
+
+            let missing = match source {
+                PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
+                PathSource::Expr(..)
+                | PathSource::Pat
+                | PathSource::Struct
+                | PathSource::TupleStruct(..) => false,
+            };
+            let mut error = false;
+            for rib in self.lifetime_ribs.iter().rev() {
+                match rib.kind {
+                    // In create-parameter mode we error here because we don't want to support
+                    // deprecated impl elision in new features like impl elision and `async fn`,
+                    // both of which work using the `CreateParameter` mode:
+                    //
+                    //     impl Foo for std::cell::Ref<u32> // note lack of '_
+                    //     async fn foo(_: std::cell::Ref<u32>) { ... }
+                    LifetimeRibKind::AnonymousCreateParameter => {
+                        error = true;
+                        break;
+                    }
+                    // `PassThrough` is the normal case.
+                    // `new_error_lifetime`, which would usually be used in the case of `ReportError`,
+                    // is unsuitable here, as these can occur from missing lifetime parameters in a
+                    // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
+                    // lifetime. Instead, we simply create an implicit lifetime, which will be checked
+                    // later, at which point a suitable error will be emitted.
+                    LifetimeRibKind::AnonymousPassThrough
+                    | LifetimeRibKind::AnonymousReportError
+                    | LifetimeRibKind::Item => break,
+                    _ => {}
+                }
+            }
+
+            if !missing {
+                continue;
+            }
+
+            let elided_lifetime_span = if segment.has_generic_args {
+                // If there are brackets, but not generic arguments, then use the opening bracket
+                segment.args_span.with_hi(segment.args_span.lo() + BytePos(1))
+            } else {
+                // If there are no brackets, use the identifier span.
+                // HACK: we use find_ancestor_inside to properly suggest elided spans in paths
+                // originating from macros, since the segment's span might be from a macro arg.
+                segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
+            };
+            if error {
+                let sess = self.r.session;
+                let mut err = rustc_errors::struct_span_err!(
+                    sess,
+                    path_span,
+                    E0726,
+                    "implicit elided lifetime not allowed here"
+                );
+                rustc_errors::add_elided_lifetime_in_path_suggestion(
+                    sess.source_map(),
+                    &mut err,
+                    expected_lifetimes,
+                    path_span,
+                    !segment.has_generic_args,
+                    elided_lifetime_span,
+                );
+                err.note("assuming a `'static` lifetime...");
+                err.emit();
+            } else {
+                self.r.lint_buffer.buffer_lint_with_diagnostic(
+                    lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
+                    segment_id,
+                    elided_lifetime_span,
+                    "hidden lifetime parameters in types are deprecated",
+                    lint::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
+                        expected_lifetimes,
+                        path_span,
+                        !segment.has_generic_args,
+                        elided_lifetime_span,
+                    ),
+                );
+            }
+        }
+    }
+
     /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
     /// label and reports an error if the label is not found or is unreachable.
     fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
@@ -944,15 +1376,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
         debug!("resolve_adt");
         self.with_current_self_item(item, |this| {
-            this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                let item_def_id = this.r.local_def_id(item.id).to_def_id();
-                this.with_self_rib(
-                    Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
-                    |this| {
-                        visit::walk_item(this, item);
-                    },
-                );
-            });
+            this.with_generic_param_rib(
+                &generics.params,
+                ItemRibKind(HasGenericParams::Yes),
+                LifetimeRibKind::Generics { kind: LifetimeBinderKind::Item, span: generics.span },
+                |this| {
+                    let item_def_id = this.r.local_def_id(item.id).to_def_id();
+                    this.with_self_rib(
+                        Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
+                        |this| {
+                            visit::walk_item(this, item);
+                        },
+                    );
+                },
+            );
         });
     }
 
@@ -1004,18 +1441,33 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         debug!("(resolving item) resolving {} ({:?})", name, item.kind);
 
         match item.kind {
-            ItemKind::TyAlias(box TyAlias { ref generics, .. })
-            | ItemKind::Fn(box Fn { ref generics, .. }) => {
-                self.compute_num_lifetime_params(item.id, generics);
-                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    visit::walk_item(this, item)
-                });
+            ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes),
+                    LifetimeRibKind::Generics {
+                        kind: LifetimeBinderKind::Item,
+                        span: generics.span,
+                    },
+                    |this| visit::walk_item(this, item),
+                );
+            }
+
+            ItemKind::Fn(box Fn { ref generics, .. }) => {
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes),
+                    LifetimeRibKind::Generics {
+                        kind: LifetimeBinderKind::Function,
+                        span: generics.span,
+                    },
+                    |this| visit::walk_item(this, item),
+                );
             }
 
             ItemKind::Enum(_, ref generics)
             | ItemKind::Struct(_, ref generics)
             | ItemKind::Union(_, ref generics) => {
-                self.compute_num_lifetime_params(item.id, generics);
                 self.resolve_adt(item, generics);
             }
 
@@ -1026,72 +1478,113 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 items: ref impl_items,
                 ..
             }) => {
-                self.compute_num_lifetime_params(item.id, generics);
                 self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
             }
 
             ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => {
-                self.compute_num_lifetime_params(item.id, generics);
                 // Create a new rib for the trait-wide type parameters.
-                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let def = this.r.local_def_id(item.id).to_def_id();
-                    this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
-                        this.visit_generics(generics);
-                        walk_list!(this, visit_param_bound, bounds);
-
-                        let walk_assoc_item = |this: &mut Self, generics, item| {
-                            this.with_generic_param_rib(generics, AssocItemRibKind, |this| {
-                                visit::walk_assoc_item(this, item, AssocCtxt::Trait)
-                            });
-                        };
-
-                        this.with_trait_items(items, |this| {
-                            for item in items {
-                                match &item.kind {
-                                    AssocItemKind::Const(_, ty, default) => {
-                                        this.visit_ty(ty);
-                                        // Only impose the restrictions of `ConstRibKind` for an
-                                        // actual constant expression in a provided default.
-                                        if let Some(expr) = default {
-                                            // We allow arbitrary const expressions inside of associated consts,
-                                            // even if they are potentially not const evaluatable.
-                                            //
-                                            // Type parameters can already be used and as associated consts are
-                                            // not used as part of the type system, this is far less surprising.
-                                            this.with_constant_rib(
-                                                IsRepeatExpr::No,
-                                                true,
-                                                None,
-                                                |this| this.visit_expr(expr),
-                                            );
-                                        }
-                                    }
-                                    AssocItemKind::Fn(box Fn { generics, .. }) => {
-                                        walk_assoc_item(this, generics, item);
-                                    }
-                                    AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
-                                        walk_assoc_item(this, generics, item);
-                                    }
-                                    AssocItemKind::MacCall(_) => {
-                                        panic!("unexpanded macro in resolve!")
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes),
+                    LifetimeRibKind::Generics {
+                        kind: LifetimeBinderKind::Item,
+                        span: generics.span,
+                    },
+                    |this| {
+                        let local_def_id = this.r.local_def_id(item.id).to_def_id();
+                        this.with_self_rib(
+                            Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
+                            |this| {
+                                this.visit_generics(generics);
+                                walk_list!(this, visit_param_bound, bounds);
+
+                                let walk_assoc_item =
+                                    |this: &mut Self,
+                                     generics: &Generics,
+                                     kind,
+                                     item: &'ast AssocItem| {
+                                        this.with_generic_param_rib(
+                                            &generics.params,
+                                            AssocItemRibKind,
+                                            LifetimeRibKind::Generics { span: generics.span, kind },
+                                            |this| {
+                                                visit::walk_assoc_item(this, item, AssocCtxt::Trait)
+                                            },
+                                        );
+                                    };
+
+                                this.with_trait_items(items, |this| {
+                                    for item in items {
+                                        match &item.kind {
+                                            AssocItemKind::Const(_, ty, default) => {
+                                                this.visit_ty(ty);
+                                                // Only impose the restrictions of `ConstRibKind` for an
+                                                // actual constant expression in a provided default.
+                                                if let Some(expr) = default {
+                                                    // We allow arbitrary const expressions inside of associated consts,
+                                                    // even if they are potentially not const evaluatable.
+                                                    //
+                                                    // Type parameters can already be used and as associated consts are
+                                                    // not used as part of the type system, this is far less surprising.
+                                                    this.with_constant_rib(
+                                                        IsRepeatExpr::No,
+                                                        true,
+                                                        None,
+                                                        |this| this.visit_expr(expr),
+                                                    );
+                                                }
+                                            }
+                                            AssocItemKind::Fn(box Fn { generics, .. }) => {
+                                                walk_assoc_item(
+                                                    this,
+                                                    generics,
+                                                    LifetimeBinderKind::Function,
+                                                    item,
+                                                );
+                                            }
+                                            AssocItemKind::TyAlias(box TyAlias {
+                                                generics,
+                                                ..
+                                            }) => {
+                                                walk_assoc_item(
+                                                    this,
+                                                    generics,
+                                                    LifetimeBinderKind::Item,
+                                                    item,
+                                                );
+                                            }
+                                            AssocItemKind::MacCall(_) => {
+                                                panic!("unexpanded macro in resolve!")
+                                            }
+                                        };
                                     }
-                                };
-                            }
-                        });
-                    });
-                });
+                                });
+                            },
+                        );
+                    },
+                );
             }
 
             ItemKind::TraitAlias(ref generics, ref bounds) => {
-                self.compute_num_lifetime_params(item.id, generics);
                 // Create a new rib for the trait-wide type parameters.
-                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let def = this.r.local_def_id(item.id).to_def_id();
-                    this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
-                        this.visit_generics(generics);
-                        walk_list!(this, visit_param_bound, bounds);
-                    });
-                });
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes),
+                    LifetimeRibKind::Generics {
+                        kind: LifetimeBinderKind::Item,
+                        span: generics.span,
+                    },
+                    |this| {
+                        let local_def_id = this.r.local_def_id(item.id).to_def_id();
+                        this.with_self_rib(
+                            Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
+                            |this| {
+                                this.visit_generics(generics);
+                                walk_list!(this, visit_param_bound, bounds);
+                            },
+                        );
+                    },
+                );
             }
 
             ItemKind::Mod(..) | ItemKind::ForeignMod(_) => {
@@ -1101,7 +1594,7 @@ 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(HasGenericParams::No, |this| {
+                self.with_item_rib(|this| {
                     this.visit_ty(ty);
                     if let Some(expr) = expr {
                         let constant_item_kind = match item.kind {
@@ -1137,13 +1630,19 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         }
     }
 
-    fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: RibKind<'a>, f: F)
-    where
+    fn with_generic_param_rib<'c, F>(
+        &'c mut self,
+        params: &'c Vec<GenericParam>,
+        kind: RibKind<'a>,
+        lifetime_kind: LifetimeRibKind,
+        f: F,
+    ) where
         F: FnOnce(&mut Self),
     {
         debug!("with_generic_param_rib");
         let mut function_type_rib = Rib::new(kind);
         let mut function_value_rib = Rib::new(kind);
+        let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
         let mut seen_bindings = FxHashMap::default();
 
         // We also can't shadow bindings from the parent item
@@ -1160,11 +1659,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             add_bindings_for_ns(TypeNS);
         }
 
-        for param in &generics.params {
-            if let GenericParamKind::Lifetime = param.kind {
-                continue;
-            }
-
+        for param in params {
             let ident = param.ident.normalize_to_macros_2_0();
             debug!("with_generic_param_rib: {}", param.id);
 
@@ -1172,24 +1667,57 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 Entry::Occupied(entry) => {
                     let span = *entry.get();
                     let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
-                    self.report_error(param.ident.span, err);
+                    if !matches!(param.kind, GenericParamKind::Lifetime) {
+                        self.report_error(param.ident.span, err);
+                    }
                 }
                 Entry::Vacant(entry) => {
                     entry.insert(param.ident.span);
                 }
             }
 
+            if param.ident.name == kw::UnderscoreLifetime {
+                rustc_errors::struct_span_err!(
+                    self.r.session,
+                    param.ident.span,
+                    E0637,
+                    "`'_` cannot be used here"
+                )
+                .span_label(param.ident.span, "`'_` is a reserved lifetime name")
+                .emit();
+                continue;
+            }
+
+            if param.ident.name == kw::StaticLifetime {
+                rustc_errors::struct_span_err!(
+                    self.r.session,
+                    param.ident.span,
+                    E0262,
+                    "invalid lifetime parameter name: `{}`",
+                    param.ident,
+                )
+                .span_label(param.ident.span, format!("'static is a reserved lifetime name"))
+                .emit();
+                continue;
+            }
+
+            let def_id = self.r.local_def_id(param.id);
+
             // Plain insert (no renaming).
             let (rib, def_kind) = match param.kind {
                 GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
                 GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
-                _ => unreachable!(),
+                GenericParamKind::Lifetime => {
+                    function_lifetime_rib.bindings.insert(ident, ());
+                    continue;
+                }
             };
-            let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
+            let res = Res::Def(def_kind, def_id.to_def_id());
             self.r.record_partial_res(param.id, PartialRes::new(res));
             rib.bindings.insert(ident, res);
         }
 
+        self.lifetime_ribs.push(function_lifetime_rib);
         self.ribs[ValueNS].push(function_value_rib);
         self.ribs[TypeNS].push(function_type_rib);
 
@@ -1197,6 +1725,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
         self.ribs[TypeNS].pop();
         self.ribs[ValueNS].pop();
+        self.lifetime_ribs.pop();
     }
 
     fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) {
@@ -1205,9 +1734,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         self.label_ribs.pop();
     }
 
-    fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce(&mut Self)) {
-        let kind = ItemRibKind(has_generic_params);
-        self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
+    fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
+        let kind = ItemRibKind(HasGenericParams::No);
+        self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
+            this.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
+        })
     }
 
     // HACK(min_const_generics,const_evaluatable_unchecked): We
@@ -1318,128 +1849,137 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     ) {
         debug!("resolve_implementation");
         // If applicable, create a rib for the type parameters.
-        self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
+        self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::ImplBlock }, |this| {
             // Dummy self type for better errors if `Self` is used in the trait path.
             this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
-                // Resolve the trait reference, if necessary.
-                this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
-                    let item_def_id = this.r.local_def_id(item_id);
-
-                    // 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);
-                    }
-
-                    let item_def_id = item_def_id.to_def_id();
-                    let res =
-                        Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
-                    this.with_self_rib(res, |this| {
-                        if let Some(trait_ref) = opt_trait_reference.as_ref() {
-                            // Resolve type arguments in the trait path.
-                            visit::walk_trait_ref(this, trait_ref);
+                this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
+                    // Resolve the trait reference, if necessary.
+                    this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
+                        let item_def_id = this.r.local_def_id(item_id);
+
+                        // 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);
                         }
-                        // Resolve the self type.
-                        this.visit_ty(self_type);
-                        // Resolve the generic parameters.
-                        this.visit_generics(generics);
-                        // Resolve the items within the impl.
-                        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 {
-                                    use crate::ResolutionError::*;
-                                    match &item.kind {
-                                        AssocItemKind::Const(_default, _ty, _expr) => {
-                                            debug!("resolve_implementation AssocItemKind::Const");
-                                            // If this is a trait impl, ensure the const
-                                            // exists in trait
-                                            this.check_trait_item(
-                                                item.id,
-                                                item.ident,
-                                                &item.kind,
-                                                ValueNS,
-                                                item.span,
-                                                |i, s, c| ConstNotMemberOfTrait(i, s, c),
-                                            );
-
-                                            // We allow arbitrary const expressions inside of associated consts,
-                                            // even if they are potentially not const evaluatable.
-                                            //
-                                            // Type parameters can already be used and as associated consts are
-                                            // not used as part of the type system, this is far less surprising.
-                                            this.with_constant_rib(
-                                                IsRepeatExpr::No,
-                                                true,
-                                                None,
-                                                |this| {
-                                                    visit::walk_assoc_item(
-                                                        this,
-                                                        item,
-                                                        AssocCtxt::Impl,
-                                                    )
-                                                },
-                                            );
-                                        }
-                                        AssocItemKind::Fn(box Fn { generics, .. }) => {
-                                            debug!("resolve_implementation AssocItemKind::Fn");
-                                            // We also need a new scope for the impl item type parameters.
-                                            this.with_generic_param_rib(
-                                                generics,
-                                                AssocItemRibKind,
-                                                |this| {
-                                                    // If this is a trait impl, ensure the method
-                                                    // exists in trait
-                                                    this.check_trait_item(
-                                                        item.id,
-                                                        item.ident,
-                                                        &item.kind,
-                                                        ValueNS,
-                                                        item.span,
-                                                        |i, s, c| MethodNotMemberOfTrait(i, s, c),
-                                                    );
-
-                                                    visit::walk_assoc_item(
-                                                        this,
-                                                        item,
-                                                        AssocCtxt::Impl,
-                                                    )
-                                                },
-                                            );
-                                        }
-                                        AssocItemKind::TyAlias(box TyAlias {
-                                            generics, ..
-                                        }) => {
-                                            debug!("resolve_implementation AssocItemKind::TyAlias");
-                                            // We also need a new scope for the impl item type parameters.
-                                            this.with_generic_param_rib(
-                                                generics,
-                                                AssocItemRibKind,
-                                                |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,
-                                                    )
-                                                },
-                                            );
-                                        }
-                                        AssocItemKind::MacCall(_) => {
-                                            panic!("unexpanded macro in resolve!")
-                                        }
-                                    }
-                                }
-                            });
+                        let item_def_id = item_def_id.to_def_id();
+                        let res =
+                            Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
+                        this.with_self_rib(res, |this| {
+                            if let Some(trait_ref) = opt_trait_reference.as_ref() {
+                                // Resolve type arguments in the trait path.
+                                visit::walk_trait_ref(this, trait_ref);
+                            }
+                            // Resolve the self type.
+                            this.visit_ty(self_type);
+                            // Resolve the generic parameters.
+                            this.visit_generics(generics);
+
+                            // Resolve the items within the impl.
+                            this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough,
+                                |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 {
+                                                use crate::ResolutionError::*;
+                                                match &item.kind {
+                                                    AssocItemKind::Const(_default, _ty, _expr) => {
+                                                        debug!("resolve_implementation AssocItemKind::Const");
+                                                        // If this is a trait impl, ensure the const
+                                                        // exists in trait
+                                                        this.check_trait_item(
+                                                            item.id,
+                                                            item.ident,
+                                                            &item.kind,
+                                                            ValueNS,
+                                                            item.span,
+                                                            |i, s, c| ConstNotMemberOfTrait(i, s, c),
+                                                        );
+
+                                                        // We allow arbitrary const expressions inside of associated consts,
+                                                        // even if they are potentially not const evaluatable.
+                                                        //
+                                                        // Type parameters can already be used and as associated consts are
+                                                        // not used as part of the type system, this is far less surprising.
+                                                        this.with_constant_rib(
+                                                            IsRepeatExpr::No,
+                                                            true,
+                                                            None,
+                                                            |this| {
+                                                                visit::walk_assoc_item(
+                                                                    this,
+                                                                    item,
+                                                                    AssocCtxt::Impl,
+                                                                )
+                                                            },
+                                                        );
+                                                    }
+                                                    AssocItemKind::Fn(box Fn { generics, .. }) => {
+                                                        debug!("resolve_implementation AssocItemKind::Fn");
+                                                        // We also need a new scope for the impl item type parameters.
+                                                        this.with_generic_param_rib(
+                                                            &generics.params,
+                                                            AssocItemRibKind,
+                                                            LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Function },
+                                                            |this| {
+                                                                // If this is a trait impl, ensure the method
+                                                                // exists in trait
+                                                                this.check_trait_item(
+                                                                    item.id,
+                                                                    item.ident,
+                                                                    &item.kind,
+                                                                    ValueNS,
+                                                                    item.span,
+                                                                    |i, s, c| MethodNotMemberOfTrait(i, s, c),
+                                                                );
+
+                                                                visit::walk_assoc_item(
+                                                                    this,
+                                                                    item,
+                                                                    AssocCtxt::Impl,
+                                                                )
+                                                            },
+                                                        );
+                                                    }
+                                                    AssocItemKind::TyAlias(box TyAlias {
+                                                        generics, ..
+                                                    }) => {
+                                                        debug!("resolve_implementation AssocItemKind::TyAlias");
+                                                        // We also need a new scope for the impl item type parameters.
+                                                        this.with_generic_param_rib(
+                                                            &generics.params,
+                                                            AssocItemRibKind,
+                                                            LifetimeRibKind::Generics { span: generics.span, 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),
+                                                                );
+
+                                                                visit::walk_assoc_item(
+                                                                    this,
+                                                                    item,
+                                                                    AssocCtxt::Impl,
+                                                                )
+                                                            },
+                                                        );
+                                                    }
+                                                    AssocItemKind::MacCall(_) => {
+                                                        panic!("unexpanded macro in resolve!")
+                                                    }
+                                                }
+                                            }
+                                        });
+                                    });
+                                },
+                            );
                         });
                     });
                 });
@@ -2117,6 +2657,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             self.r.record_partial_res(id, partial_res);
         }
 
+        self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize);
         partial_res
     }
 
@@ -2576,20 +3117,51 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             Some((ident.name, ns)),
         )
     }
+}
+
+struct LifetimeCountVisitor<'a, 'b> {
+    r: &'b mut Resolver<'a>,
+}
 
-    fn compute_num_lifetime_params(&mut self, id: NodeId, generics: &Generics) {
-        let def_id = self.r.local_def_id(id);
-        let count = generics
-            .params
-            .iter()
-            .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. }))
-            .count();
-        self.r.item_generics_num_lifetimes.insert(def_id, count);
+/// Walks the whole crate in DFS order, visiting each item, counting the declared number of
+/// lifetime generic parameters.
+impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_> {
+    fn visit_item(&mut self, item: &'ast Item) {
+        match &item.kind {
+            ItemKind::TyAlias(box TyAlias { ref generics, .. })
+            | ItemKind::Fn(box Fn { ref generics, .. })
+            | ItemKind::Enum(_, ref generics)
+            | ItemKind::Struct(_, ref generics)
+            | ItemKind::Union(_, ref generics)
+            | ItemKind::Impl(box Impl { ref generics, .. })
+            | ItemKind::Trait(box Trait { ref generics, .. })
+            | ItemKind::TraitAlias(ref generics, _) => {
+                let def_id = self.r.local_def_id(item.id);
+                let count = generics
+                    .params
+                    .iter()
+                    .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. }))
+                    .count();
+                self.r.item_generics_num_lifetimes.insert(def_id, count);
+            }
+
+            ItemKind::Mod(..)
+            | ItemKind::ForeignMod(..)
+            | ItemKind::Static(..)
+            | ItemKind::Const(..)
+            | ItemKind::Use(..)
+            | ItemKind::ExternCrate(..)
+            | ItemKind::MacroDef(..)
+            | ItemKind::GlobalAsm(..)
+            | ItemKind::MacCall(..) => {}
+        }
+        visit::walk_item(self, item)
     }
 }
 
 impl<'a> Resolver<'a> {
     pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
+        visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate);
         let mut late_resolution_visitor = LateResolutionVisitor::new(self);
         visit::walk_crate(&mut late_resolution_visitor, krate);
         for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 0926f24ae70..0bae141ce26 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1,6 +1,7 @@
 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
 use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
+use crate::late::{LifetimeBinderKind, LifetimeRibKind};
 use crate::path_names_to_string;
 use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
@@ -1793,83 +1794,118 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             (*ident, within_scope)
         })
     }
-}
 
-impl<'tcx> LifetimeContext<'_, 'tcx> {
-    crate fn report_missing_lifetime_specifiers(
+    crate fn emit_undeclared_lifetime_error(
         &self,
-        spans: Vec<Span>,
-        count: usize,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        struct_span_err!(
-            self.tcx.sess,
-            spans,
-            E0106,
-            "missing lifetime specifier{}",
-            pluralize!(count)
-        )
-    }
+        lifetime_ref: &ast::Lifetime,
+        outer_lifetime_ref: Option<Ident>,
+    ) {
+        debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
+        let mut err = if let Some(outer) = outer_lifetime_ref {
+            let mut err = struct_span_err!(
+                self.r.session,
+                lifetime_ref.ident.span,
+                E0401,
+                "can't use generic parameters from outer item",
+            );
+            err.span_label(lifetime_ref.ident.span, "use of generic parameter from outer item");
+            err.span_label(outer.span, "lifetime parameter from outer item");
+            err
+        } else {
+            let mut err = struct_span_err!(
+                self.r.session,
+                lifetime_ref.ident.span,
+                E0261,
+                "use of undeclared lifetime name `{}`",
+                lifetime_ref.ident
+            );
+            err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
+            err
+        };
+        let mut suggest_note = true;
 
-    crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
-        let mut err = struct_span_err!(
-            self.tcx.sess,
-            lifetime_ref.span,
-            E0261,
-            "use of undeclared lifetime name `{}`",
-            lifetime_ref
-        );
-        err.span_label(lifetime_ref.span, "undeclared lifetime");
-        let mut suggested_spans = vec![];
-        for missing in &self.missing_named_lifetime_spots {
-            match missing {
-                MissingLifetimeSpot::Generics(generics) => {
-                    let (span, sugg) = 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(), format!("{}, ", lifetime_ref))
-                    } else {
-                        (generics.span, format!("<{}>", lifetime_ref))
-                    };
-                    if suggested_spans.contains(&span) {
+        for rib in self.lifetime_ribs.iter().rev() {
+            match rib.kind {
+                LifetimeRibKind::Generics { span, kind } => {
+                    if !span.can_be_used_for_suggestions() && suggest_note {
+                        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,
+                            ),
+                        );
                         continue;
                     }
-                    suggested_spans.push(span);
-                    if span.can_be_used_for_suggestions() {
+
+                    let higher_ranked = matches!(
+                        kind,
+                        LifetimeBinderKind::BareFnType
+                            | LifetimeBinderKind::PolyTrait
+                            | LifetimeBinderKind::WhereBound
+                    );
+                    let (span, sugg) = if span.is_empty() {
+                        let sugg = format!(
+                            "{}<{}>{}",
+                            if higher_ranked { "for" } else { "" },
+                            lifetime_ref.ident,
+                            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);
+                        (span, sugg)
+                    };
+                    if higher_ranked {
                         err.span_suggestion(
                             span,
-                            &format!("consider introducing lifetime `{}` here", lifetime_ref),
+                            &format!(
+                                "consider making the {} lifetime-generic with a new `{}` lifetime",
+                                kind.descr(),
+                                lifetime_ref
+                            ),
+                            sugg,
+                            Applicability::MaybeIncorrect,
+                        );
+                        err.note_once(
+                            "for more information on higher-ranked polymorphism, visit \
+                             https://doc.rust-lang.org/nomicon/hrtb.html",
+                        );
+                    } else {
+                        err.span_suggestion(
+                            span,
+                            &format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
                             sugg,
                             Applicability::MaybeIncorrect,
                         );
                     }
                 }
-                MissingLifetimeSpot::HigherRanked { span, span_type } => {
-                    err.span_suggestion(
-                        *span,
-                        &format!(
-                            "consider making the {} lifetime-generic with a new `{}` lifetime",
-                            span_type.descr(),
-                            lifetime_ref
-                        ),
-                        span_type.suggestion(&lifetime_ref.to_string()),
-                        Applicability::MaybeIncorrect,
-                    );
-                    err.note(
-                        "for more information on higher-ranked polymorphism, visit \
-                         https://doc.rust-lang.org/nomicon/hrtb.html",
-                    );
-                }
+                LifetimeRibKind::Item => break,
                 _ => {}
             }
         }
+
         err.emit();
     }
+}
+
+impl<'tcx> LifetimeContext<'_, 'tcx> {
+    crate fn report_missing_lifetime_specifiers(
+        &self,
+        spans: Vec<Span>,
+        count: usize,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        struct_span_err!(
+            self.tcx.sess,
+            spans,
+            E0106,
+            "missing lifetime specifier{}",
+            pluralize!(count)
+        )
+    }
 
     /// Returns whether to add `'static` lifetime to the suggested lifetime list.
     crate fn report_elision_failure(
@@ -1950,38 +1986,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         }
     }
 
-    crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) {
-        let Some(missing_lifetime) = lifetime_refs.iter().find(|lt| {
-            lt.name == hir::LifetimeName::Implicit(true)
-        }) else { return };
-
-        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();
-
-        self.tcx.struct_span_lint_hir(
-            rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
-            missing_lifetime.hir_id,
-            spans,
-            |lint| {
-                let mut db = lint.build("hidden lifetime parameters in types are deprecated");
-                self.add_missing_lifetime_specifiers_label(
-                    &mut db,
-                    spans_with_counts,
-                    &FxHashSet::from_iter([kw::UnderscoreLifetime]),
-                    Vec::new(),
-                    &[],
-                );
-                db.emit();
-            },
-        );
-    }
-
     // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
     // generics. We are disallowing this until we can decide on how we want to handle non-'static
     // lifetimes in const generics. See issue #74052 for discussion.
@@ -2416,9 +2420,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         );
         let is_allowed_lifetime = matches!(
             lifetime_ref.name,
-            hir::LifetimeName::Implicit(_)
-                | hir::LifetimeName::Static
-                | hir::LifetimeName::Underscore
+            hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
         );
 
         if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 2bf01146fae..d5f2e2db1e3 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -164,9 +164,6 @@ crate struct LifetimeContext<'a, 'tcx> {
     map: &'a mut NamedRegionMap,
     scope: ScopeRef<'a>,
 
-    /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
-    is_in_fn_syntax: bool,
-
     is_in_const_generic: bool,
 
     /// Indicates that we only care about the definition of a trait. This should
@@ -455,7 +452,6 @@ fn do_resolve(
         tcx,
         map: &mut named_region_map,
         scope: ROOT_SCOPE,
-        is_in_fn_syntax: false,
         is_in_const_generic: false,
         trait_definition_only,
         labels_in_fn: vec![],
@@ -874,8 +870,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 was_in_fn_syntax = self.is_in_fn_syntax;
-                self.is_in_fn_syntax = true;
                 let lifetime_span: Option<Span> =
                     c.generic_params.iter().rev().find_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => Some(param.span),
@@ -917,7 +911,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     intravisit::walk_ty(this, ty);
                 });
                 self.missing_named_lifetime_spots.pop();
-                self.is_in_fn_syntax = was_in_fn_syntax;
             }
             hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
                 debug!(?bounds, ?lifetime, "TraitObject");
@@ -928,7 +921,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     }
                 });
                 match lifetime.name {
-                    LifetimeName::Implicit(_) => {
+                    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",);
@@ -1805,7 +1798,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             tcx: *tcx,
             map,
             scope: &wrap_scope,
-            is_in_fn_syntax: self.is_in_fn_syntax,
             is_in_const_generic: self.is_in_const_generic,
             trait_definition_only: self.trait_definition_only,
             labels_in_fn,
@@ -2320,7 +2312,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
             self.insert_lifetime(lifetime_ref, def);
         } else {
-            self.emit_undeclared_lifetime_error(lifetime_ref);
+            self.tcx.sess.delay_span_bug(
+                lifetime_ref.span,
+                &format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
+            );
         }
     }
 
@@ -2336,10 +2331,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         );
 
         if generic_args.parenthesized {
-            let was_in_fn_syntax = self.is_in_fn_syntax;
-            self.is_in_fn_syntax = true;
             self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty()));
-            self.is_in_fn_syntax = was_in_fn_syntax;
             return;
         }
 
@@ -2963,9 +2955,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let error = loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
-                Scope::Body { .. } => break Ok(()),
+                Scope::Body { .. } => return,
 
-                Scope::Root => break Err(None),
+                Scope::Root => break None,
 
                 Scope::Binder { s, ref lifetimes, scope_type, .. } => {
                     // collect named lifetimes for suggestions
@@ -2992,7 +2984,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
                         self.insert_lifetime(lifetime_ref, lifetime);
                     }
-                    break Ok(());
+                    return;
                 }
 
                 Scope::Elision { elide: Elide::Exact(l), .. } => {
@@ -3000,7 +2992,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     for lifetime_ref in lifetime_refs {
                         self.insert_lifetime(lifetime_ref, lifetime);
                     }
-                    break Ok(());
+                    return;
                 }
 
                 Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
@@ -3025,10 +3017,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                             _ => break,
                         }
                     }
-                    break Err(Some(&e[..]));
+                    break Some(&e[..]);
                 }
 
-                Scope::Elision { elide: Elide::Forbid, .. } => break Err(None),
+                Scope::Elision { elide: Elide::Forbid, .. } => break None,
 
                 Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
@@ -3038,14 +3030,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         };
 
-        let error = match error {
-            Ok(()) => {
-                self.report_elided_lifetime_in_ty(lifetime_refs);
-                return;
-            }
-            Err(error) => error,
-        };
-
         // If we specifically need the `scope_for_path` map, then we're in the
         // diagnostic pass and we don't want to emit more errors.
         if self.map.scope_for_path.is_some() {
@@ -3130,18 +3114,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             if let hir::ParamName::Plain(_) = lifetime_i_name {
                 let name = lifetime_i_name.ident().name;
                 if name == kw::UnderscoreLifetime || name == kw::StaticLifetime {
-                    let mut err = struct_span_err!(
-                        self.tcx.sess,
-                        lifetime_i.span,
-                        E0262,
-                        "invalid lifetime parameter name: `{}`",
-                        lifetime_i.name.ident(),
-                    );
-                    err.span_label(
+                    self.tcx.sess.delay_span_bug(
                         lifetime_i.span,
-                        format!("{} is a reserved lifetime name", name),
+                        &format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()),
                     );
-                    err.emit();
                 }
             }
 
@@ -3190,7 +3166,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                 ))
                                 .emit();
                         }
-                        hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit(_) => {
+                        hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
                             self.resolve_lifetime_ref(lt);
                         }
                         hir::LifetimeName::ImplicitObjectLifetimeDefault => {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 0335c40d70d..eed54370e23 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -11,6 +11,7 @@
 #![feature(drain_filter)]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
+#![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
@@ -27,7 +28,7 @@ pub use rustc_hir::def::{Namespace, PerNS};
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
-use rustc_ast::{Crate, Expr, ExprKind, LitKind, Path};
+use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::intern::Interned;
@@ -282,6 +283,9 @@ pub struct Segment {
     /// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
     /// nonsensical suggestions.
     has_generic_args: bool,
+    /// Signals whether this `PathSegment` has lifetime arguments.
+    has_lifetime_args: bool,
+    args_span: Span,
 }
 
 impl Segment {
@@ -290,7 +294,23 @@ impl Segment {
     }
 
     fn from_ident(ident: Ident) -> Segment {
-        Segment { ident, id: None, has_generic_args: false }
+        Segment {
+            ident,
+            id: None,
+            has_generic_args: false,
+            has_lifetime_args: false,
+            args_span: DUMMY_SP,
+        }
+    }
+
+    fn from_ident_and_id(ident: Ident, id: NodeId) -> Segment {
+        Segment {
+            ident,
+            id: Some(id),
+            has_generic_args: false,
+            has_lifetime_args: false,
+            args_span: DUMMY_SP,
+        }
     }
 
     fn names_to_string(segments: &[Segment]) -> String {
@@ -300,7 +320,28 @@ impl Segment {
 
 impl<'a> From<&'a ast::PathSegment> for Segment {
     fn from(seg: &'a ast::PathSegment) -> Segment {
-        Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() }
+        let has_generic_args = seg.args.is_some();
+        let (args_span, has_lifetime_args) = if let Some(args) = seg.args.as_deref() {
+            match args {
+                GenericArgs::AngleBracketed(args) => {
+                    let found_lifetimes = args
+                        .args
+                        .iter()
+                        .any(|arg| matches!(arg, AngleBracketedArg::Arg(GenericArg::Lifetime(_))));
+                    (args.span, found_lifetimes)
+                }
+                GenericArgs::Parenthesized(args) => (args.span, true),
+            }
+        } else {
+            (DUMMY_SP, false)
+        };
+        Segment {
+            ident: seg.ident,
+            id: Some(seg.id),
+            has_generic_args,
+            has_lifetime_args,
+            args_span,
+        }
     }
 }
 
@@ -1358,9 +1399,17 @@ impl<'a> Resolver<'a> {
     }
 
     pub fn next_node_id(&mut self) -> NodeId {
-        let next =
-            self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
-        mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next))
+        let start = self.next_node_id;
+        let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
+        self.next_node_id = ast::NodeId::from_u32(next);
+        start
+    }
+
+    pub fn next_node_ids(&mut self, count: usize) -> std::ops::Range<NodeId> {
+        let start = self.next_node_id;
+        let end = start.as_usize().checked_add(count).expect("input too large; ran out of NodeIds");
+        self.next_node_id = ast::NodeId::from_usize(end);
+        start..self.next_node_id
     }
 
     pub fn lint_buffer(&mut self) -> &mut LintBuffer {
diff --git a/src/test/ui/async-await/async-fn-path-elision.stderr b/src/test/ui/async-await/async-fn-path-elision.stderr
index 3d18d9c4125..5e0c8c29989 100644
--- a/src/test/ui/async-await/async-fn-path-elision.stderr
+++ b/src/test/ui/async-await/async-fn-path-elision.stderr
@@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
   --> $DIR/async-fn-path-elision.rs:5:20
    |
 LL | async fn error(lt: HasLifetime) {
-   |                    ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                    ^^^^^^^^^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | async fn error(lt: HasLifetime<'_>) {
+   |                               ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
index 317897ae70f..1792d8db292 100644
--- a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
+++ b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
@@ -2,9 +2,17 @@ error[E0261]: use of undeclared lifetime name `'x`
   --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:35
    |
 LL |   fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
-   |        -                          ^^ undeclared lifetime
-   |        |
-   |        help: consider introducing lifetime `'x` here: `<'x>`
+   |                                   ^^ undeclared lifetime
+   |
+   = 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 `'x` lifetime
+   |
+LL |   fn _f(arg : Box<dyn for<'x, 'a> X<Y<'x> = &'a [u32]>>) {}
+   |                           +++
+help: consider introducing lifetime `'x` here
+   |
+LL |   fn _f<'x>(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
+   |        ++++
 
 error[E0582]: binding for associated type `Y` references lifetime `'a`, which does not appear in the trait input types
   --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:33
diff --git a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
index bf0ca871503..a4bb361900f 100644
--- a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
+++ b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
@@ -4,14 +4,19 @@ error[E0261]: use of undeclared lifetime name `'b`
 LL |         + Deref<Target = Self::Item<'b>>;
    |                                     ^^ undeclared lifetime
    |
-help: consider introducing lifetime `'b` here
+   = 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 | trait Iterable<'b> {
-   |               ++++
+LL |         + for<'b> Deref<Target = Self::Item<'b>>;
+   |           +++++++
 help: consider introducing lifetime `'b` here
    |
 LL |     type Iter<'b, 'a>: Iterator<Item = Self::Item<'a>>
    |               +++
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Iterable<'b> {
+   |               ++++
 
 error[E0261]: use of undeclared lifetime name `'undeclared`
   --> $DIR/generic_associated_type_undeclared_lifetimes.rs:11:41
@@ -21,12 +26,12 @@ LL |     fn iter<'a>(&'a self) -> Self::Iter<'undeclared>;
    |
 help: consider introducing lifetime `'undeclared` here
    |
-LL | trait Iterable<'undeclared> {
-   |               +++++++++++++
-help: consider introducing lifetime `'undeclared` here
-   |
 LL |     fn iter<'undeclared, 'a>(&'a self) -> Self::Iter<'undeclared>;
    |             ++++++++++++
+help: consider introducing lifetime `'undeclared` here
+   |
+LL | trait Iterable<'undeclared> {
+   |               +++++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generic-associated-types/issue-67510.rs b/src/test/ui/generic-associated-types/issue-67510.rs
index e81a5b231a0..5725b660ab2 100644
--- a/src/test/ui/generic-associated-types/issue-67510.rs
+++ b/src/test/ui/generic-associated-types/issue-67510.rs
@@ -4,9 +4,9 @@ trait X {
     type Y<'a>;
 }
 
-fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
-  //~^ ERROR: use of undeclared lifetime name `'a`
-  //~| ERROR: use of undeclared lifetime name `'a`
-
+fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+//~^ ERROR: use of undeclared lifetime name `'a`
+//~| ERROR: use of undeclared lifetime name `'a`
+//~| ERROR: the trait `X` cannot be made into an object [E0038]
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-67510.stderr b/src/test/ui/generic-associated-types/issue-67510.stderr
index abc02b33e0e..8aeda22bad7 100644
--- a/src/test/ui/generic-associated-types/issue-67510.stderr
+++ b/src/test/ui/generic-associated-types/issue-67510.stderr
@@ -1,19 +1,50 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/issue-67510.rs:7:21
    |
-LL | fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
-   |     -               ^^ undeclared lifetime
-   |     |
-   |     help: consider introducing lifetime `'a` here: `<'a>`
+LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |                     ^^ undeclared lifetime
+   |
+   = 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 f(x: Box<dyn for<'a> X<Y<'a> = &'a ()>>) {}
+   |                 +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | fn f<'a>(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |     ++++
 
 error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/issue-67510.rs:7:26
+  --> $DIR/issue-67510.rs:7:28
+   |
+LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |                            ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL | fn f(x: Box<dyn for<'a> X<Y<'a> = &'a ()>>) {}
+   |                 +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | fn f<'a>(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |     ++++
+
+error[E0038]: the trait `X` cannot be made into an object
+  --> $DIR/issue-67510.rs:7:13
+   |
+LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |             ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-67510.rs:4:10
    |
-LL | fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
-   |     -                    ^^ undeclared lifetime
-   |     |
-   |     help: consider introducing lifetime `'a` here: `<'a>`
+LL | trait X {
+   |       - this trait cannot be made into an object...
+LL |     type Y<'a>;
+   |          ^ ...because it contains the generic associated type `Y`
+   = help: consider moving `Y` to another trait
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0038, E0261.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs
index ae64f9310d1..448d7ec2873 100644
--- a/src/test/ui/generic-associated-types/issue-70304.rs
+++ b/src/test/ui/generic-associated-types/issue-70304.rs
@@ -12,13 +12,10 @@ impl Document for DocumentImpl {
     type Cursor<'a> = DocCursorImpl<'a>;
 
     fn cursor(&self) -> Self::Cursor<'_> {
-        DocCursorImpl {
-            document: &self,
-        }
+        DocCursorImpl { document: &self }
     }
 }
 
-
 trait DocCursor<'a> {}
 
 struct DocCursorImpl<'a> {
@@ -35,7 +32,6 @@ where
     _phantom: std::marker::PhantomData<&'d ()>,
 }
 
-
 impl<'d, Cursor> Lexer<'d, Cursor>
 where
     Cursor: DocCursor<'d>,
@@ -44,15 +40,12 @@ where
     where
         Doc: Document<Cursor<'d> = Cursor>,
     {
-        Lexer {
-            cursor: document.cursor(),
-            _phantom: std::marker::PhantomData,
-        }
+        Lexer { cursor: document.cursor(), _phantom: std::marker::PhantomData }
     }
 }
 
 fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
-                                       //~^ ERROR: missing lifetime specifier
+    //~^ ERROR: missing lifetime specifier
     DocumentImpl {}
 }
 
diff --git a/src/test/ui/generic-associated-types/issue-70304.stderr b/src/test/ui/generic-associated-types/issue-70304.stderr
index c53dbf63a3c..c5f59a24057 100644
--- a/src/test/ui/generic-associated-types/issue-70304.stderr
+++ b/src/test/ui/generic-associated-types/issue-70304.stderr
@@ -1,5 +1,5 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-70304.rs:54:41
+  --> $DIR/issue-70304.rs:47:41
    |
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
    |                                         ^^ expected named lifetime parameter
diff --git a/src/test/ui/generics/generic-extern-lifetime.stderr b/src/test/ui/generics/generic-extern-lifetime.stderr
index 909848604ec..33332e760f5 100644
--- a/src/test/ui/generics/generic-extern-lifetime.stderr
+++ b/src/test/ui/generics/generic-extern-lifetime.stderr
@@ -2,7 +2,9 @@ error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/generic-extern-lifetime.rs:6:26
    |
 LL |     pub fn life2<'b>(x: &'a i32, y: &'b i32);
-   |                          ^^ undeclared lifetime
+   |                  -       ^^ undeclared lifetime
+   |                  |
+   |                  help: consider introducing lifetime `'a` here: `'a,`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/generic-extern-lifetime.rs:8:37
@@ -13,8 +15,12 @@ LL |     pub fn life4<'b>(x: for<'c> fn(&'a i32));
    = 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 |     pub fn life4<'b>(x: for<'c, 'a> fn(&'a i32));
-   |                               ++++
+LL |     pub fn life4<'b>(x: for<'a, 'c> fn(&'a i32));
+   |                             +++
+help: consider introducing lifetime `'a` here
+   |
+LL |     pub fn life4<'a, 'b>(x: for<'c> fn(&'a i32));
+   |                  +++
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/generic-extern-lifetime.rs:11:39
@@ -22,11 +28,14 @@ error[E0261]: use of undeclared lifetime name `'a`
 LL |     pub fn life7<'b>() -> for<'c> fn(&'a i32);
    |                                       ^^ undeclared lifetime
    |
-   = 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 |     pub fn life7<'b>() -> for<'c, 'a> fn(&'a i32);
-   |                                 ++++
+LL |     pub fn life7<'b>() -> for<'a, 'c> fn(&'a i32);
+   |                               +++
+help: consider introducing lifetime `'a` here
+   |
+LL |     pub fn life7<'a, 'b>() -> for<'c> fn(&'a i32);
+   |                  +++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr
index 90522a885ab..0b7d3f1e851 100644
--- a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr
@@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
   --> $DIR/path-elided.rs:7:18
    |
 LL | impl MyTrait for Foo {
-   |                  ^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                  ^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | impl MyTrait for Foo<'_> {
+   |                     ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.rs b/src/test/ui/impl-header-lifetime-elision/trait-elided.rs
index 102d259b0c8..c3e76d9cb5a 100644
--- a/src/test/ui/impl-header-lifetime-elision/trait-elided.rs
+++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.rs
@@ -1,9 +1,8 @@
 #![allow(warnings)]
 
-trait MyTrait<'a> { }
+trait MyTrait<'a> {}
 
-impl MyTrait for u32 {
-    //~^ ERROR implicit elided lifetime not allowed here
-}
+impl MyTrait for u32 {}
+//~^ ERROR implicit elided lifetime not allowed here
 
 fn main() {}
diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr
index 15bc3f106b9..412bba6be71 100644
--- a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr
@@ -1,10 +1,14 @@
 error[E0726]: implicit elided lifetime not allowed here
   --> $DIR/trait-elided.rs:5:6
    |
-LL | impl MyTrait for u32 {
-   |      ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+LL | impl MyTrait for u32 {}
+   |      ^^^^^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | impl MyTrait<'_> for u32 {}
+   |             ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-10412.rs b/src/test/ui/issues/issue-10412.rs
index 02058513685..0de170161b5 100644
--- a/src/test/ui/issues/issue-10412.rs
+++ b/src/test/ui/issues/issue-10412.rs
@@ -1,16 +1,20 @@
-trait Serializable<'self, T> { //~ ERROR lifetimes cannot use keyword names
-    fn serialize(val : &'self T) -> Vec<u8>; //~ ERROR lifetimes cannot use keyword names
-    fn deserialize(repr : &[u8]) -> &'self T; //~ ERROR lifetimes cannot use keyword names
+trait Serializable<'self, T> {
+    //~^ ERROR lifetimes cannot use keyword names
+    fn serialize(val: &'self T) -> Vec<u8>; //~ ERROR lifetimes cannot use keyword names
+    fn deserialize(repr: &[u8]) -> &'self T; //~ ERROR lifetimes cannot use keyword names
 }
 
-impl<'self> Serializable<str> for &'self str { //~ ERROR lifetimes cannot use keyword names
+impl<'self> Serializable<str> for &'self str {
     //~^ ERROR lifetimes cannot use keyword names
+    //~| ERROR lifetimes cannot use keyword names
     //~| ERROR implicit elided lifetime not allowed here
-    //~| ERROR the size for values of type `str` cannot be known at compilation time
-    fn serialize(val : &'self str) -> Vec<u8> { //~ ERROR lifetimes cannot use keyword names
+    //~| ERROR the size for values of type `str` cannot be known at compilation time [E0277]
+    fn serialize(val: &'self str) -> Vec<u8> {
+        //~^ ERROR lifetimes cannot use keyword names
         vec![1]
     }
-    fn deserialize(repr: &[u8]) -> &'self str { //~ ERROR lifetimes cannot use keyword names
+    fn deserialize(repr: &[u8]) -> &'self str {
+        //~^ ERROR lifetimes cannot use keyword names
         "hi"
     }
 }
diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr
index a91b3c90ebb..46b9fd541ad 100644
--- a/src/test/ui/issues/issue-10412.stderr
+++ b/src/test/ui/issues/issue-10412.stderr
@@ -5,51 +5,55 @@ LL | trait Serializable<'self, T> {
    |                    ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:2:25
+  --> $DIR/issue-10412.rs:3:24
    |
-LL |     fn serialize(val : &'self T) -> Vec<u8>;
-   |                         ^^^^^
+LL |     fn serialize(val: &'self T) -> Vec<u8>;
+   |                        ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:3:38
+  --> $DIR/issue-10412.rs:4:37
    |
-LL |     fn deserialize(repr : &[u8]) -> &'self T;
-   |                                      ^^^^^
+LL |     fn deserialize(repr: &[u8]) -> &'self T;
+   |                                     ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:6:6
+  --> $DIR/issue-10412.rs:7:6
    |
 LL | impl<'self> Serializable<str> for &'self str {
    |      ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:6:36
+  --> $DIR/issue-10412.rs:7:36
    |
 LL | impl<'self> Serializable<str> for &'self str {
    |                                    ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:10:25
+  --> $DIR/issue-10412.rs:12:24
    |
-LL |     fn serialize(val : &'self str) -> Vec<u8> {
-   |                         ^^^^^
+LL |     fn serialize(val: &'self str) -> Vec<u8> {
+   |                        ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:13:37
+  --> $DIR/issue-10412.rs:16:37
    |
 LL |     fn deserialize(repr: &[u8]) -> &'self str {
    |                                     ^^^^^
 
 error[E0726]: implicit elided lifetime not allowed here
-  --> $DIR/issue-10412.rs:6:13
+  --> $DIR/issue-10412.rs:7:13
    |
 LL | impl<'self> Serializable<str> for &'self str {
-   |             ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>`
+   |             ^^^^^^^^^^^^^^^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | impl<'self> Serializable<'_, str> for &'self str {
+   |                          +++
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/issue-10412.rs:6:13
+  --> $DIR/issue-10412.rs:7:13
    |
 LL | impl<'self> Serializable<str> for &'self str {
    |             ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
diff --git a/src/test/ui/lifetimes/issue-91763.stderr b/src/test/ui/lifetimes/issue-91763.stderr
index 1b1912c8e45..6ccf008c003 100644
--- a/src/test/ui/lifetimes/issue-91763.stderr
+++ b/src/test/ui/lifetimes/issue-91763.stderr
@@ -2,13 +2,17 @@ error: hidden lifetime parameters in types are deprecated
   --> $DIR/issue-91763.rs:8:20
    |
 LL | fn f() -> Ptr<Thing>;
-   |                    ^ expected named lifetime parameter
+   |                    ^ expected lifetime parameter
    |
 note: the lint level is defined here
   --> $DIR/issue-91763.rs:3:9
    |
 LL | #![deny(elided_lifetimes_in_paths)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: indicate the anonymous lifetime
+   |
+LL | fn f() -> Ptr<Thing><'_>;
+   |                     ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
index cb459f31cd2..0d6ade41511 100644
--- a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
+++ b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
@@ -9,6 +9,8 @@ LL |     a: &'b str,
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
    |
+LL | #[derive(Eq, PartialEq)]
+   |          -- lifetime `'b` is missing in item created through this procedural macro
 LL | struct Test {
    |            - help: consider introducing lifetime `'b` here: `<'b>`
 LL |     a: &'b str,
@@ -22,12 +24,12 @@ LL |     fn foo(&'b self) {}
    |
 help: consider introducing lifetime `'b` here
    |
-LL | impl<'b> T for Test {
-   |     ++++
-help: consider introducing lifetime `'b` here
-   |
 LL |     fn foo<'b>(&'b self) {}
    |           ++++
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> T for Test {
+   |     ++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
index f5e8b41b163..ac98b5896ca 100644
--- a/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
@@ -2,13 +2,13 @@ warning: hidden lifetime parameters in types are deprecated
   --> $DIR/allowed-by-default-lint.rs:9:12
    |
 LL | fn foo(x: &Foo) {}
-   |            ^^^ expected named lifetime parameter
+   |            ^^^ expected lifetime parameter
    |
    = note: requested on the command line with `--force-warn elided-lifetimes-in-paths`
-help: consider using the `'_` lifetime
+help: indicate the anonymous lifetime
    |
 LL | fn foo(x: &Foo<'_>) {}
-   |            ~~~~~~~
+   |               ++++
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/lint/reasons.rs b/src/test/ui/lint/reasons.rs
index b1792e2e9cb..da1c740c4a3 100644
--- a/src/test/ui/lint/reasons.rs
+++ b/src/test/ui/lint/reasons.rs
@@ -19,9 +19,9 @@ pub struct CheaterDetectionMechanism {}
 impl fmt::Debug for CheaterDetectionMechanism {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         //~^ WARN hidden lifetime parameters in types are deprecated
-        //~| NOTE expected named lifetime parameter
+        //~| NOTE expected lifetime parameter
         //~| NOTE explicit anonymous lifetimes aid
-        //~| HELP consider using the `'_` lifetime
+        //~| HELP indicate the anonymous lifetime
         fmt.debug_struct("CheaterDetectionMechanism").finish()
     }
 }
diff --git a/src/test/ui/lint/reasons.stderr b/src/test/ui/lint/reasons.stderr
index a692d6af703..cd8412153f1 100644
--- a/src/test/ui/lint/reasons.stderr
+++ b/src/test/ui/lint/reasons.stderr
@@ -2,7 +2,9 @@ warning: hidden lifetime parameters in types are deprecated
   --> $DIR/reasons.rs:20:34
    |
 LL |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-   |                                  ^^^^^^^^^ expected named lifetime parameter
+   |                             -----^^^^^^^^^
+   |                             |
+   |                             expected lifetime parameter
    |
    = note: explicit anonymous lifetimes aid reasoning about ownership
 note: the lint level is defined here
@@ -10,10 +12,10 @@ note: the lint level is defined here
    |
 LL | #![warn(elided_lifetimes_in_paths,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider using the `'_` lifetime
+help: indicate the anonymous lifetime
    |
 LL |     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-   |                                  ~~~~~~~~~~~~~
+   |                                           ++++
 
 warning: variable `Social_exchange_psychology` should have a snake case name
   --> $DIR/reasons.rs:30:9
diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.rs b/src/test/ui/methods/method-call-lifetime-args-unresolved.rs
index d16ba3df47b..ba7231070a0 100644
--- a/src/test/ui/methods/method-call-lifetime-args-unresolved.rs
+++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.rs
@@ -1,3 +1,6 @@
 fn main() {
-    0.clone::<'a>(); //~ ERROR use of undeclared lifetime name `'a`
+    0.clone::<'a>();
+    //~^ ERROR use of undeclared lifetime name `'a`
+    //~| WARN cannot specify lifetime arguments explicitly if late bound
+    //~| WARN this was previously accepted by the compiler
 }
diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
index c9f235c4f7d..78af19586a1 100644
--- a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
+++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
@@ -6,6 +6,21 @@ LL | fn main() {
 LL |     0.clone::<'a>();
    |               ^^ undeclared lifetime
 
-error: aborting due to previous error
+warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/method-call-lifetime-args-unresolved.rs:2:15
+   |
+LL |     0.clone::<'a>();
+   |               ^^
+   |
+  ::: $SRC_DIR/core/src/clone.rs:LL:COL
+   |
+LL |     fn clone(&self) -> Self;
+   |              - the late bound lifetime parameter is introduced here
+   |
+   = note: `#[warn(late_bound_lifetime_arguments)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0261`.
diff --git a/src/test/ui/regions/regions-name-static.rs b/src/test/ui/regions/regions-name-static.rs
index 730fd99aa68..da316c6ef5e 100644
--- a/src/test/ui/regions/regions-name-static.rs
+++ b/src/test/ui/regions/regions-name-static.rs
@@ -1,5 +1,6 @@
-struct Foo<'static> { //~ ERROR invalid lifetime parameter name: `'static`
-    x: &'static isize
+struct Foo<'static> {
+    //~^ ERROR invalid lifetime parameter name: `'static`
+    x: &'static isize,
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-name-undeclared.rs b/src/test/ui/regions/regions-name-undeclared.rs
index b8f50a40c45..7b6ede19341 100644
--- a/src/test/ui/regions/regions-name-undeclared.rs
+++ b/src/test/ui/regions/regions-name-undeclared.rs
@@ -23,14 +23,14 @@ fn bar<'a>(x: &'a isize) {
     let y: &'a isize = x;
 
     // &'a is not visible to *items*:
-    type X = Option<&'a isize>; //~ ERROR undeclared lifetime
+    type X = Option<&'a isize>; //~ ERROR can't use generic parameters from outer item
     enum E {
-        E1(&'a isize) //~ ERROR undeclared lifetime
+        E1(&'a isize) //~ ERROR can't use generic parameters from outer item
     }
     struct S {
-        f: &'a isize //~ ERROR undeclared lifetime
+        f: &'a isize //~ ERROR can't use generic parameters from outer item
     }
-    fn f(a: &'a isize) { } //~ ERROR undeclared lifetime
+    fn f(a: &'a isize) { } //~ ERROR can't use generic parameters from outer item
 
     // &'a CAN be declared on functions and used then:
     fn g<'a>(a: &'a isize) { } // OK
diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr
index 4399263f716..532603de5f7 100644
--- a/src/test/ui/regions/regions-name-undeclared.stderr
+++ b/src/test/ui/regions/regions-name-undeclared.stderr
@@ -1,19 +1,3 @@
-error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/regions-name-undeclared.rs:28:13
-   |
-LL |     enum E {
-   |           - help: consider introducing lifetime `'a` here: `<'a>`
-LL |         E1(&'a isize)
-   |             ^^ undeclared lifetime
-
-error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/regions-name-undeclared.rs:31:13
-   |
-LL |     struct S {
-   |             - help: consider introducing lifetime `'a` here: `<'a>`
-LL |         f: &'a isize
-   |             ^^ undeclared lifetime
-
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:16:24
    |
@@ -22,12 +6,12 @@ LL |     fn m4(&self, arg: &'b isize) { }
    |
 help: consider introducing lifetime `'b` here
    |
-LL | impl<'b, 'a> Foo<'a> {
-   |      +++
-help: consider introducing lifetime `'b` here
-   |
 LL |     fn m4<'b>(&self, arg: &'b isize) { }
    |          ++++
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      +++
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:17:12
@@ -37,12 +21,12 @@ LL |     fn m5(&'b self) { }
    |
 help: consider introducing lifetime `'b` here
    |
-LL | impl<'b, 'a> Foo<'a> {
-   |      +++
-help: consider introducing lifetime `'b` here
-   |
 LL |     fn m5<'b>(&'b self) { }
    |          ++++
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      +++
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:18:27
@@ -52,26 +36,54 @@ LL |     fn m6(&self, arg: Foo<'b>) { }
    |
 help: consider introducing lifetime `'b` here
    |
-LL | impl<'b, 'a> Foo<'a> {
-   |      +++
-help: consider introducing lifetime `'b` here
-   |
 LL |     fn m6<'b>(&self, arg: Foo<'b>) { }
    |          ++++
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      +++
 
-error[E0261]: use of undeclared lifetime name `'a`
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/regions-name-undeclared.rs:26:22
    |
+LL | fn bar<'a>(x: &'a isize) {
+   |        -- lifetime parameter from outer item
+...
 LL |     type X = Option<&'a isize>;
-   |           -          ^^ undeclared lifetime
+   |           -          ^^ use of generic parameter from outer item
    |           |
    |           help: consider introducing lifetime `'a` here: `<'a>`
 
-error[E0261]: use of undeclared lifetime name `'a`
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/regions-name-undeclared.rs:28:13
+   |
+LL | fn bar<'a>(x: &'a isize) {
+   |        -- lifetime parameter from outer item
+...
+LL |     enum E {
+   |           - help: consider introducing lifetime `'a` here: `<'a>`
+LL |         E1(&'a isize)
+   |             ^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/regions-name-undeclared.rs:31:13
+   |
+LL | fn bar<'a>(x: &'a isize) {
+   |        -- lifetime parameter from outer item
+...
+LL |     struct S {
+   |             - help: consider introducing lifetime `'a` here: `<'a>`
+LL |         f: &'a isize
+   |             ^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/regions-name-undeclared.rs:33:14
    |
+LL | fn bar<'a>(x: &'a isize) {
+   |        -- lifetime parameter from outer item
+...
 LL |     fn f(a: &'a isize) { }
-   |         -    ^^ undeclared lifetime
+   |         -    ^^ use of generic parameter from outer item
    |         |
    |         help: consider introducing lifetime `'a` here: `<'a>`
 
@@ -90,14 +102,14 @@ LL | ...                   &'b isize,
    |                        ^^ undeclared lifetime
    |
    = 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 |             b: Box<dyn for<'b, 'a> FnOnce(&'a isize,
+   |                            +++
 help: consider introducing lifetime `'b` here
    |
 LL | fn fn_types<'b>(a: &'a isize,
    |            ++++
-help: consider making the bound lifetime-generic with a new `'b` lifetime
-   |
-LL |             b: Box<dyn for<'a, 'b> FnOnce(&'a isize,
-   |                              ++++
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:46:36
@@ -105,15 +117,14 @@ error[E0261]: use of undeclared lifetime name `'b`
 LL | ...                   &'b isize)>,
    |                        ^^ undeclared lifetime
    |
-   = 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 |             b: Box<dyn for<'b, 'a> FnOnce(&'a isize,
+   |                            +++
 help: consider introducing lifetime `'b` here
    |
 LL | fn fn_types<'b>(a: &'a isize,
    |            ++++
-help: consider making the bound lifetime-generic with a new `'b` lifetime
-   |
-LL |             b: Box<dyn for<'a, 'b> FnOnce(&'a isize,
-   |                              ++++
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:47:17
@@ -132,13 +143,14 @@ LL |     async fn buggy(&self) -> &'a str {
    |
 help: consider introducing lifetime `'a` here
    |
-LL | impl<'a> Bug {
-   |     ++++
-help: consider introducing lifetime `'a` here
-   |
 LL |     async fn buggy<'a>(&self) -> &'a str {
    |                   ++++
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Bug {
+   |     ++++
 
 error: aborting due to 12 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0401.
+For more information about an error, try `rustc --explain E0261`.
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 7c0f8d199a9..a761ec59167 100644
--- a/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr
+++ b/src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr
@@ -5,14 +5,14 @@ LL | struct S1<F: Fn(&i32, &i32) -> &'a i32>(F);
    |                                 ^^ undeclared lifetime
    |
    = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider introducing lifetime `'a` here
-   |
-LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F);
-   |           +++
 help: consider making the bound lifetime-generic with a new `'a` lifetime
    |
 LL | struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
    |              +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F);
+   |           +++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/fn-missing-lifetime-in-item.rs:2:32
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr
new file mode 100644
index 00000000000..0ae629676fe
--- /dev/null
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr
@@ -0,0 +1,106 @@
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/missing-lifetimes-in-signature.rs:38:11
+   |
+LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |        -  ^^ undeclared lifetime
+   |        |
+   |        help: consider introducing lifetime `'a` here: `'a,`
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:19:5
+   |
+LL |   fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
+   |                            ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here
+...
+LL | /     move || {
+LL | |
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                                   ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:32:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:26:26
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                          ^^^^^^
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:55:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:49:34
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                  ^^^^^^
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:65:9
+   |
+LL | /         move || {
+LL | |             *dest = g.get();
+LL | |         }
+   | |_________^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:62:47
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                               ^^^^^^
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:77:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:72:34
+   |
+LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |                                  ^^^^^^
+
+error[E0621]: explicit lifetime required in the type of `dest`
+  --> $DIR/missing-lifetimes-in-signature.rs:77:5
+   |
+LL |   fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |                                    ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
+...
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^ lifetime `'a` required
+
+error[E0309]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:89:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+   = help: consider adding an explicit lifetime bound `G: 'a`...
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0261, E0309, E0621, E0700.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
index dd434ea5318..647b343fe06 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
@@ -14,28 +14,31 @@ impl Get<usize> for Foo {
 
 fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
+        //~^ ERROR hidden type for `impl Trait` captures lifetime
         *dest = g.get();
     }
 }
 
 // After applying suggestion for `foo`:
 fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+//~^ ERROR the parameter type `G` may not live long enough
 where
-    G: Get<T>
+    G: Get<T>,
 {
+    //~^ ERROR the parameter type `G` may not live long enough
     move || {
         *dest = g.get();
     }
 }
 
-
 // After applying suggestion for `bar`:
-fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ //~ ERROR undeclared lifetime
+fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+//~^ ERROR undeclared lifetime name `'a`
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
         *dest = g.get();
@@ -44,9 +47,11 @@ where
 
 // After applying suggestion for `baz`:
 fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+//~^ ERROR the parameter type `G` may not live long enough
 where
-    G: Get<T>
+    G: Get<T>,
 {
+    //~^ ERROR the parameter type `G` may not live long enough
     move || {
         *dest = g.get();
     }
@@ -55,6 +60,8 @@ where
 // Same as above, but show that we pay attention to lifetime names from parent item
 impl<'a> Foo {
     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+        //~^ ERROR the parameter type `G` may not live long enough
+        //~| ERROR the parameter type `G` may not live long enough
         move || {
             *dest = g.get();
         }
@@ -63,8 +70,9 @@ impl<'a> Foo {
 
 // After applying suggestion for `qux`:
 fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+//~^ ERROR explicit lifetime required in the type of `dest`
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
         *dest = g.get();
@@ -73,19 +81,20 @@ where
 
 // Potential incorrect attempt:
 fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+//~^ ERROR the parameter type `G` may not live long enough
 where
-    G: Get<T>
+    G: Get<T>,
 {
+    //~^ ERROR the parameter type `G` may not live long enough
     move || {
         *dest = g.get();
     }
 }
 
-
 // We need to tie the lifetime of `G` with the lifetime of `&mut T` and the returned closure:
 fn ok<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
         *dest = g.get();
@@ -95,7 +104,7 @@ where
 // This also works. The `'_` isn't necessary but it's where we arrive to following the suggestions:
 fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
         *dest = g.get();
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index 916a6c2bf12..6d538dfd609 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -1,11 +1,234 @@
 error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/missing-lifetimes-in-signature.rs:36:11
+  --> $DIR/missing-lifetimes-in-signature.rs:38:11
    |
 LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |        -  ^^ undeclared lifetime
    |        |
    |        help: consider introducing lifetime `'a` here: `'a,`
 
-error: aborting due to previous error
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:19:5
+   |
+LL |   fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
+   |                            ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here
+...
+LL | /     move || {
+LL | |
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                                   ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:26:37
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                     ^^^^^^^^^^^^^^^^^^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:26:26
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                          ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:26:37
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                     ^^^^^^^^^^^^^^^^^^
+help: consider introducing an explicit lifetime bound
+   |
+LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |        ~~~~~                                                   ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:30:1
+   |
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:26:26
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                          ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:30:1
+   |
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^
+help: consider introducing an explicit lifetime bound
+   |
+LL ~ fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+LL |
+LL | where
+LL |     G: Get<T>,
+LL | {
+LL |
+ ...
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:49:45
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                             ^^^^^^^^^^^^^^^^^^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:49:34
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                  ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:49:45
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                             ^^^^^^^^^^^^^^^^^^
+help: consider introducing an explicit lifetime bound
+   |
+LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b
+   |        +++     ~~~~~~~                                                  ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:53:1
+   |
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:49:34
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                  ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:53:1
+   |
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^
+help: consider introducing an explicit lifetime bound
+   |
+LL ~ fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+LL |
+LL | where
+LL |     G: Get<T>,
+LL | {
+LL |
+ ...
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:62:58
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                                          ^^^^^^^^^^^^^^^^^^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:62:47
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                               ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:62:58
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                                          ^^^^^^^^^^^^^^^^^^
+help: consider introducing an explicit lifetime bound
+   |
+LL |     fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c {
+   |            +++     ~~~~~~~                                                           ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:62:77
+   |
+LL |       fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |  _____________________________________________________________________________^
+LL | |
+LL | |
+LL | |         move || {
+LL | |             *dest = g.get();
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:62:47
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                               ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:62:77
+   |
+LL |       fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |  _____________________________________________________________________________^
+LL | |
+LL | |
+LL | |         move || {
+LL | |             *dest = g.get();
+LL | |         }
+LL | |     }
+   | |_____^
+help: consider introducing an explicit lifetime bound
+   |
+LL ~     fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+LL |
+LL |
+LL |         move || {
+LL |             *dest = g.get();
+LL |         }
+ ...
+
+error[E0621]: explicit lifetime required in the type of `dest`
+  --> $DIR/missing-lifetimes-in-signature.rs:72:45
+   |
+LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |                                  ------     ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
+   |                                  |
+   |                                  help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
+
+error[E0309]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:83:44
+   |
+LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+   |            -                               ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds
+   |            |
+   |            help: consider adding an explicit lifetime bound...: `G: 'a`
+
+error[E0309]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:87:1
+   |
+LL |   fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+   |              - help: consider adding an explicit lifetime bound...: `G: 'a`
+...
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds
+
+error: aborting due to 11 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0309, E0621, E0700.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
index 6732902c09a..b0de8bf6aa4 100644
--- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
@@ -18,5 +18,7 @@ type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
 //~^ ERROR use of undeclared lifetime name `'a`
 
 fn my_fun() -> Return<()> {}
+//~^ ERROR non-defining opaque type use in defining scope
+//~| ERROR non-defining opaque type use in defining scope
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
index fe45e39d938..d038fbbe1b4 100644
--- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
@@ -2,10 +2,42 @@ error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:65
    |
 LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
-   |             -                                                   ^^ undeclared lifetime
-   |             |
-   |             help: consider introducing lifetime `'a` here: `'a,`
+   |                                                                 ^^ undeclared lifetime
+   |
+   = 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 Return<A> = impl for<'a> WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |                       +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | type Return<'a, A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |             +++
+
+error: non-defining opaque type use in defining scope
+  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
+   |
+LL | fn my_fun() -> Return<()> {}
+   |                           ^^
+   |
+note: used non-generic type `()` for generic parameter
+  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
+   |
+LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |             ^
+
+error: non-defining opaque type use in defining scope
+  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
+   |
+LL | fn my_fun() -> Return<()> {}
+   |                           ^^
+   |
+note: used non-generic type `()` for generic parameter
+  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
+   |
+LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |             ^
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0261`.
diff --git a/src/test/ui/underscore-lifetime/in-binder.rs b/src/test/ui/underscore-lifetime/in-binder.rs
index e4ee5e8cb27..74dc331b00a 100644
--- a/src/test/ui/underscore-lifetime/in-binder.rs
+++ b/src/test/ui/underscore-lifetime/in-binder.rs
@@ -10,22 +10,22 @@ impl<'_> IceCube<'_> {}
 //~^ ERROR `'_` cannot be used here
 
 struct Struct<'_> {
-//~^ ERROR `'_` cannot be used here
+    //~^ ERROR `'_` cannot be used here
     v: Vec<&'static char>
 }
 
 enum Enum<'_> {
-//~^ ERROR `'_` cannot be used here
+    //~^ ERROR `'_` cannot be used here
     Variant
 }
 
 union Union<'_> {
-//~^ ERROR `'_` cannot be used here
+    //~^ ERROR `'_` cannot be used here
     a: u32
 }
 
 trait Trait<'_> {
-//~^ ERROR `'_` cannot be used here
+    //~^ ERROR `'_` cannot be used here
 }
 
 fn foo<'_>() {
diff --git a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
index ba624507c21..16d19872552 100644
--- a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
+++ b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
@@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
   --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:13:16
    |
 LL | impl Trait for Ref {}
-   |                ^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                ^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | impl Trait for Ref<'_> {}
+   |                   ++++
 
 error: incompatible lifetime on type
   --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21
diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
index 6c52664154b..e8df02fbad6 100644
--- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr
+++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
@@ -1,20 +1,41 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/where-lifetime-resolution.rs:6:38
    |
-LL | fn f() where
-   |     - help: consider introducing lifetime `'a` here: `<'a>`
-LL |     for<'a> dyn Trait1<'a>: Trait1<'a>, // OK
 LL |     (dyn for<'a> Trait1<'a>): Trait1<'a>,
    |                                      ^^ undeclared lifetime
+   |
+   = 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 |     (dyn for<'a> Trait1<'a>): for<'a> Trait1<'a>,
+   |                               +++++++
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |     for<'a> (dyn for<'a> Trait1<'a>): Trait1<'a>,
+   |     +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | fn f<'a>() where
+   |     ++++
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/where-lifetime-resolution.rs:8:52
    |
-LL | fn f() where
-   |     - help: consider introducing lifetime `'b` here: `<'b>`
-...
 LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
    |                                                    ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: for<'b> Trait2<'a, 'b>,
+   |                                         +++++++
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |     for<'b, 'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
+   |         +++
+help: consider introducing lifetime `'b` here
+   |
+LL | fn f<'b>() where
+   |     ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_unit.stderr b/src/tools/clippy/tests/ui/unused_unit.stderr
index 02038b5fb6b..0d2cb77855b 100644
--- a/src/tools/clippy/tests/ui/unused_unit.stderr
+++ b/src/tools/clippy/tests/ui/unused_unit.stderr
@@ -1,8 +1,8 @@
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:19:28
+  --> $DIR/unused_unit.rs:19:58
    |
 LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
-   |                            ^^^^^^ help: remove the `-> ()`
+   |                                                          ^^^^^^ help: remove the `-> ()`
    |
 note: the lint level is defined here
   --> $DIR/unused_unit.rs:12:9
@@ -11,16 +11,16 @@ LL | #![deny(clippy::unused_unit)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:20:18
+  --> $DIR/unused_unit.rs:19:28
    |
-LL |     where G: Fn() -> () {
-   |                  ^^^^^^ help: remove the `-> ()`
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                            ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:19:58
+  --> $DIR/unused_unit.rs:20:18
    |
-LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
-   |                                                          ^^^^^^ help: remove the `-> ()`
+LL |     where G: Fn() -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
   --> $DIR/unused_unit.rs:21:26
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 92f423bbb62..ad2502b0418 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -204,12 +204,11 @@ impl<'a> FnSig<'a> {
 
     pub(crate) fn from_fn_kind(
         fn_kind: &'a visit::FnKind<'_>,
-        generics: &'a ast::Generics,
         decl: &'a ast::FnDecl,
         defaultness: ast::Defaultness,
     ) -> FnSig<'a> {
         match *fn_kind {
-            visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt {
+            visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, generics, _) => match fn_ctxt {
                 visit::FnCtxt::Assoc(..) => {
                     let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
                     fn_sig.defaultness = defaultness;
@@ -3180,8 +3179,14 @@ impl Rewrite for ast::ForeignItem {
                     let inner_attrs = inner_attributes(&self.attrs);
                     let fn_ctxt = visit::FnCtxt::Foreign;
                     visitor.visit_fn(
-                        visit::FnKind::Fn(fn_ctxt, self.ident, sig, &self.vis, Some(body)),
-                        generics,
+                        visit::FnKind::Fn(
+                            fn_ctxt,
+                            self.ident,
+                            sig,
+                            &self.vis,
+                            generics,
+                            Some(body),
+                        ),
                         &sig.decl,
                         self.span,
                         defaultness,
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 3ebfa551d1c..1621eb406b1 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -382,7 +382,6 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
     pub(crate) fn visit_fn(
         &mut self,
         fk: visit::FnKind<'_>,
-        generics: &ast::Generics,
         fd: &ast::FnDecl,
         s: Span,
         defaultness: ast::Defaultness,
@@ -391,12 +390,12 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
         let indent = self.block_indent;
         let block;
         let rewrite = match fk {
-            visit::FnKind::Fn(_, ident, _, _, Some(ref b)) => {
+            visit::FnKind::Fn(_, ident, _, _, _, Some(ref b)) => {
                 block = b;
                 self.rewrite_fn_before_block(
                     indent,
                     ident,
-                    &FnSig::from_fn_kind(&fk, generics, fd, defaultness),
+                    &FnSig::from_fn_kind(&fk, fd, defaultness),
                     mk_sp(s.lo(), b.span.lo()),
                 )
             }
@@ -552,8 +551,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                             _ => visit::FnCtxt::Foreign,
                         };
                         self.visit_fn(
-                            visit::FnKind::Fn(fn_ctxt, item.ident, sig, &item.vis, Some(body)),
-                            generics,
+                            visit::FnKind::Fn(
+                                fn_ctxt,
+                                item.ident,
+                                sig,
+                                &item.vis,
+                                generics,
+                                Some(body),
+                            ),
                             &sig.decl,
                             item.span,
                             defaultness,
@@ -642,8 +647,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                     let inner_attrs = inner_attributes(&ai.attrs);
                     let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
                     self.visit_fn(
-                        visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, Some(body)),
-                        generics,
+                        visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)),
                         &sig.decl,
                         ai.span,
                         defaultness,