Skip to content

Commit 4d638bd

Browse files
committed
WIP
1 parent 26b2b8d commit 4d638bd

33 files changed

+216
-344
lines changed

compiler/rustc_hir/src/def.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -829,12 +829,7 @@ pub enum LifetimeRes {
829829
/// late resolution. Those lifetimes will be inferred by typechecking.
830830
Infer,
831831
/// `'static` lifetime.
832-
Static {
833-
/// We do not want to emit `elided_named_lifetimes`
834-
/// when we are inside of a const item or a static,
835-
/// because it would get too annoying.
836-
suppress_elision_warning: bool,
837-
},
832+
Static,
838833
/// Resolution failure.
839834
Error,
840835
/// HACK: This is used to recover the NodeId of an elided lifetime.

compiler/rustc_lint/src/context/diagnostics.rs

+2-14
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@ use rustc_errors::{
88
elided_lifetime_in_path_suggestion, Applicability, Diag, DiagArgValue, LintDiagnostic,
99
};
1010
use rustc_middle::middle::stability;
11-
use rustc_session::lint::{BuiltinLintDiag, ElidedLifetimeResolution};
11+
use rustc_session::lint::BuiltinLintDiag;
1212
use rustc_session::Session;
13-
use rustc_span::symbol::kw;
1413
use rustc_span::BytePos;
1514
use tracing::debug;
1615

17-
use crate::lints::{self, ElidedNamedLifetime};
16+
use crate::lints::{self};
1817

1918
mod check_cfg;
2019

@@ -446,16 +445,5 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
446445
BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => {
447446
lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag)
448447
}
449-
BuiltinLintDiag::ElidedNamedLifetimes { elided: (span, kind), resolution } => {
450-
match resolution {
451-
ElidedLifetimeResolution::Static => {
452-
ElidedNamedLifetime { span, kind, name: kw::StaticLifetime, declaration: None }
453-
}
454-
ElidedLifetimeResolution::Param(name, declaration) => {
455-
ElidedNamedLifetime { span, kind, name, declaration: Some(declaration) }
456-
}
457-
}
458-
.decorate_lint(diag)
459-
}
460448
}
461449
}

