1+ use clippy_config:: Conf ;
12use clippy_utils:: diagnostics:: { span_lint, span_lint_and_then} ;
3+ use clippy_utils:: msrvs:: { self , Msrv } ;
24use clippy_utils:: trait_ref_of_method;
35use itertools:: Itertools ;
46use rustc_ast:: visit:: { try_visit, walk_list} ;
@@ -20,7 +22,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
2022use rustc_middle:: hir:: map:: Map ;
2123use rustc_middle:: hir:: nested_filter as middle_nested_filter;
2224use rustc_middle:: lint:: in_external_macro;
23- use rustc_session:: declare_lint_pass ;
25+ use rustc_session:: impl_lint_pass ;
2426use rustc_span:: Span ;
2527use rustc_span:: def_id:: LocalDefId ;
2628use rustc_span:: symbol:: { Ident , kw} ;
@@ -91,7 +93,19 @@ declare_clippy_lint! {
9193 "unused lifetimes in function definitions"
9294}
9395
94- declare_lint_pass ! ( Lifetimes => [ NEEDLESS_LIFETIMES , EXTRA_UNUSED_LIFETIMES ] ) ;
96+ pub struct Lifetimes {
97+ msrv : Msrv ,
98+ }
99+
100+ impl Lifetimes {
101+ pub fn new ( conf : & ' static Conf ) -> Self {
102+ Self {
103+ msrv : conf. msrv . clone ( ) ,
104+ }
105+ }
106+ }
107+
108+ impl_lint_pass ! ( Lifetimes => [ NEEDLESS_LIFETIMES , EXTRA_UNUSED_LIFETIMES ] ) ;
95109
96110impl < ' tcx > LateLintPass < ' tcx > for Lifetimes {
97111 fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx Item < ' _ > ) {
@@ -102,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
102116 ..
103117 } = item. kind
104118 {
105- check_fn_inner ( cx, sig, Some ( id) , None , generics, item. span , true ) ;
119+ check_fn_inner ( cx, sig, Some ( id) , None , generics, item. span , true , & self . msrv ) ;
106120 } else if let ItemKind :: Impl ( impl_) = item. kind {
107121 if !item. span . from_expansion ( ) {
108122 report_extra_impl_lifetimes ( cx, impl_) ;
@@ -121,6 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
121135 item. generics ,
122136 item. span ,
123137 report_extra_lifetimes,
138+ & self . msrv ,
124139 ) ;
125140 }
126141 }
@@ -131,11 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
131146 TraitFn :: Required ( sig) => ( None , Some ( sig) ) ,
132147 TraitFn :: Provided ( id) => ( Some ( id) , None ) ,
133148 } ;
134- check_fn_inner ( cx, sig, body, trait_sig, item. generics , item. span , true ) ;
149+ check_fn_inner ( cx, sig, body, trait_sig, item. generics , item. span , true , & self . msrv ) ;
135150 }
136151 }
152+
153+ extract_msrv_attr ! ( LateContext ) ;
137154}
138155
156+ #[ allow( clippy:: too_many_arguments) ]
139157fn check_fn_inner < ' tcx > (
140158 cx : & LateContext < ' tcx > ,
141159 sig : & ' tcx FnSig < ' _ > ,
@@ -144,6 +162,7 @@ fn check_fn_inner<'tcx>(
144162 generics : & ' tcx Generics < ' _ > ,
145163 span : Span ,
146164 report_extra_lifetimes : bool ,
165+ msrv : & Msrv ,
147166) {
148167 if in_external_macro ( cx. sess ( ) , span) || has_where_lifetimes ( cx, generics) {
149168 return ;
@@ -195,7 +214,7 @@ fn check_fn_inner<'tcx>(
195214 }
196215 }
197216
198- if let Some ( ( elidable_lts, usages) ) = could_use_elision ( cx, sig. decl , body, trait_sig, generics. params ) {
217+ if let Some ( ( elidable_lts, usages) ) = could_use_elision ( cx, sig. decl , body, trait_sig, generics. params , msrv ) {
199218 if usages. iter ( ) . any ( |usage| !usage. ident . span . eq_ctxt ( span) ) {
200219 return ;
201220 }
@@ -216,6 +235,7 @@ fn could_use_elision<'tcx>(
216235 body : Option < BodyId > ,
217236 trait_sig : Option < & [ Ident ] > ,
218237 named_generics : & ' tcx [ GenericParam < ' _ > ] ,
238+ msrv : & Msrv ,
219239) -> Option < ( Vec < LocalDefId > , Vec < Lifetime > ) > {
220240 // There are two scenarios where elision works:
221241 // * no output references, all input references have different LT
@@ -249,17 +269,17 @@ fn could_use_elision<'tcx>(
249269 let input_lts = input_visitor. lts ;
250270 let output_lts = output_visitor. lts ;
251271
252- if let Some ( trait_sig) = trait_sig {
253- if explicit_self_type ( cx, func, trait_sig. first ( ) . copied ( ) ) {
254- return None ;
255- }
272+ if let Some ( trait_sig) = trait_sig
273+ && non_elidable_self_type ( cx, func, trait_sig. first ( ) . copied ( ) , msrv )
274+ {
275+ return None ;
256276 }
257277
258278 if let Some ( body_id) = body {
259279 let body = cx. tcx . hir ( ) . body ( body_id) ;
260280
261281 let first_ident = body. params . first ( ) . and_then ( |param| param. pat . simple_ident ( ) ) ;
262- if explicit_self_type ( cx, func, first_ident) {
282+ if non_elidable_self_type ( cx, func, first_ident, msrv ) {
263283 return None ;
264284 }
265285
@@ -332,9 +352,15 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet<LocalDefI
332352 . collect ( )
333353}
334354
335- // elision doesn't work for explicit self types, see rust-lang/rust#69064
336- fn explicit_self_type < ' tcx > ( cx : & LateContext < ' tcx > , func : & FnDecl < ' tcx > , ident : Option < Ident > ) -> bool {
337- if let Some ( ident) = ident
355+ // elision doesn't work for explicit self types before Rust 1.81, see rust-lang/rust#69064
356+ fn non_elidable_self_type < ' tcx > (
357+ cx : & LateContext < ' tcx > ,
358+ func : & FnDecl < ' tcx > ,
359+ ident : Option < Ident > ,
360+ msrv : & Msrv ,
361+ ) -> bool {
362+ if !msrv. meets ( msrvs:: EXPLICIT_SELF_TYPE_ELISION )
363+ && let Some ( ident) = ident
338364 && ident. name == kw:: SelfLower
339365 && !func. implicit_self . has_implicit_self ( )
340366 && let Some ( self_ty) = func. inputs . first ( )
0 commit comments