about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/lifetime_collector.rs2
-rw-r--r--compiler/rustc_hir/src/def.rs9
-rw-r--r--compiler/rustc_lint/messages.ftl4
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs13
-rw-r--r--compiler/rustc_lint/src/lints.rs10
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs33
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs7
-rw-r--r--compiler/rustc_resolve/src/late.rs79
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs11
-rw-r--r--library/alloc/src/string.rs2
-rw-r--r--library/core/src/fmt/rt.rs20
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.stderr13
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs2
-rw-r--r--tests/ui/async-await/issues/issue-63388-1.rs2
-rw-r--r--tests/ui/async-await/issues/issue-63388-1.stderr13
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.full.stderr10
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.min.stderr10
-rw-r--r--tests/ui/const-generics/type-dependent/issue-71348.rs1
-rw-r--r--tests/ui/consts/min_const_fn/min_const_fn.rs4
-rw-r--r--tests/ui/consts/min_const_fn/min_const_fn.stderr22
-rw-r--r--tests/ui/generics/generic-no-mangle.fixed2
-rw-r--r--tests/ui/generics/generic-no-mangle.rs2
-rw-r--r--tests/ui/impl-trait/impl-fn-hrtb-bounds.rs1
-rw-r--r--tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr12
-rw-r--r--tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs1
-rw-r--r--tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr14
-rw-r--r--tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs1
-rw-r--r--tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr10
-rw-r--r--tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs1
-rw-r--r--tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr12
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs1
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr16
-rw-r--r--tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs12
-rw-r--r--tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr14
-rw-r--r--tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs27
-rw-r--r--tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr40
-rw-r--r--tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs17
-rw-r--r--tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr26
-rw-r--r--tests/ui/lint/elided-named-lifetimes/static.rs46
-rw-r--r--tests/ui/lint/elided-named-lifetimes/static.stderr32
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-elision.rs2
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-elision.stderr14
-rw-r--r--tests/ui/self/elision/ignore-non-reference-lifetimes.rs2
-rw-r--r--tests/ui/self/elision/ignore-non-reference-lifetimes.stderr16
-rw-r--r--tests/ui/self/elision/lt-ref-self-async.fixed2
-rw-r--r--tests/ui/self/elision/lt-ref-self-async.rs2
-rw-r--r--tests/ui/self/self_lifetime-async.rs2
-rw-r--r--tests/ui/self/self_lifetime-async.stderr18
-rw-r--r--tests/ui/self/self_lifetime.rs2
-rw-r--r--tests/ui/self/self_lifetime.stderr18
-rw-r--r--tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs1
-rw-r--r--tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr10
-rw-r--r--tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs1
-rw-r--r--tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr12
59 files changed, 628 insertions, 61 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index bcc2c29a2ff..9b46e7c46b6 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -837,7 +837,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                 (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
             }
-            LifetimeRes::Static | LifetimeRes::Error => return None,
+            LifetimeRes::Static { .. } | LifetimeRes::Error => return None,
             res => panic!(
                 "Unexpected lifetime resolution {:?} for {:?} at {:?}",
                 res, ident, ident.span
@@ -1656,7 +1656,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
 
                 // Opaques do not capture `'static`
-                LifetimeRes::Static | LifetimeRes::Error => {
+                LifetimeRes::Static { .. } | LifetimeRes::Error => {
                     continue;
                 }
 
@@ -2069,7 +2069,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 hir::LifetimeName::Param(param)
             }
             LifetimeRes::Infer => hir::LifetimeName::Infer,
-            LifetimeRes::Static => hir::LifetimeName::Static,
+            LifetimeRes::Static { .. } => hir::LifetimeName::Static,
             LifetimeRes::Error => hir::LifetimeName::Error,
             res => panic!(
                 "Unexpected lifetime resolution {:?} for {:?} at {:?}",
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
index 77cc2a36a53..76c957afa54 100644
--- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs
+++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
@@ -27,7 +27,7 @@ impl<'ast> LifetimeCollectVisitor<'ast> {
                     self.collected_lifetimes.insert(lifetime);
                 }
             }
-            LifetimeRes::Static | LifetimeRes::Error => {
+            LifetimeRes::Static { .. } | LifetimeRes::Error => {
                 self.collected_lifetimes.insert(lifetime);
             }
             LifetimeRes::Infer => {}
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 36e29d2dcb2..c5dc4dacab6 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -863,8 +863,13 @@ pub enum LifetimeRes {
     /// This variant is used for anonymous lifetimes that we did not resolve during
     /// late resolution. Those lifetimes will be inferred by typechecking.
     Infer,
-    /// Explicit `'static` lifetime.
-    Static,
+    /// `'static` lifetime.
+    Static {
+        /// We do not want to emit `elided_named_lifetimes`
+        /// when we are inside of a const item or a static,
+        /// because it would get too annoying.
+        suppress_elision_warning: bool,
+    },
     /// Resolution failure.
     Error,
     /// HACK: This is used to recover the NodeId of an elided lifetime.
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 08a50050a36..31b7eb5ee7d 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -252,6 +252,10 @@ lint_duplicate_macro_attribute =
 
 lint_duplicate_matcher_binding = duplicate matcher binding
 
+lint_elided_named_lifetime = elided lifetime has a name
+    .label_elided = this elided lifetime gets resolved as `{$name}`
+    .label_named = lifetime `{$name}` declared here
+
 lint_enum_intrinsics_mem_discriminant =
     the return value of `mem::discriminant` is unspecified when called with a non-enum type
     .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index f289d4c81b3..fd43afa1743 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -10,6 +10,7 @@ use rustc_errors::{
 use rustc_middle::middle::stability;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::Session;
+use rustc_span::symbol::kw;
 use rustc_span::BytePos;
 use tracing::debug;
 
@@ -441,5 +442,17 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
         BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => {
             lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag)
         }
+        BuiltinLintDiag::ElidedIsStatic { elided } => {
+            lints::ElidedNamedLifetime { elided, name: kw::StaticLifetime, named_declaration: None }
+                .decorate_lint(diag)
+        }
+        BuiltinLintDiag::ElidedIsParam { elided, param: (param_name, param_span) } => {
+            lints::ElidedNamedLifetime {
+                elided,
+                name: param_name,
+                named_declaration: Some(param_span),
+            }
+            .decorate_lint(diag)
+        }
     }
 }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index c6bcb1f3e83..2712e25668a 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -2612,6 +2612,16 @@ pub(crate) struct ElidedLifetimesInPaths {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_elided_named_lifetime)]
