about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-06-22 10:48:58 +0000
committerbors <bors@rust-lang.org>2022-06-22 10:48:58 +0000
commit10f4ce324baf7cfb7ce2b2096662b82b79204944 (patch)
treec1c264be332d6fabab112d732142d0593e54fd25
parent89a0783f1c8fef46b1c8de57dc611a1d753bf0d5 (diff)
parent576661cb5f4cdcf2ae56f5b210db4b2ef19e0184 (diff)
Auto merge of #98279 - cjgillot:all-fresh-nofn, r=petrochenkov
Create elided lifetime parameters for function-like types

Split from https://github.com/rust-lang/rust/pull/97720

This PR refactor lifetime generic parameters in bare function types and parenthesized traits to introduce the additional required lifetimes as fresh parameters in a `for<>` bound.

This PR does the same to lifetimes appearing in closure signatures, and as-if introducing `for<>` bounds on closures (without the associated change in semantics).

r? `@petrochenkov`
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs57
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs11
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs75
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs51
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs9
-rw-r--r--compiler/rustc_hir/src/def.rs7
-rw-r--r--compiler/rustc_hir/src/hir.rs3
-rw-r--r--compiler/rustc_hir/src/intravisit.rs6
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs877
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs15
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs73
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs6
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs66
-rw-r--r--src/librustdoc/clean/mod.rs58
-rw-r--r--src/librustdoc/clean/utils.rs9
-rw-r--r--src/test/ui/generic-associated-types/issue-70304.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-70304.stderr13
-rw-r--r--src/test/ui/generic-associated-types/issue-95305.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-95305.stderr12
-rw-r--r--src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr6
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr4
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs4
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr16
-rw-r--r--src/test/ui/impl-header-lifetime-elision/dyn-trait.rs4
-rw-r--r--src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr2
-rw-r--r--src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs13
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr4
28 files changed, 808 insertions, 599 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 095a4b26a86..3babe73030a 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -165,6 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     if let Async::Yes { closure_id, .. } = asyncness {
                         self.lower_expr_async_closure(
                             capture_clause,
+                            e.id,
                             closure_id,
                             decl,
                             body,
@@ -173,6 +174,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     } else {
                         self.lower_expr_closure(
                             capture_clause,
+                            e.id,
                             movability,
                             decl,
                             body,
@@ -604,6 +606,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `static |_task_context| -> <ret_ty> { body }`:
         let generator_kind = hir::ExprKind::Closure {
             capture_clause,
+            bound_generic_params: &[],
             fn_decl,
             body,
             fn_decl_span: self.lower_span(span),
@@ -828,6 +831,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_expr_closure(
         &mut self,
         capture_clause: CaptureBy,
+        closure_id: NodeId,
         movability: Movability,
         decl: &FnDecl,
         body: &Expr,
@@ -848,16 +852,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
             (body_id, generator_option)
         });
 
-        // Lower outside new scope to preserve `is_in_loop_condition`.
-        let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
-
-        hir::ExprKind::Closure {
-            capture_clause,
-            fn_decl,
-            body,
-            fn_decl_span: self.lower_span(fn_decl_span),
-            movability: generator_option,
-        }
+        self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
+            // Lower outside new scope to preserve `is_in_loop_condition`.
+            let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
+
+            hir::ExprKind::Closure {
+                capture_clause,
+                bound_generic_params,
+                fn_decl,
+                body,
+                fn_decl_span: this.lower_span(fn_decl_span),
+                movability: generator_option,
+            }
+        })
     }
 
     fn generator_movability_for_fn(
@@ -897,6 +904,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         &mut self,
         capture_clause: CaptureBy,
         closure_id: NodeId,
+        inner_closure_id: NodeId,
         decl: &FnDecl,
         body: &Expr,
         fn_decl_span: Span,
@@ -927,7 +935,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     if let FnRetTy::Ty(ty) = &decl.output { Some(ty.clone()) } else { None };
                 let async_body = this.make_async_expr(
                     capture_clause,
-                    closure_id,
+                    inner_closure_id,
                     async_ret_ty,
                     body.span,
                     hir::AsyncGeneratorKind::Closure,
@@ -938,18 +946,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
             body_id
         });
 
-        // We need to lower the declaration outside the new scope, because we
-        // have to conserve the state of being inside a loop condition for the
-        // closure argument types.
-        let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
-
-        hir::ExprKind::Closure {
-            capture_clause,
-            fn_decl,
-            body,
-            fn_decl_span: self.lower_span(fn_decl_span),
-            movability: None,
-        }
+        self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
+            // We need to lower the declaration outside the new scope, because we
+            // have to conserve the state of being inside a loop condition for the
+            // closure argument types.
+            let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
+
+            hir::ExprKind::Closure {
+                capture_clause,
+                bound_generic_params,
+                fn_decl,
+                body,
+                fn_decl_span: this.lower_span(fn_decl_span),
+                movability: None,
+            }
+        })
     }
 
     /// Destructure the LHS of complex assignments.
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 717918116e5..0ef21371694 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1386,16 +1386,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> =
             self.lower_generic_params_mut(&generics.params).collect();
+
+        // Introduce extra lifetimes if late resolution tells us to.
+        let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
+        params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
+            self.lifetime_res_to_generic_param(ident, node_id, res)
+        }));
+
         let has_where_clause_predicates = !generics.where_clause.predicates.is_empty();
         let where_clause_span = self.lower_span(generics.where_clause.span);
         let span = self.lower_span(generics.span);
         let res = f(self);
 
-        let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
         let impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
-        params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
-            self.lifetime_res_to_generic_param(ident, node_id, res)
-        }));
         params.extend(impl_trait_defs.into_iter());
 
         let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 4fa2cd5e23b..e8b92eaad5c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -223,6 +223,12 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
     }
 
     /// Obtain the list of lifetimes parameters to add to an item.
+    ///
+    /// Extra lifetime parameters should only be added in places that can appear
+    /// as a `binder` in `LifetimeRes`.
+    ///
+    /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
+    /// should appear at the enclosing `PolyTraitRef`.
     fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
         self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
     }
