rustc_lint/
lifetime_syntax.rs

1use rustc_data_structures::fx::FxIndexMap;
2use rustc_hir::intravisit::{self, Visitor};
3use rustc_hir::{self as hir, LifetimeSource};
4use rustc_session::{declare_lint, declare_lint_pass};
5use rustc_span::Span;
6use rustc_span::def_id::LocalDefId;
7use tracing::instrument;
8
9use crate::{LateContext, LateLintPass, LintContext, lints};
10
11#[doc = r" The `mismatched_lifetime_syntaxes` lint detects when the same"]
#[doc = r" lifetime is referred to by different syntaxes between function"]
#[doc = r" arguments and return values."]
#[doc = r""]
#[doc = r" The three kinds of syntaxes are:"]
#[doc = r""]
#[doc = r" 1. Named lifetimes. These are references (`&'a str`) or paths"]
#[doc = r"    (`Person<'a>`) that use a lifetime with a name, such as"]
#[doc = r"    `'static` or `'a`."]
#[doc = r""]
#[doc = r" 2. Elided lifetimes. These are references with no explicit"]
#[doc = r"    lifetime (`&str`), references using the anonymous lifetime"]
#[doc = r"    (`&'_ str`), and paths using the anonymous lifetime"]
#[doc = r"    (`Person<'_>`)."]
#[doc = r""]
#[doc = r" 3. Hidden lifetimes. These are paths that do not contain any"]
#[doc = r"    visual indication that it contains a lifetime (`Person`)."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,compile_fail"]
#[doc = r" #![deny(mismatched_lifetime_syntaxes)]"]
#[doc = r""]
#[doc = r" pub fn mixing_named_with_elided(v: &'static u8) -> &u8 {"]
#[doc = r"     v"]
#[doc = r" }"]
#[doc = r""]
#[doc = r" struct Person<'a> {"]
#[doc = r"     name: &'a str,"]
#[doc = r" }"]
#[doc = r""]
#[doc = r" pub fn mixing_hidden_with_elided(v: Person) -> Person<'_> {"]
#[doc = r"     v"]
#[doc = r" }"]
#[doc = r""]
#[doc = r" struct Foo;"]
#[doc = r""]
#[doc = r" impl Foo {"]
#[doc = r"     // Lifetime elision results in the output lifetime becoming"]
#[doc = r"     // `'static`, which is not what was intended."]
#[doc = r"     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {"]
#[doc = r"         unsafe { &mut *(x as *mut _) }"]
#[doc = r"     }"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc = r" Lifetime elision is useful because it frees you from having to"]
#[doc = r" give each lifetime its own name and show the relation of input"]
#[doc = r" and output lifetimes for common cases. However, a lifetime"]
#[doc = r" that uses inconsistent syntax between related arguments and"]
#[doc = r" return values is more confusing."]
#[doc = r""]
#[doc = r" In certain `unsafe` code, lifetime elision combined with"]
#[doc = r" inconsistent lifetime syntax may result in unsound code."]
pub static MISMATCHED_LIFETIME_SYNTAXES: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: "MISMATCHED_LIFETIME_SYNTAXES",
            default_level: ::rustc_lint_defs::Warn,
            desc: "detects when a lifetime uses different syntax between arguments and return values",
            is_externally_loaded: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_lint! {
12    /// The `mismatched_lifetime_syntaxes` lint detects when the same
13    /// lifetime is referred to by different syntaxes between function
14    /// arguments and return values.
15    ///
16    /// The three kinds of syntaxes are:
17    ///
18    /// 1. Named lifetimes. These are references (`&'a str`) or paths
19    ///    (`Person<'a>`) that use a lifetime with a name, such as
20    ///    `'static` or `'a`.
21    ///
22    /// 2. Elided lifetimes. These are references with no explicit
23    ///    lifetime (`&str`), references using the anonymous lifetime
24    ///    (`&'_ str`), and paths using the anonymous lifetime
25    ///    (`Person<'_>`).
26    ///
27    /// 3. Hidden lifetimes. These are paths that do not contain any
28    ///    visual indication that it contains a lifetime (`Person`).
29    ///
30    /// ### Example
31    ///
32    /// ```rust,compile_fail
33    /// #![deny(mismatched_lifetime_syntaxes)]
34    ///
35    /// pub fn mixing_named_with_elided(v: &'static u8) -> &u8 {
36    ///     v
37    /// }
38    ///
39    /// struct Person<'a> {
40    ///     name: &'a str,
41    /// }
42    ///
43    /// pub fn mixing_hidden_with_elided(v: Person) -> Person<'_> {
44    ///     v
45    /// }
46    ///
47    /// struct Foo;
48    ///
49    /// impl Foo {
50    ///     // Lifetime elision results in the output lifetime becoming
51    ///     // `'static`, which is not what was intended.
52    ///     pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
53    ///         unsafe { &mut *(x as *mut _) }
54    ///     }
55    /// }
56    /// ```
57    ///
58    /// {{produces}}
59    ///
60    /// ### Explanation
61    ///
62    /// Lifetime elision is useful because it frees you from having to
63    /// give each lifetime its own name and show the relation of input
64    /// and output lifetimes for common cases. However, a lifetime
65    /// that uses inconsistent syntax between related arguments and
66    /// return values is more confusing.
67    ///
68    /// In certain `unsafe` code, lifetime elision combined with
69    /// inconsistent lifetime syntax may result in unsound code.
70    pub MISMATCHED_LIFETIME_SYNTAXES,
71    Warn,
72    "detects when a lifetime uses different syntax between arguments and return values"
73}
74
75pub struct LifetimeSyntax;
#[automatically_derived]
impl ::core::marker::Copy for LifetimeSyntax { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for LifetimeSyntax { }
#[automatically_derived]
impl ::core::clone::Clone for LifetimeSyntax {
    #[inline]
    fn clone(&self) -> LifetimeSyntax { *self }
}
impl ::rustc_lint_defs::LintPass for LifetimeSyntax {
    fn name(&self) -> &'static str { "LifetimeSyntax" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        <[_]>::into_vec(::alloc::boxed::box_new([MISMATCHED_LIFETIME_SYNTAXES]))
    }
}
impl LifetimeSyntax {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        <[_]>::into_vec(::alloc::boxed::box_new([MISMATCHED_LIFETIME_SYNTAXES]))
    }
}declare_lint_pass!(LifetimeSyntax => [MISMATCHED_LIFETIME_SYNTAXES]);
76
77impl<'tcx> LateLintPass<'tcx> for LifetimeSyntax {
78    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("check_fn",
                                    "rustc_lint::lifetime_syntax", ::tracing::Level::INFO,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/lifetime_syntax.rs"),
                                    ::tracing_core::__macro_support::Option::Some(78u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_lint::lifetime_syntax"),
                                    ::tracing_core::field::FieldSet::new(&[],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::INFO <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::INFO <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{ meta.fields().value_set(&[]) })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        { check_fn_like(cx, fd); }
    }
}#[instrument(skip_all)]
79    fn check_fn(
80        &mut self,
81        cx: &LateContext<'tcx>,
82        _: intravisit::FnKind<'tcx>,
83        fd: &'tcx hir::FnDecl<'tcx>,
84        _: &'tcx hir::Body<'tcx>,
85        _: Span,
86        _: LocalDefId,
87    ) {
88        check_fn_like(cx, fd);
89    }
90
91    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("check_trait_item",
                                    "rustc_lint::lifetime_syntax", ::tracing::Level::INFO,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/lifetime_syntax.rs"),
                                    ::tracing_core::__macro_support::Option::Some(91u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_lint::lifetime_syntax"),
                                    ::tracing_core::field::FieldSet::new(&[],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::INFO <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::INFO <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{ meta.fields().value_set(&[]) })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            match ti.kind {
                hir::TraitItemKind::Const(..) => {}
                hir::TraitItemKind::Fn(fn_sig, _trait_fn) =>
                    check_fn_like(cx, fn_sig.decl),
                hir::TraitItemKind::Type(..) => {}
            }
        }
    }
}#[instrument(skip_all)]
92    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, ti: &'tcx hir::TraitItem<'tcx>) {
93        match ti.kind {
94            hir::TraitItemKind::Const(..) => {}
95            hir::TraitItemKind::Fn(fn_sig, _trait_fn) => check_fn_like(cx, fn_sig.decl),
96            hir::TraitItemKind::Type(..) => {}
97        }
98    }
99
100    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("check_foreign_item",
                                    "rustc_lint::lifetime_syntax", ::tracing::Level::INFO,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/lifetime_syntax.rs"),
                                    ::tracing_core::__macro_support::Option::Some(100u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_lint::lifetime_syntax"),
                                    ::tracing_core::field::FieldSet::new(&[],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::INFO <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::INFO <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{ meta.fields().value_set(&[]) })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            match fi.kind {
                hir::ForeignItemKind::Fn(fn_sig, _idents, _generics) =>
                    check_fn_like(cx, fn_sig.decl),
                hir::ForeignItemKind::Static(..) => {}
                hir::ForeignItemKind::Type => {}
            }
        }
    }
}#[instrument(skip_all)]
101    fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, fi: &'tcx hir::ForeignItem<'tcx>) {
102        match fi.kind {
103            hir::ForeignItemKind::Fn(fn_sig, _idents, _generics) => check_fn_like(cx, fn_sig.decl),
104            hir::ForeignItemKind::Static(..) => {}
105            hir::ForeignItemKind::Type => {}
106        }
107    }
108}
109
110fn check_fn_like<'tcx>(cx: &LateContext<'tcx>, fd: &'tcx hir::FnDecl<'tcx>) {
111    if fd.inputs.is_empty() {
112        return;
113    }
114    let hir::FnRetTy::Return(output) = fd.output else {
115        return;
116    };
117
118    let mut map: FxIndexMap<hir::LifetimeKind, LifetimeGroup<'_>> = FxIndexMap::default();
119
120    LifetimeInfoCollector::collect(output, |info| {
121        let group = map.entry(info.lifetime.kind).or_default();
122        group.outputs.push(info);
123    });
124    if map.is_empty() {
125        return;
126    }
127
128    for input in fd.inputs {
129        LifetimeInfoCollector::collect(input, |info| {
130            if let Some(group) = map.get_mut(&info.lifetime.kind) {
131                group.inputs.push(info);
132            }
133        });
134    }
135
136    for LifetimeGroup { ref inputs, ref outputs } in map.into_values() {
137        if inputs.is_empty() {
138            continue;
139        }
140        if !lifetimes_use_matched_syntax(inputs, outputs) {
141            emit_mismatch_diagnostic(cx, inputs, outputs);
142        }
143    }
144}
145
146#[derive(#[automatically_derived]
impl<'tcx> ::core::default::Default for LifetimeGroup<'tcx> {
    #[inline]
    fn default() -> LifetimeGroup<'tcx> {
        LifetimeGroup {
            inputs: ::core::default::Default::default(),
            outputs: ::core::default::Default::default(),
        }
    }
}Default)]
147struct LifetimeGroup<'tcx> {
148    inputs: Vec<Info<'tcx>>,
149    outputs: Vec<Info<'tcx>>,
150}
151
152#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LifetimeSyntaxCategory {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                LifetimeSyntaxCategory::Hidden => "Hidden",
                LifetimeSyntaxCategory::Elided => "Elided",
                LifetimeSyntaxCategory::Named => "Named",
            })
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for LifetimeSyntaxCategory { }Copy, #[automatically_derived]
impl ::core::clone::Clone for LifetimeSyntaxCategory {
    #[inline]
    fn clone(&self) -> LifetimeSyntaxCategory { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for LifetimeSyntaxCategory {
    #[inline]
    fn eq(&self, other: &LifetimeSyntaxCategory) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq)]
153enum LifetimeSyntaxCategory {
154    Hidden,
155    Elided,
156    Named,
157}
158
159impl LifetimeSyntaxCategory {
160    fn new(lifetime: &hir::Lifetime) -> Option<Self> {
161        use LifetimeSource::*;
162        use hir::LifetimeSyntax::*;
163
164        match (lifetime.syntax, lifetime.source) {
165            // E.g. `&T`.
166            (Implicit, Reference) |
167            // E.g. `&'_ T`.
168            (ExplicitAnonymous, Reference) |
169            // E.g. `ContainsLifetime<'_>`.
170            (ExplicitAnonymous, Path { .. }) |
171            // E.g. `+ '_`, `+ use<'_>`.
172            (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => {
173                Some(Self::Elided)
174            }
175
176            // E.g. `ContainsLifetime`.
177            (Implicit, Path { .. }) => {
178                Some(Self::Hidden)
179            }
180
181            // E.g. `&'a T`.
182            (ExplicitBound, Reference) |
183            // E.g. `ContainsLifetime<'a>`.
184            (ExplicitBound, Path { .. }) |
185            // E.g. `+ 'a`, `+ use<'a>`.
186            (ExplicitBound, OutlivesBound | PreciseCapturing) => {
187                Some(Self::Named)
188            }
189
190            (Implicit, OutlivesBound | PreciseCapturing) |
191            (_, Other) => {
192                None
193            }
194        }
195    }
196}
197
198#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for LifetimeSyntaxCategories<T>
    {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f,
            "LifetimeSyntaxCategories", "hidden", &self.hidden, "elided",
            &self.elided, "named", &&self.named)
    }
}Debug, #[automatically_derived]
impl<T: ::core::default::Default> ::core::default::Default for
    LifetimeSyntaxCategories<T> {
    #[inline]
    fn default() -> LifetimeSyntaxCategories<T> {
        LifetimeSyntaxCategories {
            hidden: ::core::default::Default::default(),
            elided: ::core::default::Default::default(),
            named: ::core::default::Default::default(),
        }
    }
}Default)]
199pub struct LifetimeSyntaxCategories<T> {
200    pub hidden: T,
201    pub elided: T,
202    pub named: T,
203}
204
205impl<T> LifetimeSyntaxCategories<T> {
206    fn select(&mut self, category: LifetimeSyntaxCategory) -> &mut T {
207        use LifetimeSyntaxCategory::*;
208
209        match category {
210            Elided => &mut self.elided,
211            Hidden => &mut self.hidden,
212            Named => &mut self.named,
213        }
214    }
215}
216
217impl<T> LifetimeSyntaxCategories<Vec<T>> {
218    pub fn len(&self) -> LifetimeSyntaxCategories<usize> {
219        LifetimeSyntaxCategories {
220            hidden: self.hidden.len(),
221            elided: self.elided.len(),
222            named: self.named.len(),
223        }
224    }
225
226    pub fn iter_unnamed(&self) -> impl Iterator<Item = &T> {
227        let Self { hidden, elided, named: _ } = self;
228        std::iter::chain(hidden, elided)
229    }
230}
231
232impl std::ops::Add for LifetimeSyntaxCategories<usize> {
233    type Output = Self;
234
235    fn add(self, rhs: Self) -> Self::Output {
236        Self {
237            hidden: self.hidden + rhs.hidden,
238            elided: self.elided + rhs.elided,
239            named: self.named + rhs.named,
240        }
241    }
242}
243
244fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
245    let (first, inputs) = input_info.split_first().unwrap();
246    std::iter::chain(inputs, output_info).all(|info| info.syntax_category == first.syntax_category)
247}
248
249fn emit_mismatch_diagnostic<'tcx>(
250    cx: &LateContext<'tcx>,
251    input_info: &[Info<'_>],
252    output_info: &[Info<'_>],
253) {
254    // There can only ever be zero or one bound lifetime
255    // for a given lifetime resolution.
256    let mut bound_lifetime = None;
257
258    // We offer the following kinds of suggestions (when appropriate
259    // such that the suggestion wouldn't violate the lint):
260    //
261    // 1. Every lifetime becomes named, when there is already a
262    //    user-provided name.
263    //
264    // 2. A "mixed" signature, where references become implicit
265    //    and paths become explicitly anonymous.
266    //
267    // 3. Every lifetime becomes implicit.
268    //
269    // 4. Every lifetime becomes explicitly anonymous.
270    //
271    // Number 2 is arguably the most common pattern and the one we
272    // should push strongest. Number 3 is likely the next most common,
273    // followed by number 1. Coming in at a distant last would be
274    // number 4.
275    //
276    // Beyond these, there are variants of acceptable signatures that
277    // we won't suggest because they are very low-value. For example,
278    // we will never suggest `fn(&T1, &'_ T2) -> &T3` even though that
279    // would pass the lint.
280    //
281    // The following collections are the lifetime instances that we
282    // suggest changing to a given alternate style.
283
284    // 1. Convert all to named.
285    let mut suggest_change_to_explicit_bound = Vec::new();
286
287    // 2. Convert to mixed. We track each kind of change separately.
288    let mut suggest_change_to_mixed_implicit = Vec::new();
289    let mut suggest_change_to_mixed_explicit_anonymous = Vec::new();
290
291    // 3. Convert all to implicit.
292    let mut suggest_change_to_implicit = Vec::new();
293
294    // 4. Convert all to explicit anonymous.
295    let mut suggest_change_to_explicit_anonymous = Vec::new();
296
297    // Some styles prevent using implicit syntax at all.
298    let mut allow_suggesting_implicit = true;
299
300    // It only makes sense to suggest mixed if we have both sources.
301    let mut saw_a_reference = false;
302    let mut saw_a_path = false;
303
304    for info in input_info.iter().chain(output_info) {
305        use LifetimeSource::*;
306        use hir::LifetimeSyntax::*;
307
308        let lifetime = info.lifetime;
309
310        if lifetime.syntax == ExplicitBound {
311            bound_lifetime = Some(info);
312        }
313
314        match (lifetime.syntax, lifetime.source) {
315            // E.g. `&T`.
316            (Implicit, Reference) => {
317                suggest_change_to_explicit_anonymous.push(info);
318                suggest_change_to_explicit_bound.push(info);
319            }
320
321            // E.g. `&'_ T`.
322            (ExplicitAnonymous, Reference) => {
323                suggest_change_to_implicit.push(info);
324                suggest_change_to_explicit_bound.push(info);
325            }
326
327            // E.g. `ContainsLifetime`.
328            (Implicit, Path { .. }) => {
329                suggest_change_to_mixed_explicit_anonymous.push(info);
330                suggest_change_to_explicit_anonymous.push(info);
331                suggest_change_to_explicit_bound.push(info);
332            }
333
334            // E.g. `ContainsLifetime<'_>`, `+ '_`, `+ use<'_>`.
335            (ExplicitAnonymous, Path { .. } | OutlivesBound | PreciseCapturing) => {
336                suggest_change_to_explicit_bound.push(info);
337            }
338
339            // E.g. `&'a T`.
340            (ExplicitBound, Reference) => {
341                suggest_change_to_implicit.push(info);
342                suggest_change_to_mixed_implicit.push(info);
343                suggest_change_to_explicit_anonymous.push(info);
344            }
345
346            // E.g. `ContainsLifetime<'a>`, `+ 'a`, `+ use<'a>`.
347            (ExplicitBound, Path { .. } | OutlivesBound | PreciseCapturing) => {
348                suggest_change_to_mixed_explicit_anonymous.push(info);
349                suggest_change_to_explicit_anonymous.push(info);
350            }
351
352            (Implicit, OutlivesBound | PreciseCapturing) => {
353                {
    ::core::panicking::panic_fmt(format_args!("This syntax / source combination is not possible"));
};panic!("This syntax / source combination is not possible");
354            }
355
356            (_, Other) => {
357                {
    ::core::panicking::panic_fmt(format_args!("This syntax / source combination has already been skipped"));
};panic!("This syntax / source combination has already been skipped");
358            }
359        }
360
361        if #[allow(non_exhaustive_omitted_patterns)] match lifetime.source {
    Path { .. } | OutlivesBound | PreciseCapturing => true,
    _ => false,
}matches!(lifetime.source, Path { .. } | OutlivesBound | PreciseCapturing) {
362            allow_suggesting_implicit = false;
363        }
364
365        match lifetime.source {
366            Reference => saw_a_reference = true,
367            Path { .. } => saw_a_path = true,
368            _ => {}
369        }
370    }
371
372    let categorize = |infos: &[Info<'_>]| {
373        let mut categories = LifetimeSyntaxCategories::<Vec<_>>::default();
374        for info in infos {
375            categories.select(info.syntax_category).push(info.reporting_span());
376        }
377        categories
378    };
379
380    let inputs = categorize(input_info);
381    let outputs = categorize(output_info);
382
383    let make_implicit_suggestions =
384        |infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::<Vec<_>>();
385
386    let explicit_bound_suggestion = bound_lifetime.map(|info| {
387        build_mismatch_suggestion(info.lifetime.ident.as_str(), &suggest_change_to_explicit_bound)
388    });
389
390    let is_bound_static = bound_lifetime.is_some_and(|info| info.lifetime.is_static());
391
392    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/lifetime_syntax.rs:392",
                        "rustc_lint::lifetime_syntax", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/lifetime_syntax.rs"),
                        ::tracing_core::__macro_support::Option::Some(392u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::lifetime_syntax"),
                        ::tracing_core::field::FieldSet::new(&["bound_lifetime",
                                        "explicit_bound_suggestion", "is_bound_static"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&bound_lifetime)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&explicit_bound_suggestion)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&is_bound_static)
                                            as &dyn Value))])
            });
    } else { ; }
};tracing::debug!(?bound_lifetime, ?explicit_bound_suggestion, ?is_bound_static);
393
394    let should_suggest_mixed =
395        // Do we have a mixed case?
396        (saw_a_reference && saw_a_path) &&
397        // Is there anything to change?
398        (!suggest_change_to_mixed_implicit.is_empty() ||
399         !suggest_change_to_mixed_explicit_anonymous.is_empty()) &&
400        // If we have `'static`, we don't want to remove it.
401        !is_bound_static;
402
403    let mixed_suggestion = should_suggest_mixed.then(|| {
404        let implicit_suggestions = make_implicit_suggestions(&suggest_change_to_mixed_implicit);
405
406        let explicit_anonymous_suggestions = suggest_change_to_mixed_explicit_anonymous
407            .iter()
408            .map(|info| info.suggestion("'_"))
409            .collect();
410
411        lints::MismatchedLifetimeSyntaxesSuggestion::Mixed {
412            implicit_suggestions,
413            explicit_anonymous_suggestions,
414            optional_alternative: false,
415        }
416    });
417
418    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/lifetime_syntax.rs:418",
                        "rustc_lint::lifetime_syntax", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/lifetime_syntax.rs"),
                        ::tracing_core::__macro_support::Option::Some(418u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::lifetime_syntax"),
                        ::tracing_core::field::FieldSet::new(&["suggest_change_to_mixed_implicit",
                                        "suggest_change_to_mixed_explicit_anonymous",
                                        "mixed_suggestion"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&suggest_change_to_mixed_implicit)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&suggest_change_to_mixed_explicit_anonymous)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&mixed_suggestion)
                                            as &dyn Value))])
            });
    } else { ; }
};tracing::debug!(
419        ?suggest_change_to_mixed_implicit,
420        ?suggest_change_to_mixed_explicit_anonymous,
421        ?mixed_suggestion,
422    );
423
424    let should_suggest_implicit =
425        // Is there anything to change?
426        !suggest_change_to_implicit.is_empty() &&
427        // We never want to hide the lifetime in a path (or similar).
428        allow_suggesting_implicit &&
429        // If we have `'static`, we don't want to remove it.
430        !is_bound_static;
431
432    let implicit_suggestion = should_suggest_implicit.then(|| {
433        let suggestions = make_implicit_suggestions(&suggest_change_to_implicit);
434
435        lints::MismatchedLifetimeSyntaxesSuggestion::Implicit {
436            suggestions,
437            optional_alternative: false,
438        }
439    });
440
441    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/lifetime_syntax.rs:441",
                        "rustc_lint::lifetime_syntax", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/lifetime_syntax.rs"),
                        ::tracing_core::__macro_support::Option::Some(441u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::lifetime_syntax"),
                        ::tracing_core::field::FieldSet::new(&["should_suggest_implicit",
                                        "suggest_change_to_implicit", "allow_suggesting_implicit",
                                        "implicit_suggestion"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&should_suggest_implicit)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&suggest_change_to_implicit)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&allow_suggesting_implicit
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&implicit_suggestion)
                                            as &dyn Value))])
            });
    } else { ; }
};tracing::debug!(
442        ?should_suggest_implicit,
443        ?suggest_change_to_implicit,
444        allow_suggesting_implicit,
445        ?implicit_suggestion,
446    );
447
448    let should_suggest_explicit_anonymous =
449        // Is there anything to change?
450        !suggest_change_to_explicit_anonymous.is_empty() &&
451        // If we have `'static`, we don't want to remove it.
452        !is_bound_static;
453
454    let explicit_anonymous_suggestion = should_suggest_explicit_anonymous
455        .then(|| build_mismatch_suggestion("'_", &suggest_change_to_explicit_anonymous));
456
457    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/lifetime_syntax.rs:457",
                        "rustc_lint::lifetime_syntax", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/lifetime_syntax.rs"),
                        ::tracing_core::__macro_support::Option::Some(457u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::lifetime_syntax"),
                        ::tracing_core::field::FieldSet::new(&["should_suggest_explicit_anonymous",
                                        "suggest_change_to_explicit_anonymous",
                                        "explicit_anonymous_suggestion"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&should_suggest_explicit_anonymous)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&suggest_change_to_explicit_anonymous)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&explicit_anonymous_suggestion)
                                            as &dyn Value))])
            });
    } else { ; }
};tracing::debug!(
458        ?should_suggest_explicit_anonymous,
459        ?suggest_change_to_explicit_anonymous,
460        ?explicit_anonymous_suggestion,
461    );
462
463    // We can produce a number of suggestions which may overwhelm
464    // the user. Instead, we order the suggestions based on Rust
465    // idioms. The "best" choice is shown to the user and the
466    // remaining choices are shown to tools only.
467    let mut suggestions = Vec::new();
468    suggestions.extend(explicit_bound_suggestion);
469    suggestions.extend(mixed_suggestion);
470    suggestions.extend(implicit_suggestion);
471    suggestions.extend(explicit_anonymous_suggestion);
472
473    cx.emit_span_lint(
474        MISMATCHED_LIFETIME_SYNTAXES,
475        inputs.iter_unnamed().chain(outputs.iter_unnamed()).copied().collect::<Vec<_>>(),
476        lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions },
477    );
478}
479
480fn build_mismatch_suggestion(
481    lifetime_name: &str,
482    infos: &[&Info<'_>],
483) -> lints::MismatchedLifetimeSyntaxesSuggestion {
484    let lifetime_name = lifetime_name.to_owned();
485
486    let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect();
487
488    lints::MismatchedLifetimeSyntaxesSuggestion::Explicit {
489        lifetime_name,
490        suggestions,
491        optional_alternative: false,
492    }
493}
494
495#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for Info<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "Info",
            "lifetime", &self.lifetime, "syntax_category",
            &self.syntax_category, "ty", &&self.ty)
    }
}Debug)]
496struct Info<'tcx> {
497    lifetime: &'tcx hir::Lifetime,
498    syntax_category: LifetimeSyntaxCategory,
499    ty: &'tcx hir::Ty<'tcx>,
500}
501
502impl<'tcx> Info<'tcx> {
503    /// When reporting a lifetime that is implicit, we expand the span
504    /// to include the type. Otherwise we end up pointing at nothing,
505    /// which is a bit confusing.
506    fn reporting_span(&self) -> Span {
507        if self.lifetime.is_implicit() { self.ty.span } else { self.lifetime.ident.span }
508    }
509
510    /// When removing an explicit lifetime from a reference,
511    /// we want to remove the whitespace after the lifetime.
512    ///
513    /// ```rust
514    /// fn x(a: &'_ u8) {}
515    /// ```
516    ///
517    /// Should become:
518    ///
519    /// ```rust
520    /// fn x(a: &u8) {}
521    /// ```
522    // FIXME: Ideally, we'd also remove the lifetime declaration.
523    fn removing_span(&self) -> Span {
524        let mut span = self.lifetime.ident.span;
525        if let hir::TyKind::Ref(_, mut_ty) = self.ty.kind {
526            span = span.until(mut_ty.ty.span);
527        }
528        span
529    }
530
531    fn suggestion(&self, lifetime_name: &str) -> (Span, String) {
532        self.lifetime.suggestion(lifetime_name)
533    }
534}
535
536struct LifetimeInfoCollector<'tcx, F> {
537    info_func: F,
538    ty: &'tcx hir::Ty<'tcx>,
539}
540
541impl<'tcx, F> LifetimeInfoCollector<'tcx, F>
542where
543    F: FnMut(Info<'tcx>),
544{
545    fn collect(ty: &'tcx hir::Ty<'tcx>, info_func: F) {
546        let mut this = Self { info_func, ty };
547
548        intravisit::walk_unambig_ty(&mut this, ty);
549    }
550}
551
552impl<'tcx, F> Visitor<'tcx> for LifetimeInfoCollector<'tcx, F>
553where
554    F: FnMut(Info<'tcx>),
555{
556    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("visit_lifetime",
                                    "rustc_lint::lifetime_syntax", ::tracing::Level::INFO,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/lifetime_syntax.rs"),
                                    ::tracing_core::__macro_support::Option::Some(556u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_lint::lifetime_syntax"),
                                    ::tracing_core::field::FieldSet::new(&["lifetime"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::INFO <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::INFO <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&lifetime)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if let Some(syntax_category) =
                    LifetimeSyntaxCategory::new(lifetime) {
                let info = Info { lifetime, syntax_category, ty: self.ty };
                (self.info_func)(info);
            }
        }
    }
}#[instrument(skip(self))]
557    fn visit_lifetime(&mut self, lifetime: &'tcx hir::Lifetime) {
558        if let Some(syntax_category) = LifetimeSyntaxCategory::new(lifetime) {
559            let info = Info { lifetime, syntax_category, ty: self.ty };
560            (self.info_func)(info);
561        }
562    }
563
564    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("visit_ty",
                                    "rustc_lint::lifetime_syntax", ::tracing::Level::INFO,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/lifetime_syntax.rs"),
                                    ::tracing_core::__macro_support::Option::Some(564u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_lint::lifetime_syntax"),
                                    ::tracing_core::field::FieldSet::new(&["ty"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::INFO <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::INFO <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Self::Result = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let old_ty = std::mem::replace(&mut self.ty, ty.as_unambig_ty());
            intravisit::walk_ty(self, ty);
            self.ty = old_ty;
        }
    }
}#[instrument(skip(self))]
565    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) -> Self::Result {
566        let old_ty = std::mem::replace(&mut self.ty, ty.as_unambig_ty());
567        intravisit::walk_ty(self, ty);
568        self.ty = old_ty;
569    }
570}