about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-09-01 04:21:26 +0000
committerbors <bors@rust-lang.org>2024-09-01 04:21:26 +0000
commit78d5c04d9c64a57134e6bd39090847351379e6ae (patch)
treee4563724353b2eb1a275b4acb928133a9170341b
parent43eaa5c6246057b1675f42631967ad500eaf47d5 (diff)
parent2261ffa19fc8066b69f3498e106cd951e346e74c (diff)
downloadrust-78d5c04d9c64a57134e6bd39090847351379e6ae.tar.gz
rust-78d5c04d9c64a57134e6bd39090847351379e6ae.zip
Auto merge of #129841 - matthiaskrgr:rollup-pkavdtl, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #128495 (core: use `compare_bytes` for more slice element types)
 - #128641 (refactor: standardize duplicate processes in parser)
 - #129207 (Lint that warns when an elided lifetime ends up being a named lifetime)
 - #129493 (Create opaque definitions in resolver.)
 - #129619 (Update stacker to 0.1.17)
 - #129672 (Make option-like-enum.rs UB-free and portable)
 - #129780 (add crashtests for several old unfixed ICEs)
 - #129832 (Remove stray dot in `std::char::from_u32_unchecked` documentation)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock6
-rw-r--r--compiler/rustc_ast/src/visit.rs16
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs36
-rw-r--r--compiler/rustc_ast_lowering/src/lifetime_collector.rs2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-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/def_collector.rs116
-rw-r--r--compiler/rustc_resolve/src/late.rs81
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs11
-rw-r--r--library/alloc/src/string.rs2
-rw-r--r--library/core/src/char/mod.rs2
-rw-r--r--library/core/src/fmt/rt.rs20
-rw-r--r--library/core/src/net/parser.rs56
-rw-r--r--library/core/src/slice/cmp.rs43
-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/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr4
-rw-r--r--src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr4
-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/crashes/117460.rs8
-rw-r--r--tests/crashes/119095.rs48
-rw-r--r--tests/crashes/126443.rs15
-rw-r--r--tests/crashes/128097.rs6
-rw-r--r--tests/debuginfo/option-like-enum.rs39
-rw-r--r--tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir8
-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/coroutine/print/coroutine-print-verbose-1.stderr6
-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/nll/ty-outlives/impl-trait-captures.stderr8
-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
77 files changed, 876 insertions, 234 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 23c7a5bc60f..7244ae14fb8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4978,15 +4978,15 @@ dependencies = [
 
 [[package]]
 name = "stacker"
-version = "0.1.15"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
+checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b"
 dependencies = [
  "cc",
  "cfg-if",
  "libc",
  "psm",
- "winapi",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index fe07ec48f1f..7b041768983 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -69,14 +69,14 @@ pub enum FnKind<'a> {
     Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
 
     /// E.g., `|x, y| body`.
-    Closure(&'a ClosureBinder, &'a FnDecl, &'a Expr),
+    Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
 }
 
 impl<'a> FnKind<'a> {
     pub fn header(&self) -> Option<&'a FnHeader> {
         match *self {
             FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
-            FnKind::Closure(_, _, _) => None,
+            FnKind::Closure(..) => None,
         }
     }
 
@@ -90,7 +90,7 @@ impl<'a> FnKind<'a> {
     pub fn decl(&self) -> &'a FnDecl {
         match self {
             FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
-            FnKind::Closure(_, decl, _) => decl,
+            FnKind::Closure(_, _, decl, _) => decl,
         }
     }
 
@@ -839,7 +839,7 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
             try_visit!(walk_fn_decl(visitor, decl));
             visit_opt!(visitor, visit_block, body);
         }
-        FnKind::Closure(binder, decl, body) => {
+        FnKind::Closure(binder, _coroutine_kind, decl, body) => {
             try_visit!(visitor.visit_closure_binder(binder));
             try_visit!(walk_fn_decl(visitor, decl));
             try_visit!(visitor.visit_expr(body));
@@ -1107,7 +1107,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
         ExprKind::Closure(box Closure {
             binder,
             capture_clause,
-            coroutine_kind: _,
+            coroutine_kind,
             constness: _,
             movability: _,
             fn_decl,
@@ -1116,7 +1116,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
             fn_arg_span: _,
         }) => {
             try_visit!(visitor.visit_capture_by(capture_clause));
-            try_visit!(visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id))
+            try_visit!(visitor.visit_fn(
+                FnKind::Closure(binder, coroutine_kind, fn_decl, body),
+                *span,
+                *id
+            ))
         }
         ExprKind::Block(block, opt_label) => {
             visit_opt!(visitor, visit_label, opt_label);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index bcc2c29a2ff..754fbae4d02 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -45,7 +45,6 @@ use std::collections::hash_map::Entry;
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, *};
-use rustc_ast_pretty::pprust;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxIndexSet;
@@ -837,7 +836,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
@@ -1399,24 +1398,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span });
                         }
 