@@ -721,6 +727,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     /// Converts a lifetime into a new generic parameter.
+    #[tracing::instrument(level = "debug", skip(self))]
     fn lifetime_res_to_generic_param(
         &mut self,
         ident: Ident,
@@ -731,7 +738,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             LifetimeRes::Param { .. } => {
                 (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
             }
-            LifetimeRes::Fresh { .. } => (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided),
+            LifetimeRes::Fresh { param, .. } => {
+                // Late resolution delegates to us the creation of the `LocalDefId`.
+                let _def_id = self.create_def(
+                    self.current_hir_id_owner,
+                    param,
+                    DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                );
+                debug!(?_def_id);
+
+                (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+            }
             LifetimeRes::Static | LifetimeRes::Error => return None,
             res => panic!(
                 "Unexpected lifetime resolution {:?} for {:?} at {:?}",
@@ -777,11 +794,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// Register a binder to be ignored for lifetime capture.
     #[tracing::instrument(level = "debug", skip(self, f))]
     #[inline]
-    fn with_lifetime_binder<T>(&mut self, binder: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
+    fn with_lifetime_binder<T>(
+        &mut self,
+        binder: NodeId,
+        generic_params: &[GenericParam],
+        f: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> T,
+    ) -> T {
+        let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
+        let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
+        debug!(?extra_lifetimes);
+        generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
+            self.lifetime_res_to_generic_param(ident, node_id, res)
+        }));
+        let generic_params = self.arena.alloc_from_iter(generic_params);
+        debug!(?generic_params);
+
         if let Some(ctxt) = &mut self.captured_lifetimes {
             ctxt.binders_to_ignore.insert(binder);
         }
-        let ret = f(self);
+        let ret = f(self, generic_params);
         if let Some(ctxt) = &mut self.captured_lifetimes {
             ctxt.binders_to_ignore.remove(&binder);
         }
@@ -1178,15 +1209,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let lifetime = self.lower_lifetime(&region);
                 hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
             }
-            TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| {
-                hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
-                    generic_params: this.lower_generic_params(&f.generic_params),
-                    unsafety: this.lower_unsafety(f.unsafety),
-                    abi: this.lower_extern(f.ext),
-                    decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
-                    param_names: this.lower_fn_params_to_names(&f.decl),
-                }))
-            }),
+            TyKind::BareFn(ref f) => {
+                self.with_lifetime_binder(t.id, &f.generic_params, |this, generic_params| {
+                    hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
+                        generic_params,
+                        unsafety: this.lower_unsafety(f.unsafety),
+                        abi: this.lower_extern(f.ext),
+                        decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+                        param_names: this.lower_fn_params_to_names(&f.decl),
+                    }))
+                })
+            }
             TyKind::Never => hir::TyKind::Never,
             TyKind::Tup(ref tys) => hir::TyKind::Tup(
                 self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
@@ -1814,8 +1847,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
                 hir::LifetimeName::Param(param, p_name)
             }
-            LifetimeRes::Fresh { mut param, binder } => {
+            LifetimeRes::Fresh { param, binder } => {
                 debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
+                let mut param = self.local_def_id(param);
                 if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
                     if !captured_lifetimes.binders_to_ignore.contains(&binder) {
                         match captured_lifetimes.captures.entry(param) {
@@ -1952,13 +1986,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         p: &PolyTraitRef,
         itctx: ImplTraitContext,
     ) -> hir::PolyTraitRef<'hir> {
-        let bound_generic_params = self.lower_generic_params(&p.bound_generic_params);
-
-        let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| {
-            this.lower_trait_ref(&p.trait_ref, itctx)
-        });
-
-        hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
+        self.with_lifetime_binder(
+            p.trait_ref.ref_id,
+            &p.bound_generic_params,
+            |this, bound_generic_params| {
+                let trait_ref = this.lower_trait_ref(&p.trait_ref, itctx);
+                hir::PolyTraitRef { bound_generic_params, trait_ref, span: this.lower_span(p.span) }
+            },
+        )
     }
 
     fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index bd95b5850df..52ba5daf014 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -191,9 +191,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
                 }
                 GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
-                    ParenthesizedGenericArgs::Ok => {
-                        self.lower_parenthesized_parameter_data(segment.id, data)
-                    }
+                    ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
                     ParenthesizedGenericArgs::Err => {
                         let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
                         err.span_label(data.span, "only `Fn` traits may use parentheses");
@@ -351,7 +349,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     fn lower_parenthesized_parameter_data(
         &mut self,
-        id: NodeId,
         data: &ParenthesizedArgs,
     ) -> (GenericArgsCtor<'hir>, bool) {
         // Switch to `PassThrough` mode for anonymous lifetimes; this
@@ -359,31 +356,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // a hidden lifetime parameter. This is needed for backwards
         // compatibility, even in contexts like an impl header where
         // we generally don't permit such things (see #51008).
-        self.with_lifetime_binder(id, |this| {
-            let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
-            let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| {
-                this.lower_ty_direct(
-                    ty,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
-                )
-            }));
-            let output_ty = match output {
-                FnRetTy::Ty(ty) => this
-                    .lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
-                FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])),
-            };
-            let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))];
-            let binding = this.output_ty_binding(output_ty.span, output_ty);
-            (
-                GenericArgsCtor {
-                    args,
-                    bindings: arena_vec![this; binding],
-                    parenthesized: true,
-                    span: data.inputs_span,
-                },
-                false,
-            )
-        })
+        let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
+        let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
+            self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
+        }));
+        let output_ty = match output {
+            FnRetTy::Ty(ty) => {
+                self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
+            }
+            FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
+        };
+        let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))];
+        let binding = self.output_ty_binding(output_ty.span, output_ty);
+        (
+            GenericArgsCtor {
+                args,
+                bindings: arena_vec![self; binding],
+                parenthesized: true,
+                span: data.inputs_span,
+            },
+            false,
+        )
     }
 
     /// An associated type binding `Output = $ty`.
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index d6b5089712a..1db4b902f71 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -254,6 +254,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     /// *user* has a name for. In that case, we'll be able to map
     /// `fr` to a `Region<'tcx>`, and that region will be one of
     /// named variants.
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
         let error_region = self.to_error_region(fr)?;
 
@@ -290,7 +291,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     if free_region.bound_region.is_named() {
                         // A named region that is actually named.
                         Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) })
-                    } else {
+                    } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) {
                         // If we spuriously thought that the region is named, we should let the
                         // system generate a true name for error messages. Currently this can
                         // happen if we have an elided name in an async fn for example: the
@@ -301,6 +302,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                             name,
                             source: RegionNameSource::AnonRegionFromAsyncFn(span),
                         })
+                    } else {
+                        None
                     }
                 }
 
