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 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 (Implicit, Reference) |
167 (ExplicitAnonymous, Reference) |
169 (ExplicitAnonymous, Path { .. }) |
171 (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => {
173 Some(Self::Elided)
174 }
175
176 (Implicit, Path { .. }) => {
178 Some(Self::Hidden)
179 }
180
181 (ExplicitBound, Reference) |
183 (ExplicitBound, Path { .. }) |
185 (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 let mut bound_lifetime = None;
257
258 let mut suggest_change_to_explicit_bound = Vec::new();
286
287 let mut suggest_change_to_mixed_implicit = Vec::new();
289 let mut suggest_change_to_mixed_explicit_anonymous = Vec::new();
290
291 let mut suggest_change_to_implicit = Vec::new();
293
294 let mut suggest_change_to_explicit_anonymous = Vec::new();
296
297 let mut allow_suggesting_implicit = true;
299
300 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 (Implicit, Reference) => {
317 suggest_change_to_explicit_anonymous.push(info);
318 suggest_change_to_explicit_bound.push(info);
319 }
320
321 (ExplicitAnonymous, Reference) => {
323 suggest_change_to_implicit.push(info);
324 suggest_change_to_explicit_bound.push(info);
325 }
326
327 (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 (ExplicitAnonymous, Path { .. } | OutlivesBound | PreciseCapturing) => {
336 suggest_change_to_explicit_bound.push(info);
337 }
338
339 (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 (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 (saw_a_reference && saw_a_path) &&
397 (!suggest_change_to_mixed_implicit.is_empty() ||
399 !suggest_change_to_mixed_explicit_anonymous.is_empty()) &&
400 !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 !suggest_change_to_implicit.is_empty() &&
427 allow_suggesting_implicit &&
429 !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 !suggest_change_to_explicit_anonymous.is_empty() &&
451 !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 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 fn reporting_span(&self) -> Span {
507 if self.lifetime.is_implicit() { self.ty.span } else { self.lifetime.ident.span }
508 }
509
510 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}