about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-01-13 10:02:46 +0100
committerSamuel Tardieu <sam@rfc1149.net>2025-01-13 23:34:19 +0100
commit8b7cfc75dd1925f2f5b01a6bf1291c778d2fd224 (patch)
treea227d67209c710db45ded47aac58bedf4068f9fe
parent8f257c71a3a352afa93c34f4af44143e886a2e15 (diff)
downloadrust-8b7cfc75dd1925f2f5b01a6bf1291c778d2fd224.tar.gz
rust-8b7cfc75dd1925f2f5b01a6bf1291c778d2fd224.zip
Rust 1.81 and later support elision with explicit self types
Commit 9ef6e2199c885ffd671b321dfbf16ff0934f4d80 introduced a check to
ensure that Clippy doesn't consider a lifetime present in an explicit
self type as being the default for an elided output lifetime. For
example, elision did not work in the case like:

```rust
  fn func(self: &Rc<Self>, &str) -> &str { … }
```

Since Rust 1.81.0, the lifetime in the self type is now considered
the default for elision. Elision should then be suggested when
appropriate.
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/lifetimes.rs52
-rw-r--r--clippy_utils/src/msrvs.rs2
-rw-r--r--tests/ui/needless_lifetimes.fixed28
-rw-r--r--tests/ui/needless_lifetimes.rs20
-rw-r--r--tests/ui/needless_lifetimes.stderr154
6 files changed, 184 insertions, 74 deletions
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 1e8cfe22b22..a0eae8f6d1c 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -681,7 +681,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
     store.register_late_pass(move |_| Box::new(loops::Loops::new(conf)));
     store.register_late_pass(|_| Box::<main_recursion::MainRecursion>::default());
-    store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
+    store.register_late_pass(move |_| Box::new(lifetimes::Lifetimes::new(conf)));
     store.register_late_pass(|_| Box::new(entry::HashMapPass));
     store.register_late_pass(|_| Box::new(minmax::MinMaxPass));
     store.register_late_pass(|_| Box::new(zero_div_zero::ZeroDiv));
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs
index 0d71be61651..540d8b26f8e 100644
--- a/clippy_lints/src/lifetimes.rs
+++ b/clippy_lints/src/lifetimes.rs
@@ -1,4 +1,6 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::trait_ref_of_method;
 use itertools::Itertools;
 use rustc_ast::visit::{try_visit, walk_list};
@@ -20,7 +22,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter as middle_nested_filter;
 use rustc_middle::lint::in_external_macro;
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{Ident, kw};
@@ -91,7 +93,19 @@ declare_clippy_lint! {
     "unused lifetimes in function definitions"
 }
 
-declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
+pub struct Lifetimes {
+    msrv: Msrv,
+}
+
+impl Lifetimes {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
+    }
+}
+
+impl_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
 
 impl<'tcx> LateLintPass<'tcx> for Lifetimes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
@@ -102,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
             ..
         } = item.kind
         {
-            check_fn_inner(cx, sig, Some(id), None, generics, item.span, true);
+            check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, &self.msrv);
         } else if let ItemKind::Impl(impl_) = item.kind {
             if !item.span.from_expansion() {
                 report_extra_impl_lifetimes(cx, impl_);
@@ -121,6 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
                 item.generics,
                 item.span,
                 report_extra_lifetimes,
+                &self.msrv,
             );
         }
     }
@@ -131,11 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
                 TraitFn::Required(sig) => (None, Some(sig)),
                 TraitFn::Provided(id) => (Some(id), None),
             };
-            check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true);
+            check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true, &self.msrv);
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
+#[allow(clippy::too_many_arguments)]
 fn check_fn_inner<'tcx>(
     cx: &LateContext<'tcx>,
     sig: &'tcx FnSig<'_>,
@@ -144,6 +162,7 @@ fn check_fn_inner<'tcx>(
     generics: &'tcx Generics<'_>,
     span: Span,
     report_extra_lifetimes: bool,
+    msrv: &Msrv,
 ) {
     if in_external_macro(cx.sess(), span) || has_where_lifetimes(cx, generics) {
         return;
@@ -195,7 +214,7 @@ fn check_fn_inner<'tcx>(
         }
     }
 
-    if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params) {
+    if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params, msrv) {
         if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) {
             return;
         }