-                        let span = t.span;
-
-                        // HACK: pprust breaks strings with newlines when the type
-                        // gets too long. We don't want these to show up in compiler
-                        // output or built artifacts, so replace them here...
-                        // Perhaps we should instead format APITs more robustly.
-                        let ident = Ident::from_str_and_span(
-                            &pprust::ty_to_string(t).replace('\n', " "),
-                            span,
-                        );
-
-                        self.create_def(
-                            self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
-                            *def_node_id,
-                            ident.name,
-                            DefKind::TyParam,
-                            span,
-                        );
+                        let def_id = self.local_def_id(*def_node_id);
+                        let name = self.tcx.item_name(def_id.to_def_id());
+                        let ident = Ident::new(name, span);
                         let (param, bounds, path) = self.lower_universal_param_and_bounds(
                             *def_node_id,
                             span,
@@ -1618,13 +1602,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         opaque_ty_span: Span,
         lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
     ) -> hir::TyKind<'hir> {
-        let opaque_ty_def_id = self.create_def(
-            self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
-            opaque_ty_node_id,
-            kw::Empty,
-            DefKind::OpaqueTy,
-            opaque_ty_span,
-        );
+        let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
         debug!(?opaque_ty_def_id);
 
         // Map from captured (old) lifetime to synthetic (new) lifetime.
@@ -1656,7 +1634,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
 
                 // Opaques do not capture `'static`
-                LifetimeRes::Static | LifetimeRes::Error => {
+                LifetimeRes::Static { .. } | LifetimeRes::Error => {
                     continue;
                 }
 
@@ -2069,7 +2047,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_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index a9b65456b8c..ed9672a9e79 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1485,7 +1485,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
         let disallowed = (!tilde_const_allowed).then(|| match fk {
             FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span },
-            FnKind::Closure(_, _, _) => TildeConstReason::Closure,
+            FnKind::Closure(..) => TildeConstReason::Closure,
         });
         self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
     }
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 69cbf8c4161..38c6c8a8d11 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -22,7 +22,7 @@ rustc_index = { path = "../rustc_index", package = "rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] }
-stacker = "0.1.15"
+stacker = "0.1.17"
 tempfile = "3.2"
 thin-vec = "0.2.12"
 tracing = "0.1"
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/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 3595db78e93..a70d51606f7 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -2,6 +2,7 @@ use std::mem;
 
 use rustc_ast::visit::FnKind;
 use rustc_ast::*;
+use rustc_ast_pretty::pprust;
 use rustc_expand::expand::AstFragment;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
@@ -120,8 +121,6 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
 
 impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
     fn visit_item(&mut self, i: &'a Item) {
-        debug!("visit_item: {:?}", i);
-
         // Pick the def data. This need not be unique, but the more
         // information we encapsulate into, the better
         let mut opt_macro_data = None;
@@ -183,38 +182,51 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
     }
 
     fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
-        if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
-            match sig.header.coroutine_kind {
-                Some(coroutine_kind) => {
-                    self.visit_generics(generics);
-
-                    // For async functions, we need to create their inner defs inside of a
-                    // closure to match their desugared representation. Besides that,
-                    // we must mirror everything that `visit::walk_fn` below does.
-                    self.visit_fn_header(&sig.header);
-                    for param in &sig.decl.inputs {
-                        self.visit_param(param);
-                    }
-                    self.visit_fn_ret_ty(&sig.decl.output);
-                    // If this async fn has no body (i.e. it's an async fn signature in a trait)
-                    // then the closure_def will never be used, and we should avoid generating a
-                    // def-id for it.
-                    if let Some(body) = body {
-                        let closure_def = self.create_def(
-                            coroutine_kind.closure_id(),
-                            kw::Empty,
-                            DefKind::Closure,
-                            span,
-                        );
-                        self.with_parent(closure_def, |this| this.visit_block(body));
-                    }
-                    return;
+        match fn_kind {
+            FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body)
+                if let Some(coroutine_kind) = header.coroutine_kind =>
+            {
+                self.visit_fn_header(header);
+                self.visit_generics(generics);
+
+                // For async functions, we need to create their inner defs inside of a
+                // closure to match their desugared representation. Besides that,
+                // we must mirror everything that `visit::walk_fn` below does.
+                let FnDecl { inputs, output } = &**decl;
+                for param in inputs {
+                    self.visit_param(param);
+                }
+
+                let (return_id, return_span) = coroutine_kind.return_id();
+                let return_def =
+                    self.create_def(return_id, kw::Empty, DefKind::OpaqueTy, return_span);
+                self.with_parent(return_def, |this| this.visit_fn_ret_ty(output));
+
+                // If this async fn has no body (i.e. it's an async fn signature in a trait)
+                // then the closure_def will never be used, and we should avoid generating a
+                // def-id for it.
+                if let Some(body) = body {
+                    let closure_def = self.create_def(
+                        coroutine_kind.closure_id(),
+                        kw::Empty,
+                        DefKind::Closure,
+                        span,
+                    );
+                    self.with_parent(closure_def, |this| this.visit_block(body));
                 }
-                None => {}
             }
-        }
+            FnKind::Closure(binder, Some(coroutine_kind), decl, body) => {
+                self.visit_closure_binder(binder);
+                visit::walk_fn_decl(self, decl);
 
-        visit::walk_fn(self, fn_kind);
+                // Async closures desugar to closures inside of closures, so
+                // we must create two defs.
+                let coroutine_def =
+                    self.create_def(coroutine_kind.closure_id(), kw::Empty, DefKind::Closure, span);
+                self.with_parent(coroutine_def, |this| visit::walk_expr(this, body));
+            }
+            _ => visit::walk_fn(self, fn_kind),
+        }
     }
 
     fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