compiler/rustc_lint/src/elided.rs

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
use rustc_hir::{
2+
ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, TraitItem, TraitItemKind,
3+
};
4+
use rustc_middle::ty::layout::HasTyCtxt;
5+
use rustc_session::{declare_lint, impl_lint_pass};
6+
use rustc_span::symbol::kw;
7+
8+
use crate::lints::{ElidedNamedLifetime, ElidedNamedLifetimeSuggestion};
9+
use crate::{LateContext, LateLintPass, LintContext};
10+
11+
declare_lint! {
12+
/// The `elided_named_lifetimes` lint detects when an elided
13+
/// lifetime ends up being a named lifetime, such as `'static`
14+
/// or some lifetime parameter `'a`.
15+
///
16+
/// ### Example
17+
///
18+
/// ```rust,compile_fail
19+
/// #![deny(elided_named_lifetimes)]
20+
/// struct Foo;
21+
/// impl Foo {
22+
/// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
23+
/// unsafe { &mut *(x as *mut _) }
24+
/// }
25+
/// }
26+
/// ```
27+
///
28+
/// {{produces}}
29+
///
30+
/// ### Explanation
31+
///
32+
/// Lifetime elision is quite useful, because it frees you from having
33+
/// to give each lifetime its own name, but sometimes it can produce
34+
/// somewhat surprising resolutions. In safe code, it is mostly okay,
35+
/// because the borrow checker prevents any unsoundness, so the worst
36+
/// case scenario is you get a confusing error message in some other place.
37+
/// But with `unsafe` code, such unexpected resolutions may lead to unsound code.
38+
pub ELIDED_NAMED_LIFETIMES,
39+
Warn,
40+
"detects when an elided lifetime gets resolved to be `'static` or some named parameter"
41+
}
42+
43+
#[derive(Clone, Debug, Default)]
44+
pub(crate) struct ElidedNamedLifetimes {
45+
allow_static: bool,
46+
}
47+
48+
impl_lint_pass!(ElidedNamedLifetimes => [ELIDED_NAMED_LIFETIMES]);
49+
50+
impl<'tcx> LateLintPass<'tcx> for ElidedNamedLifetimes {
51+
fn check_trait_item(&mut self, _: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
52+
if let TraitItemKind::Const(..) = item.kind {
53+
self.allow_static = true;
54+
}
55+
}
56+
fn check_trait_item_post(&mut self, _: &LateContext<'tcx>, _: &'tcx TraitItem<'tcx>) {
57+
self.allow_static = false;
58+
}
59+
60+
fn check_impl_item(&mut self, _: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
61+
if let ImplItemKind::Const(..) = item.kind {
62+
self.allow_static = true;
63+
}
64+
}
65+
fn check_impl_item_post(&mut self, _: &LateContext<'tcx>, _: &'tcx ImplItem<'tcx>) {
66+
self.allow_static = false;
67+
}
68+
69+
fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
70+
if let ItemKind::Const(..) | ItemKind::Static(..) = item.kind {
71+
self.allow_static = true;
72+
}
73+
}
74+
fn check_item_post(&mut self, _: &LateContext<'tcx>, _: &'tcx Item<'tcx>) {
75+
self.allow_static = false;
76+
}
77+
78+
fn check_lifetime(&mut self, cx: &LateContext<'tcx>, lifetime: &'tcx Lifetime) {
79+
// `.is_elided()` should probably be called `.resolves_to_elided()`,
80+
// and `.is_anonymous()` is actually the thing that we need here.
81+
if !lifetime.is_anonymous() {
82+
return;
83+
}
84+
let (name, declaration) = match lifetime.res {
85+
LifetimeName::Param(param) => {
86+
let name = cx.tcx().item_name(param.into());
87+
if name == kw::UnderscoreLifetime {
88+
return;
89+
}
90+
let span = cx.tcx().def_span(param);
91+
(name, Some(span))
92+
}
93+
LifetimeName::Static => {
94+
if self.allow_static {
95+
return;
96+
}
97+
(kw::StaticLifetime, None)
98+
}
99+
LifetimeName::ImplicitObjectLifetimeDefault
100+
| LifetimeName::Error
101+
| LifetimeName::Infer => return,
102+
};
103+
cx.emit_lint(
104+
ELIDED_NAMED_LIFETIMES,
105+
ElidedNamedLifetime {
106+
span: lifetime.ident.span,
107+
sugg: {
108+
let (span, code) = lifetime.suggestion(name.as_str());
109+
ElidedNamedLifetimeSuggestion { span, code }
110+
},
111+
name,
112+
declaration,
113+
},
114+
)
115+
}
116+
}

compiler/rustc_lint/src/late.rs

+2
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
286286
cx.with_param_env(trait_item.owner_id, |cx| {
287287
lint_callback!(cx, check_trait_item, trait_item);
288288
hir_visit::walk_trait_item(cx, trait_item);
289+
lint_callback!(cx, check_trait_item_post, trait_item);
289290
});
290291
});
291292
self.context.generics = generics;
@@ -305,6 +306,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
305306
}
306307

307308
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
309+
lint_callback!(self, check_lifetime, lt);
308310
hir_visit::walk_lifetime(self, lt);
309311
}
310312

compiler/rustc_lint/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ mod context;
5050
mod deref_into_dyn_supertrait;
5151
mod drop_forget_useless;
5252
mod early;
53+
mod elided;
5354
mod enum_intrinsics_non_enums;
5455
mod errors;
5556
mod expect;
@@ -91,6 +92,7 @@ use async_fn_in_trait::AsyncFnInTrait;
9192
use builtin::*;
9293
use deref_into_dyn_supertrait::*;
9394
use drop_forget_useless::*;
95+
use elided::ElidedNamedLifetimes;
9496
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
9597
use for_loops_over_fallibles::*;
9698
use hidden_unicode_codepoints::*;
@@ -243,6 +245,7 @@ late_lint_methods!(
243245
NonLocalDefinitions: NonLocalDefinitions::default(),
244246
ImplTraitOvercaptures: ImplTraitOvercaptures,
245247
TailExprDropOrder: TailExprDropOrder,
248+
ElidedNamedLifetimes: ElidedNamedLifetimes::default(),
246249
]
247250
]
248251
);