@@ -362,6 +365,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     ///  | fn foo(x: &u32) { .. }
     ///           ------- fully elaborated type of `x` is `&'1 u32`
     /// ```
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_arguments(
         &self,
         fr: RegionVid,
@@ -651,6 +655,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     ///  | let x = Some(&22);
     ///        - fully elaborated type of `x` is `Option<&'1 u32>`
     /// ```
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
         let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
         let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
@@ -670,6 +675,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     /// must be a closure since, in a free fn, such an argument would
     /// have to either also appear in an argument (if using elision)
     /// or be early bound (named, not in argument).
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
         let tcx = self.infcx.tcx;
         let hir = tcx.hir();
@@ -801,6 +807,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         }
     }
 
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_yield_ty(
         &self,
         fr: RegionVid,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 3927523f4c6..d0893cd09d8 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -722,8 +722,7 @@ pub enum LifetimeRes {
         /// Id of the introducing place. That can be:
         /// - an item's id, for the item's generic parameters;
         /// - a TraitRef's ref_id, identifying the `for<...>` binder;
-        /// - a BareFn type's id;
-        /// - a Path's id when this path has parenthesized generic args.
+        /// - a BareFn type's id.
         ///
         /// This information is used for impl-trait lifetime captures, to know when to or not to
         /// capture any given lifetime.
@@ -732,7 +731,9 @@ pub enum LifetimeRes {
     /// Created a generic parameter for an anonymous lifetime.
     Fresh {
         /// Id of the generic parameter that introduced it.
-        param: LocalDefId,
+        ///
+        /// Creating the associated `LocalDefId` is the responsibility of lowering.
+        param: NodeId,
         /// Id of the introducing place. See `Param`.
         binder: NodeId,
     },
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 5a06f8eab7e..a7fc59255d7 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1932,6 +1932,7 @@ pub enum ExprKind<'hir> {
     /// `Option<Movability>`.
     Closure {
         capture_clause: CaptureBy,
+        bound_generic_params: &'hir [GenericParam<'hir>],
         fn_decl: &'hir FnDecl<'hir>,
         body: BodyId,
         fn_decl_span: Span,
@@ -3480,7 +3481,7 @@ impl<'hir> Node<'hir> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
-    rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
+    rustc_data_structures::static_assert_size!(super::Expr<'static>, 64);
     rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
     rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
     rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index cce5aa9f732..e68274e2ad9 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -1169,12 +1169,16 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             walk_list!(visitor, visit_arm, arms);
         }
         ExprKind::Closure {
+            bound_generic_params,
             ref fn_decl,
             body,
             capture_clause: _,
             fn_decl_span: _,
             movability: _,
-        } => visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id),
+        } => {
+            walk_list!(visitor, visit_generic_param, bound_generic_params);
+            visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
+        }
         ExprKind::Block(ref block, ref opt_label) => {
             walk_list!(visitor, visit_label, opt_label);
             visitor.visit_block(block);
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 7317ce7335a..7bf91df9f76 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1459,11 +1459,13 @@ impl<'a> State<'a> {
             }
             hir::ExprKind::Closure {
                 capture_clause,
+                bound_generic_params,
                 ref fn_decl,
                 body,
                 fn_decl_span: _,
                 movability: _,
             } => {
+                self.print_formal_generic_params(bound_generic_params);
                 self.print_capture_clause(capture_clause);
 
                 self.print_closure_params(&fn_decl, body);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 381073a3f66..e36f55b2e02 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -20,9 +20,7 @@ use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
-use rustc_hir::definitions::DefPathData;
 use rustc_hir::{PrimTy, TraitCandidate};
-use rustc_index::vec::Idx;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -238,14 +236,21 @@ enum LifetimeRibKind {
     /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
     AnonConst,
 
-    /// For **Modern** cases, create a new anonymous region parameter
-    /// and reference that.
+    /// Create a new anonymous lifetime parameter and reference it.
     ///
-    /// For **Dyn Bound** cases, pass responsibility to
-    /// `resolve_lifetime` code.
+    /// If `report_in_path`, report an error when encountering lifetime elision in a path:
+    /// ```compile_fail
+    /// struct Foo<'a> { x: &'a () }
+    /// async fn foo(x: Foo) {}
+    /// ```
     ///
-    /// For **Deprecated** cases, report an error.
-    AnonymousCreateParameter(NodeId),
+    /// Note: the error should not trigger when the elided lifetime is in a pattern or
+    /// expression-position path:
+    /// ```
+    /// struct Foo<'a> { x: &'a () }
+    /// async fn foo(Foo { x: _ }: Foo<'_>) {}
+    /// ```
+    AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
 
     /// Give a hard error when either `&` or `'_` is written. Used to
     /// rule out things like `where T: Foo<'_>`. Does not imply an
@@ -635,7 +640,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                     |this| {
                         this.visit_generic_params(&bare_fn.generic_params, false);
                         this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(ty.id, false),
+                            LifetimeRibKind::AnonymousCreateParameter {
+                                binder: ty.id,
+                                report_in_path: false,
+                            },
                             |this| walk_list!(this, visit_param, &bare_fn.decl.inputs),
                         );
                         this.with_lifetime_rib(
@@ -721,15 +729,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             // a body, or if there's no body for some other reason.
             FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
             | FnKind::Fn(_, _, sig, _, generics, None) => {
+                self.visit_fn_header(&sig.header);
+                self.visit_generics(generics);
                 // We don't need to deal with patterns in parameters, because
                 // they are not possible for foreign or bodiless functions.
                 self.with_lifetime_rib(
                     LifetimeRibKind::AnonymousPassThrough(fn_id, false),
-                    |this| {
-                        this.visit_fn_header(&sig.header);
-                        this.visit_generics(generics);
-                        walk_list!(this, visit_param, &sig.decl.inputs);
-                    },
+                    |this| walk_list!(this, visit_param, &sig.decl.inputs),
                 );
                 self.with_lifetime_rib(
                     LifetimeRibKind::AnonymousPassThrough(fn_id, true),
@@ -746,86 +752,127 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             self.diagnostic_metadata.current_function = Some((fn_kind, sp));
         }
         debug!("(resolving function) entering function");
-        let declaration = fn_kind.decl();
 
         // Create a value rib for the function.
         self.with_rib(ValueNS, rib_kind, |this| {
             // Create a label rib for the function.
             this.with_label_rib(FnItemRibKind, |this| {
-                let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
-
-                if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
-                    this.visit_generics(generics);
-                }
+                match fn_kind {
+                    FnKind::Fn(_, _, sig, _, generics, body) => {
+                        this.visit_generics(generics);
 
-                if let Some(async_node_id) = async_node_id {
-                    // 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(fn_id),
-                        |this| {
+                        let declaration = &sig.decl;
+                        let async_node_id = sig.header.asyncness.opt_return_id();
+
+                        // Argument-position elided lifetimes must be transformed into fresh
+                        // generic parameters.  This is especially useful for `async fn`, where
+                        // these fresh generic parameters can be applied to the opaque `impl Trait`
+                        // return type.
+                        let rib = if async_node_id.is_some() {
+                            // Only emit a hard error for `async fn`, since this kind of
+                            // elision has always been allowed in regular `fn`s.
+                            LifetimeRibKind::AnonymousCreateParameter {
+                                binder: fn_id,
+                                report_in_path: true,
+                            }
+                        } else {
+                            LifetimeRibKind::AnonymousPassThrough(fn_id, false)
+                        };
+                        this.with_lifetime_rib(
+                            rib,
                             // Add each argument to the rib.
-                            this.resolve_params(&declaration.inputs)
-                        },
-                    );
-
-                    // Construct the list of in-scope lifetime parameters for async lowering.
-                    // We include all lifetime parameters, either named or "Fresh".
-                    // The order of those parameters does not matter, as long as it is
-                    // deterministic.
-                    let mut extra_lifetime_params =
-                        this.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
-                    for rib in this.lifetime_ribs.iter().rev() {
-                        extra_lifetime_params.extend(
-                            rib.bindings
-                                .iter()
-                                .map(|(&ident, &(node_id, res))| (ident, node_id, res)),
+                            |this| this.resolve_params(&declaration.inputs),
                         );
-                        match rib.kind {
-                            LifetimeRibKind::Item => break,
-                            LifetimeRibKind::AnonymousCreateParameter(id) => {
-                                if let Some(earlier_fresh) =
-                                    this.r.extra_lifetime_params_map.get(&id)
-                                {
-                                    extra_lifetime_params.extend(earlier_fresh);
+
+                        // Construct the list of in-scope lifetime parameters for async lowering.
+                        // We include all lifetime parameters, either named or "Fresh".
+                        // The order of those parameters does not matter, as long as it is
+                        // deterministic.
+                        if let Some(async_node_id) = async_node_id {
+                            let mut extra_lifetime_params = this
+                                .r
+                                .extra_lifetime_params_map
+                                .get(&fn_id)
+                                .cloned()
+                                .unwrap_or_default();
+                            for rib in this.lifetime_ribs.iter().rev() {
+                                extra_lifetime_params.extend(
+                                    rib.bindings
+                                        .iter()
+                                        .map(|(&ident, &(node_id, res))| (ident, node_id, res)),
+                                );
+                                match rib.kind {
+                                    LifetimeRibKind::Item => break,
+                                    LifetimeRibKind::AnonymousCreateParameter {
+                                        binder, ..
+                                    } => {
+                                        if let Some(earlier_fresh) =
+                                            this.r.extra_lifetime_params_map.get(&binder)
+                                        {
+                                            extra_lifetime_params.extend(earlier_fresh);
+                                        }
+                                    }
+                                    _ => {}
                                 }
                             }
-                            _ => {}
+                            this.r
+                                .extra_lifetime_params_map
+                                .insert(async_node_id, extra_lifetime_params);
                         }
-                    }
-                    this.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
 
-                    this.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(async_node_id, true),
-                        |this| visit::walk_fn_ret_ty(this, &declaration.output),
-                    );
-                } else {
-                    // Add each argument to the rib.
-                    this.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(fn_id, false),
-                        |this| this.resolve_params(&declaration.inputs),
-                    );
-                    this.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(fn_id, true),
-                        |this| visit::walk_fn_ret_ty(this, &declaration.output),
-                    );
-                };
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(
+                                // For async fn, the return type appears inside a custom
+                                // `impl Future` RPIT, so we override the binder's id.
+                                async_node_id.unwrap_or(fn_id),
+                                true,
+                            ),
+                            |this| visit::walk_fn_ret_ty(this, &declaration.output),
+                        );
 
-                // Ignore errors in function bodies if this is rustdoc
-                // Be sure not to set this until the function signature has been resolved.
-                let previous_state = replace(&mut this.in_func_body, true);
-                // Resolve the function body, potentially inside the body of an async closure
-                this.with_lifetime_rib(
-                    LifetimeRibKind::AnonymousPassThrough(fn_id, false),
-                    |this| match fn_kind {
-                        FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
-                        FnKind::Closure(_, body) => this.visit_expr(body),
-                    },
-                );
+                        if let Some(body) = body {
+                            // Ignore errors in function bodies if this is rustdoc
+                            // Be sure not to set this until the function signature has been resolved.
+                            let previous_state = replace(&mut this.in_func_body, true);
+                            // Resolve the function body, potentially inside the body of an async closure
+                            this.with_lifetime_rib(
+                                LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                                |this| this.visit_block(body),
+                            );
+
+                            debug!("(resolving function) leaving function");
+                            this.in_func_body = previous_state;
+                        }
+                    }
+                    FnKind::Closure(declaration, body) => {
+                        // We do not have any explicit generic lifetime parameter.
+                        // FIXME(rfc3216): Change when implementing `for<>` bounds on closures.
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousCreateParameter {
+                                binder: fn_id,
+                                report_in_path: false,
+                            },
+                            // Add each argument to the rib.
+                            |this| this.resolve_params(&declaration.inputs),
+                        );
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(fn_id, true),
+                            |this| 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
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                            |this| this.visit_expr(body),
+                        );
 
-                debug!("(resolving function) leaving function");
-                this.in_func_body = previous_state;
+                        debug!("(resolving function) leaving function");
+                        this.in_func_body = previous_state;
+                    }
+                }
             })
         });
         self.diagnostic_metadata.current_function = previous_value;
@@ -902,19 +949,66 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         self.diagnostic_metadata.currently_processing_generics = prev;
     }
 
+    fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
+        self.visit_ident(constraint.ident);
+        if let Some(ref gen_args) = constraint.gen_args {
+            // Forbid anonymous lifetimes in GAT parameters until proper semantics are decided.
+            self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+                this.visit_generic_args(gen_args.span(), gen_args)
+            });
+        }
+        match constraint.kind {
+            AssocConstraintKind::Equality { ref term } => match term {
+                Term::Ty(ty) => self.visit_ty(ty),
+                Term::Const(c) => self.visit_anon_const(c),
+            },
+            AssocConstraintKind::Bound { ref bounds } => {
+                walk_list!(self, visit_param_bound, bounds, BoundKind::Bound);
+            }
+        }
+    }
+
     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(ref data) => {
-                    self.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(path_segment.id, false),
-                        |this| walk_list!(this, visit_ty, &data.inputs),
-                    );
-                    self.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(path_segment.id, true),
-                        |this| visit::walk_fn_ret_ty(this, &data.output),
-                    )
+                GenericArgs::Parenthesized(p_args) => {
+                    // Probe the lifetime ribs to know how to behave.
+                    for rib in self.lifetime_ribs.iter().rev() {
+                        match rib.kind {
+                            // We are inside a `PolyTraitRef`.  The lifetimes are
+                            // to be intoduced in that (maybe implicit) `for<>` binder.
+                            LifetimeRibKind::Generics {
+                                binder,
+                                kind: LifetimeBinderKind::PolyTrait,
+                                ..
+                            } => {
+                                self.with_lifetime_rib(
+                                    LifetimeRibKind::AnonymousCreateParameter {
+                                        binder,
+                                        report_in_path: false,
+                                    },
+                                    |this| walk_list!(this, visit_ty, &p_args.inputs),
+                                );
+                                self.with_lifetime_rib(
+                                    LifetimeRibKind::AnonymousPassThrough(binder, true),
+                                    |this| visit::walk_fn_ret_ty(this, &p_args.output),
+                                );
+                                break;
+                            }
+                            // We have nowhere to introduce generics.  Code is malformed,
+                            // so use regular lifetime resolution to avoid spurious errors.
+                            LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
+                                visit::walk_generic_args(self, path_span, args);
+                                break;
+                            }
+                            LifetimeRibKind::AnonymousPassThrough(..)
+                            | LifetimeRibKind::AnonymousCreateParameter { .. }
+                            | LifetimeRibKind::AnonymousReportError
+                            | LifetimeRibKind::AnonConst
+                            | LifetimeRibKind::ConstGeneric => {}
+                        }
+                    }
                 }
             }
         }
