1use std::fmt::Debug;
2
3use rustc_ast as ast;
4use rustc_ast::CRATE_NODE_ID;
5use rustc_attr_ir::lint::{LintCheck, LintCheckKind};
6use rustc_attr_ir::target::{AstTarget, Target};
7use rustc_attr_ir::{Attribute, DocAttribute, find_attr};
8use rustc_attr_parsing::{AttributeParser, Recovery, ShouldEmit};
9use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
10use rustc_data_structures::unord::UnordSet;
11use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, MultiSpan, msg};
12use rustc_feature::{Features, GateIssue};
13use rustc_hir as hir;
14use rustc_hir::HirId;
15use rustc_hir::intravisit::{self, Visitor};
16use rustc_index::IndexVec;
17use rustc_lint_defs::builtin::{
18 self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
19 UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES,
20};
21use rustc_lint_defs::{
22 Level, Lint, LintExpectationId, LintId, StableLintExpectationId, UnstableLintExpectationId,
23};
24use rustc_middle::hir::nested_filter;
25use rustc_middle::lint::{
26 LevelSpec, LintExpectation, LintLevelSource, ShallowLintLevelMap, StableLevelSpec,
27 UnstableLevelSpec, emit_lint_base, reveal_actual_level_spec,
28};
29use rustc_middle::query::Providers;
30use rustc_middle::ty::{RegisteredTools, TyCtxt};
31use rustc_session::Session;
32use rustc_span::def_id::CRATE_MOD_ID;
33use rustc_span::{AttrId, DUMMY_SP, Span, Symbol, sym};
34use rustc_structures::LintName;
35use tracing::{debug, instrument};
36
37use crate::builtin::MISSING_DOCS;
38use crate::context::{CheckLintNameResult, LintStore};
39use crate::diagnostics::{
40 CheckNameUnknownTool, DeprecatedLintName, DeprecatedLintNameFromCommandLine,
41 IgnoredUnlessCrateSpecified, OverruledAttribute, OverruledAttributeLint, OverruledAttributeSub,
42 RemovedLint, RemovedLintFromCommandLine, RenamedLint, RenamedLintFromCommandLine,
43 RenamedLintSuggestion, RequestedLevel, UnknownLint, UnknownLintFromCommandLine,
44 UnknownLintSuggestion, UnknownToolInScopedLint, UnsupportedGroup,
45};
46use crate::late::unerased_lint_store;
47
48#[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)]
52struct LintLevelSets {
53 list: IndexVec<LintStackIndex, LintSet>,
55}
56
57#[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! {
58 struct LintStackIndex {
59 const COMMAND_LINE = 0;
60 }
61}
62
63#[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 parent", &self.specs, &&self.parent)
}
}Debug)]
72struct LintSet {
73 specs: FxIndexMap<LintId, UnstableLevelSpec>,
74 parent: LintStackIndex,
75}
76
77impl LintLevelSets {
78 fn new() -> Self {
79 LintLevelSets { list: IndexVec::new() }
80 }
81
82 fn get_lint_level_spec(
83 &self,
84 lint: &'static Lint,
85 idx: LintStackIndex,
86 aux: Option<&FxIndexMap<LintId, UnstableLevelSpec>>,
87 sess: &Session,
88 ) -> UnstableLevelSpec {
89 reveal_actual_level_spec(sess, LintId::of(lint), |id| {
90 self.raw_lint_level_spec(id, idx, aux)
91 })
92 }
93
94 fn raw_lint_level_spec(
95 &self,
96 id: LintId,
97 mut idx: LintStackIndex,
98 aux: Option<&FxIndexMap<LintId, UnstableLevelSpec>>,
99 ) -> Option<UnstableLevelSpec> {
100 if let Some(specs) = aux
101 && let Some(level_spec) = specs.get(&id)
102 {
103 return Some(*level_spec);
104 }
105
106 loop {
107 let LintSet { ref specs, parent } = self.list[idx];
108 if let Some(level_spec) = specs.get(&id) {
109 return Some(*level_spec);
110 }
111 if idx == COMMAND_LINE {
112 return None;
113 }
114 idx = parent;
115 }
116 }
117}
118
119fn skippable_lints(tcx: TyCtxt<'_>, (): ()) -> UnordSet<LintId> {
120 let store = unerased_lint_store(&tcx.sess);
121 let root_map = tcx.shallow_lint_levels_on(hir::CRATE_OWNER_ID);
122
123 let mut skippable: FxHashSet<LintId> = store
124 .get_lints()
125 .into_iter()
126 .filter(|lint| {
127 let has_future_breakage =
129 lint.future_incompatible.is_some_and(|fut| fut.report_in_deps);
130 !has_future_breakage && !lint.eval_always
131 })
132 .filter(|lint| {
133 let level_spec =
134 root_map.lint_level_spec_at_node(tcx, LintId::of(lint), hir::CRATE_HIR_ID);
135 level_spec.is_allow()
137 || (#[allow(non_exhaustive_omitted_patterns)] match level_spec.src {
LintLevelSource::Default => true,
_ => false,
}matches!(level_spec.src, LintLevelSource::Default)
138 && lint.default_level(tcx.sess.edition()) == Level::Allow)
139 })
140 .map(|lint| LintId::of(*lint))
141 .collect();
142
143 for owner in tcx.hir_crate_items(()).owners() {
144 let map = tcx.shallow_lint_levels_on(owner);
145
146 for (_, specs) in map.specs.iter() {
148 for (lint, level_spec) in specs.iter() {
149 if !level_spec.is_allow() {
150 skippable.remove(lint);
151 }
152 }
153 }
154 }
155
156 skippable.into()
157}
158
159{}
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/bbcdfd90a3f81ca2a5f6d69b943a6ff0d8582102/compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(159u32),
::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::unreachable_default_msg(),
},
}
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/bbcdfd90a3f81ca2a5f6d69b943a6ff0d8582102/compiler/rustc_lint/src/levels.rs:159",
"rustc_lint::levels", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/bbcdfd90a3f81ca2a5f6d69b943a6ff0d8582102/compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(159u32),
::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)]
160fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
161 let store = unerased_lint_store(tcx.sess);
162 let attrs = tcx.hir_attr_map(owner);
163
164 let mut levels = LintLevelsBuilder {
165 sess: tcx.sess,
166 features: tcx.features(),
167 provider: LintLevelQueryMap {
168 tcx,
169 cur: owner.into(),
170 specs: ShallowLintLevelMap::default(),
171 empty: FxIndexMap::default(),
172 attrs,
173 },
174 lint_added_lints: false,
175 store,
176 registered_lint_tools: tcx.registered_lint_tools(()),
177 };
178
179 if owner == hir::CRATE_OWNER_ID {
180 levels.add_command_line();
181 }
182
183 match attrs.map.range(..) {
184 [] => {}
186 &[(local_id, _)] => levels.add_id(HirId { owner, local_id }),
188 _ => match tcx.hir_owner_node(owner) {
192 hir::OwnerNode::Item(item) => levels.visit_item(item),
193 hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item),
194 hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item),
195 hir::OwnerNode::ImplItem(item) => levels.visit_impl_item(item),
196 hir::OwnerNode::Crate(mod_) => {
197 levels.add_id(hir::CRATE_HIR_ID);
198 levels.visit_mod(mod_, mod_.spans.inner_span, CRATE_MOD_ID)
199 }
200 hir::OwnerNode::Synthetic => unreachable!(),
201 },
202 }
203
204 let specs = levels.provider.specs;
205
206 #[cfg(debug_assertions)]
207 for (_, v) in specs.specs.iter() {
208 debug_assert!(!v.is_empty());
209 }
210
211 specs
212}
213
214pub struct TopDown {
215 sets: LintLevelSets,
216 cur: LintStackIndex,
217}
218
219pub trait LintLevelsProvider {
220 type LintExpectationId: Copy + Debug + Into<LintExpectationId>;
221
222 fn current_specs(&self) -> &FxIndexMap<LintId, LevelSpec<Self::LintExpectationId>>;
223
224 fn insert(&mut self, id: LintId, level_spec: LevelSpec<Self::LintExpectationId>);
225
226 fn get_lint_level_spec(
227 &self,
228 lint: &'static Lint,
229 sess: &Session,
230 ) -> LevelSpec<Self::LintExpectationId>;
231
232 fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation);
233
234 fn mk_lint_expectation_id(&self, attr_id: AttrId, lint_index: u16) -> Self::LintExpectationId;
235}
236
237impl LintLevelsProvider for TopDown {
238 type LintExpectationId = UnstableLintExpectationId;
239
240 fn current_specs(&self) -> &FxIndexMap<LintId, UnstableLevelSpec> {
241 &self.sets.list[self.cur].specs
242 }
243
244 fn insert(&mut self, id: LintId, level_spec: UnstableLevelSpec) {
245 self.sets.list[self.cur].specs.insert(id, level_spec);
246 }
247
248 fn get_lint_level_spec(&self, lint: &'static Lint, sess: &Session) -> UnstableLevelSpec {
249 self.sets.get_lint_level_spec(lint, self.cur, Some(self.current_specs()), sess)
250 }
251
252 fn push_expectation(&mut self, _: Self::LintExpectationId, _: LintExpectation) {}
253
254 fn mk_lint_expectation_id(&self, attr_id: AttrId, lint_index: u16) -> Self::LintExpectationId {
255 UnstableLintExpectationId { attr_id, lint_index }
256 }
257}
258
259struct LintLevelQueryMap<'tcx> {
260 tcx: TyCtxt<'tcx>,
261 cur: HirId,
262 specs: ShallowLintLevelMap,
263 empty: FxIndexMap<LintId, StableLevelSpec>,
265 attrs: &'tcx hir::AttributeMap<'tcx>,
266}
267
268impl LintLevelsProvider for LintLevelQueryMap<'_> {
269 type LintExpectationId = StableLintExpectationId;
270
271 fn current_specs(&self) -> &FxIndexMap<LintId, StableLevelSpec> {
272 self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
273 }
274
275 fn insert(&mut self, id: LintId, level_spec: StableLevelSpec) {
276 self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, level_spec);
277 }
278
279 fn get_lint_level_spec(&self, lint: &'static Lint, _: &Session) -> StableLevelSpec {
280 self.specs.lint_level_spec_at_node(self.tcx, LintId::of(lint), self.cur)
281 }
282
283 fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation) {
284 self.specs.expectations.push((id, expectation))
285 }
286
287 fn mk_lint_expectation_id(&self, _attr_id: AttrId, lint_index: u16) -> Self::LintExpectationId {
288 StableLintExpectationId { hir_id: self.cur, lint_index }
289 }
290}
291
292impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
293 fn add_id(&mut self, hir_id: HirId) {
294 self.provider.cur = hir_id;
295 self.add_hir(self.provider.attrs.get(hir_id.local_id), hir_id == hir::CRATE_HIR_ID);
296 }
297}
298
299impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
300 type NestedFilter = nested_filter::OnlyBodies;
301
302 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
303 self.provider.tcx
304 }
305
306 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
307 self.add_id(param.hir_id);
308 intravisit::walk_param(self, param);
309 }
310
311 fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
312 self.add_id(it.hir_id());
313 intravisit::walk_item(self, it);
314 }
315
316 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
317 self.add_id(it.hir_id());
318 intravisit::walk_foreign_item(self, it);
319 }
320
321 fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
322 self.add_id(s.hir_id);
323 intravisit::walk_stmt(self, s);
324 }
325
326 fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
327 self.add_id(e.hir_id);
328 intravisit::walk_expr(self, e);
329 }
330
331 fn visit_pat_field(&mut self, f: &'tcx hir::PatField<'tcx>) -> Self::Result {
332 self.add_id(f.hir_id);
333 intravisit::walk_pat_field(self, f);
334 }
335
336 fn visit_expr_field(&mut self, f: &'tcx hir::ExprField<'tcx>) {
337 self.add_id(f.hir_id);
338 intravisit::walk_expr_field(self, f);
339 }
340
341 fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
342 self.add_id(s.hir_id);
343 intravisit::walk_field_def(self, s);
344 }
345
346 fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
347 self.add_id(v.hir_id);
348 intravisit::walk_variant(self, v);
349 }
350
351 fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
352 self.add_id(l.hir_id);
353 intravisit::walk_local(self, l);
354 }
355
356 fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
357 self.add_id(a.hir_id);
358 intravisit::walk_arm(self, a);
359 }
360
361 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
362 self.add_id(trait_item.hir_id());
363 intravisit::walk_trait_item(self, trait_item);
364 }
365
366 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
367 self.add_id(impl_item.hir_id());
368 intravisit::walk_impl_item(self, impl_item);
369 }
370}
371
372pub struct LintLevelsBuilder<'s, P> {
373 sess: &'s Session,
374 features: &'s Features,
375 provider: P,
376 lint_added_lints: bool,
377 store: &'s LintStore,
378 registered_lint_tools: &'s RegisteredTools,
379}
380
381pub(crate) struct BuilderPush {
382 prev: LintStackIndex,
383}
384
385impl<'s> LintLevelsBuilder<'s, TopDown> {
386 pub(crate) fn new(
387 sess: &'s Session,
388 features: &'s Features,
389 lint_added_lints: bool,
390 store: &'s LintStore,
391 registered_lint_tools: &'s RegisteredTools,
392 ) -> Self {
393 let mut builder = LintLevelsBuilder {
394 sess,
395 features,
396 provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE },
397 lint_added_lints,
398 store,
399 registered_lint_tools,
400 };
401 builder.process_command_line();
402 {
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);
403 builder
404 }
405
406 pub fn crate_root(
407 sess: &'s Session,
408 features: &'s Features,
409 lint_added_lints: bool,
410 store: &'s LintStore,
411 registered_lint_tools: &'s RegisteredTools,
412 crate_attrs: &[ast::Attribute],
413 ) -> Self {
414 let mut builder = Self::new(sess, features, lint_added_lints, store, registered_lint_tools);
415 builder.add_ast(crate_attrs, true);
416 builder
417 }
418
419 fn process_command_line(&mut self) {
420 self.provider.cur = self
421 .provider
422 .sets
423 .list
424 .push(LintSet { specs: FxIndexMap::default(), parent: COMMAND_LINE });
425 self.add_command_line();
426 }
427
428 pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush {
443 let prev = self.provider.cur;
444 self.provider.cur =
445 self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev });
446
447 self.add_ast(attrs, is_crate_node);
448
449 if self.provider.current_specs().is_empty() {
450 self.provider.sets.list.pop();
451 self.provider.cur = prev;
452 }
453
454 BuilderPush { prev }
455 }
456
457 pub(crate) fn pop(&mut self, push: BuilderPush) {
459 self.provider.cur = push.prev;
460 std::mem::forget(push);
461 }
462}
463
464#[cfg(debug_assertions)]
465impl Drop for BuilderPush {
466 fn drop(&mut self) {
467 {
::core::panicking::panic_fmt(format_args!("Found a `push` without a `pop`."));
};panic!("Found a `push` without a `pop`.");
468 }
469}
470
471impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P>
472where
473 LevelSpec<P::LintExpectationId>: Into<LevelSpec>,
474{
475 pub(crate) fn sess(&self) -> &Session {
476 self.sess
477 }
478
479 pub(crate) fn features(&self) -> &Features {
480 self.features
481 }
482
483 fn add_command_line(&mut self) {
484 for &(ref lint_name, level) in &self.sess.opts.lint_opts {
485 let lint_name = LintName::from_str(lint_name);
486 if lint_name.is(sym::warnings) && #[allow(non_exhaustive_omitted_patterns)] match level {
Level::ForceWarn => true,
_ => false,
}matches!(level, Level::ForceWarn) {
488 self.sess
489 .dcx()
490 .emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
491 }
492
493 match self.store.check_lint_name(lint_name, self.registered_lint_tools) {
494 CheckLintNameResult::Renamed(replacement) => {
495 let suggestion = RenamedLintSuggestion::WithoutSpan { replacement };
496 let requested_level = RequestedLevel { level, lint_name };
497 let lint = RenamedLintFromCommandLine {
498 lint_name,
499 replacement,
500 suggestion,
501 requested_level,
502 };
503 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
504 }
505 CheckLintNameResult::Removed(ref reason) => {
506 let requested_level = RequestedLevel { level, lint_name };
507 let lint = RemovedLintFromCommandLine { lint_name, reason, requested_level };
508 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
509 }
510 CheckLintNameResult::NoLint(suggestion) => {
511 let suggestion = suggestion.map(|(replacement, from_rustc)| {
512 UnknownLintSuggestion::WithoutSpan { replacement, from_rustc }
513 });
514 let requested_level = RequestedLevel { level, lint_name };
515 let lint =
516 UnknownLintFromCommandLine { lint_name, suggestion, requested_level };
517 self.emit_lint(UNKNOWN_LINTS, lint);
518 }
519 CheckLintNameResult::Tool(_, Some(replacement)) => {
520 let requested_level = RequestedLevel { level, lint_name };
521 let lint = DeprecatedLintNameFromCommandLine {
522 lint_name,
523 replacement,
524 requested_level,
525 };
526 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
527 }
528 CheckLintNameResult::NoTool(tool_name) => {
529 self.sess.dcx().emit_err(CheckNameUnknownTool {
530 tool_name,
531 sub: RequestedLevel { level, lint_name },
532 });
533 }
534 _ => {}
535 };
536
537 let Some(ids) = self.store.find_lints(lint_name) else {
538 continue;
540 };
541 for &id in ids {
542 if let Some(level_spec) = self.provider.current_specs().get(&id)
544 && #[allow(non_exhaustive_omitted_patterns)] match level_spec.level() {
Level::ForceWarn | Level::Forbid => true,
_ => false,
}matches!(level_spec.level(), Level::ForceWarn | Level::Forbid)
545 {
546 continue;
547 }
548
549 if self.check_gated_lint(id, DUMMY_SP, true) {
550 let src = LintLevelSource::CommandLine(lint_name, level);
551 self.provider.insert(id, LevelSpec::new(level, None, src));
552 }
553 }
554 }
555 }
556
557 fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec<P::LintExpectationId>) {
561 let level = level_spec.level();
562 let lint_id = level_spec.lint_id();
563 let src = level_spec.src;
564
565 let old_level_spec = self.provider.get_lint_level_spec(id.lint, self.sess);
566 let old_level = old_level_spec.level();
567 let old_src = old_level_spec.src;
568
569 if self.lint_added_lints && level == Level::Deny && old_level == Level::Forbid {
576 return;
578 } else if self.lint_added_lints && level != Level::Forbid && old_level == Level::Forbid {
579 let fcw_warning = match old_src {
586 LintLevelSource::Default => false,
587 LintLevelSource::Node { name, .. } => self.store.is_lint_group(name),
588 LintLevelSource::CommandLine(name, _) => self.store.is_lint_group(name),
589 };
590 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/bbcdfd90a3f81ca2a5f6d69b943a6ff0d8582102/compiler/rustc_lint/src/levels.rs:590",
"rustc_lint::levels", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/bbcdfd90a3f81ca2a5f6d69b943a6ff0d8582102/compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(590u32),
::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!(
591 "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
592 fcw_warning,
593 self.provider.current_specs(),
594 old_src,
595 id.lint.name_lower(),
596 );
597 let sub = match old_src {
598 LintLevelSource::Default => {
599 OverruledAttributeSub::DefaultSource { id: id.to_string() }
600 }
601 LintLevelSource::Node { span, reason, .. } => {
602 OverruledAttributeSub::NodeSource { span, reason }
603 }
604 LintLevelSource::CommandLine(lint_name, _) => {
605 OverruledAttributeSub::CommandLineSource { forbidden_lint_name: lint_name }
606 }
607 };
608 if !fcw_warning {
609 self.sess.dcx().emit_err(OverruledAttribute {
610 span: src.span(),
611 overruled: src.span(),
612 lint_level: level.as_str(),
613 lint_name: src.name(),
614 sub,
615 });
616 } else {
617 self.emit_span_lint(
618 FORBIDDEN_LINT_GROUPS,
619 src.span().into(),
620 OverruledAttributeLint {
621 overruled: src.span(),
622 lint_level: level.as_str(),
623 lint_name: src.name(),
624 sub,
625 },
626 );
627 }
628
629 if !fcw_warning {
633 return;
634 }
635 }
636
637 if let Level::Expect = level
641 && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS)
642 {
643 return;
644 }
645
646 match (old_level, level) {
647 (Level::ForceWarn, Level::Expect) => {
649 self.provider.insert(id, LevelSpec::new(Level::ForceWarn, lint_id, old_src))
650 }
651 (Level::ForceWarn, _) => {
653 self.provider.insert(id, LevelSpec::new(Level::ForceWarn, None, old_src))
654 }
655 _ => self.provider.insert(id, LevelSpec::new(level, lint_id, src)),
657 };
658 }
659
660 fn add_ast(&mut self, attrs: &[rustc_ast::Attribute], is_crate_node: bool) {
661 if attrs.is_empty() {
662 return;
663 }
664 for attr in attrs {
665 if attr.has_name(sym::automatically_derived) {
667 self.provider.insert(
668 LintId::of(SINGLE_USE_LIFETIMES),
669 LevelSpec::new(Level::Allow, None, LintLevelSource::Default),
670 );
671 }
672 }
673 let parsed = AttributeParser::parse_limited_all(
674 self.sess,
675 attrs,
676 Some(&|attr| {
677 (attr.path_matches(&[sym::allow])
696 || attr.path_matches(&[sym::warn])
697 || attr.path_matches(&[sym::deny])
698 || attr.path_matches(&[sym::forbid])
699 || attr.path_matches(&[sym::expect]))
700 && attr.meta_item_list().is_some()
701 }),
702 AstTarget::None(Target::Crate),
703 DUMMY_SP,
704 CRATE_NODE_ID,
705 Some(self.features),
706 ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
707 Some(self.registered_lint_tools),
708 );
709 self.add_hir_inner(&parsed, is_crate_node)
710 }
711
712 fn add_hir(&mut self, attrs: &[Attribute], is_crate_node: bool) {
713 if attrs.is_empty() {
714 return;
715 }
716 if {
{
'done:
{
for i in attrs {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(Doc(DocAttribute {
hidden: Some(_), .. })) => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Tool(..) |
::rustc_attr_ir::Attribute::DeriveHelper(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}.is_some()
}find_attr!(attrs, Doc(DocAttribute { hidden: Some(_), .. })) {
718 self.provider.insert(
719 LintId::of(MISSING_DOCS),
720 LevelSpec::new(Level::Allow, None, LintLevelSource::Default),
721 );
722 }
723 self.add_hir_inner(attrs, is_crate_node)
724 }
725
726 fn add_hir_inner(&mut self, attrs: &[Attribute], is_crate_node: bool) {
727 let Some(lint_checks) = {
'done:
{
for i in attrs {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(LintCheck(lints)) => {
break 'done Some(lints.clone());
}
::rustc_attr_ir::Attribute::Tool(..) |
::rustc_attr_ir::Attribute::DeriveHelper(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}find_attr!(attrs, LintCheck(lints) => lints.clone()) else {
728 return;
729 };
730
731 let sess = self.sess;
732
733 for (lint_index, lint_check) in lint_checks.into_iter().enumerate() {
735 let LintCheck { lint_name, kind, reason, attr_id, attr_span: _, lint_span, tool_span } =
736 lint_check;
737 let LintName { tool, name: _ } = lint_name;
738
739 let level = match kind {
740 LintCheckKind::Allow => Level::Allow,
741 LintCheckKind::Warn => Level::Warn,
742 LintCheckKind::Deny => Level::Deny,
743 LintCheckKind::Forbid => Level::Forbid,
744 LintCheckKind::Expect => Level::Expect,
745 };
746
747 let lint_id = (level == Level::Expect)
750 .then(|| self.provider.mk_lint_expectation_id(attr_id.attr_id, lint_index as u16));
751
752 let lint_result = self.store.check_lint_name(lint_name, self.registered_lint_tools);
753
754 let (ids, name): (_, LintName) = match lint_result {
755 CheckLintNameResult::Ok(ids) => (ids, lint_name),
756
757 CheckLintNameResult::Tool(ids, new_lint_name) => {
758 let name = match new_lint_name {
759 None => lint_name,
760 Some(replacement) => {
761 self.emit_span_lint(
762 builtin::RENAMED_AND_REMOVED_LINTS,
763 lint_span.into(),
764 DeprecatedLintName {
765 lint_name,
766 suggestion: lint_span,
767 replacement,
768 },
769 );
770 replacement
771 }
772 };
773 (ids, name)
774 }
775
776 CheckLintNameResult::MissingTool => {
777 continue;
782 }
783
784 CheckLintNameResult::NoTool(tool_name) => {
785 sess.dcx().emit_err(UnknownToolInScopedLint {
786 span: Some(tool_span.unwrap()),
787 tool_name,
788 lint_name,
789 is_nightly_build: sess.is_nightly_build(),
790 });
791 continue;
792 }
793
794 CheckLintNameResult::Renamed(replacement) => {
795 if self.lint_added_lints {
796 let suggestion =
797 RenamedLintSuggestion::WithSpan { suggestion: lint_span, replacement };
798
799 self.emit_span_lint(
800 RENAMED_AND_REMOVED_LINTS,
801 lint_span.into(),
802 RenamedLint { name: lint_name, replacement, suggestion },
803 );
804 }
805
806 let replace_check =
810 self.store.check_lint_name(replacement, self.registered_lint_tools);
811 let (CheckLintNameResult::Ok(ids) | CheckLintNameResult::Tool(ids, _)) =
812 replace_check
813 else {
814 {
::core::panicking::panic_fmt(format_args!("renamed lint does not exist: {0} :{1:?}",
replacement, replace_check));
};panic!("renamed lint does not exist: {replacement} :{replace_check:?}");
815 };
816
817 (ids, replacement)
818 }
819
820 CheckLintNameResult::Removed(ref reason) => {
821 if self.lint_added_lints {
822 self.emit_span_lint(
823 RENAMED_AND_REMOVED_LINTS,
824 lint_span.into(),
825 RemovedLint { name: lint_name, reason },
826 );
827 }
828 continue;
829 }
830
831 CheckLintNameResult::NoLint(suggestion) => {
832 if self.lint_added_lints {
833 let suggestion = suggestion.map(|(replacement, from_rustc)| {
834 UnknownLintSuggestion::WithSpan {
835 suggestion: lint_span,
836 replacement,
837 from_rustc,
838 }
839 });
840 self.emit_span_lint(
841 UNKNOWN_LINTS,
842 lint_span.into(),
843 UnknownLint { name: lint_name, suggestion },
844 );
845 }
846 continue;
847 }
848 };
849
850 let src = LintLevelSource::Node { name, span: lint_span, reason };
851 for &id in ids {
852 if self.check_gated_lint(id, lint_span, false) {
853 self.insert_spec(id, LevelSpec::new(level, lint_id, src));
854 }
855 }
856
857 if let (Level::Expect, Some(expect_id)) = (level, lint_id) {
863 let is_unfulfilled_lint_expectations = match ids {
867 [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
868 _ => false,
869 };
870 self.provider.push_expectation(
871 expect_id,
872 LintExpectation::new(reason, lint_span, is_unfulfilled_lint_expectations, tool),
873 );
874 }
875 }
876
877 if self.lint_added_lints && !is_crate_node {
878 for (id, level_spec) in self.provider.current_specs().iter() {
879 if !id.lint.crate_level_only {
880 continue;
881 }
882
883 let LintLevelSource::Node { name: lint_attr_name, span: lint_attr_span, .. } =
884 level_spec.src
885 else {
886 continue;
887 };
888
889 self.emit_span_lint(
890 UNUSED_ATTRIBUTES,
891 lint_attr_span.into(),
892 IgnoredUnlessCrateSpecified {
893 level: level_spec.level().as_str(),
894 lint_name: lint_attr_name,
895 },
896 );
897 break;
899 }
900 }
901 }
902
903 #[track_caller]
907 fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
908 let feature = if let Some(feature) = lint_id.lint.feature_gate
909 && !self.features.enabled(feature)
910 && !span.allows_unstable(feature)
911 {
912 feature
914 } else {
915 return true;
917 };
918
919 struct UnknownLint<'a> {
920 sess: &'a Session,
921 lint_id: LintId,
922 feature: Symbol,
923 lint_from_cli: bool,
924 }
925
926 impl<'a, 'b> Diagnostic<'a> for UnknownLint<'b> {
927 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: rustc_errors::Level) -> Diag<'a> {
928 let Self { sess, lint_id, feature, lint_from_cli } = self;
929 let mut lint = Diag::new(dcx, level, rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("unknown lint: `{$name}`"))msg!("unknown lint: `{$name}`"))
930 .with_arg("name", lint_id.lint.name_lower())
931 .with_note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the `{$name}` lint is unstable"))msg!("the `{$name}` lint is unstable"));
932 if feature != sym::staged_api {
935 rustc_session::diagnostics::add_feature_diagnostics_for_issue(
936 &mut lint,
937 sess,
938 feature,
939 GateIssue::Language,
940 lint_from_cli,
941 None,
942 );
943 }
944 lint
945 }
946 }
947
948 if self.lint_added_lints {
949 let lint = builtin::UNKNOWN_LINTS;
950 let level_spec = self.lint_level_spec(builtin::UNKNOWN_LINTS);
951 emit_lint_base(
952 self.sess,
953 lint,
954 level_spec,
955 Some(span.into()),
956 UnknownLint { sess: &self.sess, lint_id, feature, lint_from_cli },
957 );
958 }
959
960 false
961 }
962
963 pub fn lint_level_spec(&self, lint: &'static Lint) -> LevelSpec<P::LintExpectationId> {
965 self.provider.get_lint_level_spec(lint, self.sess)
966 }
967
968 #[track_caller]
971 pub(crate) fn opt_span_lint(
972 &self,
973 lint: &'static Lint,
974 span: Option<MultiSpan>,
975 decorator: impl for<'a> Diagnostic<'a>,
976 ) {
977 let level_spec = self.lint_level_spec(lint);
978 emit_lint_base(self.sess, lint, level_spec, span, decorator)
979 }
980
981 #[track_caller]
982 pub fn emit_span_lint(
983 &self,
984 lint: &'static Lint,
985 span: MultiSpan,
986 decorator: impl for<'a> Diagnostic<'a>,
987 ) {
988 let level_spec = self.lint_level_spec(lint);
989 emit_lint_base(self.sess, lint, level_spec, Some(span), decorator);
990 }
991
992 #[track_caller]
993 pub fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a>) {
994 let level_spec = self.lint_level_spec(lint);
995 emit_lint_base(self.sess, lint, level_spec, None, decorator);
996 }
997}
998
999pub(crate) fn provide(providers: &mut Providers) {
1000 *providers = Providers { shallow_lint_levels_on, skippable_lints, ..*providers };
1001}