compiler/rustc_lint/src/lints.rs

+16-29
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ use rustc_errors::{
77
Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag,
88
EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
99
};
10+
use rustc_hir as hir;
1011
use rustc_hir::def::Namespace;
1112
use rustc_hir::def_id::DefId;
12-
use rustc_hir::{self as hir, MissingLifetimeKind};
1313
use rustc_macros::{LintDiagnostic, Subdiagnostic};
1414
use rustc_middle::ty::inhabitedness::InhabitedPredicate;
1515
use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt};
@@ -2624,16 +2624,23 @@ pub(crate) struct ElidedLifetimesInPaths {
26242624
pub subdiag: ElidedLifetimeInPathSubdiag,
26252625
}
26262626

2627+
#[allow(unused)]
26272628
pub(crate) struct ElidedNamedLifetime {
26282629
pub span: Span,
2629-
pub kind: MissingLifetimeKind,
26302630
pub name: Symbol,
26312631
pub declaration: Option<Span>,
2632+
pub sugg: ElidedNamedLifetimeSuggestion,
2633+
}
2634+
2635+
pub(crate) struct ElidedNamedLifetimeSuggestion {
2636+
pub span: Span,
2637+
pub code: String,
26322638
}
26332639

26342640
impl<G: EmissionGuarantee> LintDiagnostic<'_, G> for ElidedNamedLifetime {
26352641
fn decorate_lint(self, diag: &mut rustc_errors::Diag<'_, G>) {
2636-
let Self { span, kind, name, declaration } = self;
2642+
let Self { span, name, declaration, sugg } = self;
2643+
diag.span(span);
26372644
diag.primary_message(fluent::lint_elided_named_lifetime);
26382645
diag.arg("name", name);
26392646
diag.span_label(span, fluent::lint_label_elided);
@@ -2647,32 +2654,12 @@ impl<G: EmissionGuarantee> LintDiagnostic<'_, G> for ElidedNamedLifetime {
26472654
if name != rustc_span::symbol::kw::StaticLifetime {
26482655
return;
26492656
}
2650-
match kind {
2651-
MissingLifetimeKind::Underscore => diag.span_suggestion_verbose(
2652-
span,
2653-
fluent::lint_suggestion,
2654-
format!("{name}"),
2655-
Applicability::MachineApplicable,
2656-
),
2657-
MissingLifetimeKind::Ampersand => diag.span_suggestion_verbose(
2658-
span.shrink_to_hi(),
2659-
fluent::lint_suggestion,
2660-
format!("{name} "),
2661-
Applicability::MachineApplicable,
2662-
),
2663-
MissingLifetimeKind::Comma => diag.span_suggestion_verbose(
2664-
span.shrink_to_hi(),
2665-
fluent::lint_suggestion,
2666-
format!("{name}, "),
2667-
Applicability::MachineApplicable,
2668-
),
2669-
MissingLifetimeKind::Brackets => diag.span_suggestion_verbose(
2670-
span.shrink_to_hi(),
2671-
fluent::lint_suggestion,
2672-
format!("<{name}>"),
2673-
Applicability::MachineApplicable,
2674-
),
2675-
};
2657+
diag.span_suggestion_verbose(
2658+
sugg.span,
2659+
fluent::lint_suggestion,
2660+
sugg.code,
2661+
Applicability::MachineApplicable,
2662+
);
26762663
}
26772664
}
26782665