@@ -1243,13 +1337,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         for i in &mut indices {
             let rib = &self.lifetime_ribs[i];
             let normalized_ident = ident.normalize_to_macros_2_0();
-            if let Some(&(_, region)) = rib.bindings.get(&normalized_ident) {
-                self.record_lifetime_res(lifetime.id, region);
+            if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
+                self.record_lifetime_res(lifetime.id, res);
 
-                if let LifetimeRes::Param { param, .. } = region {
+                if let LifetimeRes::Param { param, .. } = res {
                     match self.lifetime_uses.entry(param) {
                         Entry::Vacant(v) => {
-                            debug!("First use of {:?} at {:?}", region, ident.span);
+                            debug!("First use of {:?} at {:?}", res, ident.span);
                             let use_set = self
                                 .lifetime_ribs
                                 .iter()
@@ -1264,17 +1358,19 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                     }
                                     // An anonymous lifetime is legal here, go ahead.
                                     LifetimeRibKind::AnonymousPassThrough(_, false)
-                                    | LifetimeRibKind::AnonymousCreateParameter(_) => {
+                                    | LifetimeRibKind::AnonymousCreateParameter { .. } => {
                                         Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
                                     }
-                                    _ => None,
+                                    LifetimeRibKind::Generics { .. }
+                                    | LifetimeRibKind::ConstGeneric
+                                    | LifetimeRibKind::AnonConst => None,
                                 })
                                 .unwrap_or(LifetimeUseSet::Many);
                             debug!(?use_ctxt, ?use_set);
                             v.insert(use_set);
                         }
                         Entry::Occupied(mut o) => {
-                            debug!("Many uses of {:?} at {:?}", region, ident.span);
+                            debug!("Many uses of {:?} at {:?}", res, ident.span);
                             *o.get_mut() = LifetimeUseSet::Many;
                         }
                     }
@@ -1319,8 +1415,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         for i in (0..self.lifetime_ribs.len()).rev() {
             let rib = &mut self.lifetime_ribs[i];
             match rib.kind {
-                LifetimeRibKind::AnonymousCreateParameter(item_node_id) => {
-                    self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id);
+                LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+                    let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder);
+                    self.record_lifetime_res(lifetime.id, res);
                     return;
                 }
                 LifetimeRibKind::AnonymousReportError => {
@@ -1353,7 +1450,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     return;
                 }
                 LifetimeRibKind::Item => break,
-                _ => {}
+                LifetimeRibKind::Generics { .. }
+                | LifetimeRibKind::ConstGeneric
+                | LifetimeRibKind::AnonConst => {}
             }
         }
         // This resolution is wrong, it passes the work to HIR lifetime resolution.