@@ -334,27 +346,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
     fn visit_expr(&mut self, expr: &'a Expr) {
         let parent_def = match expr.kind {
             ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
-            ExprKind::Closure(ref closure) => {
-                // Async closures desugar to closures inside of closures, so
-                // we must create two defs.
-                let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span);
-                match closure.coroutine_kind {
-                    Some(coroutine_kind) => {
-                        self.with_parent(closure_def, |this| {
-                            let coroutine_def = this.create_def(
-                                coroutine_kind.closure_id(),
-                                kw::Empty,
-                                DefKind::Closure,
-                                expr.span,
-                            );
-                            this.with_parent(coroutine_def, |this| visit::walk_expr(this, expr));
-                        });
-                        return;
-                    }
-                    None => closure_def,
-                }
-            }
-            ExprKind::Gen(_, _, _, _) => {
+            ExprKind::Closure(..) | ExprKind::Gen(..) => {
                 self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
             }
             ExprKind::ConstBlock(ref constant) => {
@@ -381,6 +373,26 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
             TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
             // Anonymous structs or unions are visited later after defined.
             TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {}
+            TyKind::ImplTrait(id, _) => {
+                // HACK: pprust breaks strings with newlines when the type
+                // gets too long. We don't want these to show up in compiler
+                // output or built artifacts, so replace them here...
+                // Perhaps we should instead format APITs more robustly.
+                let name = Symbol::intern(&pprust::ty_to_string(ty).replace('\n', " "));
+                let kind = match self.impl_trait_context {
+                    ImplTraitContext::Universal => DefKind::TyParam,
+                    ImplTraitContext::Existential => DefKind::OpaqueTy,
+                };
+                let id = self.create_def(*id, name, kind, ty.span);
+                match self.impl_trait_context {
+                    // Do not nest APIT, as we desugar them as `impl_trait: bounds`,
+                    // so the `impl_trait` node is not a parent to `bounds`.
+                    ImplTraitContext::Universal => visit::walk_ty(self, ty),
+                    ImplTraitContext::Existential => {
+                        self.with_parent(id, |this| visit::walk_ty(this, ty))
+                    }
+                };
+            }
             _ => visit::walk_ty(self, ty),
         }
     }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 40fdb01a72c..a0386ddcbb3 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1010,7 +1010,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                             this.in_func_body = previous_state;
                         }
                     }
