diff options
| author | Samuel Moelius <sam@moeli.us> | 2022-10-28 13:17:36 -0400 |
|---|---|---|
| committer | Samuel Moelius <sam@moeli.us> | 2022-10-28 13:17:36 -0400 |
| commit | e9216d836c7190fe5d90e0c48ca73de5b8e3e4f8 (patch) | |
| tree | cded1edbc4f9d68c378bd2cc677d6ff2b8ed841e | |
| parent | 43268141da663e42bf3cd1bb4964c5af20c7e979 (diff) | |
| download | rust-e9216d836c7190fe5d90e0c48ca73de5b8e3e4f8.tar.gz rust-e9216d836c7190fe5d90e0c48ca73de5b8e3e4f8.zip | |
Improve `needless_lifetimes`
| -rw-r--r-- | clippy_lints/src/lifetimes.rs | 120 | ||||
| -rw-r--r-- | tests/ui/needless_lifetimes.rs | 8 | ||||
| -rw-r--r-- | tests/ui/needless_lifetimes.stderr | 100 |
3 files changed, 168 insertions, 60 deletions
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 13878eda0f1..996eb277426 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::trait_ref_of_method; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; @@ -151,6 +151,7 @@ fn check_fn_inner<'tcx>( .params .iter() .filter(|param| matches!(param.kind, GenericParamKind::Type { .. })); + for typ in types { for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) { if pred.origin == PredicateOrigin::WhereClause { @@ -187,15 +188,30 @@ fn check_fn_inner<'tcx>( } } } - if could_use_elision(cx, decl, body, trait_sig, generics.params) { - span_lint( + + if let Some(elidable_lts) = could_use_elision(cx, decl, body, trait_sig, generics.params) { + let lts = elidable_lts + .iter() + // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a + // `Node::GenericParam`. + .filter_map(|&(def_id, _)| cx.tcx.hir().get_by_def_id(def_id).ident()) + .map(|ident| ident.to_string()) + .collect::<Vec<_>>() + .join(", "); + + span_lint_and_then( cx, NEEDLESS_LIFETIMES, span.with_hi(decl.output.span().hi()), - "explicit lifetimes given in parameter types where they could be elided \ - (or replaced with `'_` if needed by type declaration)", + &format!("the following explicit lifetimes could be elided: {lts}"), + |diag| { + if let Some(span) = elidable_lts.iter().find_map(|&(_, span)| span) { + diag.span_help(span, "replace with `'_` in generic arguments such as here"); + } + }, ); } + if report_extra_lifetimes { self::report_extra_lifetimes(cx, decl, generics); } @@ -220,13 +236,14 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: } } +#[expect(clippy::too_many_lines)] fn could_use_elision<'tcx>( cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, body: Option<BodyId>, trait_sig: Option<&[Ident]>, named_generics: &'tcx [GenericParam<'_>], -) -> bool { +) -> Option<Vec<(LocalDefId, Option<Span>)>> { // There are two scenarios where elision works: // * no output references, all input references have different LT // * output references, exactly one input reference with same LT @@ -253,7 +270,7 @@ fn could_use_elision<'tcx>( } if input_visitor.abort() || output_visitor.abort() { - return false; + return None; } let input_lts = input_visitor.lts; @@ -261,7 +278,7 @@ fn could_use_elision<'tcx>( if let Some(trait_sig) = trait_sig { if explicit_self_type(cx, func, trait_sig.first().copied()) { - return false; + return None; } } @@ -270,7 +287,7 @@ fn could_use_elision<'tcx>( let first_ident = body.params.first().and_then(|param| param.pat.simple_ident()); if explicit_self_type(cx, func, first_ident) { - return false; + return None; } let mut checker = BodyLifetimeChecker { @@ -278,14 +295,14 @@ fn could_use_elision<'tcx>( }; checker.visit_expr(body.value); if checker.lifetimes_used_in_body { - return false; + return None; } } // check for lifetimes from higher scopes for lt in input_lts.iter().chain(output_lts.iter()) { if !allowed_lts.contains(lt) { - return false; + return None; } } @@ -301,14 +318,14 @@ fn could_use_elision<'tcx>( for lt in input_visitor.nested_elision_site_lts { if let RefLt::Named(def_id) = lt { if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) { - return false; + return None; } } } for lt in output_visitor.nested_elision_site_lts { if let RefLt::Named(def_id) = lt { if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) { - return false; + return None; } } } @@ -316,32 +333,47 @@ fn could_use_elision<'tcx>( // no input lifetimes? easy case! if input_lts.is_empty() { - false + None } else if output_lts.is_empty() { // no output lifetimes, check distinctness of input lifetimes // only unnamed and static, ok let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static); if unnamed_and_static { - return false; + return None; + } + // we have no output reference, so we can elide explicit lifetimes that occur at most once + let elidable_lts = named_lifetime_occurrences(&input_lts) + .into_iter() + .filter_map(|(def_id, occurrences)| { + if occurrences <= 1 { + Some((def_id, input_visitor.sample_generic_arg_span.get(&def_id).copied())) + } else { + None + } + }) + .collect::<Vec<_>>(); + if elidable_lts.is_empty() { + None + } else { + Some(elidable_lts) } - // we have no output reference, so we only need all distinct lifetimes - input_lts.len() == unique_lifetimes(&input_lts) } else { // we have output references, so we need one input reference, // and all output lifetimes must be the same - if unique_lifetimes(&output_lts) > 1 { - return false; - } if input_lts.len() == 1 { match (&input_lts[0], &output_lts[0]) { - (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true, - (&RefLt::Named(_), &RefLt::Unnamed) => true, - _ => false, /* already elided, different named lifetimes - * or something static going on */ + (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => { + Some(vec![(n1, input_visitor.sample_generic_arg_span.get(&n1).copied())]) + }, + (&RefLt::Named(n), &RefLt::Unnamed) => { + Some(vec![(n, input_visitor.sample_generic_arg_span.get(&n).copied())]) + }, + _ => None, /* already elided, different named lifetimes + * or something static going on */ } } else { - false + None } } } @@ -358,10 +390,24 @@ fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxH allowed_lts } -/// Number of unique lifetimes in the given vector. +/// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve +/// relative order. #[must_use] -fn unique_lifetimes(lts: &[RefLt]) -> usize { - lts.iter().collect::<FxHashSet<_>>().len() +fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> { + let mut occurrences = Vec::new(); + for lt in lts { + if let &RefLt::Named(curr_def_id) = lt { + if let Some(i) = occurrences + .iter() + .position(|&(prev_def_id, _)| prev_def_id == curr_def_id) + { + occurrences[i].1 += 1; + } else { + occurrences.push((curr_def_id, 1)); + } + } + } + occurrences } const CLOSURE_TRAIT_BOUNDS: [LangItem; 3] = [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce]; @@ -370,6 +416,7 @@ const CLOSURE_TRAIT_BOUNDS: [LangItem; 3] = [LangItem::Fn, LangItem::FnMut, Lang struct RefVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, lts: Vec<RefLt>, + sample_generic_arg_span: FxHashMap<LocalDefId, Span>, nested_elision_site_lts: Vec<RefLt>, unelided_trait_object_lifetime: bool, } @@ -379,6 +426,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { Self { cx, lts: Vec::new(), + sample_generic_arg_span: FxHashMap::default(), nested_elision_site_lts: Vec::new(), unelided_trait_object_lifetime: false, } @@ -472,6 +520,22 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { _ => walk_ty(self, ty), } } + + fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) { + if let GenericArg::Lifetime(l) = generic_arg + && let LifetimeName::Param(def_id, _) = l.name + { + self.sample_generic_arg_span.entry(def_id).or_insert(l.span); + } + // Replace with `walk_generic_arg` if/when https://github.com/rust-lang/rust/pull/103692 lands. + // walk_generic_arg(self, generic_arg); + match generic_arg { + GenericArg::Lifetime(lt) => self.visit_lifetime(lt), + GenericArg::Type(ty) => self.visit_ty(ty), + GenericArg::Const(ct) => self.visit_anon_const(&ct.value), + GenericArg::Infer(inf) => self.visit_infer(inf), + } + } } /// Are any lifetimes mentioned in the `where` clause? If so, we don't try to diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index fc686b1dac0..3fe12214294 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -419,4 +419,12 @@ mod issue7296 { } } +mod false_negative { + #![allow(unused)] + + fn foo<'a>(x: &'a u8, y: &'_ u8) {} + + fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {} +} + fn main() {} diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 3c428fd4674..94787b95181 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -1,4 +1,4 @@ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a, 'b --> $DIR/needless_lifetimes.rs:11:1 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} @@ -6,185 +6,221 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a, 'b --> $DIR/needless_lifetimes.rs:13:1 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:23:1 | LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:57:1 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:62:1 | LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a, 'b --> $DIR/needless_lifetimes.rs:74:1 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace with `'_` in generic arguments such as here + --> $DIR/needless_lifetimes.rs:74:37 + | +LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} + | ^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:98:1 | LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace with `'_` in generic arguments such as here + --> $DIR/needless_lifetimes.rs:98:32 + | +LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> + | ^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 's --> $DIR/needless_lifetimes.rs:128:5 | LL | fn self_and_out<'s>(&'s self) -> &'s u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 's, 't --> $DIR/needless_lifetimes.rs:137:5 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:156:1 | LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace with `'_` in generic arguments such as here + --> $DIR/needless_lifetimes.rs:156:33 + | +LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { + | ^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:186:1 | LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:192:1 | LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace with `'_` in generic arguments such as here + --> $DIR/needless_lifetimes.rs:192:37 + | +LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { + | ^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:211:1 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:219:1 | LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:255:1 | LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:262:9 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:266:9 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:279:9 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:311:5 | LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:320:5 | LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:332:5 | LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:347:5 | LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:360:5 | LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:363:5 | LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:385:9 | LL | fn implicit<'a>(&'a self) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:388:9 | LL | fn implicit_mut<'a>(&'a mut self) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:399:9 | LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:405:9 | LL | fn implicit<'a>(&'a self) -> &'a (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:406:9 | LL | fn implicit_provided<'a>(&'a self) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:415:9 | LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) +error: the following explicit lifetimes could be elided: 'a --> $DIR/needless_lifetimes.rs:416:9 | LL | fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 31 previous errors +error: the following explicit lifetimes could be elided: 'a + --> $DIR/needless_lifetimes.rs:425:5 + | +LL | fn foo<'a>(x: &'a u8, y: &'_ u8) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the following explicit lifetimes could be elided: 'a + --> $DIR/needless_lifetimes.rs:427:5 + | +LL | fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 33 previous errors |