@@ -1377,27 +1476,21 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
-    fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) {
+    fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) -> LifetimeRes {
         debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
         debug!(?ident.span);
-        let item_def_id = self.r.local_def_id(item_node_id);
-        let def_node_id = self.r.next_node_id();
-        let def_id = self.r.create_def(
-            item_def_id,
-            def_node_id,
-            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-            self.parent_scope.expansion.to_expn_id(),
-            ident.span,
-        );
-        debug!(?def_id);
 
-        let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id };
-        self.record_lifetime_res(id, region);
-        self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push((
-            ident,
-            def_node_id,
-            region,
-        ));
+        // Leave the responsibility to create the `LocalDefId` to lowering.
+        let param = self.r.next_node_id();
+        let res = LifetimeRes::Fresh { param, binder };
+
+        // Record the created lifetime parameter so lowering can pick it up and add it to HIR.
+        self.r
+            .extra_lifetime_params_map
+            .entry(binder)
+            .or_insert_with(Vec::new)
+            .push((ident, param, res));
+        res
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -1447,7 +1540,60 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 | PathSource::Struct
                 | PathSource::TupleStruct(..) => false,
             };
-            let mut res = LifetimeRes::Error;
+
+            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)
+            };
+            let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
+
+            let node_ids = self.r.next_node_ids(expected_lifetimes);
+            self.record_lifetime_res(
+                segment_id,
+                LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
+            );
+
+            if !missing {
+                // Do not create a parameter for patterns and expressions.
+                for rib in self.lifetime_ribs.iter().rev() {
+                    match rib.kind {
+                        LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+                            let res = LifetimeRes::Anonymous { binder, elided: true };
+                            for id in node_ids {
+                                self.record_lifetime_res(id, res);
+                            }
+                            break;
+                        }
+                        // `LifetimeRes::Error`, which would usually be used in the case of
+                        // `ReportError`, is unsuitable here, as we don't emit an error yet.  Instead,
+                        // we simply resolve to an implicit lifetime, which will be checked later, at
+                        // which point a suitable error will be emitted.
+                        LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
+                            // FIXME(cjgillot) This resolution is wrong, but this does not matter
+                            // since these cases are erroneous anyway.  Lifetime resolution should
+                            // emit a "missing lifetime specifier" diagnostic.
+                            let res =
+                                LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
+                            for id in node_ids {
+                                self.record_lifetime_res(id, res);
+                            }
+                            break;
+                        }
+                        LifetimeRibKind::AnonymousCreateParameter { .. }
+                        | LifetimeRibKind::Generics { .. }
+                        | LifetimeRibKind::ConstGeneric
+                        | LifetimeRibKind::AnonConst => {}
+                    }
+                }
+                continue;
+            }
+
+            let mut should_lint = true;
             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
@@ -1456,72 +1602,68 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     //
                     //     impl Foo for std::cell::Ref<u32> // note lack of '_
                     //     async fn foo(_: std::cell::Ref<u32>) { ... }
-                    LifetimeRibKind::AnonymousCreateParameter(_) => {
+                    LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } => {
+                        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();
+                        should_lint = false;
+
+                        for id in node_ids {
+                            self.record_lifetime_res(id, LifetimeRes::Error);
+                        }
+                        break;
+                    }
+                    // Do not create a parameter for patterns and expressions.
+                    LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+                        for id in node_ids {
+                            let res = self.create_fresh_lifetime(id, ident, binder);
+                            self.record_lifetime_res(id, res);
+                        }
                         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(binder, _) => {
-                        res = LifetimeRes::Anonymous { binder, elided: true };
+                        let res = LifetimeRes::Anonymous { binder, elided: true };
+                        for id in node_ids {
+                            self.record_lifetime_res(id, res);
+                        }
                         break;
                     }
+                    // `LifetimeRes::Error`, which would usually be used in the case of
+                    // `ReportError`, is unsuitable here, as we don't emit an error yet.  Instead,
+                    // we simply resolve to an implicit lifetime, which will be checked later, at
+                    // which point a suitable error will be emitted.
                     LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
                         // FIXME(cjgillot) This resolution is wrong, but this does not matter
                         // since these cases are erroneous anyway.  Lifetime resolution should
                         // emit a "missing lifetime specifier" diagnostic.
-                        res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
+                        let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
+                        for id in node_ids {
+                            self.record_lifetime_res(id, res);
+                        }
                         break;
                     }
-                    _ => {}
+                    LifetimeRibKind::Generics { .. }
+                    | LifetimeRibKind::ConstGeneric
+                    | LifetimeRibKind::AnonConst => {}
                 }
             }
 
-            let node_ids = self.r.next_node_ids(expected_lifetimes);
-            self.record_lifetime_res(
-                segment_id,
-                LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
-            );
-            for i in 0..expected_lifetimes {
-                let id = node_ids.start.plus(i);
-                self.record_lifetime_res(id, res);
-            }
-
-            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 let LifetimeRes::Error = res {
-                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 {
+            if should_lint {
                 self.r.lint_buffer.buffer_lint_with_diagnostic(
                     lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
                     segment_id,
@@ -1732,72 +1874,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                             |this| {
                                 this.visit_generics(generics);
                                 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits);
-
-                                let walk_assoc_item =
-                                    |this: &mut Self,
-                                     generics: &Generics,
-                                     kind,
-                                     item: &'ast AssocItem| {
-                                        this.with_generic_param_rib(
-                                            &generics.params,
-                                            AssocItemRibKind,
-                                            LifetimeRibKind::Generics {
-                                                binder: item.id,
-                                                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,
-                                                        HasGenericParams::Yes,
-                                                        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!")
-                                            }
-                                        };
-                                    }
-                                });
+                                this.resolve_trait_items(items);
                             },
                         );
                     },
@@ -2073,16 +2150,53 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     }
 
     /// When evaluating a `trait` use its associated types' idents for suggestions in E0412.