-                    FnKind::Closure(binder, declaration, body) => {
+                    FnKind::Closure(binder, _, declaration, body) => {
                         this.visit_closure_binder(binder);
 
                         this.with_lifetime_rib(
@@ -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/char/mod.rs b/library/core/src/char/mod.rs
index e6574ac3c72..fa3c2075423 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -122,7 +122,7 @@ pub const fn from_u32(i: u32) -> Option<char> {
     self::convert::from_u32(i)
 }
 
-/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`].
+/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`]
 /// instead.
 #[stable(feature = "char_from_unchecked", since = "1.5.0")]
 #[rustc_const_stable(feature = "const_char_from_u32_unchecked", since = "1.81.0")]
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/library/core/src/net/parser.rs b/library/core/src/net/parser.rs
index a8ec71f0dd8..73230f6ee5b 100644
--- a/library/core/src/net/parser.rs
+++ b/library/core/src/net/parser.rs
@@ -112,18 +112,18 @@ impl<'a> Parser<'a> {
         max_digits: Option<usize>,
         allow_zero_prefix: bool,
     ) -> Option<T> {
-        // If max_digits.is_some(), then we are parsing a `u8` or `u16` and
-        // don't need to use checked arithmetic since it fits within a `u32`.
-        if let Some(max_digits) = max_digits {
-            // u32::MAX = 4_294_967_295u32, which is 10 digits long.
-            // `max_digits` must be less than 10 to not overflow a `u32`.
-            debug_assert!(max_digits < 10);
-
-            self.read_atomically(move |p| {
-                let mut result = 0_u32;
-                let mut digit_count = 0;
-                let has_leading_zero = p.peek_char() == Some('0');
+        self.read_atomically(move |p| {
+            let mut digit_count = 0;
+            let has_leading_zero = p.peek_char() == Some('0');
+
+            // If max_digits.is_some(), then we are parsing a `u8` or `u16` and
+            // don't need to use checked arithmetic since it fits within a `u32`.
+            let result = if let Some(max_digits) = max_digits {
+                // u32::MAX = 4_294_967_295u32, which is 10 digits long.
+                // `max_digits` must be less than 10 to not overflow a `u32`.
+                debug_assert!(max_digits < 10);
 
+                let mut result = 0_u32;
                 while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
                     result *= radix;
                     result += digit;
@@ -134,19 +134,9 @@ impl<'a> Parser<'a> {
                     }
                 }
 
-                if digit_count == 0 {
-                    None
-                } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 {
-                    None
-                } else {
-                    result.try_into().ok()
-                }
-            })
-        } else {
-            self.read_atomically(move |p| {
+                result.try_into().ok()
+            } else {
                 let mut result = T::ZERO;
-                let mut digit_count = 0;
-                let has_leading_zero = p.peek_char() == Some('0');
 
                 while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
                     result = result.checked_mul(radix)?;
@@ -154,15 +144,17 @@ impl<'a> Parser<'a> {
                     digit_count += 1;
                 }
 
-                if digit_count == 0 {
-                    None
-                } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 {
-                    None
-                } else {
-                    Some(result)
-                }
-            })
-        }
+                Some(result)
+            };
+
+            if digit_count == 0 {
+                None
+            } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 {
+                None
+            } else {
+                result
+            }
+        })
     }
 
     /// Reads an IPv4 address.
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index d19d0eae166..1769612def0 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -3,7 +3,8 @@
 use super::{from_raw_parts, memchr};
 use crate::cmp::{self, BytewiseEq, Ordering};
 use crate::intrinsics::compare_bytes;
-use crate::mem;
+use crate::num::NonZero;
+use crate::{ascii, mem};
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, U> PartialEq<[U]> for [T]
@@ -182,19 +183,41 @@ impl<A: Ord> SliceOrd for A {
     }
 }
 