+pub(crate) struct ElidedNamedLifetime {
+    #[label(lint_label_elided)]
+    pub elided: Span,
+    pub name: Symbol,
+    #[label(lint_label_named)]
+    pub named_declaration: Option<Span>,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_invalid_crate_type_value)]
 pub(crate) struct UnknownCrateTypes {
     #[subdiagnostic]
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 04fd7c9c627..7063f488209 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -42,6 +42,7 @@ declare_lint_pass! {
         DUPLICATE_MACRO_ATTRIBUTES,
         ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
         ELIDED_LIFETIMES_IN_PATHS,
+        ELIDED_NAMED_LIFETIMES,
         EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
         EXPORTED_PRIVATE_DEPENDENCIES,
         FFI_UNWIND_CALLS,
@@ -1863,6 +1864,38 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `elided_named_lifetimes` lint detects when an elided
+    /// lifetime ends up being a named lifetime, such as `'static`
+    /// or some lifetime parameter `'a`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(elided_named_lifetimes)]
+    /// struct Foo;
+    /// impl Foo {
+    ///     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
+    ///         unsafe { &mut *(x as *mut _) }
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Lifetime elision is quite useful, because it frees you from having
+    /// to give each lifetime its own name, but sometimes it can produce
+    /// somewhat surprising resolutions. In safe code, it is mostly okay,
+    /// because the borrow checker prevents any unsoundness, so the worst
+    /// case scenario is you get a confusing error message in some other place.
+    /// But with `unsafe` code, such unexpected resolutions may lead to unsound code.
+    pub ELIDED_NAMED_LIFETIMES,
+    Warn,
+    "detects when an elided lifetime gets resolved to be `'static` or some named parameter"
+}
+
+declare_lint! {
     /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait
     /// objects.
     ///
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index c17b85db3b0..8ddbff284cc 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -589,6 +589,13 @@ pub enum BuiltinLintDiag {
     },
     MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
     ElidedLifetimesInPaths(usize, Span, bool, Span),
+    ElidedIsStatic {
+        elided: Span,
+    },
+    ElidedIsParam {
+        elided: Span,
+        param: (Symbol, Span),
+    },
     UnknownCrateTypes {
         span: Span,
         candidate: Option<Symbol>,
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 40fdb01a72c..8ec0469ed6d 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1557,14 +1557,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         if ident.name == kw::StaticLifetime {
             self.record_lifetime_res(
                 lifetime.id,
-                LifetimeRes::Static,
+                LifetimeRes::Static { suppress_elision_warning: false },
                 LifetimeElisionCandidate::Named,
             );
             return;
         }
 
         if ident.name == kw::UnderscoreLifetime {
-            return self.resolve_anonymous_lifetime(lifetime, false);
+            return self.resolve_anonymous_lifetime(lifetime, lifetime.id, false);
         }
 
         let mut lifetime_rib_iter = self.lifetime_ribs.iter().rev();
@@ -1667,13 +1667,23 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
+    fn resolve_anonymous_lifetime(
+        &mut self,
+        lifetime: &Lifetime,
+        id_for_lint: NodeId,
+        elided: bool,
+    ) {
         debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
 
         let kind =
             if elided { MissingLifetimeKind::Ampersand } else { MissingLifetimeKind::Underscore };
-        let missing_lifetime =
-            MissingLifetime { id: lifetime.id, span: lifetime.ident.span, kind, count: 1 };
+        let missing_lifetime = MissingLifetime {
+            id: lifetime.id,
+            span: lifetime.ident.span,
+            kind,
+            count: 1,
+            id_for_lint,
+        };
         let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
         for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() {
             debug!(?rib.kind);
@@ -1697,7 +1707,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     if lifetimes_in_scope.is_empty() {
                         self.record_lifetime_res(
                             lifetime.id,
-                            LifetimeRes::Static,
+                            // We are inside a const item, so do not warn.
+                            LifetimeRes::Static { suppress_elision_warning: true },
                             elision_candidate,
                         );
                         return;
@@ -1800,7 +1811,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
             LifetimeElisionCandidate::Ignore,
         );
-        self.resolve_anonymous_lifetime(&lt, true);
+        self.resolve_anonymous_lifetime(&lt, anchor_id, true);
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -1916,6 +1927,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             };
             let missing_lifetime = MissingLifetime {
                 id: node_ids.start,
+                id_for_lint: segment_id,
                 span: elided_lifetime_span,
                 kind,
                 count: expected_lifetimes,
@@ -2039,8 +2051,44 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
             panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)")
         }
+
+        match candidate {
+            LifetimeElisionCandidate::Missing(missing @ MissingLifetime { .. }) => {
+                debug_assert_eq!(id, missing.id);
+                match res {
+                    LifetimeRes::Static { suppress_elision_warning } => {
+                        if !suppress_elision_warning {
+                            self.r.lint_buffer.buffer_lint(
+                                lint::builtin::ELIDED_NAMED_LIFETIMES,
+                                missing.id_for_lint,
+                                missing.span,
+                                BuiltinLintDiag::ElidedIsStatic { elided: missing.span },
+                            );
+                        }
+                    }
+                    LifetimeRes::Param { param, binder: _ } => {
+                        let tcx = self.r.tcx();
+                        self.r.lint_buffer.buffer_lint(
+                            lint::builtin::ELIDED_NAMED_LIFETIMES,
+                            missing.id_for_lint,
+                            missing.span,
+                            BuiltinLintDiag::ElidedIsParam {
+                                elided: missing.span,
+                                param: (tcx.item_name(param.into()), tcx.source_span(param)),
+                            },
+                        );
+                    }
+                    LifetimeRes::Fresh { .. }
+                    | LifetimeRes::Infer
+                    | LifetimeRes::Error
+                    | LifetimeRes::ElidedAnchor { .. } => {}
+                }
+            }
+            LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => {}
+        }
+
         match res {
-            LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => {
+            LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static { .. } => {
                 if let Some(ref mut candidates) = self.lifetime_elision_candidates {
                     candidates.push((res, candidate));
                 }
@@ -2558,9 +2606,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
             ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => {
                 self.with_static_rib(def_kind, |this| {
-                    this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
-                        this.visit_ty(ty);
-                    });
+                    this.with_lifetime_rib(
+                        LifetimeRibKind::Elided(LifetimeRes::Static {
+                            suppress_elision_warning: true,
+                        }),
+                        |this| {
+                            this.visit_ty(ty);
+                        },
+                    );
                     if let Some(expr) = expr {
                         // We already forbid generic params because of the above item rib,
                         // so it doesn't matter whether this is a trivial constant.
@@ -2589,7 +2642,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                         this.visit_generics(generics);
 
                         this.with_lifetime_rib(
-                            LifetimeRibKind::Elided(LifetimeRes::Static),
+                            LifetimeRibKind::Elided(LifetimeRes::Static {
+                                suppress_elision_warning: true,
+                            }),
                             |this| this.visit_ty(ty),
                         );
 
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index f778b0ee3ac..8f516c2db09 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -102,6 +102,13 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str
 pub(super) struct MissingLifetime {
     /// Used to overwrite the resolution with the suggestion, to avoid cascading errors.
     pub id: NodeId,
+    /// As we cannot yet emit lints in this crate and have to buffer them instead,
+    /// we need to associate each lint with some `NodeId`,
+    /// however for some `MissingLifetime`s their `NodeId`s are "fake",
+    /// in a sense that they are temporary and not get preserved down the line,
+    /// which means that the lints for those nodes will not get emitted.
+    /// To combat this, we can try to use some other `NodeId`s as a fallback option.
+    pub id_for_lint: NodeId,
     /// Where to suggest adding the lifetime.
     pub span: Span,
     /// How the lifetime was introduced, to have the correct space and comma.
@@ -3028,7 +3035,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     maybe_static = true;
                     in_scope_lifetimes = vec![(
                         Ident::with_dummy_span(kw::StaticLifetime),
-                        (DUMMY_NODE_ID, LifetimeRes::Static),
+                        (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
                     )];
                 }
             } else if elided_len == 0 {
@@ -3040,7 +3047,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                     maybe_static = true;
                     in_scope_lifetimes = vec![(
                         Ident::with_dummy_span(kw::StaticLifetime),
-                        (DUMMY_NODE_ID, LifetimeRes::Static),
+                        (DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
                     )];
                 }
             } else if num_params == 1 {
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index e628be1546f..bc8b7e24bf1 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -2313,7 +2313,7 @@ impl<'b> Pattern for &'b String {
     }
 
     #[inline]
-    fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&str>
+    fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
     where
         Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
     {
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
index f29ac99b292..eee4a9e4c6c 100644
--- a/library/core/src/fmt/rt.rs
+++ b/library/core/src/fmt/rt.rs
@@ -110,43 +110,43 @@ impl<'a> Argument<'a> {
     }
 
     #[inline(always)]
-    pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> {
+    pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'b> {
         Self::new(x, Display::fmt)
     }
     #[inline(always)]
-    pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'_> {
+    pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'b> {
         Self::new(x, Debug::fmt)
     }
     #[inline(always)]
-    pub fn new_debug_noop<'b, T: Debug>(x: &'b T) -> Argument<'_> {
+    pub fn new_debug_noop<'b, T: Debug>(x: &'b T) -> Argument<'b> {
         Self::new(x, |_, _| Ok(()))
     }
     #[inline(always)]
-    pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'_> {
+    pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'b> {
         Self::new(x, Octal::fmt)
     }
     #[inline(always)]
-    pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'_> {
+    pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'b> {
         Self::new(x, LowerHex::fmt)
     }
     #[inline(always)]
-    pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'_> {
+    pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'b> {
         Self::new(x, UpperHex::fmt)
     }
     #[inline(always)]
-    pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'_> {
+    pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'b> {
         Self::new(x, Pointer::fmt)
     }
     #[inline(always)]
-    pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'_> {
+    pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'b> {
         Self::new(x, Binary::fmt)
     }
     #[inline(always)]
-    pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'_> {
+    pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'b> {
         Self::new(x, LowerExp::fmt)
     }
     #[inline(always)]