-    fn with_trait_items<T>(
-        &mut self,
-        trait_items: &'ast [P<AssocItem>],
-        f: impl FnOnce(&mut Self) -> T,
-    ) -> T {
+    fn resolve_trait_items(&mut self, trait_items: &'ast [P<AssocItem>]) {
         let trait_assoc_items =
             replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(&trait_items));
-        let result = f(self);
+
+        let walk_assoc_item =
+            |this: &mut Self, generics: &Generics, kind, item: &'ast AssocItem| {
+                this.with_generic_param_rib(
+                    &generics.params,
+                    AssocItemRibKind,
+                    LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind },
+                    |this| visit::walk_assoc_item(this, item, AssocCtxt::Trait),
+                );
+            };
+
+        for item in trait_items {
+            match &item.kind {
+                AssocItemKind::Const(_, ty, default) => {
+                    self.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.
+                        self.with_constant_rib(
+                            IsRepeatExpr::No,
+                            HasGenericParams::Yes,
+                            None,
+                            |this| this.visit_expr(expr),
+                        );
+                    }
+                }
+                AssocItemKind::Fn(box Fn { generics, .. }) => {
+                    walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
+                }
+                AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
+                    walk_assoc_item(self, generics, LifetimeBinderKind::Item, item);
+                }
+                AssocItemKind::MacCall(_) => {
+                    panic!("unexpanded macro in resolve!")
+                }
+            };
+        }
+
         self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items;
-        result
     }
 
     /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
@@ -2140,142 +2254,159 @@ 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.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, binder: item_id, 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| {
-                this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter(item_id), |this| {
-                    // Resolve the trait reference, if necessary.
-                    this.with_optional_trait_ref(opt_trait_reference.as_ref(), self_type, |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);
-                            }
-                            // Resolve the self type.
-                            this.visit_ty(self_type);
-                            // Resolve the generic parameters.
-                            this.visit_generics(generics);
+        self.with_generic_param_rib(
+            &generics.params,
+            ItemRibKind(HasGenericParams::Yes),
+            LifetimeRibKind::Generics {
+                span: generics.span,
+                binder: item_id,
+                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| {
+                    this.with_lifetime_rib(
+                        LifetimeRibKind::AnonymousCreateParameter {
+                            binder: item_id,
+                            report_in_path: true
+                        },
+                        |this| {
+                            // Resolve the trait reference, if necessary.
+                            this.with_optional_trait_ref(
+                                opt_trait_reference.as_ref(),
+                                self_type,
+                                |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 items within the impl.
-                            this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false),
-                                |this| {
-                                    this.with_current_self_type(self_type, |this| {
-                                        this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
-                                            debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
-                                            for item in impl_items {
-                                                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,
-                                                            HasGenericParams::Yes,
-                                                            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 { binder: item.id, 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 { binder: item.id, 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!")
-                                                    }
-                                                }
-                                            }
-                                        });
+                                    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(item_id,false),
+                                            |this| {
+                                                this.with_current_self_type(self_type, |this| {
+                                                    this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
+                                                        debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
+                                                        for item in impl_items {
+                                                            this.resolve_impl_item(&**item);
+                                                        }
+                                                    });
+                                                });
+                                            },
+                                        );
                                     });
                                 },
                             );
-                        });
-                    });
+                        },
+                    );
                 });