compiler/rustc_lint/src/passes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ macro_rules! late_lint_methods {
3434
d: rustc_span::Span,
3535
e: rustc_span::def_id::LocalDefId);
3636
fn check_trait_item(a: &'tcx rustc_hir::TraitItem<'tcx>);
37+
fn check_trait_item_post(a: &'tcx rustc_hir::TraitItem<'tcx>);
3738
fn check_impl_item(a: &'tcx rustc_hir::ImplItem<'tcx>);
3839
fn check_impl_item_post(a: &'tcx rustc_hir::ImplItem<'tcx>);
3940
fn check_struct_def(a: &'tcx rustc_hir::VariantData<'tcx>);
@@ -43,6 +44,7 @@ macro_rules! late_lint_methods {
4344
fn check_attribute(a: &'tcx rustc_ast::Attribute);
4445
fn check_attributes(a: &'tcx [rustc_ast::Attribute]);
4546
fn check_attributes_post(a: &'tcx [rustc_ast::Attribute]);
47+
fn check_lifetime(lt: &'tcx rustc_hir::Lifetime);
4648
]);
4749
)
4850
}

compiler/rustc_lint_defs/src/builtin.rs

-33
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ declare_lint_pass! {
4242
DUPLICATE_MACRO_ATTRIBUTES,
4343
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
4444
ELIDED_LIFETIMES_IN_PATHS,
45-
ELIDED_NAMED_LIFETIMES,
4645
EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
4746
EXPORTED_PRIVATE_DEPENDENCIES,
4847
FFI_UNWIND_CALLS,
@@ -1863,38 +1862,6 @@ declare_lint! {
18631862
"hidden lifetime parameters in types are deprecated"
18641863
}
18651864

1866-
declare_lint! {
1867-
/// The `elided_named_lifetimes` lint detects when an elided
1868-
/// lifetime ends up being a named lifetime, such as `'static`
1869-
/// or some lifetime parameter `'a`.
1870-
///
1871-
/// ### Example
1872-
///
1873-
/// ```rust,compile_fail
1874-
/// #![deny(elided_named_lifetimes)]
1875-
/// struct Foo;
1876-
/// impl Foo {
1877-
/// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
1878-
/// unsafe { &mut *(x as *mut _) }
1879-
/// }
1880-
/// }
1881-
/// ```
1882-
///
1883-
/// {{produces}}
1884-
///
1885-
/// ### Explanation
1886-
///
1887-
/// Lifetime elision is quite useful, because it frees you from having
1888-
/// to give each lifetime its own name, but sometimes it can produce
1889-
/// somewhat surprising resolutions. In safe code, it is mostly okay,
1890-
/// because the borrow checker prevents any unsoundness, so the worst
1891-
/// case scenario is you get a confusing error message in some other place.
1892-
/// But with `unsafe` code, such unexpected resolutions may lead to unsound code.
1893-
pub ELIDED_NAMED_LIFETIMES,
1894-
Warn,
1895-
"detects when an elided lifetime gets resolved to be `'static` or some named parameter"
1896-
}
1897-
18981865
declare_lint! {
18991866
/// The `bare_trait_objects` lint suggests using `dyn Trait` for trait
19001867
/// objects.

compiler/rustc_lint_defs/src/lib.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_data_structures::stable_hasher::{
1010
};
1111
use rustc_error_messages::{DiagMessage, MultiSpan};
1212
use rustc_hir::def::Namespace;
13-
use rustc_hir::{HashStableContext, HirId, MissingLifetimeKind};
13+
use rustc_hir::{HashStableContext, HirId};
1414
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
1515
use rustc_span::edition::Edition;
1616
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
@@ -556,12 +556,6 @@ pub enum DeprecatedSinceKind {
556556
InVersion(String),
557557
}
558558

559-
#[derive(Debug)]
560-
pub enum ElidedLifetimeResolution {
561-
Static,
562-
Param(Symbol, Span),
563-
}
564-
565559
// This could be a closure, but then implementing derive trait
566560
// becomes hacky (and it gets allocated).
567561
#[derive(Debug)]
@@ -574,10 +568,6 @@ pub enum BuiltinLintDiag {
574568
},
575569
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
576570
ElidedLifetimesInPaths(usize, Span, bool, Span),
577-
ElidedNamedLifetimes {
578-
elided: (Span, MissingLifetimeKind),
579-
resolution: ElidedLifetimeResolution,
580-
},
581571
UnknownCrateTypes {
582572
span: Span,
583573
candidate: Option<Symbol>,

0 commit comments

Comments
 (0)