-    pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'_> {
+    pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'b> {
         Self::new(x, UpperExp::fmt)
     }
     #[inline(always)]
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
index f325d27b8c7..50f845e2d92 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
@@ -1,3 +1,14 @@
+error: elided lifetime has a name
+  --> tests/ui/needless_lifetimes.rs:266:52
+   |
+LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
+   |                              --                    ^ this elided lifetime gets resolved as `'a`
+   |                              |
+   |                              lifetime `'a` declared here
+   |
+   = note: `-D elided-named-lifetimes` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
+
 error: the following explicit lifetimes could be elided: 'a, 'b
   --> tests/ui/needless_lifetimes.rs:17:23
    |
@@ -553,5 +564,5 @@ LL -         fn one_input<'a>(x: &'a u8) -> &'a u8 {
 LL +         fn one_input(x: &u8) -> &u8 {
    |
 
-error: aborting due to 46 previous errors
+error: aborting due to 47 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index 1848ef80fc4..4246453e64c 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -1,3 +1,12 @@
+error: elided lifetime has a name
+  --> tests/ui/ptr_arg.rs:295:56
+   |
+LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
+   |                        -- lifetime `'a` declared here  ^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `-D elided-named-lifetimes` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
+
 error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
   --> tests/ui/ptr_arg.rs:13:14
    |
@@ -212,5 +221,5 @@ error: using a reference to `Cow` is not recommended
 LL |     fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str {
    |                                        ^^^^^^^^^^^^^^^^ help: change this to: `&str`
 
-error: aborting due to 24 previous errors
+error: aborting due to 25 previous errors
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index 198dc93f6b1..c0547bc3c8d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -117,7 +117,7 @@ impl Attrs {
 }
 
 impl Attrs {
-    pub fn by_key<'attrs>(&'attrs self, key: &'attrs Symbol) -> AttrQuery<'_> {
+    pub fn by_key<'attrs>(&'attrs self, key: &'attrs Symbol) -> AttrQuery<'attrs> {
         AttrQuery { attrs: self, key }
     }
 
@@ -594,7 +594,7 @@ impl<'attr> AttrQuery<'attr> {
     /// #[doc(html_root_url = "url")]
     ///       ^^^^^^^^^^^^^ key
     /// ```
-    pub fn find_string_value_in_tt(self, key: &'attr Symbol) -> Option<&str> {
+    pub fn find_string_value_in_tt(self, key: &'attr Symbol) -> Option<&'attr str> {
         self.tt_values().find_map(|tt| {
             let name = tt.token_trees.iter()
                 .skip_while(|tt| !matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym, ..} )) if *sym == *key))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index f5fe8f87701..dde1f142ab0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -197,7 +197,7 @@ impl Body {
     pub fn blocks<'a>(
         &'a self,
         db: &'a dyn DefDatabase,
-    ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + '_ {
+    ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + 'a {
         self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
     }
 
diff --git a/tests/ui/async-await/issues/issue-63388-1.rs b/tests/ui/async-await/issues/issue-63388-1.rs
index 32026a22a16..a6f499ba94e 100644
--- a/tests/ui/async-await/issues/issue-63388-1.rs
+++ b/tests/ui/async-await/issues/issue-63388-1.rs
@@ -9,7 +9,7 @@ trait Foo {}
 impl Xyz {
     async fn do_sth<'a>(
         &'a self, foo: &dyn Foo
-    ) -> &dyn Foo
+    ) -> &dyn Foo  //~ WARNING elided lifetime has a name
     {
         //~^ ERROR explicit lifetime required in the type of `foo` [E0621]
         foo
diff --git a/tests/ui/async-await/issues/issue-63388-1.stderr b/tests/ui/async-await/issues/issue-63388-1.stderr
index f7f285ad0cc..ef74bfe3237 100644
--- a/tests/ui/async-await/issues/issue-63388-1.stderr
+++ b/tests/ui/async-await/issues/issue-63388-1.stderr
@@ -1,3 +1,14 @@
+warning: elided lifetime has a name
+  --> $DIR/issue-63388-1.rs:12:10
+   |
+LL |     async fn do_sth<'a>(
+   |                     -- lifetime `'a` declared here
+LL |         &'a self, foo: &dyn Foo
+LL |     ) -> &dyn Foo
+   |          ^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
 error[E0621]: explicit lifetime required in the type of `foo`
   --> $DIR/issue-63388-1.rs:13:5
    |
@@ -10,6 +21,6 @@ LL | |         foo
 LL | |     }
    | |_____^ lifetime `'a` required
 
-error: aborting due to 1 previous error
+error: aborting due to 1 previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0621`.
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
new file mode 100644
index 00000000000..177ff20fbf9
--- /dev/null
+++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr
@@ -0,0 +1,10 @@
+warning: elided lifetime has a name
+  --> $DIR/issue-71348.rs:18:68
+   |
+LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
+   |            -- lifetime `'a` declared here                          ^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
index 858900a500d..5aee282952a 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
+++ b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr
@@ -1,3 +1,11 @@
+warning: elided lifetime has a name
+  --> $DIR/issue-71348.rs:18:68
+   |
+LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
+   |            -- lifetime `'a` declared here                          ^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
 error: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/issue-71348.rs:10:24
    |
@@ -30,5 +38,5 @@ help: add `#![feature(unsized_const_params)]` to the crate attributes to enable
 LL + #![feature(unsized_const_params)]
    |
 
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs
index 2ffbd015485..97e786405fe 100644
--- a/tests/ui/const-generics/type-dependent/issue-71348.rs
+++ b/tests/ui/const-generics/type-dependent/issue-71348.rs
@@ -17,6 +17,7 @@ trait Get<'a, const N: &'static str> {
 impl Foo {
     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
     //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter
+    //~^^ WARNING elided lifetime has a name
     where
         Self: Get<'a, N>,
     {
diff --git a/tests/ui/consts/min_const_fn/min_const_fn.rs b/tests/ui/consts/min_const_fn/min_const_fn.rs
index 76245c08ffc..f7663f6044e 100644
--- a/tests/ui/consts/min_const_fn/min_const_fn.rs
+++ b/tests/ui/consts/min_const_fn/min_const_fn.rs
@@ -44,8 +44,8 @@ impl<T> Foo<T> {
 impl<'a, T> Foo<T> {
     const fn new_lt(t: T) -> Self { Foo(t) }
     const fn into_inner_lt(self) -> T { self.0 } //~ destructor of
-    const fn get_lt(&'a self) -> &T { &self.0 }
-    const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+    const fn get_lt(&'a self) -> &T { &self.0 } //~ WARNING elided lifetime has a name
+    const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } //~ WARNING elided lifetime has a name
     //~^ mutable references
     //~| mutable references
     //~| mutable references
diff --git a/tests/ui/consts/min_const_fn/min_const_fn.stderr b/tests/ui/consts/min_const_fn/min_const_fn.stderr
index daa0ab2614f..4b348a182b8 100644
--- a/tests/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/tests/ui/consts/min_const_fn/min_const_fn.stderr
@@ -1,3 +1,23 @@
+warning: elided lifetime has a name
+  --> $DIR/min_const_fn.rs:47:34
+   |
+LL | impl<'a, T> Foo<T> {
+   |      -- lifetime `'a` declared here
+...
+LL |     const fn get_lt(&'a self) -> &T { &self.0 }
+   |                                  ^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
+warning: elided lifetime has a name
+  --> $DIR/min_const_fn.rs:48:42
+   |
+LL | impl<'a, T> Foo<T> {
+   |      -- lifetime `'a` declared here
+...
+LL |     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+   |                                          ^ this elided lifetime gets resolved as `'a`
+
 error[E0493]: destructor of `Foo<T>` cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:37:25
    |
@@ -228,7 +248,7 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                  |
    |                  the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 24 previous errors
+error: aborting due to 24 previous errors; 2 warnings emitted
 
 Some errors have detailed explanations: E0493, E0658.
 For more information about an error, try `rustc --explain E0493`.
diff --git a/tests/ui/generics/generic-no-mangle.fixed b/tests/ui/generics/generic-no-mangle.fixed
index 69db712f9dc..2776848c45f 100644
--- a/tests/ui/generics/generic-no-mangle.fixed
+++ b/tests/ui/generics/generic-no-mangle.fixed
@@ -1,5 +1,5 @@
 //@ run-rustfix
-#![allow(dead_code)]
+#![allow(dead_code, elided_named_lifetimes)]
 #![deny(no_mangle_generic_items)]
 
 pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
diff --git a/tests/ui/generics/generic-no-mangle.rs b/tests/ui/generics/generic-no-mangle.rs
index 2288b5bbe70..5314005d31f 100644
--- a/tests/ui/generics/generic-no-mangle.rs
+++ b/tests/ui/generics/generic-no-mangle.rs
@@ -1,5 +1,5 @@
 //@ run-rustfix
-#![allow(dead_code)]
+#![allow(dead_code, elided_named_lifetimes)]
 #![deny(no_mangle_generic_items)]
 
 #[no_mangle]
diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs
index da7530b4e7a..a7f38b5c16a 100644
--- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs
+++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs
@@ -13,6 +13,7 @@ fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
 
 fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
     //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
+    //~| WARNING elided lifetime has a name
     |x| x
 }
 
diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
index 7d108b30b76..d0f8f7689d1 100644
--- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
+++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
@@ -1,5 +1,5 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/impl-fn-hrtb-bounds.rs:19:38
+  --> $DIR/impl-fn-hrtb-bounds.rs:20:38
    |
 LL | fn d() -> impl Fn() -> (impl Debug + '_) {
    |                                      ^^ expected named lifetime parameter
@@ -10,6 +10,14 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're
 LL | fn d() -> impl Fn() -> (impl Debug + 'static) {
    |                                      ~~~~~~~
 
+warning: elided lifetime has a name
+  --> $DIR/impl-fn-hrtb-bounds.rs:14:52
+   |
+LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
+   |                    -- lifetime `'a` declared here  ^^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
 error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
   --> $DIR/impl-fn-hrtb-bounds.rs:4:41
    |
@@ -46,7 +54,7 @@ note: lifetime declared here
 LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
    |                    ^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 4 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0106, E0657.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs
index 8aba3de530b..2f17c0ff508 100644
--- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs
+++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs
@@ -3,6 +3,7 @@ use std::fmt::Debug;
 
 fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
     //~^ ERROR cannot resolve opaque type
+    //~| WARNING elided lifetime has a name
     |x| x
     //~^ ERROR expected generic lifetime parameter, found `'_`
 }
diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
index c2386e8c88b..50a9f3ebeab 100644
--- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
+++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr
@@ -1,9 +1,17 @@
+warning: elided lifetime has a name
+  --> $DIR/impl-fn-predefined-lifetimes.rs:4:48
+   |
+LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
+   |      -- lifetime `'a` declared here            ^^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
 error[E0792]: expected generic lifetime parameter, found `'_`
-  --> $DIR/impl-fn-predefined-lifetimes.rs:6:9
+  --> $DIR/impl-fn-predefined-lifetimes.rs:7:9
    |
 LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
    |                                                -- this generic parameter must be used with a generic lifetime parameter
-LL |
+...
 LL |     |x| x
    |         ^
 
@@ -13,7 +21,7 @@ error[E0720]: cannot resolve opaque type
 LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
    |                                   ^^^^^^^^^^^^^^^ cannot resolve opaque type
 
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0720, E0792.
 For more information about an error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
index 73c8a6c0aed..e48441f533d 100644
--- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
+++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
@@ -1,6 +1,7 @@
 //@ check-pass
 
 pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
+    //~^ WARNING elided lifetime has a name
     v.into_iter()
 }
 
diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
new file mode 100644
index 00000000000..bff3ffd934a
--- /dev/null
+++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
@@ -0,0 +1,10 @@
+warning: elided lifetime has a name
+  --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:82
+   |
+LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
+   |             -- lifetime `'a` declared here                                       ^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs
index d0a8fe795ef..63a2c9be9eb 100644
--- a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs
+++ b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.rs
@@ -47,5 +47,6 @@ fn l<'a>(_: &'a str, _: &'a str) -> &str { "" }
 
 // This is ok because both `'a` are for the same parameter.
 fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
+//~^ WARNING elided lifetime has a name
 
 fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
index 23ef36888f0..f835d2655bb 100644
--- a/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
+++ b/tests/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
@@ -105,6 +105,16 @@ help: consider using the `'a` lifetime
 LL | fn l<'a>(_: &'a str, _: &'a str) -> &'a str { "" }
    |                                      ++
 
-error: aborting due to 7 previous errors
+warning: elided lifetime has a name
+  --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:49:29
+   |
+LL | fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
+   |      --                     ^ this elided lifetime gets resolved as `'a`
+   |      |
+   |      lifetime `'a` declared here
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
+error: aborting due to 7 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs
index a1126d6bb15..598633d7576 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.rs
@@ -4,6 +4,7 @@ struct Foo {
 
 impl Foo {
   fn foo<'a>(&'a self, x: &i32) -> &i32 {
+    //~^ WARNING elided lifetime has a name
 
     if true { &self.field } else { x } //~ ERROR explicit lifetime
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr
index 6dda9e61a79..2d5d4fb0e72 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr
@@ -1,12 +1,22 @@
+warning: elided lifetime has a name
+  --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:6:36
+   |
+LL |   fn foo<'a>(&'a self, x: &i32) -> &i32 {
+   |          --                        ^ this elided lifetime gets resolved as `'a`
+   |          |
+   |          lifetime `'a` declared here
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
 error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:8:36
+  --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:9:36
    |
 LL |   fn foo<'a>(&'a self, x: &i32) -> &i32 {
    |                           ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
-LL |
+...
 LL |     if true { &self.field } else { x }
    |                                    ^ lifetime `'a` required
 
-error: aborting due to 1 previous error
+error: aborting due to 1 previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0621`.
diff --git a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs
new file mode 100644
index 00000000000..eac7c32a9aa
--- /dev/null
+++ b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.rs
@@ -0,0 +1,12 @@
+#![deny(elided_named_lifetimes)]
+
+struct Foo;
+
+impl Foo {
+    pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
+        //~^ ERROR elided lifetime has a name
+        unsafe { &mut *(x as *mut _) }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr
new file mode 100644
index 00000000000..8c5426a60cb
--- /dev/null
+++ b/tests/ui/lint/elided-named-lifetimes/example-from-issue48686.stderr
@@ -0,0 +1,14 @@
+error: elided lifetime has a name
+  --> $DIR/example-from-issue48686.rs:6:50
+   |
+LL |     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
+   |                                                  ^ this elided lifetime gets resolved as `'static`
+   |
+note: the lint level is defined here
+  --> $DIR/example-from-issue48686.rs:1:9
+   |
+LL | #![deny(elided_named_lifetimes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs b/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs
new file mode 100644
index 00000000000..2f9083ed65f
--- /dev/null
+++ b/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.rs
@@ -0,0 +1,27 @@
+#![deny(elided_named_lifetimes)]
+
+fn ampersand<'a>(x: &'a u8) -> &u8 {
+    //~^ ERROR elided lifetime has a name
+    x
+}
+
+struct Brackets<'a>(&'a u8);
+
+fn brackets<'a>(x: &'a u8) -> Brackets {
+    //~^ ERROR elided lifetime has a name
+    Brackets(x)
+}
+
+struct Comma<'a, T>(&'a T);
+
+fn comma<'a>(x: &'a u8) -> Comma<u8> {
+    //~^ ERROR elided lifetime has a name
+    Comma(x)
+}
+
+fn underscore<'a>(x: &'a u8) -> &'_ u8 {
+    //~^ ERROR elided lifetime has a name
+    x
+}
+
+fn main() {}
diff --git a/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr b/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr
new file mode 100644
index 00000000000..249ae146b16
--- /dev/null
+++ b/tests/ui/lint/elided-named-lifetimes/missing-lifetime-kind.stderr
@@ -0,0 +1,40 @@
+error: elided lifetime has a name
+  --> $DIR/missing-lifetime-kind.rs:3:32
+   |
+LL | fn ampersand<'a>(x: &'a u8) -> &u8 {
+   |              --                ^ this elided lifetime gets resolved as `'a`
+   |              |
+   |              lifetime `'a` declared here
+   |
+note: the lint level is defined here
+  --> $DIR/missing-lifetime-kind.rs:1:9
+   |
+LL | #![deny(elided_named_lifetimes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: elided lifetime has a name
+  --> $DIR/missing-lifetime-kind.rs:10:31
+   |
+LL | fn brackets<'a>(x: &'a u8) -> Brackets {
+   |             --                ^^^^^^^^ this elided lifetime gets resolved as `'a`
+   |             |
+   |             lifetime `'a` declared here
+
+error: elided lifetime has a name
+  --> $DIR/missing-lifetime-kind.rs:17:33
+   |
+LL | fn comma<'a>(x: &'a u8) -> Comma<u8> {
+   |          --                     ^ this elided lifetime gets resolved as `'a`
+   |          |
+   |          lifetime `'a` declared here
+
+error: elided lifetime has a name
+  --> $DIR/missing-lifetime-kind.rs:22:34
+   |
+LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 {
+   |               --                 ^^ this elided lifetime gets resolved as `'a`
+   |               |
+   |               lifetime `'a` declared here
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs
new file mode 100644
index 00000000000..4f9218130fb
--- /dev/null
+++ b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.rs
@@ -0,0 +1,17 @@
+#![allow(elided_named_lifetimes)]
+
+#[warn(elided_named_lifetimes)]
+mod foo {
+    fn bar(x: &'static u8) -> &u8 {
+        //~^ WARNING elided lifetime has a name
+        x
+    }
+
+    #[deny(elided_named_lifetimes)]
+    fn baz(x: &'static u8) -> &u8 {
+        //~^ ERROR elided lifetime has a name
+        x
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr
new file mode 100644
index 00000000000..c465aab1a03
--- /dev/null
+++ b/tests/ui/lint/elided-named-lifetimes/not-tied-to-crate.stderr
@@ -0,0 +1,26 @@
+warning: elided lifetime has a name
+  --> $DIR/not-tied-to-crate.rs:5:31
+   |
+LL |     fn bar(x: &'static u8) -> &u8 {
+   |                               ^ this elided lifetime gets resolved as `'static`
+   |
+note: the lint level is defined here
+  --> $DIR/not-tied-to-crate.rs:3:8
+   |
+LL | #[warn(elided_named_lifetimes)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^
+
+error: elided lifetime has a name
+  --> $DIR/not-tied-to-crate.rs:11:31
+   |
+LL |     fn baz(x: &'static u8) -> &u8 {
+   |                               ^ this elided lifetime gets resolved as `'static`
+   |
+note: the lint level is defined here
+  --> $DIR/not-tied-to-crate.rs:10:12
+   |
+LL |     #[deny(elided_named_lifetimes)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error; 1 warning emitted
+
diff --git a/tests/ui/lint/elided-named-lifetimes/static.rs b/tests/ui/lint/elided-named-lifetimes/static.rs
new file mode 100644
index 00000000000..dc8222c6e6e
--- /dev/null
+++ b/tests/ui/lint/elided-named-lifetimes/static.rs
@@ -0,0 +1,46 @@
+#![deny(elided_named_lifetimes)]
+
+use std::borrow::Cow;
+
+const A: &[u8] = &[];
+static B: &str = "hello";
+
+trait Trait {
+    const C: &u8 = &0;
+}
+
+impl Trait for () {
+    const C: &u8 = &1;
+}
+
+fn ampersand(x: &'static u8) -> &u8 {
+    //~^ ERROR elided lifetime has a name
+    x
+}
+
+struct Brackets<'a>(&'a u8);
+
+fn brackets(x: &'static u8) -> Brackets {
+    //~^ ERROR elided lifetime has a name
+    Brackets(x)
+}
+
+struct Comma<'a, T>(&'a T);
+
+fn comma(x: &'static u8) -> Comma<u8> {
+    //~^ ERROR elided lifetime has a name
+    Comma(x)
+}
+
+fn underscore(x: &'static u8) -> &'_ u8 {
+    //~^ ERROR elided lifetime has a name
+    x
+}
+
+const NESTED: &Vec<&Box<Cow<str>>> = &vec![];
+
+fn main() {
+    const HELLO: &str = "Hello";
+    static WORLD: &str = "world";
+    println!("{HELLO}, {WORLD}!")
+}
diff --git a/tests/ui/lint/elided-named-lifetimes/static.stderr b/tests/ui/lint/elided-named-lifetimes/static.stderr
new file mode 100644
index 00000000000..d2e9776cb4f
--- /dev/null
+++ b/tests/ui/lint/elided-named-lifetimes/static.stderr
@@ -0,0 +1,32 @@
+error: elided lifetime has a name
+  --> $DIR/static.rs:16:33
+   |
+LL | fn ampersand(x: &'static u8) -> &u8 {
+   |                                 ^ this elided lifetime gets resolved as `'static`
+   |
+note: the lint level is defined here
+  --> $DIR/static.rs:1:9
+   |
+LL | #![deny(elided_named_lifetimes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: elided lifetime has a name
+  --> $DIR/static.rs:23:32
+   |
+LL | fn brackets(x: &'static u8) -> Brackets {
+   |                                ^^^^^^^^ this elided lifetime gets resolved as `'static`
+
+error: elided lifetime has a name
+  --> $DIR/static.rs:30:34
+   |
+LL | fn comma(x: &'static u8) -> Comma<u8> {
+   |                                  ^ this elided lifetime gets resolved as `'static`
+
+error: elided lifetime has a name
+  --> $DIR/static.rs:35:35
+   |
+LL | fn underscore(x: &'static u8) -> &'_ u8 {
+   |                                   ^^ this elided lifetime gets resolved as `'static`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/object-lifetime/object-lifetime-default-elision.rs b/tests/ui/object-lifetime/object-lifetime-default-elision.rs
index f7c0261cfbb..ede6af51174 100644
--- a/tests/ui/object-lifetime/object-lifetime-default-elision.rs
+++ b/tests/ui/object-lifetime/object-lifetime-default-elision.rs
@@ -46,6 +46,8 @@ fn load1(ss: &dyn SomeTrait) -> &dyn SomeTrait {
 }
 
 fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait {
+    //~^ WARNING elided lifetime has a name
+
     // Same as `load1` but with an explicit name thrown in for fun.
 
     ss
diff --git a/tests/ui/object-lifetime/object-lifetime-default-elision.stderr b/tests/ui/object-lifetime/object-lifetime-default-elision.stderr
index b5995687927..b44a184c684 100644
--- a/tests/ui/object-lifetime/object-lifetime-default-elision.stderr
+++ b/tests/ui/object-lifetime/object-lifetime-default-elision.stderr
@@ -1,5 +1,15 @@
+warning: elided lifetime has a name
+  --> $DIR/object-lifetime-default-elision.rs:48:40
+   |
+LL | fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait {
+   |          --                            ^ this elided lifetime gets resolved as `'a`
+   |          |
+   |          lifetime `'a` declared here
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
 error: lifetime may not live long enough
-  --> $DIR/object-lifetime-default-elision.rs:71:5
+  --> $DIR/object-lifetime-default-elision.rs:73:5
    |
 LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
    |          -- -- lifetime `'b` defined here
@@ -11,5 +21,5 @@ LL |     ss
    |
    = help: consider adding the following bound: `'a: 'b`
 
-error: aborting due to 1 previous error
+error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
index f7f61b8c810..cedc6f0f9bc 100644
--- a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
+++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs
@@ -4,9 +4,11 @@ struct Foo<'a>(&'a str);
 
 impl<'b> Foo<'b> {
     fn a<'a>(self: Self, a: &'a str) -> &str {
+        //~^ WARNING elided lifetime has a name
         a
     }
     fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
+        //~^ WARNING elided lifetime has a name
         a
     }
 }
diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
new file mode 100644
index 00000000000..4465dbae529
--- /dev/null
+++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr
@@ -0,0 +1,16 @@
+warning: elided lifetime has a name
+  --> $DIR/ignore-non-reference-lifetimes.rs:6:41
+   |
+LL |     fn a<'a>(self: Self, a: &'a str) -> &str {
+   |          -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
+warning: elided lifetime has a name
+  --> $DIR/ignore-non-reference-lifetimes.rs:10:44
+   |
+LL |     fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
+   |          -- lifetime `'a` declared here    ^ this elided lifetime gets resolved as `'a`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/self/elision/lt-ref-self-async.fixed b/tests/ui/self/elision/lt-ref-self-async.fixed
index aa1d62012da..914511641b8 100644
--- a/tests/ui/self/elision/lt-ref-self-async.fixed
+++ b/tests/ui/self/elision/lt-ref-self-async.fixed
@@ -1,6 +1,6 @@
 //@ edition:2018
 //@ run-rustfix
-#![allow(non_snake_case, dead_code)]
+#![allow(non_snake_case, dead_code, elided_named_lifetimes)]
 
 use std::pin::Pin;
 
diff --git a/tests/ui/self/elision/lt-ref-self-async.rs b/tests/ui/self/elision/lt-ref-self-async.rs
index 38de0fd39f0..0c11b271c35 100644
--- a/tests/ui/self/elision/lt-ref-self-async.rs
+++ b/tests/ui/self/elision/lt-ref-self-async.rs
@@ -1,6 +1,6 @@
 //@ edition:2018
 //@ run-rustfix
-#![allow(non_snake_case, dead_code)]
+#![allow(non_snake_case, dead_code, elided_named_lifetimes)]
 
 use std::pin::Pin;
 
diff --git a/tests/ui/self/self_lifetime-async.rs b/tests/ui/self/self_lifetime-async.rs
index 7d6eb3f5eaf..fd690207118 100644
--- a/tests/ui/self/self_lifetime-async.rs
+++ b/tests/ui/self/self_lifetime-async.rs
@@ -4,11 +4,13 @@
 struct Foo<'a>(&'a ());
 impl<'a> Foo<'a> {
     async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
+    //~^ WARNING elided lifetime has a name
 }
 
 type Alias = Foo<'static>;
 impl Alias {
     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
+    //~^ WARNING elided lifetime has a name
 }
 
 fn main() {}
diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr
new file mode 100644
index 00000000000..32de3fd18c9
--- /dev/null
+++ b/tests/ui/self/self_lifetime-async.stderr
@@ -0,0 +1,18 @@
+warning: elided lifetime has a name
+  --> $DIR/self_lifetime-async.rs:6:44
+   |
+LL |     async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
+   |                  --                        ^ this elided lifetime gets resolved as `'b`
+   |                  |
+   |                  lifetime `'b` declared here
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
+warning: elided lifetime has a name
+  --> $DIR/self_lifetime-async.rs:12:52
+   |
+LL |     async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
+   |                  -- lifetime `'a` declared here    ^ this elided lifetime gets resolved as `'a`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/self/self_lifetime.rs b/tests/ui/self/self_lifetime.rs
index 3f655b960b1..0607c3b9317 100644
--- a/tests/ui/self/self_lifetime.rs
+++ b/tests/ui/self/self_lifetime.rs
@@ -5,11 +5,13 @@
 struct Foo<'a>(&'a ());
 impl<'a> Foo<'a> {
     fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
+    //~^ WARNING elided lifetime has a name
 }
 
 type Alias = Foo<'static>;
 impl Alias {
     fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
+    //~^ WARNING elided lifetime has a name
 }
 
 fn main() {}
diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr
new file mode 100644
index 00000000000..cd8f4d8adf8
--- /dev/null
+++ b/tests/ui/self/self_lifetime.stderr
@@ -0,0 +1,18 @@
+warning: elided lifetime has a name
+  --> $DIR/self_lifetime.rs:7:38
+   |
+LL |     fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
+   |            --                        ^ this elided lifetime gets resolved as `'b`
+   |            |
+   |            lifetime `'b` declared here
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
+warning: elided lifetime has a name
+  --> $DIR/self_lifetime.rs:13:46
+   |
+LL |     fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
+   |            -- lifetime `'a` declared here    ^ this elided lifetime gets resolved as `'a`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs
index 735efe89cba..daec66709b6 100644
--- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs
+++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs
@@ -64,6 +64,7 @@ mod in_path {
 
 // This must not err, as the `&` actually resolves to `'a`.
 fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) {
+    //~^ WARNING elided lifetime has a name
     f("f");
 }
 
diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
index 61a2925f582..30f4509d49d 100644
--- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
+++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
@@ -124,6 +124,14 @@ LL -     fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() }
 LL +     fn g(mut x: impl Foo<()>) -> Option<()> { x.next() }
    |
 
+warning: elided lifetime has a name
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:66:57
+   |
+LL | fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) {
+   |                       -- lifetime `'a` declared here    ^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
 error[E0658]: anonymous lifetimes in `impl Trait` are unstable
   --> $DIR/impl-trait-missing-lifetime-gated.rs:6:35
    |
@@ -244,7 +252,7 @@ help: consider introducing a named lifetime parameter
 LL |     fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() }
    |         ++++                 +++
 
-error: aborting due to 16 previous errors
+error: aborting due to 16 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0106, E0658.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
index b641f5941dc..b61bea16e3b 100644
--- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
+++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
@@ -100,6 +100,7 @@ where
 
 // This also works. The `'_` isn't necessary but it's where we arrive to following the suggestions:
 fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a
+//~^ WARNING elided lifetime has a name
 where
     G: Get<T>,
 {
diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index 88a18e9d06d..ea01dcd5020 100644
--- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -6,6 +6,14 @@ LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |        |
    |        help: consider introducing lifetime `'a` here: `'a,`
 
+warning: elided lifetime has a name
+  --> $DIR/missing-lifetimes-in-signature.rs:102:64
+   |
+LL | fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a
+   |        -- lifetime `'a` declared here                          ^^ this elided lifetime gets resolved as `'a`
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
 error[E0700]: hidden type for `impl FnOnce()` captures lifetime that does not appear in bounds
   --> $DIR/missing-lifetimes-in-signature.rs:19:5
    |
@@ -125,7 +133,7 @@ help: consider adding an explicit lifetime bound
 LL |     G: Get<T> + 'a,
    |               ++++
 
-error: aborting due to 8 previous errors
+error: aborting due to 8 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0261, E0309, E0311, E0621, E0700.
 For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs
index c584a58cb32..c178fcf5a91 100644
--- a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs
+++ b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.rs
@@ -2,7 +2,7 @@
 
 type Opaque2<T> = impl Sized;
 type Opaque<'a, T> = Opaque2<T>;
-fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
+fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x } //~ WARNING elided lifetime has a name
 //~^ ERROR: hidden type for `Opaque2<T>` captures lifetime that does not appear in bounds
 
 fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr
index 03cc943d509..e2c21f1636b 100644
--- a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr
+++ b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr
@@ -1,3 +1,13 @@
+warning: elided lifetime has a name
+  --> $DIR/missing_lifetime_bound.rs:5:41
+   |
+LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
+   |             --                          ^ this elided lifetime gets resolved as `'a`
+   |             |
+   |             lifetime `'a` declared here
+   |
+   = note: `#[warn(elided_named_lifetimes)]` on by default
+
 error[E0700]: hidden type for `Opaque2<T>` captures lifetime that does not appear in bounds
   --> $DIR/missing_lifetime_bound.rs:5:47
    |
@@ -9,6 +19,6 @@ LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x }
    |             |
    |             hidden type `&'a i32` captures the lifetime `'a` as defined here
 
-error: aborting due to 1 previous error
+error: aborting due to 1 previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0700`.