-            });
-        });
+            },
+        );
+    }
+
+    fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
+        use crate::ResolutionError::*;
+        match &item.kind {
+            AssocItemKind::Const(_, ty, default) => {
+                debug!("resolve_implementation AssocItemKind::Const");
+                // If this is a trait impl, ensure the const
+                // exists in trait
+                self.check_trait_item(
+                    item.id,
+                    item.ident,
+                    &item.kind,
+                    ValueNS,
+                    item.span,
+                    |i, s, c| ConstNotMemberOfTrait(i, s, c),
+                );
+
+                self.visit_ty(ty);
+                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.
+                    self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
+                        this.visit_expr(expr)
+                    });
+                }
+            }
+            AssocItemKind::Fn(box Fn { generics, .. }) => {
+                debug!("resolve_implementation AssocItemKind::Fn");
+                // We also need a new scope for the impl item type parameters.
+                self.with_generic_param_rib(
+                    &generics.params,
+                    AssocItemRibKind,
+                    LifetimeRibKind::Generics {
+                        binder: item.id,
+                        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.
+                self.with_generic_param_rib(
+                    &generics.params,
+                    AssocItemRibKind,
+                    LifetimeRibKind::Generics {
+                        binder: item.id,
+                        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!")
+            }
+        }
     }
 
     fn check_trait_item<F>(
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 7d2b7de17bf..68bcba7147b 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2242,9 +2242,18 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
             ]
             .contains(&Some(did))
             {
-                let (span, span_type) = match &trait_ref.bound_generic_params {
-                    [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
-                    [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
+                let (span, span_type) = if let Some(bound) =
+                    trait_ref.bound_generic_params.iter().rfind(|param| {
+                        matches!(
+                            param.kind,
+                            hir::GenericParamKind::Lifetime {
+                                kind: hir::LifetimeParamKind::Explicit
+                            }
+                        )
+                    }) {
+                    (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail)
+                } else {
+                    (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty)
                 };
                 self.missing_named_lifetime_spots
                     .push(MissingLifetimeSpot::HigherRanked { span, span_type });
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 55574b83607..ed5d1165c7d 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -29,8 +29,6 @@ use std::cell::Cell;
 use std::fmt;
 use std::mem::take;
 
-use tracing::{debug, span, Level};
-
 trait RegionExt {
     fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
 
@@ -572,41 +570,38 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         });
     }
 
-    fn visit_fn(
-        &mut self,
-        fk: intravisit::FnKind<'tcx>,
-        fd: &'tcx hir::FnDecl<'tcx>,
-        b: hir::BodyId,
-        s: rustc_span::Span,
-        hir_id: hir::HirId,
-    ) {
-        let name = match fk {
-            intravisit::FnKind::ItemFn(id, _, _) => id.name,
-            intravisit::FnKind::Method(id, _) => id.name,
-            intravisit::FnKind::Closure => sym::closure,
-        };
-        let name = name.as_str();
-        let span = span!(Level::DEBUG, "visit_fn", name);
-        let _enter = span.enter();
-        match fk {
-            // Any `Binders` are handled elsewhere
-            intravisit::FnKind::ItemFn(..) | intravisit::FnKind::Method(..) => {
-                intravisit::walk_fn(self, fk, fd, b, s, hir_id)
-            }
-            intravisit::FnKind::Closure => {
-                self.map.late_bound_vars.insert(hir_id, vec![]);
-                let scope = Scope::Binder {
-                    hir_id,
-                    lifetimes: FxIndexMap::default(),
-                    next_early_index: self.next_early_index(),
-                    s: self.scope,
-                    opaque_type_parent: false,
-                    scope_type: BinderScopeType::Normal,
-                    allow_late_bound: true,
-                    where_bound_origin: None,
-                };
-                self.with(scope, move |this| intravisit::walk_fn(this, fk, fd, b, s, hir_id));
-            }
+    fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
+        if let hir::ExprKind::Closure { bound_generic_params, .. } = e.kind {
+            let next_early_index = self.next_early_index();
+            let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
+                bound_generic_params
+                    .iter()
+                    .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
+                    .enumerate()
+                    .map(|(late_bound_idx, param)| {
+                        let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
+                        let r = late_region_as_bound_region(self.tcx, &pair.1);
+                        (pair, r)
+                    })
+                    .unzip();
+            self.map.late_bound_vars.insert(e.hir_id, binders);
+            let scope = Scope::Binder {
+                hir_id: e.hir_id,
+                lifetimes,
+                s: self.scope,
+                next_early_index,
+                opaque_type_parent: false,
+                scope_type: BinderScopeType::Normal,
+                allow_late_bound: true,
+                where_bound_origin: None,
+            };
+            self.with(scope, |this| {
+                // a closure has no bounds, so everything
+                // contained within is scoped within its binder.
+                intravisit::walk_expr(this, e)
+            });
+        } else {
+            intravisit::walk_expr(self, e)
         }
     }
 
@@ -755,7 +750,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let next_early_index = self.next_early_index();
                 let lifetime_span: Option<Span> =
                     c.generic_params.iter().rev().find_map(|param| match param.kind {
-                        GenericParamKind::Lifetime { .. } => Some(param.span),
+                        GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
+                            Some(param.span)
+                        }
                         _ => None,
                     });
                 let (span, span_type) = if let Some(span) = lifetime_span {
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 4641b36aad1..84e3180b491 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2920,13 +2920,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     ) {
         for br in referenced_regions.difference(&constrained_regions) {
             let br_name = match *br {
+                ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
+                    "an anonymous lifetime".to_string()
+                }
                 ty::BrNamed(_, name) => format!("lifetime `{}`", name),
-                ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(),
             };
 
             let mut err = generate_err(&br_name);
 
-            if let ty::BrAnon(_) = *br {
+            if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
                 // The only way for an anonymous lifetime to wind up
                 // in the return type but **also** be unconstrained is
                 // if it only appears in "associated types" in the
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index acb2aa44ad5..95c82a7d2c3 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -628,24 +628,40 @@ fn compare_number_of_generics<'tcx>(
     let mut err_occurred = None;
     for (kind, trait_count, impl_count) in matchings {
         if impl_count != trait_count {
+            let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
+                let mut spans = generics
+                    .params
+                    .iter()
+                    .filter(|p| match p.kind {
+                        hir::GenericParamKind::Lifetime {
+                            kind: hir::LifetimeParamKind::Elided,
+                        } => {
+                            // A fn can have an arbitrary number of extra elided lifetimes for the
+                            // same signature.
+                            !matches!(kind, ty::AssocKind::Fn)
+                        }
+                        _ => true,
+                    })
+                    .map(|p| p.span)
+                    .collect::<Vec<Span>>();
+                if spans.is_empty() {
+                    spans = vec![generics.span]
+                }
+                spans
+            };
             let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
                 let trait_item = tcx.hir().expect_trait_item(def_id);
-                if trait_item.generics.params.is_empty() {
-                    (Some(vec![trait_item.generics.span]), vec![])
-                } else {
-                    let arg_spans: Vec<Span> =
-                        trait_item.generics.params.iter().map(|p| p.span).collect();
-                    let impl_trait_spans: Vec<Span> = trait_item
-                        .generics
-                        .params
-                        .iter()
-                        .filter_map(|p| match p.kind {
-                            GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
-                            _ => None,
-                        })
-                        .collect();
-                    (Some(arg_spans), impl_trait_spans)
-                }
+                let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
+                let impl_trait_spans: Vec<Span> = trait_item
+                    .generics
+                    .params
+                    .iter()
+                    .filter_map(|p| match p.kind {
+                        GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
+                        _ => None,
+                    })
+                    .collect();
+                (Some(arg_spans), impl_trait_spans)
             } else {
                 (trait_span.map(|s| vec![s]), vec![])
             };
@@ -660,23 +676,7 @@ fn compare_number_of_generics<'tcx>(
                     _ => None,
                 })
                 .collect();
-            let spans = if impl_item.generics.params.is_empty() {
-                vec![impl_item.generics.span]
-            } else {
-                impl_item
-                    .generics
-                    .params
-                    .iter()
-                    .filter(|p| {
-                        matches!(
-                            p.kind,
-                            hir::GenericParamKind::Type { .. }
-                                | hir::GenericParamKind::Const { .. }
-                        )
-                    })
-                    .map(|p| p.span)
-                    .collect::<Vec<Span>>()
-            };
+            let spans = arg_spans(impl_.kind, impl_item.generics);
             let span = spans.first().copied();
 
             let mut err = tcx.sess.struct_span_err_with_code(
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index fd30691c324..9e5c4afc717 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -222,10 +222,15 @@ impl<'tcx> Clean<'tcx, Option<Lifetime>> for ty::Region<'tcx> {
         match **self {
             ty::ReStatic => Some(Lifetime::statik()),
             ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
-                Some(Lifetime(name))
+                if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
+            }
+            ty::ReEarlyBound(ref data) => {
+                if data.name != kw::UnderscoreLifetime {
+                    Some(Lifetime(data.name))
+                } else {
+                    None
+                }
             }
-            ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)),
-
             ty::ReLateBound(..)
             | ty::ReFree(..)
             | ty::ReVar(..)
@@ -530,29 +535,25 @@ fn clean_generic_param<'tcx>(
     GenericParamDef { name, kind }
 }
 
+/// Synthetic type-parameters are inserted after normal ones.
+/// In order for normal parameters to be able to refer to synthetic ones,
+/// scans them first.
+fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
+    match param.kind {
+        hir::GenericParamKind::Type { synthetic, .. } => synthetic,
+        _ => false,
+    }
+}
+
+/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
+///
+/// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
+fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
+    matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided })
+}
+
 impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics {
-        // Synthetic type-parameters are inserted after normal ones.
-        // In order for normal parameters to be able to refer to synthetic ones,
-        // scans them first.
-        fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
-            match param.kind {
-                hir::GenericParamKind::Type { synthetic, .. } => synthetic,
-                _ => false,
-            }
-        }
-        /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
-        ///
-        /// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information.
-        ///
-        /// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param
-        fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
-            matches!(
-                param.kind,
-                hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided }
-            )
-        }
-
         let impl_trait_params = self
             .params
             .iter()
@@ -991,6 +992,7 @@ impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> {
             generic_params: self
                 .bound_generic_params
                 .iter()
+                .filter(|p| !is_elided_lifetime(p))
                 .map(|x| clean_generic_param(cx, None, x))
                 .collect(),
         }