@@ -216,6 +235,7 @@ fn could_use_elision<'tcx>(
     body: Option<BodyId>,
     trait_sig: Option<&[Ident]>,
     named_generics: &'tcx [GenericParam<'_>],
+    msrv: &Msrv,
 ) -> Option<(Vec<LocalDefId>, Vec<Lifetime>)> {
     // There are two scenarios where elision works:
     // * no output references, all input references have different LT
@@ -249,17 +269,17 @@ fn could_use_elision<'tcx>(
     let input_lts = input_visitor.lts;
     let output_lts = output_visitor.lts;
 
-    if let Some(trait_sig) = trait_sig {
-        if explicit_self_type(cx, func, trait_sig.first().copied()) {
-            return None;
-        }
+    if let Some(trait_sig) = trait_sig
+        && non_elidable_self_type(cx, func, trait_sig.first().copied(), msrv)
+    {
+        return None;
     }
 
     if let Some(body_id) = body {
         let body = cx.tcx.hir().body(body_id);
 
         let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
-        if explicit_self_type(cx, func, first_ident) {
+        if non_elidable_self_type(cx, func, first_ident, msrv) {
             return None;
         }
 
@@ -332,9 +352,15 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet<LocalDefI
         .collect()
 }
 
-// elision doesn't work for explicit self types, see rust-lang/rust#69064
-fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
-    if let Some(ident) = ident
+// elision doesn't work for explicit self types before Rust 1.81, see rust-lang/rust#69064
+fn non_elidable_self_type<'tcx>(
+    cx: &LateContext<'tcx>,
+    func: &FnDecl<'tcx>,
+    ident: Option<Ident>,
+    msrv: &Msrv,
+) -> bool {
+    if !msrv.meets(msrvs::EXPLICIT_SELF_TYPE_ELISION)
+        && let Some(ident) = ident
         && ident.name == kw::SelfLower
         && !func.implicit_self.has_implicit_self()
         && let Some(self_ty) = func.inputs.first()
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index 2169a5fdd63..62b70ef6af4 100644
--- a/clippy_utils/src/msrvs.rs
+++ b/clippy_utils/src/msrvs.rs
@@ -20,7 +20,7 @@ macro_rules! msrv_aliases {
 msrv_aliases! {
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY }
     1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP }
-    1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE }
+    1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION }
     1,80,0 { BOX_INTO_ITER }
     1,77,0 { C_STR_LITERALS }
     1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed
index 77188254316..86cf9a9cdb6 100644
--- a/tests/ui/needless_lifetimes.fixed
+++ b/tests/ui/needless_lifetimes.fixed
@@ -6,6 +6,7 @@
     clippy::boxed_local,
     clippy::extra_unused_type_parameters,
     clippy::needless_pass_by_value,
+    clippy::redundant_allocation,
     clippy::unnecessary_wraps,
     dyn_drop,
     clippy::get_first
@@ -443,11 +444,20 @@ mod issue7296 {
         fn implicit_mut(&mut self) -> &() {
             &()
         }
-
-        fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
+        #[clippy::msrv = "1.81"]
+        fn explicit(self: &Arc<Self>) -> &() {
+            &()
+        }
+        #[clippy::msrv = "1.81"]
+        fn explicit_mut(self: &mut Rc<Self>) -> &() {
             &()
         }
-        fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
+        #[clippy::msrv = "1.80"]
+        fn explicit_older<'a>(self: &'a Arc<Self>) -> &'a () {
+            &()
+        }
+        #[clippy::msrv = "1.80"]
+        fn explicit_mut_older<'a>(self: &'a mut Rc<Self>) -> &'a () {
             &()
         }
 
@@ -462,8 +472,16 @@ mod issue7296 {
             &()
         }
 
-        fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
-        fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
+        #[clippy::msrv = "1.81"]
+        fn explicit(self: &Arc<Self>) -> &();
+        #[clippy::msrv = "1.81"]
+        fn explicit_provided(self: &Arc<Self>) -> &() {
+            &()
+        }
+        #[clippy::msrv = "1.80"]
+        fn explicit_older<'a>(self: &'a Arc<Self>) -> &'a ();
+        #[clippy::msrv = "1.80"]
+        fn explicit_provided_older<'a>(self: &'a Arc<Self>) -> &'a () {
             &()
         }
 
diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs
index c74121d0d7b..1ee0f4c6092 100644
--- a/tests/ui/needless_lifetimes.rs
+++ b/tests/ui/needless_lifetimes.rs
@@ -6,6 +6,7 @@
     clippy::boxed_local,
     clippy::extra_unused_type_parameters,
     clippy::needless_pass_by_value,
+    clippy::redundant_allocation,
     clippy::unnecessary_wraps,
     dyn_drop,
     clippy::get_first
@@ -443,13 +444,22 @@ mod issue7296 {
         fn implicit_mut<'a>(&'a mut self) -> &'a () {
             &()
         }
-
+        #[clippy::msrv = "1.81"]
         fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
             &()
         }
+        #[clippy::msrv = "1.81"]
         fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
             &()
         }
+        #[clippy::msrv = "1.80"]
+        fn explicit_older<'a>(self: &'a Arc<Self>) -> &'a () {
+            &()
+        }
+        #[clippy::msrv = "1.80"]
+        fn explicit_mut_older<'a>(self: &'a mut Rc<Self>) -> &'a () {
+            &()
+        }
 
         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
             &()
@@ -462,10 +472,18 @@ mod issue7296 {
             &()
         }
 
+        #[clippy::msrv = "1.81"]
         fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
+        #[clippy::msrv = "1.81"]
         fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
             &()
         }
+        #[clippy::msrv = "1.80"]
+        fn explicit_older<'a>(self: &'a Arc<Self>) -> &'a ();
+        #[clippy::msrv = "1.80"]
+        fn explicit_provided_older<'a>(self: &'a Arc<Self>) -> &'a () {
+            &()
+        }
 
         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
         fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr
index 5a739201d3d..465d529bf16 100644
--- a/tests/ui/needless_lifetimes.stderr
+++ b/tests/ui/needless_lifetimes.stderr
@@ -1,5 +1,5 @@
 error: elided lifetime has a name
-  --> tests/ui/needless_lifetimes.rs:266:52
+  --> tests/ui/needless_lifetimes.rs:267:52
    |
 LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    |                              --                    ^ this elided lifetime gets resolved as `'a`
@@ -10,7 +10,7 @@ LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    = 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
+  --> tests/ui/needless_lifetimes.rs:18:23
    |
 LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
    |                       ^^  ^^       ^^          ^^
@@ -24,7 +24,7 @@ LL + fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {}
    |
 
 error: the following explicit lifetimes could be elided: 'a, 'b
-  --> tests/ui/needless_lifetimes.rs:19:24
+  --> tests/ui/needless_lifetimes.rs:20:24
    |
 LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
    |                        ^^  ^^       ^^          ^^
@@ -36,7 +36,7 @@ LL + fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {}
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:29:15
+  --> tests/ui/needless_lifetimes.rs:30:15
    |
 LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
    |               ^^      ^^                 ^^