-// `compare_bytes` compares a sequence of unsigned bytes lexicographically.
-// this matches the order we want for [u8], but no others (not even [i8]).
-impl SliceOrd for u8 {
+/// Marks that a type should be treated as an unsigned byte for comparisons.
+///
+/// # Safety
+/// * The type must be readable as an `u8`, meaning it has to have the same
+///   layout as `u8` and always be initialized.
+/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
+///   value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
+#[rustc_specialization_trait]
+unsafe trait UnsignedBytewiseOrd {}
+
+unsafe impl UnsignedBytewiseOrd for bool {}
+unsafe impl UnsignedBytewiseOrd for u8 {}
+unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
+unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
+unsafe impl UnsignedBytewiseOrd for ascii::Char {}
+
+// `compare_bytes` compares a sequence of unsigned bytes lexicographically, so
+// use it if the requirements for `UnsignedBytewiseOrd` are fulfilled.
+impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
     #[inline]
     fn compare(left: &[Self], right: &[Self]) -> Ordering {
-        // Since the length of a slice is always less than or equal to isize::MAX, this never underflows.
+        // Since the length of a slice is always less than or equal to
+        // isize::MAX, this never underflows.
         let diff = left.len() as isize - right.len() as isize;
-        // This comparison gets optimized away (on x86_64 and ARM) because the subtraction updates flags.
+        // This comparison gets optimized away (on x86_64 and ARM) because the
+        // subtraction updates flags.
         let len = if left.len() < right.len() { left.len() } else { right.len() };
-        // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
-        // We use the minimum of both lengths which guarantees that both regions are
-        // valid for reads in that interval.
-        let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
+        let left = left.as_ptr().cast();
+        let right = right.as_ptr().cast();
+        // SAFETY: `left` and `right` are references and are thus guaranteed to
+        // be valid. `UnsignedBytewiseOrd` is only implemented for types that
+        // are valid u8s and can be compared the same way. We use the minimum
+        // of both lengths which guarantees that both regions are valid for
+        // reads in that interval.
+        let mut order = unsafe { compare_bytes(left, right, len) as isize };
         if order == 0 {
             order = diff;
         }
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/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr
index 960cae90124..dfe3ed4b522 100644
--- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr
+++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory
   --> RUSTLIB/core/src/slice/cmp.rs:LL:CC
    |
-LL |         let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory
+LL |         let mut order = unsafe { compare_bytes(left, right, len) as isize };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr
index 5439418f267..48ce9ae7656 100644
--- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr
+++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
   --> RUSTLIB/core/src/slice/cmp.rs:LL:CC
    |
-LL |         let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
+LL |         let mut order = unsafe { compare_bytes(left, right, len) as isize };
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
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/crashes/117460.rs b/tests/crashes/117460.rs
new file mode 100644
index 00000000000..4878a35ffe5
--- /dev/null
+++ b/tests/crashes/117460.rs
@@ -0,0 +1,8 @@
+//@ known-bug: #117460
+#![feature(generic_const_exprs)]
+
+struct Matrix<D = [(); 2 + 2]> {
+    d: D,
+}
+
+impl Matrix {}
diff --git a/tests/crashes/119095.rs b/tests/crashes/119095.rs
new file mode 100644
index 00000000000..28742e0d5da
--- /dev/null
+++ b/tests/crashes/119095.rs
@@ -0,0 +1,48 @@
+//@ known-bug: #119095
+//@ compile-flags: --edition=2021
+
+fn any<T>() -> T {
+    loop {}
+}
+
+trait Acquire {
+    type Connection;
+}
+
+impl Acquire for &'static () {
+    type Connection = ();
+}
+
+trait Unit {}
+impl Unit for () {}
+
+fn get_connection<T>() -> impl Unit
+where
+    T: Acquire,
+    T::Connection: Unit,
+{
+    any::<T::Connection>()
+}
+
+fn main() {
+    let future = async { async { get_connection::<&'static ()>() }.await };
+
+    future.resolve_me();
+}
+
+trait ResolveMe {
+    fn resolve_me(self);
+}
+
+impl<S> ResolveMe for S
+where
+    (): CheckSend<S>,
+{
+    fn resolve_me(self) {}
+}
+
+trait CheckSend<F> {}
+impl<F> CheckSend<F> for () where F: Send {}
+
+trait NeverImplemented {}
+impl<E, F> CheckSend<F> for E where E: NeverImplemented {}
diff --git a/tests/crashes/126443.rs b/tests/crashes/126443.rs
new file mode 100644
index 00000000000..fba779444f9
--- /dev/null
+++ b/tests/crashes/126443.rs
@@ -0,0 +1,15 @@
+//@ known-bug: #126443
+//@ compile-flags: -Copt-level=0
+#![feature(generic_const_exprs)]
+
+fn double_up<const M: usize>() -> [(); M * 2] {
+    todo!()
+}
+
+fn quadruple_up<const N: usize>() -> [(); N * 2 * 2] {
+    double_up()
+}
+
+fn main() {
+    quadruple_up::<0>();
+}
diff --git a/tests/crashes/128097.rs b/tests/crashes/128097.rs
new file mode 100644
index 00000000000..6ffca640cbd
--- /dev/null
+++ b/tests/crashes/128097.rs
@@ -0,0 +1,6 @@
+//@ known-bug: #128097
+#![feature(explicit_tail_calls)]
+fn f(x: &mut ()) {
+    let _y: String;
+    become f(x);
+}
diff --git a/tests/debuginfo/option-like-enum.rs b/tests/debuginfo/option-like-enum.rs
index d370796efa9..72a41986dce 100644
--- a/tests/debuginfo/option-like-enum.rs
+++ b/tests/debuginfo/option-like-enum.rs
@@ -8,22 +8,22 @@
 // gdb-command:run
 
 // gdb-command:print some
-// gdb-check:$1 = core::option::Option<&u32>::Some(0x12345678)
+// gdb-check:$1 = core::option::Option<&u32>::Some(0x[...])
 
 // gdb-command:print none
 // gdb-check:$2 = core::option::Option<&u32>::None
 
 // gdb-command:print full
-// gdb-check:$3 = option_like_enum::MoreFields::Full(454545, 0x87654321, 9988)
+// gdb-check:$3 = option_like_enum::MoreFields::Full(454545, 0x[...], 9988)
 
-// gdb-command:print empty_gdb.discr
-// gdb-check:$4 = (*mut isize) 0x1
+// gdb-command:print empty
+// gdb-check:$4 = option_like_enum::MoreFields::Empty
 
 // gdb-command:print droid
-// gdb-check:$5 = option_like_enum::NamedFields::Droid{id: 675675, range: 10000001, internals: 0x43218765}
+// gdb-check:$5 = option_like_enum::NamedFields::Droid{id: 675675, range: 10000001, internals: 0x[...]}
 
-// gdb-command:print void_droid_gdb.internals
-// gdb-check:$6 = (*mut isize) 0x1
+// gdb-command:print void_droid
+// gdb-check:$6 = option_like_enum::NamedFields::Void
 
 // gdb-command:print nested_non_zero_yep
 // gdb-check:$7 = option_like_enum::NestedNonZero::Yep(10.5, option_like_enum::NestedNonZeroField {a: 10, b: 20, c: 0x[...]})
@@ -39,19 +39,19 @@
 // lldb-command:run
 
 // lldb-command:v some
-// lldb-check:[...] Some(&0x12345678)
+// lldb-check:[...] Some(&0x[...])
 
 // lldb-command:v none
 // lldb-check:[...] None
 
 // lldb-command:v full
-// lldb-check:[...] Full(454545, &0x87654321, 9988)
+// lldb-check:[...] Full(454545, &0x[...], 9988)
 
 // lldb-command:v empty
 // lldb-check:[...] Empty
 
 // lldb-command:v droid
-// lldb-check:[...] Droid { id: 675675, range: 10000001, internals: &0x43218765 }
+// lldb-check:[...] Droid { id: 675675, range: 10000001, internals: &0x[...] }
 
 // lldb-command:v void_droid
 // lldb-check:[...] Void
@@ -76,11 +76,6 @@
 // contains a non-nullable pointer, then this value is used as the discriminator.
 // The test cases in this file make sure that something readable is generated for
 // this kind of types.
-// If the non-empty variant contains a single non-nullable pointer than the whole
-// item is represented as just a pointer and not wrapped in a struct.
-// Unfortunately (for these test cases) the content of the non-discriminant fields
-// in the null-case is not defined. So we just read the discriminator field in
-// this case (by casting the value to a memory-equivalent struct).
 
 enum MoreFields<'a> {
     Full(u32, &'a isize, i16),
@@ -120,32 +115,26 @@ fn main() {
     let some_str: Option<&'static str> = Some("abc");
     let none_str: Option<&'static str> = None;
 
-    let some: Option<&u32> = Some(unsafe { std::mem::transmute(0x12345678_usize) });
+    let some: Option<&u32> = Some(&1234);
     let none: Option<&u32> = None;
 
-    let full = MoreFields::Full(454545, unsafe { std::mem::transmute(0x87654321_usize) }, 9988);
-
+    let full = MoreFields::Full(454545, &1234, 9988);
     let empty = MoreFields::Empty;
-    let empty_gdb: &MoreFieldsRepr = unsafe { std::mem::transmute(&MoreFields::Empty) };
 
     let droid = NamedFields::Droid {
         id: 675675,
         range: 10000001,
-        internals: unsafe { std::mem::transmute(0x43218765_usize) }
+        internals: &1234,
     };
-
     let void_droid = NamedFields::Void;
-    let void_droid_gdb: &NamedFieldsRepr = unsafe { std::mem::transmute(&NamedFields::Void) };
 
-    let x = 'x';
     let nested_non_zero_yep = NestedNonZero::Yep(
         10.5,
         NestedNonZeroField {
             a: 10,
             b: 20,
-            c: &x
+            c: &'x',
         });
-
     let nested_non_zero_nope = NestedNonZero::Nope;
 
     zzz(); // #break
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
index c1c2fdcfa94..109a41d1ef9 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
@@ -3,14 +3,14 @@
     field_tys: {
         _0: CoroutineSavedTy {
             ty: Coroutine(
-                DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
+                DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
                 [
                     (),
                     std::future::ResumeTy,
                     (),
                     (),
                     CoroutineWitness(
-                        DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
+                        DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
                         [],
                     ),
                     (),
@@ -24,14 +24,14 @@
         },
         _1: CoroutineSavedTy {
             ty: Coroutine(
-                DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
+                DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
                 [
                     (),
                     std::future::ResumeTy,
                     (),
                     (),
                     CoroutineWitness(
-                        DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
+                        DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
                         [],
                     ),
                     (),
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/coroutine/print/coroutine-print-verbose-1.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr
index 934ab08cf17..daf88fc1f23 100644
--- a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr
+++ b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr
@@ -10,7 +10,7 @@ note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/coroutine-print-verbose-1.rs:35:9
    |
 LL |         let _non_send_gen = make_non_send_coroutine();
-   |             ------------- has type `Opaque(DefId(0:34 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine::{opaque#0}), [])` which is not `Send`
+   |             ------------- has type `Opaque(DefId(0:24 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine::{opaque#0}), [])` which is not `Send`
 LL |         yield;
    |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
 note: required by a bound in `require_send`
@@ -33,12 +33,12 @@ note: required because it's used within this coroutine
    |
 LL |     #[coroutine] || {
    |                  ^^
-note: required because it appears within the type `Opaque(DefId(0:35 ~ coroutine_print_verbose_1[75fb]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
+note: required because it appears within the type `Opaque(DefId(0:29 ~ coroutine_print_verbose_1[75fb]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
   --> $DIR/coroutine-print-verbose-1.rs:41:30
    |
 LL | pub fn make_gen2<T>(t: T) -> impl Coroutine<Return = T> {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: required because it appears within the type `Opaque(DefId(0:36 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine2::{opaque#0}), [])`
+note: required because it appears within the type `Opaque(DefId(0:32 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine2::{opaque#0}), [])`
   --> $DIR/coroutine-print-verbose-1.rs:47:34
    |
 LL | fn make_non_send_coroutine2() -> impl Coroutine<Return = Arc<RefCell<i32>>> {
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/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
index 3ceefbc4066..87bbd50a15c 100644
--- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
+++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -1,16 +1,16 @@
-error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), ['a/#0, T, 'a/#0])` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `Opaque(DefId(0:11 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), ['a/#0, T, 'a/#0])` captures lifetime that does not appear in bounds
   --> $DIR/impl-trait-captures.rs:11:5
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
    |                  --     ------------ opaque type defined here
    |                  |
-   |                  hidden type `&ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) T` captures the anonymous lifetime defined here
+   |                  hidden type `&ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_), '_)) T` captures the anonymous lifetime defined here
 LL |     x
    |     ^
    |
-help: add a `use<...>` bound to explicitly capture `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`
+help: add a `use<...>` bound to explicitly capture `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_), '_))`
    |
-LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + use<'a, ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)), T> {
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + use<'a, ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::'_), '_)), T> {
    |                                      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to 1 previous error
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`.