#![deny(mismatched_lifetime_syntaxes)] #[derive(Copy, Clone)] struct ContainsLifetime<'a>(&'a u8); struct S(u8); // ref to ref fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } // path to path fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v } fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v } fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's named elsewhere is confusing v } fn explicit_bound_path_to_explicit_anonymous_path<'a>( v: ContainsLifetime<'a>, ) -> ContainsLifetime<'_> { //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } // ref to path fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(v) } fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(v) } fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } // path to ref fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v.0 } fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v.0 } fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing v.0 } fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing v.0 } impl S { fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } // --- fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(&self.0) } fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } } // If a function uses the `'static` lifetime, we should not suggest // replacing it with an explicitly anonymous or implicit // lifetime. Only suggest using `'static` everywhere. mod static_suggestions { #[derive(Copy, Clone)] struct ContainsLifetime<'a>(&'a u8); struct S(u8); fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } impl S { fn static_ref_to_implicit_ref(&'static self) -> &u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } } } /// `impl Trait` uses lifetimes in some additional ways. mod impl_trait { #[derive(Copy, Clone)] struct ContainsLifetime<'a>(&'a u8); fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } fn explicit_bound_path_to_impl_trait_precise_capture<'a>( v: ContainsLifetime<'a>, ) -> impl FnOnce() + use<'_> { //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } } /// `dyn Trait` uses lifetimes in some additional ways. mod dyn_trait { use std::iter; #[derive(Copy, Clone)] struct ContainsLifetime<'a>(&'a u8); fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { //~^ ERROR eliding a lifetime that's named elsewhere is confusing Box::new(iter::once(v)) } fn explicit_bound_path_to_dyn_trait_bound<'a>( v: ContainsLifetime<'a>, ) -> Box + '_> { //~^ ERROR hiding a lifetime that's named elsewhere is confusing Box::new(iter::once(v)) } } /// These tests serve to exercise edge cases of the lint formatting mod diagnostic_output { #[derive(Copy, Clone)] struct ContainsLifetime<'a>(&'a u8); fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 { //~^ ERROR eliding a lifetime that's named elsewhere is confusing v.0 } fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { //~^ ERROR eliding a lifetime that's named elsewhere is confusing (v, v) } fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) { //~^ ERROR hiding or eliding a lifetime that's named elsewhere is confusing (v.0, v) } fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) { //~^ ERROR eliding a lifetime that's named elsewhere is confusing (v, v, ContainsLifetime(v)) } } /// Trait functions are represented differently in the HIR. Make sure /// we visit them. mod trait_functions { #[derive(Copy, Clone)] struct ContainsLifetime<'a>(&'a u8); trait TheTrait { fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; //~^ ERROR hiding a lifetime that's elided elsewhere is confusing fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; //~^ ERROR hiding a lifetime that's elided elsewhere is confusing } impl TheTrait for &u8 { fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(v) } fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(self) } } } /// Extern functions are represented differently in the HIR. Make sure /// we visit them. mod foreign_functions { #[derive(Copy, Clone)] struct ContainsLifetime<'a>(&'a u8); extern "Rust" { fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; //~^ ERROR hiding a lifetime that's elided elsewhere is confusing } } /// These usages are expected to **not** trigger the lint mod acceptable_uses { #[derive(Copy, Clone)] struct ContainsLifetime<'a>(&'a u8); struct S(u8); fn implicit_ref_to_implicit_ref(v: &u8) -> &u8 { v } fn explicit_anonymous_ref_to_explicit_anonymous_ref(v: &'_ u8) -> &'_ u8 { v } fn explicit_bound_ref_to_explicit_bound_ref<'a>(v: &'a u8) -> &'a u8 { v } fn implicit_path_to_implicit_path(v: ContainsLifetime) -> ContainsLifetime { v } fn explicit_anonymous_path_to_explicit_anonymous_path( v: ContainsLifetime<'_>, ) -> ContainsLifetime<'_> { v } fn explicit_bound_path_to_explicit_bound_path<'a>( v: ContainsLifetime<'a>, ) -> ContainsLifetime<'a> { v } fn explicit_anonymous_ref_to_explicit_anonymous_path(v: &'_ u8) -> ContainsLifetime<'_> { ContainsLifetime(v) } fn explicit_bound_ref_to_explicit_bound_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { ContainsLifetime(v) } fn explicit_anonymous_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 { v.0 } fn explicit_bound_path_to_explicit_bound_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { v.0 } // These may be surprising, but ampersands count as enough of a // visual indicator that a reference exists that we treat // references with implicit lifetimes the same as if they were // explicitly anonymous. fn implicit_ref_to_explicit_anonymous_ref(v: &u8) -> &'_ u8 { v } fn explicit_anonymous_ref_to_implicit_ref(v: &'_ u8) -> &u8 { v } fn implicit_ref_to_explicit_anonymous_path(v: &u8) -> ContainsLifetime<'_> { ContainsLifetime(v) } fn explicit_anonymous_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 { v.0 } impl S { fn method_implicit_ref_to_explicit_anonymous_ref(&self) -> &'_ u8 { &self.0 } fn method_explicit_anonymous_ref_to_implicit_ref(&'_ self) -> &u8 { &self.0 } fn method_implicit_ref_to_explicit_anonymous_path(&self) -> ContainsLifetime<'_> { ContainsLifetime(&self.0) } } // `dyn Trait` has an "embedded" lifetime that we should **not** // lint about. fn dyn_trait_does_not_have_a_lifetime_generic(v: &u8) -> &dyn core::fmt::Debug { v } } fn main() {}