@@ -48,7 +48,7 @@ LL + fn in_and_out(x: &u8, _y: u8) -> &u8 {
    |
 
 error: the following explicit lifetimes could be elided: 'b
-  --> tests/ui/needless_lifetimes.rs:41:31
+  --> tests/ui/needless_lifetimes.rs:42:31
    |
 LL | fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
    |                               ^^                  ^^
@@ -60,7 +60,7 @@ LL + fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:48:27
+  --> tests/ui/needless_lifetimes.rs:49:27
    |
 LL | fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 {
    |                           ^^           ^^
@@ -72,7 +72,7 @@ LL + fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 {
    |
 
 error: the following explicit lifetimes could be elided: 'b
-  --> tests/ui/needless_lifetimes.rs:65:26
+  --> tests/ui/needless_lifetimes.rs:66:26
    |
 LL | fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
    |                          ^^                  ^^
@@ -84,7 +84,7 @@ LL + fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:72:22
+  --> tests/ui/needless_lifetimes.rs:73:22
    |
 LL | fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> {
    |                      ^^           ^^
@@ -96,7 +96,7 @@ LL + fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:81:21
+  --> tests/ui/needless_lifetimes.rs:82:21
    |
 LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
    |                     ^^      ^^                        ^^
@@ -108,7 +108,7 @@ LL + fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:86:28
+  --> tests/ui/needless_lifetimes.rs:87:28
    |
 LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
    |                            ^^         ^^                        ^^
@@ -120,7 +120,7 @@ LL + fn where_clause_without_lt<T>(x: &u8, _y: u8) -> Result<&u8, ()>
    |
 
 error: the following explicit lifetimes could be elided: 'a, 'b
-  --> tests/ui/needless_lifetimes.rs:98:21
+  --> tests/ui/needless_lifetimes.rs:99:21
    |
 LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
    |                     ^^  ^^          ^^        ^^
@@ -132,7 +132,7 @@ LL + fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {}
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:122:15
+  --> tests/ui/needless_lifetimes.rs:123:15
    |
 LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
    |               ^^               ^^                   ^^
@@ -144,7 +144,7 @@ LL + fn fn_bound_2<F, I>(_m: Lt<'_, I>, _f: F) -> Lt<'_, I>
    |
 
 error: the following explicit lifetimes could be elided: 's
-  --> tests/ui/needless_lifetimes.rs:152:21
+  --> tests/ui/needless_lifetimes.rs:153:21
    |
 LL |     fn self_and_out<'s>(&'s self) -> &'s u8 {
    |                     ^^   ^^           ^^
@@ -156,7 +156,7 @@ LL +     fn self_and_out(&self) -> &u8 {
    |
 
 error: the following explicit lifetimes could be elided: 't
-  --> tests/ui/needless_lifetimes.rs:159:30
+  --> tests/ui/needless_lifetimes.rs:160:30
    |
 LL |     fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
    |                              ^^                 ^^
@@ -168,7 +168,7 @@ LL +     fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 {
    |
 
 error: the following explicit lifetimes could be elided: 's
-  --> tests/ui/needless_lifetimes.rs:166:26
+  --> tests/ui/needless_lifetimes.rs:167:26
    |
 LL |     fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 {
    |                          ^^       ^^
@@ -180,7 +180,7 @@ LL +     fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 {
    |
 
 error: the following explicit lifetimes could be elided: 's, 't
-  --> tests/ui/needless_lifetimes.rs:170:29
+  --> tests/ui/needless_lifetimes.rs:171:29
    |
 LL |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
    |                             ^^  ^^   ^^            ^^
@@ -192,7 +192,7 @@ LL +     fn distinct_self_and_in(&self, _x: &u8) {}
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:189:19
+  --> tests/ui/needless_lifetimes.rs:190:19
    |
 LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
    |                   ^^            ^^       ^^
@@ -204,7 +204,7 @@ LL + fn struct_with_lt(_foo: Foo<'_>) -> &str {
    |
 
 error: the following explicit lifetimes could be elided: 'b
-  --> tests/ui/needless_lifetimes.rs:207:25
+  --> tests/ui/needless_lifetimes.rs:208:25
    |
 LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
    |                         ^^                ^^
@@ -216,7 +216,7 @@ LL + fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:215:21
+  --> tests/ui/needless_lifetimes.rs:216:21
    |
 LL | fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str {
    |                     ^^             ^^
@@ -228,7 +228,7 @@ LL + fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:230:22
+  --> tests/ui/needless_lifetimes.rs:231:22
    |
 LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
    |                      ^^         ^^               ^^
@@ -240,7 +240,7 @@ LL + fn trait_obj_elided2(_arg: &dyn Drop) -> &str {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:236:18
+  --> tests/ui/needless_lifetimes.rs:237:18
    |
 LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
    |                  ^^                 ^^       ^^
@@ -252,7 +252,7 @@ LL + fn alias_with_lt(_foo: FooAlias<'_>) -> &str {
    |
 
 error: the following explicit lifetimes could be elided: 'b
-  --> tests/ui/needless_lifetimes.rs:254:24
+  --> tests/ui/needless_lifetimes.rs:255:24
    |
 LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
    |                        ^^                     ^^
@@ -264,7 +264,7 @@ LL + fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:262:20
+  --> tests/ui/needless_lifetimes.rs:263:20
    |
 LL | fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str {
    |                    ^^             ^^
@@ -276,7 +276,7 @@ LL + fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:266:30
+  --> tests/ui/needless_lifetimes.rs:267:30
    |
 LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    |                              ^^         ^^          ^
@@ -288,7 +288,7 @@ LL + fn named_input_elided_output(_arg: &str) -> &str {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:274:19
+  --> tests/ui/needless_lifetimes.rs:275:19
    |
 LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
    |                   ^^                                ^^
@@ -300,7 +300,7 @@ LL + fn trait_bound_ok<T: WithLifetime<'static>>(_: &u8, _: T) {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:310:24
+  --> tests/ui/needless_lifetimes.rs:311:24
    |
 LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
    |                        ^^      ^^             ^^
@@ -312,7 +312,7 @@ LL + fn out_return_type_lts(e: &str) -> Cow<'_> {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:317:24
+  --> tests/ui/needless_lifetimes.rs:318:24
    |
 LL |         fn needless_lt<'a>(x: &'a u8) {}
    |                        ^^      ^^
@@ -324,7 +324,7 @@ LL +         fn needless_lt(x: &u8) {}
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:321:24
+  --> tests/ui/needless_lifetimes.rs:322:24
    |
 LL |         fn needless_lt<'a>(_x: &'a u8) {}
    |                        ^^       ^^
@@ -336,7 +336,7 @@ LL +         fn needless_lt(_x: &u8) {}
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:332:10
+  --> tests/ui/needless_lifetimes.rs:333:10
    |
 LL |     impl<'a> Foo for Baz<'a> {}
    |          ^^              ^^
@@ -348,7 +348,7 @@ LL +     impl Foo for Baz<'_> {}
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:334:16
+  --> tests/ui/needless_lifetimes.rs:335:16
    |
 LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
    |                ^^   ^^                     ^^
@@ -360,7 +360,7 @@ LL +         fn baz(&self) -> impl Foo + '_ {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:366:55
+  --> tests/ui/needless_lifetimes.rs:367:55
    |
 LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
    |                                                       ^^      ^^                                    ^^
@@ -372,7 +372,7 @@ LL +     fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(&
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:375:26
+  --> tests/ui/needless_lifetimes.rs:376:26
    |
 LL |     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
    |                          ^^                           ^^                ^^
@@ -384,7 +384,7 @@ LL +     fn generics_elidable<T: Fn(&i32) -> &i32>(i: &i32, f: T) -> &i32 {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:387:30
+  --> tests/ui/needless_lifetimes.rs:388:30
    |
 LL |     fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32
    |                              ^^         ^^                ^^
@@ -396,7 +396,7 @@ LL +     fn where_clause_elidable<T>(i: &i32, f: T) -> &i32
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:402:28
+  --> tests/ui/needless_lifetimes.rs:403:28
    |
 LL |     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
    |                            ^^      ^^                               ^^
@@ -408,7 +408,7 @@ LL +     fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:415:28
+  --> tests/ui/needless_lifetimes.rs:416:28
    |
 LL |     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
    |                            ^^      ^^
@@ -420,7 +420,7 @@ LL +     fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:418:28
+  --> tests/ui/needless_lifetimes.rs:419:28
    |
 LL |     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
    |                            ^^      ^^
@@ -432,7 +432,7 @@ LL +     fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:440:21
+  --> tests/ui/needless_lifetimes.rs:441:21
    |
 LL |         fn implicit<'a>(&'a self) -> &'a () {
    |                     ^^   ^^           ^^
@@ -444,7 +444,7 @@ LL +         fn implicit(&self) -> &() {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:443:25
+  --> tests/ui/needless_lifetimes.rs:444:25
    |
 LL |         fn implicit_mut<'a>(&'a mut self) -> &'a () {
    |                         ^^   ^^               ^^
@@ -456,7 +456,31 @@ LL +         fn implicit_mut(&mut self) -> &() {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:454:31
+  --> tests/ui/needless_lifetimes.rs:448:21
+   |
+LL |         fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
+   |                     ^^         ^^                ^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
+LL +         fn explicit(self: &Arc<Self>) -> &() {
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/needless_lifetimes.rs:452:25
+   |
+LL |         fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
+   |                         ^^         ^^                   ^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
+LL +         fn explicit_mut(self: &mut Rc<Self>) -> &() {
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/needless_lifetimes.rs:464:31
    |
 LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |                               ^^                          ^^         ^^
@@ -468,7 +492,7 @@ LL +         fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &() {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:460:21
+  --> tests/ui/needless_lifetimes.rs:470:21
    |
 LL |         fn implicit<'a>(&'a self) -> &'a ();
    |                     ^^   ^^           ^^
@@ -480,7 +504,7 @@ LL +         fn implicit(&self) -> &();
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:461:30
+  --> tests/ui/needless_lifetimes.rs:471:30
    |
 LL |         fn implicit_provided<'a>(&'a self) -> &'a () {
    |                              ^^   ^^           ^^
@@ -492,7 +516,31 @@ LL +         fn implicit_provided(&self) -> &() {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:470:31
+  --> tests/ui/needless_lifetimes.rs:476:21
+   |
+LL |         fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
+   |                     ^^         ^^                ^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
+LL +         fn explicit(self: &Arc<Self>) -> &();
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/needless_lifetimes.rs:478:30
+   |
+LL |         fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
+   |                              ^^         ^^                ^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
+LL +         fn explicit_provided(self: &Arc<Self>) -> &() {
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> tests/ui/needless_lifetimes.rs:488:31
    |
 LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
    |                               ^^                          ^^         ^^
@@ -504,7 +552,7 @@ LL +         fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &();
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:471:40
+  --> tests/ui/needless_lifetimes.rs:489:40
    |
 LL |         fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |                                        ^^                          ^^         ^^
@@ -516,7 +564,7 @@ LL +         fn lifetime_elsewhere_provided(self: Box<Self>, here: &()) -> &() {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:480:12
+  --> tests/ui/needless_lifetimes.rs:498:12
    |
 LL |     fn foo<'a>(x: &'a u8, y: &'_ u8) {}
    |            ^^      ^^
@@ -528,7 +576,7 @@ LL +     fn foo(x: &u8, y: &'_ u8) {}
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:482:12
+  --> tests/ui/needless_lifetimes.rs:500:12
    |
 LL |     fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {}
    |            ^^      ^^
@@ -540,7 +588,7 @@ LL +     fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {}
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:489:18
+  --> tests/ui/needless_lifetimes.rs:507:18
    |
 LL |     fn one_input<'a>(x: &'a u8) -> &'a u8 {
    |                  ^^      ^^         ^^
@@ -552,7 +600,7 @@ LL +     fn one_input(x: &u8) -> &u8 {
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:494:42
+  --> tests/ui/needless_lifetimes.rs:512:42
    |
 LL |     fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 {
    |                                          ^^          ^^
@@ -564,7 +612,7 @@ LL +     fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8)
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> tests/ui/needless_lifetimes.rs:510:22
+  --> tests/ui/needless_lifetimes.rs:528:22
    |
 LL |         fn one_input<'a>(x: &'a u8) -> &'a u8 {
    |                      ^^      ^^         ^^
@@ -577,7 +625,7 @@ LL +         fn one_input(x: &u8) -> &u8 {
    |
 
 error: the following explicit lifetimes could be elided: 'py
-  --> tests/ui/needless_lifetimes.rs:605:14
+  --> tests/ui/needless_lifetimes.rs:623:14
    |
 LL |     impl<'t, 'py> ContentString<'t> {
    |              ^^^
@@ -593,7 +641,7 @@ LL ~         fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Conte
    |
 
 error: the following explicit lifetimes could be elided: 'py
-  --> tests/ui/needless_lifetimes.rs:615:14
+  --> tests/ui/needless_lifetimes.rs:633:14
    |
 LL |     impl<'t, 'py> ContentString<'t> {
    |              ^^^
@@ -609,7 +657,7 @@ LL ~         fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Co
    |
 
 error: the following explicit lifetimes could be elided: 'py
-  --> tests/ui/needless_lifetimes.rs:635:14
+  --> tests/ui/needless_lifetimes.rs:653:14
    |
 LL |     impl<'t, 'py> ContentString<'t> {
    |              ^^^
@@ -627,7 +675,7 @@ LL ~         ) -> Content<'t, '_> {
    |
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_lifetimes.rs:656:9
+  --> tests/ui/needless_lifetimes.rs:674:9
    |
 LL |         &x.b
    |         ^^^^ help: change this to: `x.b`
@@ -635,5 +683,5 @@ LL |         &x.b
    = note: `-D clippy::needless-borrow` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]`
 
-error: aborting due to 52 previous errors
+error: aborting due to 56 previous errors