@@ -1865,8 +1867,12 @@ impl<'tcx> Clean<'tcx, BareFunctionDecl> for hir::BareFnTy<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> BareFunctionDecl {
         let (generic_params, decl) = enter_impl_trait(cx, |cx| {
             // NOTE: generics must be cleaned before args
-            let generic_params =
-                self.generic_params.iter().map(|x| clean_generic_param(cx, None, x)).collect();
+            let generic_params = self
+                .generic_params
+                .iter()
+                .filter(|p| !is_elided_lifetime(p))
+                .map(|x| clean_generic_param(cx, None, x))
+                .collect();
             let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
             let decl = clean_fn_decl_with_args(cx, self.decl, args);
             (generic_params, decl)
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 41ab0e9377d..16574f94c00 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -84,12 +84,9 @@ pub(crate) fn substs_to_args<'tcx>(
     let mut ret_val =
         Vec::with_capacity(substs.len().saturating_sub(if skip_first { 1 } else { 0 }));
     ret_val.extend(substs.iter().filter_map(|kind| match kind.unpack() {
-        GenericArgKind::Lifetime(lt) => match *lt {
-            ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrAnon(_), .. }) => {
-                Some(GenericArg::Lifetime(Lifetime::elided()))
-            }
-            _ => lt.clean(cx).map(GenericArg::Lifetime),
-        },
+        GenericArgKind::Lifetime(lt) => {
+            Some(GenericArg::Lifetime(lt.clean(cx).unwrap_or(Lifetime::elided())))
+        }
         GenericArgKind::Type(_) if skip_first => {
             skip_first = false;
             None
diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs
index 1c3d166a1af..c9fd7248a80 100644
--- a/src/test/ui/generic-associated-types/issue-70304.rs
+++ b/src/test/ui/generic-associated-types/issue-70304.rs
@@ -45,7 +45,7 @@ where
 }
 
 fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
-    //~^ ERROR: missing lifetime specifier
+    //~^ ERROR `'_` cannot be used here [E0637]
     //~| 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 08efc82c886..b3881ccb099 100644
--- a/src/test/ui/generic-associated-types/issue-70304.stderr
+++ b/src/test/ui/generic-associated-types/issue-70304.stderr
@@ -1,14 +1,8 @@
-error[E0106]: missing lifetime specifier
+error[E0637]: `'_` cannot be used here
   --> $DIR/issue-70304.rs:47:41
    |
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
-   |                                         ^^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
-   |
-LL | fn create_doc() -> impl Document<Cursor<'static> = DocCursorImpl<'_>> {
-   |                                         ~~~~~~~
+   |                                         ^^ `'_` is a reserved lifetime name
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-70304.rs:47:61
@@ -24,4 +18,5 @@ LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'static>> {
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0106, E0637.
+For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/generic-associated-types/issue-95305.rs b/src/test/ui/generic-associated-types/issue-95305.rs
index 9ead347984b..2365daada11 100644
--- a/src/test/ui/generic-associated-types/issue-95305.rs
+++ b/src/test/ui/generic-associated-types/issue-95305.rs
@@ -9,7 +9,7 @@ trait Foo {
 }
 
 fn foo(x: &impl Foo<Item<'_> = u32>) { }
-                       //~^ ERROR missing lifetime specifier
+                       //~^ ERROR `'_` cannot be used here [E0637]
 
 fn bar(x: &impl for<'a> Foo<Item<'a> = &'_ u32>) { }
                                       //~^ ERROR missing lifetime specifier
diff --git a/src/test/ui/generic-associated-types/issue-95305.stderr b/src/test/ui/generic-associated-types/issue-95305.stderr
index 2b48378dc43..8624d880d4e 100644
--- a/src/test/ui/generic-associated-types/issue-95305.stderr
+++ b/src/test/ui/generic-associated-types/issue-95305.stderr
@@ -1,13 +1,8 @@
-error[E0106]: missing lifetime specifier
+error[E0637]: `'_` cannot be used here
   --> $DIR/issue-95305.rs:11:26
    |
 LL | fn foo(x: &impl Foo<Item<'_> = u32>) { }
-   |                          ^^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL | fn foo<'a>(x: &impl Foo<Item<'a> = u32>) { }
-   |       ++++                   ~~
+   |                          ^^ `'_` is a reserved lifetime name
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-95305.rs:14:41
@@ -22,4 +17,5 @@ LL | fn bar(x: &impl for<'a> Foo<Item<'a> = &'a u32>) { }
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0106, E0637.
+For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr
index 76d39c88b61..1458bf0c4a4 100644
--- a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr
+++ b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr
@@ -8,7 +8,7 @@ LL |     type A = u32;
    |           ^ lifetimes do not match type in trait
 
 error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters
-  --> $DIR/parameter_number_and_kind_impl.rs:17:16
+  --> $DIR/parameter_number_and_kind_impl.rs:17:12
    |
 LL |     type B<'a, 'b>;
    |            --  --
@@ -16,7 +16,9 @@ LL |     type B<'a, 'b>;
    |            expected 0 type parameters
 ...
 LL |     type B<'a, T> = Vec<T>;
-   |                ^ found 1 type parameter
+   |            ^^  ^
+   |            |
+   |            found 1 type parameter
 
 error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration
   --> $DIR/parameter_number_and_kind_impl.rs:19:11
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
index 1e2575116a8..0bfa7b3cc7c 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
@@ -23,7 +23,7 @@ error[E0308]: mismatched types
 LL |     foo(bar, "string", |s| s.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `FnOnce<(&&str,)>`
+   = note: expected trait `for<'r, 's> FnOnce<(&'r &'s str,)>`
               found trait `for<'r> FnOnce<(&'r &str,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:45:24
@@ -61,7 +61,7 @@ error[E0308]: mismatched types
 LL |     foo(baz, "string", |s| s.0.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected trait `FnOnce<(&Wrapper<'_>,)>`
+   = note: expected trait `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
               found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:48:24
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
index fe319e6c851..172bf218c0d 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
@@ -6,8 +6,8 @@ trait SomeTrait<'a> {
 
 fn give_me_ice<T>() {
     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-    //~^ ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
-    //~| ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
+    //~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
+    //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
 }
 
 fn callee<T: Fn<(&'static (),)>>() {
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
index 13b68b07240..ecca4b999e7 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
@@ -1,24 +1,24 @@
-error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied
+error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied
   --> $DIR/issue-85455.rs:8:5
    |
 LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
-LL | fn give_me_ice<T: SomeTrait<'_>>() {
-   |                 +++++++++++++++
+LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
+   |                 +++++++++++++++++++++++
 
-error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied
+error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied
   --> $DIR/issue-85455.rs:8:14
    |
 LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T`
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
-LL | fn give_me_ice<T: SomeTrait<'_>>() {
-   |                 +++++++++++++++
+LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
+   |                 +++++++++++++++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs
index c508c0ac9d5..359c08c98d1 100644
--- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs
+++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs
@@ -13,6 +13,10 @@ impl StaticTrait for Box<dyn Debug> { }
 trait NotStaticTrait { }
 impl NotStaticTrait for Box<dyn Debug + '_> { }
 
+// Check that we don't err when the trait has a lifetime parameter.
+trait TraitWithLifetime<'a> { }
+impl NotStaticTrait for &dyn TraitWithLifetime<'_> { }
+
 fn static_val<T: StaticTrait>(_: T) {
 }
 
diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
index 88c260b18cb..762698c4fc1 100644
--- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
@@ -1,5 +1,5 @@
 error[E0521]: borrowed data escapes outside of function
-  --> $DIR/dyn-trait.rs:20:5
+  --> $DIR/dyn-trait.rs:24:5
    |
 LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
    |                          --  - `x` is a reference that is only valid in the function body
diff --git a/src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs b/src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs
new file mode 100644
index 00000000000..ff84d251149
--- /dev/null
+++ b/src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+struct Foo<'a> {
+    x: &'a (),
+}
+
+// The lifetime in pattern-position `Foo` is elided.
+// Verify that lowering does not create an independent lifetime parameter for it.
+fn foo<'a>(Foo { x }: Foo<'a>) {
+    *x
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr
index cce0a31bfbb..d85ea6529f6 100644
--- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr
@@ -10,8 +10,8 @@ LL |   y.push(z);
    |
 help: consider introducing a named lifetime parameter
    |
-LL | fn foo<'a>(x:Box<dyn Fn(&'a u8, &'a u8)> , y: Vec<&u8>, z: &u8) {
-   |       ++++               ++      ++
+LL | fn foo<'a>(x:Box<dyn Fn(&u8, &u8)> , y: Vec<&'a u8>, z: &'a u8) {
+   |       ++++                                   ++          ++
 
 error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
   --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3