1use std::fmt::Debug;
2
3use rustc_ast as ast;
4use rustc_ast::attr::AttributeExt;
5use rustc_ast_pretty::pprust;
6use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
7use rustc_data_structures::unord::UnordSet;
8use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, MultiSpan, msg};
9use rustc_feature::{Features, GateIssue};
10use rustc_hir as hir;
11use rustc_hir::HirId;
12use rustc_hir::intravisit::{self, Visitor};
13use rustc_index::IndexVec;
14use rustc_lint_defs::builtin::{
15 self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
16 UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES,
17};
18use rustc_lint_defs::{
19 Level, Lint, LintExpectationId, LintId, StableLintExpectationId, UnstableLintExpectationId,
20};
21use rustc_middle::hir::nested_filter;
22use rustc_middle::lint::{
23 LevelSpec, LintExpectation, LintLevelSource, ShallowLintLevelMap, StableLevelSpec,
24 UnstableLevelSpec, emit_lint_base, reveal_actual_level_spec,
25};
26use rustc_middle::query::Providers;
27use rustc_middle::ty::{RegisteredTools, TyCtxt};
28use rustc_session::Session;
29use rustc_span::def_id::CRATE_MOD_ID;
30use rustc_span::{AttrId, DUMMY_SP, Span, Symbol, sym};
31use tracing::{debug, instrument};
32
33use crate::builtin::MISSING_DOCS;
34use crate::context::{CheckLintNameResult, LintStore};
35use crate::diagnostics::{
36 CheckNameUnknownTool, DeprecatedLintName, DeprecatedLintNameFromCommandLine,
37 IgnoredUnlessCrateSpecified, MalformedAttribute, MalformedAttributeSub, OverruledAttribute,
38 OverruledAttributeLint, OverruledAttributeSub, RemovedLint, RemovedLintFromCommandLine,
39 RenamedLint, RenamedLintFromCommandLine, RenamedLintSuggestion, RequestedLevel, UnknownLint,
40 UnknownLintFromCommandLine, UnknownLintSuggestion, UnknownToolInScopedLint, UnsupportedGroup,
41};
42use crate::late::unerased_lint_store;
43
44#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LintLevelSets {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f, "LintLevelSets",
"list", &&self.list)
}
}Debug)]
48struct LintLevelSets {
49 list: IndexVec<LintStackIndex, LintSet>,
51}
52
53#[automatically_derived]
impl ::core::marker::Copy for LintStackIndex { }
const COMMAND_LINE: LintStackIndex = LintStackIndex::from_u32(0);
impl LintStackIndex {
#[doc = r" Maximum value the index can take, as a `u32`."]
const MAX_AS_U32: u32 = 0xFFFF_FF00;
#[doc = r" Maximum value the index can take."]
const MAX: Self = Self::from_u32(0xFFFF_FF00);
#[doc = r" Zero value of the index."]
const ZERO: Self = Self::from_u32(0);
#[doc = r" Creates a new index from a given `usize`."]
#[doc = r""]
#[doc = r" # Panics"]
#[doc = r""]
#[doc = r" Will panic if `value` exceeds `MAX`."]
#[inline]
const fn from_usize(value: usize) -> Self {
if !(value <= (0xFFFF_FF00 as usize)) {
::core::panicking::panic("assertion failed: value <= (0xFFFF_FF00 as usize)")
};
unsafe { Self::from_u32_unchecked(value as u32) }
}
#[doc = r" Creates a new index from a given `u32`."]
#[doc = r""]
#[doc = r" # Panics"]
#[doc = r""]
#[doc = r" Will panic if `value` exceeds `MAX`."]
#[inline]
const fn from_u32(value: u32) -> Self {
if !(value <= 0xFFFF_FF00) {
::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
};
unsafe { Self::from_u32_unchecked(value) }
}
#[doc = r" Creates a new index from a given `u16`."]
#[doc = r""]
#[doc = r" # Panics"]
#[doc = r""]
#[doc = r" Will panic if `value` exceeds `MAX`."]
#[inline]
const fn from_u16(value: u16) -> Self {
let value = value as u32;
if !(value <= 0xFFFF_FF00) {
::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
};
unsafe { Self::from_u32_unchecked(value) }
}
#[doc = r" Creates a new index from a given `u32`."]
#[doc = r""]
#[doc = r" # Safety"]
#[doc = r""]
#[doc =
r" The provided value must be less than or equal to the maximum value for the newtype."]
#[doc =
r" Providing a value outside this range is undefined due to layout restrictions."]
#[doc = r""]
#[doc = r" Prefer using `from_u32`."]
#[inline]
const unsafe fn from_u32_unchecked(value: u32) -> Self {
Self {
private_use_as_methods_instead: unsafe {
std::mem::transmute(value)
},
}
}
#[doc = r" Extracts the value of this index as a `usize`."]
#[inline]
const fn index(self) -> usize { self.as_usize() }
#[doc = r" Extracts the value of this index as a `u32`."]
#[inline]
const fn as_u32(self) -> u32 {
unsafe { std::mem::transmute(self.private_use_as_methods_instead) }
}
#[doc = r" Extracts the value of this index as a `usize`."]
#[inline]
const fn as_usize(self) -> usize { self.as_u32() as usize }
}
impl std::ops::Add<usize> for LintStackIndex {
type Output = Self;
#[inline]
fn add(self, other: usize) -> Self {
Self::from_usize(self.index() + other)
}
}
impl std::ops::AddAssign<usize> for LintStackIndex {
#[inline]
fn add_assign(&mut self, other: usize) { *self = *self + other; }
}
impl rustc_index::Idx for LintStackIndex {
#[inline]
fn new(value: usize) -> Self { Self::from_usize(value) }
#[inline]
fn index(self) -> usize { self.as_usize() }
}
impl From<LintStackIndex> for u32 {
#[inline]
fn from(v: LintStackIndex) -> u32 { v.as_u32() }
}
impl From<LintStackIndex> for usize {
#[inline]
fn from(v: LintStackIndex) -> usize { v.as_usize() }
}
impl From<usize> for LintStackIndex {
#[inline]
fn from(value: usize) -> Self { Self::from_usize(value) }
}
impl From<u32> for LintStackIndex {
#[inline]
fn from(value: u32) -> Self { Self::from_u32(value) }
}
impl ::std::cmp::Eq for LintStackIndex {}
impl ::std::cmp::PartialEq for LintStackIndex {
fn eq(&self, other: &Self) -> bool { self.as_u32().eq(&other.as_u32()) }
}
impl ::std::marker::StructuralPartialEq for LintStackIndex {}
impl ::std::hash::Hash for LintStackIndex {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
self.as_u32().hash(state)
}
}
impl ::std::fmt::Debug for LintStackIndex {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_fmt(format_args!("{0}", self.as_u32()))
}
}rustc_index::newtype_index! {
54 struct LintStackIndex {
55 const COMMAND_LINE = 0;
56 }
57}
58
59#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LintSet {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "LintSet",
"specs", &self.specs, "parent", &&self.parent)
}
}Debug)]
68struct LintSet {
69 specs: FxIndexMap<LintId, UnstableLevelSpec>,
70 parent: LintStackIndex,
71}
72
73impl LintLevelSets {
74 fn new() -> Self {
75 LintLevelSets { list: IndexVec::new() }
76 }
77
78 fn get_lint_level_spec(
79 &self,
80 lint: &'static Lint,
81 idx: LintStackIndex,
82 aux: Option<&FxIndexMap<LintId, UnstableLevelSpec>>,
83 sess: &Session,
84 ) -> UnstableLevelSpec {
85 reveal_actual_level_spec(sess, LintId::of(lint), |id| {
86 self.raw_lint_level_spec(id, idx, aux)
87 })
88 }
89
90 fn raw_lint_level_spec(
91 &self,
92 id: LintId,
93 mut idx: LintStackIndex,
94 aux: Option<&FxIndexMap<LintId, UnstableLevelSpec>>,
95 ) -> Option<UnstableLevelSpec> {
96 if let Some(specs) = aux
97 && let Some(level_spec) = specs.get(&id)
98 {
99 return Some(*level_spec);
100 }
101
102 loop {
103 let LintSet { ref specs, parent } = self.list[idx];
104 if let Some(level_spec) = specs.get(&id) {
105 return Some(*level_spec);
106 }
107 if idx == COMMAND_LINE {
108 return None;
109 }
110 idx = parent;
111 }
112 }
113}
114
115fn skippable_lints(tcx: TyCtxt<'_>, (): ()) -> UnordSet<LintId> {
116 let store = unerased_lint_store(&tcx.sess);
117 let root_map = tcx.shallow_lint_levels_on(hir::CRATE_OWNER_ID);
118
119 let mut skippable: FxHashSet<LintId> = store
120 .get_lints()
121 .into_iter()
122 .filter(|lint| {
123 let has_future_breakage =
125 lint.future_incompatible.is_some_and(|fut| fut.report_in_deps);
126 !has_future_breakage && !lint.eval_always
127 })
128 .filter(|lint| {
129 let level_spec =
130 root_map.lint_level_spec_at_node(tcx, LintId::of(lint), hir::CRATE_HIR_ID);
131 level_spec.is_allow()
133 || (#[allow(non_exhaustive_omitted_patterns)] match level_spec.src {
LintLevelSource::Default => true,
_ => false,
}matches!(level_spec.src, LintLevelSource::Default)
134 && lint.default_level(tcx.sess.edition()) == Level::Allow)
135 })
136 .map(|lint| LintId::of(*lint))
137 .collect();
138
139 for owner in tcx.hir_crate_items(()).owners() {
140 let map = tcx.shallow_lint_levels_on(owner);
141
142 for (_, specs) in map.specs.iter() {
144 for (lint, level_spec) in specs.iter() {
145 if !level_spec.is_allow() {
146 skippable.remove(lint);
147 }
148 }
149 }
150 }
151
152 skippable.into()
153}
154
155{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::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("shallow_lint_levels_on",
"rustc_lint::levels", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/c36f1457196e315bc204b9564a6a5a7fe7f5a51f/compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(155u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::levels"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("owner")
}> =
::tracing::__macro_support::FieldName::new("owner");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::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};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&owner)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
(move ||
{
#[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: ShallowLintLevelMap =
loop {};
return __tracing_attr_fake_return;
}
{
let store = unerased_lint_store(tcx.sess);
let attrs = tcx.hir_attr_map(owner);
let mut levels =
LintLevelsBuilder {
sess: tcx.sess,
features: tcx.features(),
provider: LintLevelQueryMap {
tcx,
cur: owner.into(),
specs: ShallowLintLevelMap::default(),
empty: FxIndexMap::default(),
attrs,
},
lint_added_lints: false,
store,
registered_lint_tools: tcx.registered_lint_tools(()),
};
if owner == hir::CRATE_OWNER_ID {
levels.add_command_line();
}
match attrs.map.range(..) {
[] => {}
&[(local_id, _)] =>
levels.add_id(HirId { owner, local_id }),
_ =>
match tcx.hir_owner_node(owner) {
hir::OwnerNode::Item(item) => levels.visit_item(item),
hir::OwnerNode::ForeignItem(item) =>
levels.visit_foreign_item(item),
hir::OwnerNode::TraitItem(item) =>
levels.visit_trait_item(item),
hir::OwnerNode::ImplItem(item) =>
levels.visit_impl_item(item),
hir::OwnerNode::Crate(mod_) => {
levels.add_id(hir::CRATE_HIR_ID);
levels.visit_mod(mod_, mod_.spans.inner_span, CRATE_MOD_ID)
}
hir::OwnerNode::Synthetic =>
::core::panicking::panic("internal error: entered unreachable code"),
},
}
let specs = levels.provider.specs;
for (_, v) in specs.specs.iter() {
if true {
if !!v.is_empty() {
::core::panicking::panic("assertion failed: !v.is_empty()")
};
};
}
specs
}
})();
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/c36f1457196e315bc204b9564a6a5a7fe7f5a51f/compiler/rustc_lint/src/levels.rs:155",
"rustc_lint::levels", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/c36f1457196e315bc204b9564a6a5a7fe7f5a51f/compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(155u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::levels"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("return")
}> =
::tracing::__macro_support::FieldName::new("return");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
x;#[instrument(level = "trace", skip(tcx), ret)]
156fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
157 let store = unerased_lint_store(tcx.sess);
158 let attrs = tcx.hir_attr_map(owner);
159
160 let mut levels = LintLevelsBuilder {
161 sess: tcx.sess,
162 features: tcx.features(),
163 provider: LintLevelQueryMap {
164 tcx,
165 cur: owner.into(),
166 specs: ShallowLintLevelMap::default(),
167 empty: FxIndexMap::default(),
168 attrs,
169 },
170 lint_added_lints: false,
171 store,
172 registered_lint_tools: tcx.registered_lint_tools(()),
173 };
174
175 if owner == hir::CRATE_OWNER_ID {
176 levels.add_command_line();
177 }
178
179 match attrs.map.range(..) {
180 [] => {}
182 &[(local_id, _)] => levels.add_id(HirId { owner, local_id }),
184 _ => match tcx.hir_owner_node(owner) {
188 hir::OwnerNode::Item(item) => levels.visit_item(item),
189 hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item),
190 hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item),
191 hir::OwnerNode::ImplItem(item) => levels.visit_impl_item(item),
192 hir::OwnerNode::Crate(mod_) => {
193 levels.add_id(hir::CRATE_HIR_ID);
194 levels.visit_mod(mod_, mod_.spans.inner_span, CRATE_MOD_ID)
195 }
196 hir::OwnerNode::Synthetic => unreachable!(),
197 },
198 }
199
200 let specs = levels.provider.specs;
201
202 #[cfg(debug_assertions)]
203 for (_, v) in specs.specs.iter() {
204 debug_assert!(!v.is_empty());
205 }
206
207 specs
208}
209
210pub struct TopDown {
211 sets: LintLevelSets,
212 cur: LintStackIndex,
213}
214
215pub trait LintLevelsProvider {
216 type LintExpectationId: Copy + Debug + Into<LintExpectationId>;
217
218 fn current_specs(&self) -> &FxIndexMap<LintId, LevelSpec<Self::LintExpectationId>>;
219
220 fn insert(&mut self, id: LintId, level_spec: LevelSpec<Self::LintExpectationId>);
221
222 fn get_lint_level_spec(
223 &self,
224 lint: &'static Lint,
225 sess: &Session,
226 ) -> LevelSpec<Self::LintExpectationId>;
227
228 fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation);
229
230 fn mk_lint_expectation_id(
231 &self,
232 attr_id: AttrId,
233 attr_index: usize,
234 lint_index: u16,
235 ) -> Self::LintExpectationId;
236}
237
238impl LintLevelsProvider for TopDown {
239 type LintExpectationId = UnstableLintExpectationId;
240
241 fn current_specs(&self) -> &FxIndexMap<LintId, UnstableLevelSpec> {
242 &self.sets.list[self.cur].specs
243 }
244
245 fn insert(&mut self, id: LintId, level_spec: UnstableLevelSpec) {
246 self.sets.list[self.cur].specs.insert(id, level_spec);
247 }
248
249 fn get_lint_level_spec(&self, lint: &'static Lint, sess: &Session) -> UnstableLevelSpec {
250 self.sets.get_lint_level_spec(lint, self.cur, Some(self.current_specs()), sess)
251 }
252
253 fn push_expectation(&mut self, _: Self::LintExpectationId, _: LintExpectation) {}
254
255 fn mk_lint_expectation_id(
256 &self,
257 attr_id: AttrId,
258 _attr_index: usize,
259 lint_index: u16,
260 ) -> Self::LintExpectationId {
261 UnstableLintExpectationId { attr_id, lint_index }
262 }
263}
264
265struct LintLevelQueryMap<'tcx> {
266 tcx: TyCtxt<'tcx>,
267 cur: HirId,
268 specs: ShallowLintLevelMap,
269 empty: FxIndexMap<LintId, StableLevelSpec>,
271 attrs: &'tcx hir::AttributeMap<'tcx>,
272}
273
274impl LintLevelsProvider for LintLevelQueryMap<'_> {
275 type LintExpectationId = StableLintExpectationId;
276
277 fn current_specs(&self) -> &FxIndexMap<LintId, StableLevelSpec> {
278 self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
279 }
280
281 fn insert(&mut self, id: LintId, level_spec: StableLevelSpec) {
282 self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, level_spec);
283 }
284
285 fn get_lint_level_spec(&self, lint: &'static Lint, _: &Session) -> StableLevelSpec {
286 self.specs.lint_level_spec_at_node(self.tcx, LintId::of(lint), self.cur)
287 }
288
289 fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation) {
290 self.specs.expectations.push((id, expectation))
291 }
292
293 fn mk_lint_expectation_id(
294 &self,
295 _attr_id: AttrId,
296 attr_index: usize,
297 lint_index: u16,
298 ) -> Self::LintExpectationId {
299 let attr_index = attr_index.try_into().unwrap();
300 StableLintExpectationId { hir_id: self.cur, attr_index, lint_index }
301 }
302}
303
304impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
305 fn add_id(&mut self, hir_id: HirId) {
306 self.provider.cur = hir_id;
307 self.add(self.provider.attrs.get(hir_id.local_id), hir_id == hir::CRATE_HIR_ID);
308 }
309}
310
311impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
312 type NestedFilter = nested_filter::OnlyBodies;
313
314 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
315 self.provider.tcx
316 }
317
318 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
319 self.add_id(param.hir_id);
320 intravisit::walk_param(self, param);
321 }
322
323 fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
324 self.add_id(it.hir_id());
325 intravisit::walk_item(self, it);
326 }
327
328 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
329 self.add_id(it.hir_id());
330 intravisit::walk_foreign_item(self, it);
331 }
332
333 fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
334 self.add_id(s.hir_id);
335 intravisit::walk_stmt(self, s);
336 }
337
338 fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
339 self.add_id(e.hir_id);
340 intravisit::walk_expr(self, e);
341 }
342
343 fn visit_pat_field(&mut self, f: &'tcx hir::PatField<'tcx>) -> Self::Result {
344 self.add_id(f.hir_id);
345 intravisit::walk_pat_field(self, f);
346 }
347
348 fn visit_expr_field(&mut self, f: &'tcx hir::ExprField<'tcx>) {
349 self.add_id(f.hir_id);
350 intravisit::walk_expr_field(self, f);
351 }
352
353 fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
354 self.add_id(s.hir_id);
355 intravisit::walk_field_def(self, s);
356 }
357
358 fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
359 self.add_id(v.hir_id);
360 intravisit::walk_variant(self, v);
361 }
362
363 fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
364 self.add_id(l.hir_id);
365 intravisit::walk_local(self, l);
366 }
367
368 fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
369 self.add_id(a.hir_id);
370 intravisit::walk_arm(self, a);
371 }
372
373 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
374 self.add_id(trait_item.hir_id());
375 intravisit::walk_trait_item(self, trait_item);
376 }
377
378 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
379 self.add_id(impl_item.hir_id());
380 intravisit::walk_impl_item(self, impl_item);
381 }
382}
383
384pub struct LintLevelsBuilder<'s, P> {
385 sess: &'s Session,
386 features: &'s Features,
387 provider: P,
388 lint_added_lints: bool,
389 store: &'s LintStore,
390 registered_lint_tools: &'s RegisteredTools,
391}
392
393pub(crate) struct BuilderPush {
394 prev: LintStackIndex,
395}
396
397impl<'s> LintLevelsBuilder<'s, TopDown> {
398 pub(crate) fn new(
399 sess: &'s Session,
400 features: &'s Features,
401 lint_added_lints: bool,
402 store: &'s LintStore,
403 registered_lint_tools: &'s RegisteredTools,
404 ) -> Self {
405 let mut builder = LintLevelsBuilder {
406 sess,
407 features,
408 provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE },
409 lint_added_lints,
410 store,
411 registered_lint_tools,
412 };
413 builder.process_command_line();
414 {
match (&builder.provider.sets.list.len(), &1) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(builder.provider.sets.list.len(), 1);
415 builder
416 }
417
418 pub fn crate_root(
419 sess: &'s Session,
420 features: &'s Features,
421 lint_added_lints: bool,
422 store: &'s LintStore,
423 registered_lint_tools: &'s RegisteredTools,
424 crate_attrs: &[ast::Attribute],
425 ) -> Self {
426 let mut builder = Self::new(sess, features, lint_added_lints, store, registered_lint_tools);
427 builder.add(crate_attrs, true);
428 builder
429 }
430
431 fn process_command_line(&mut self) {
432 self.provider.cur = self
433 .provider
434 .sets
435 .list
436 .push(LintSet { specs: FxIndexMap::default(), parent: COMMAND_LINE });
437 self.add_command_line();
438 }
439
440 pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush {
455 let prev = self.provider.cur;
456 self.provider.cur =
457 self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev });
458
459 self.add(attrs, is_crate_node);
460
461 if self.provider.current_specs().is_empty() {
462 self.provider.sets.list.pop();
463 self.provider.cur = prev;
464 }
465
466 BuilderPush { prev }
467 }
468
469 pub(crate) fn pop(&mut self, push: BuilderPush) {
471 self.provider.cur = push.prev;
472 std::mem::forget(push);
473 }
474}
475
476#[cfg(debug_assertions)]
477impl Drop for BuilderPush {
478 fn drop(&mut self) {
479 {
::core::panicking::panic_fmt(format_args!("Found a `push` without a `pop`."));
};panic!("Found a `push` without a `pop`.");
480 }
481}
482
483impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P>
484where
485 LevelSpec<P::LintExpectationId>: Into<LevelSpec>,
486{
487 pub(crate) fn sess(&self) -> &Session {
488 self.sess
489 }
490
491 pub(crate) fn features(&self) -> &Features {
492 self.features
493 }
494
495 fn add_command_line(&mut self) {
496 for &(ref lint_name, level) in &self.sess.opts.lint_opts {
497 let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
499 if lint_name_only == crate::WARNINGS.name_lower() && #[allow(non_exhaustive_omitted_patterns)] match level {
Level::ForceWarn => true,
_ => false,
}matches!(level, Level::ForceWarn) {
500 self.sess
501 .dcx()
502 .emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
503 }
504 match self.store.check_lint_name(lint_name_only, tool_name, self.registered_lint_tools)
505 {
506 CheckLintNameResult::Renamed(ref replace) => {
507 let name = lint_name.as_str();
508 let suggestion = RenamedLintSuggestion::WithoutSpan { replace };
509 let requested_level = RequestedLevel { level, lint_name };
510 let lint =
511 RenamedLintFromCommandLine { name, replace, suggestion, requested_level };
512 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
513 }
514 CheckLintNameResult::Removed(ref reason) => {
515 let name = lint_name.as_str();
516 let requested_level = RequestedLevel { level, lint_name };
517 let lint = RemovedLintFromCommandLine { name, reason, requested_level };
518 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
519 }
520 CheckLintNameResult::NoLint(suggestion) => {
521 let name = lint_name.clone();
522 let suggestion = suggestion.map(|(replace, from_rustc)| {
523 UnknownLintSuggestion::WithoutSpan { replace, from_rustc }
524 });
525 let requested_level = RequestedLevel { level, lint_name };
526 let lint = UnknownLintFromCommandLine { name, suggestion, requested_level };
527 self.emit_lint(UNKNOWN_LINTS, lint);
528 }
529 CheckLintNameResult::Tool(_, Some(ref replace)) => {
530 let name = lint_name.clone();
531 let requested_level = RequestedLevel { level, lint_name };
532 let lint = DeprecatedLintNameFromCommandLine { name, replace, requested_level };
533 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
534 }
535 CheckLintNameResult::NoTool => {
536 self.sess.dcx().emit_err(CheckNameUnknownTool {
537 tool_name: tool_name.unwrap(),
538 sub: RequestedLevel { level, lint_name },
539 });
540 }
541 _ => {}
542 };
543
544 let lint_flag_val = Symbol::intern(lint_name);
545
546 let Some(ids) = self.store.find_lints(lint_name) else {
547 continue;
549 };
550 for &id in ids {
551 if let Some(level_spec) = self.provider.current_specs().get(&id)
553 && #[allow(non_exhaustive_omitted_patterns)] match level_spec.level() {
Level::ForceWarn | Level::Forbid => true,
_ => false,
}matches!(level_spec.level(), Level::ForceWarn | Level::Forbid)
554 {
555 continue;
556 }
557
558 if self.check_gated_lint(id, DUMMY_SP, true) {
559 let src = LintLevelSource::CommandLine(lint_flag_val, level);
560 self.provider.insert(id, LevelSpec::new(level, None, src));
561 }
562 }
563 }
564 }
565
566 fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec<P::LintExpectationId>) {
570 let level = level_spec.level();
571 let lint_id = level_spec.lint_id();
572 let src = level_spec.src;
573
574 let old_level_spec = self.provider.get_lint_level_spec(id.lint, self.sess);
575 let old_level = old_level_spec.level();
576 let old_src = old_level_spec.src;
577
578 if self.lint_added_lints && level == Level::Deny && old_level == Level::Forbid {
585 return;
587 } else if self.lint_added_lints && level != Level::Forbid && old_level == Level::Forbid {
588 let fcw_warning = match old_src {
595 LintLevelSource::Default => false,
596 LintLevelSource::Node { name, .. } => self.store.is_lint_group(name),
597 LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
598 };
599 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/c36f1457196e315bc204b9564a6a5a7fe7f5a51f/compiler/rustc_lint/src/levels.rs:599",
"rustc_lint::levels", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/c36f1457196e315bc204b9564a6a5a7fe7f5a51f/compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(599u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::levels"),
::tracing_core::field::FieldSet::new(&["message"],
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("fcw_warning={0:?}, specs.get(&id) = {1:?}, old_src={2:?}, id_name={3:?}",
fcw_warning, self.provider.current_specs(), old_src,
id.lint.name_lower()) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(
600 "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
601 fcw_warning,
602 self.provider.current_specs(),
603 old_src,
604 id.lint.name_lower(),
605 );
606 let sub = match old_src {
607 LintLevelSource::Default => {
608 OverruledAttributeSub::DefaultSource { id: id.to_string() }
609 }
610 LintLevelSource::Node { span, reason, .. } => {
611 OverruledAttributeSub::NodeSource { span, reason }
612 }
613 LintLevelSource::CommandLine(name, _) => {
614 OverruledAttributeSub::CommandLineSource { id: name }
615 }
616 };
617 if !fcw_warning {
618 self.sess.dcx().emit_err(OverruledAttribute {
619 span: src.span(),
620 overruled: src.span(),
621 lint_level: level.as_str(),
622 lint_source: src.name(),
623 sub,
624 });
625 } else {
626 self.emit_span_lint(
627 FORBIDDEN_LINT_GROUPS,
628 src.span().into(),
629 OverruledAttributeLint {
630 overruled: src.span(),
631 lint_level: level.as_str(),
632 lint_source: src.name(),
633 sub,
634 },
635 );
636 }
637
638 if !fcw_warning {
642 return;
643 }
644 }
645
646 if let Level::Expect = level
650 && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS)
651 {
652 return;
653 }
654
655 match (old_level, level) {
656 (Level::ForceWarn, Level::Expect) => {
658 self.provider.insert(id, LevelSpec::new(Level::ForceWarn, lint_id, old_src))
659 }
660 (Level::ForceWarn, _) => {
662 self.provider.insert(id, LevelSpec::new(Level::ForceWarn, None, old_src))
663 }
664 _ => self.provider.insert(id, LevelSpec::new(level, lint_id, src)),
666 };
667 }
668
669 fn add(&mut self, attrs: &[impl AttributeExt], is_crate_node: bool) {
670 let sess = self.sess;
671 for (attr_index, attr) in attrs.iter().enumerate() {
672 if attr.is_automatically_derived_attr() {
673 self.provider.insert(
674 LintId::of(SINGLE_USE_LIFETIMES),
675 LevelSpec::new(Level::Allow, None, LintLevelSource::Default),
676 );
677 continue;
678 }
679
680 if attr.is_doc_hidden() {
682 self.provider.insert(
683 LintId::of(MISSING_DOCS),
684 LevelSpec::new(Level::Allow, None, LintLevelSource::Default),
685 );
686 continue;
687 }
688
689 let level = match Level::from_opt_symbol(attr.name()) {
690 None => continue,
691 Some(level) => level,
692 };
693
694 let Some(mut metas) = attr.meta_item_list() else { continue };
695
696 let Some(tail_li) = metas.last() else {
698 continue;
700 };
701
702 let mut reason = None;
705 if let Some(item) = tail_li.meta_item() {
706 match item.kind {
707 ast::MetaItemKind::Word => {} ast::MetaItemKind::NameValue(ref name_value) => {
709 if item.path == sym::reason {
710 if let ast::LitKind::Str(rationale, _) = name_value.kind {
711 reason = Some(rationale);
712 } else {
713 sess.dcx().emit_err(MalformedAttribute {
714 span: name_value.span,
715 sub: MalformedAttributeSub::ReasonMustBeStringLiteral(
716 name_value.span,
717 ),
718 });
719 }
720 metas.pop().unwrap();
722 } else {
723 sess.dcx().emit_err(MalformedAttribute {
724 span: item.span,
725 sub: MalformedAttributeSub::BadAttributeArgument(item.span),
726 });
727 }
728 }
729 ast::MetaItemKind::List(_) => {
730 sess.dcx().emit_err(MalformedAttribute {
731 span: item.span,
732 sub: MalformedAttributeSub::BadAttributeArgument(item.span),
733 });
734 }
735 }
736 }
737
738 for (lint_index, li) in metas.iter_mut().enumerate() {
739 let lint_id = (level == Level::Expect).then(|| {
742 self.provider.mk_lint_expectation_id(attr.id(), attr_index, lint_index as u16)
743 });
744
745 let sp = li.span();
746 let meta_item = match li {
747 ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => meta_item,
748 _ => {
749 let sub = if let Some(item) = li.meta_item()
750 && let ast::MetaItemKind::NameValue(_) = item.kind
751 && item.path == sym::reason
752 {
753 MalformedAttributeSub::ReasonMustComeLast(sp)
754 } else {
755 MalformedAttributeSub::BadAttributeArgument(sp)
756 };
757
758 sess.dcx().emit_err(MalformedAttribute { span: sp, sub });
759 continue;
760 }
761 };
762 let tool_ident = if meta_item.path.segments.len() > 1 {
763 Some(meta_item.path.segments.remove(0).ident)
764 } else {
765 None
766 };
767 let tool_name = tool_ident.map(|ident| ident.name);
768 let name = pprust::path_to_string(&meta_item.path);
769 let lint_result =
770 self.store.check_lint_name(&name, tool_name, self.registered_lint_tools);
771
772 let (ids, name) = match lint_result {
773 CheckLintNameResult::Ok(ids) => {
774 let name =
775 meta_item.path.segments.last().expect("empty lint name").ident.name;
776 (ids, name)
777 }
778
779 CheckLintNameResult::Tool(ids, new_lint_name) => {
780 let name = match new_lint_name {
781 None => {
782 let complete_name =
783 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}",
tool_ident.unwrap().name, name))
})format!("{}::{}", tool_ident.unwrap().name, name);
784 Symbol::intern(complete_name)
785 }
786 Some(new_lint_name) => {
787 self.emit_span_lint(
788 builtin::RENAMED_AND_REMOVED_LINTS,
789 sp.into(),
790 DeprecatedLintName {
791 name,
792 suggestion: sp,
793 replace: &new_lint_name,
794 },
795 );
796 Symbol::intern(&new_lint_name)
797 }
798 };
799 (ids, name)
800 }
801
802 CheckLintNameResult::MissingTool => {
803 continue;
808 }
809
810 CheckLintNameResult::NoTool => {
811 sess.dcx().emit_err(UnknownToolInScopedLint {
812 span: tool_ident.map(|ident| ident.span),
813 tool_name: tool_name.unwrap(),
814 lint_name: pprust::path_to_string(&meta_item.path),
815 is_nightly_build: sess.is_nightly_build(),
816 });
817 continue;
818 }
819
820 CheckLintNameResult::Renamed(ref replace) => {
821 if self.lint_added_lints {
822 let suggestion =
823 RenamedLintSuggestion::WithSpan { suggestion: sp, replace };
824 let name =
825 tool_ident.map(|tool| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool, name))
})format!("{tool}::{name}")).unwrap_or(name);
826 self.emit_span_lint(
827 RENAMED_AND_REMOVED_LINTS,
828 sp.into(),
829 RenamedLint { name: name.as_str(), replace, suggestion },
830 );
831 }
832
833 let CheckLintNameResult::Ok(ids) =
839 self.store.check_lint_name(replace, None, self.registered_lint_tools)
840 else {
841 {
::core::panicking::panic_fmt(format_args!("renamed lint does not exist: {0}",
replace));
};panic!("renamed lint does not exist: {replace}");
842 };
843
844 (ids, Symbol::intern(&replace))
845 }
846
847 CheckLintNameResult::Removed(ref reason) => {
848 if self.lint_added_lints {
849 let name =
850 tool_ident.map(|tool| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool, name))
})format!("{tool}::{name}")).unwrap_or(name);
851 self.emit_span_lint(
852 RENAMED_AND_REMOVED_LINTS,
853 sp.into(),
854 RemovedLint { name: name.as_str(), reason },
855 );
856 }
857 continue;
858 }
859
860 CheckLintNameResult::NoLint(suggestion) => {
861 if self.lint_added_lints {
862 let name =
863 tool_ident.map(|tool| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool, name))
})format!("{tool}::{name}")).unwrap_or(name);
864 let suggestion = suggestion.map(|(replace, from_rustc)| {
865 UnknownLintSuggestion::WithSpan {
866 suggestion: sp,
867 replace,
868 from_rustc,
869 }
870 });
871 self.emit_span_lint(
872 UNKNOWN_LINTS,
873 sp.into(),
874 UnknownLint { name, suggestion },
875 );
876 }
877 continue;
878 }
879 };
880
881 let src = LintLevelSource::Node { name, span: sp, reason };
882 for &id in ids {
883 if self.check_gated_lint(id, sp, false) {
884 self.insert_spec(id, LevelSpec::new(level, lint_id, src));
885 }
886 }
887
888 if let (Level::Expect, Some(expect_id)) = (level, lint_id) {
894 let is_unfulfilled_lint_expectations = match ids {
898 [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
899 _ => false,
900 };
901 self.provider.push_expectation(
902 expect_id,
903 LintExpectation::new(
904 reason,
905 sp,
906 is_unfulfilled_lint_expectations,
907 tool_name,
908 ),
909 );
910 }
911 }
912 }
913
914 if self.lint_added_lints && !is_crate_node {
915 for (id, level_spec) in self.provider.current_specs().iter() {
916 if !id.lint.crate_level_only {
917 continue;
918 }
919
920 let LintLevelSource::Node { name: lint_attr_name, span: lint_attr_span, .. } =
921 level_spec.src
922 else {
923 continue;
924 };
925
926 self.emit_span_lint(
927 UNUSED_ATTRIBUTES,
928 lint_attr_span.into(),
929 IgnoredUnlessCrateSpecified {
930 level: level_spec.level().as_str(),
931 name: lint_attr_name,
932 },
933 );
934 break;
936 }
937 }
938 }
939
940 #[track_caller]
944 fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
945 let feature = if let Some(feature) = lint_id.lint.feature_gate
946 && !self.features.enabled(feature)
947 && !span.allows_unstable(feature)
948 {
949 feature
951 } else {
952 return true;
954 };
955
956 struct UnknownLint<'a> {
957 sess: &'a Session,
958 lint_id: LintId,
959 feature: Symbol,
960 lint_from_cli: bool,
961 }
962
963 impl<'a, 'b> Diagnostic<'a> for UnknownLint<'b> {
964 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: rustc_errors::Level) -> Diag<'a> {
965 let Self { sess, lint_id, feature, lint_from_cli } = self;
966 let mut lint = Diag::new(dcx, level, rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("unknown lint: `{$name}`"))msg!("unknown lint: `{$name}`"))
967 .with_arg("name", lint_id.lint.name_lower())
968 .with_note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the `{$name}` lint is unstable"))msg!("the `{$name}` lint is unstable"));
969 if feature != sym::staged_api {
972 rustc_session::diagnostics::add_feature_diagnostics_for_issue(
973 &mut lint,
974 sess,
975 feature,
976 GateIssue::Language,
977 lint_from_cli,
978 None,
979 );
980 }
981 lint
982 }
983 }
984
985 if self.lint_added_lints {
986 let lint = builtin::UNKNOWN_LINTS;
987 let level_spec = self.lint_level_spec(builtin::UNKNOWN_LINTS);
988 emit_lint_base(
989 self.sess,
990 lint,
991 level_spec,
992 Some(span.into()),
993 UnknownLint { sess: &self.sess, lint_id, feature, lint_from_cli },
994 );
995 }
996
997 false
998 }
999
1000 pub fn lint_level_spec(&self, lint: &'static Lint) -> LevelSpec<P::LintExpectationId> {
1002 self.provider.get_lint_level_spec(lint, self.sess)
1003 }
1004
1005 #[track_caller]
1008 pub(crate) fn opt_span_lint(
1009 &self,
1010 lint: &'static Lint,
1011 span: Option<MultiSpan>,
1012 decorator: impl for<'a> Diagnostic<'a>,
1013 ) {
1014 let level_spec = self.lint_level_spec(lint);
1015 emit_lint_base(self.sess, lint, level_spec, span, decorator)
1016 }
1017
1018 #[track_caller]
1019 pub fn emit_span_lint(
1020 &self,
1021 lint: &'static Lint,
1022 span: MultiSpan,
1023 decorator: impl for<'a> Diagnostic<'a>,
1024 ) {
1025 let level_spec = self.lint_level_spec(lint);
1026 emit_lint_base(self.sess, lint, level_spec, Some(span), decorator);
1027 }
1028
1029 #[track_caller]
1030 pub fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a>) {
1031 let level_spec = self.lint_level_spec(lint);
1032 emit_lint_base(self.sess, lint, level_spec, None, decorator);
1033 }
1034}
1035
1036pub(crate) fn provide(providers: &mut Providers) {
1037 *providers = Providers { shallow_lint_levels_on, skippable_lints, ..*providers };
1038}
1039
1040pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
1041 match lint_name.split_once("::") {
1042 Some((tool_name, lint_name)) => {
1043 let tool_name = Symbol::intern(tool_name);
1044
1045 (Some(tool_name), lint_name)
1046 }
1047 None => (None, lint_name),
1048 }
1049}