1use rustc_ast as ast;
2use rustc_ast::{DUMMY_NODE_ID, NodeId};
3use rustc_attr_parsing::AttributeParser;
4use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
5use rustc_data_structures::unord::UnordSet;
6use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, MultiSpan, msg};
7use rustc_feature::{Features, GateIssue};
8use rustc_hir::attrs::{LintAttribute, LintAttributeKind, LintInstance};
9use rustc_hir::intravisit::{self, Visitor};
10use rustc_hir::{self as hir, HirId, Target, find_attr};
11use rustc_index::IndexVec;
12use rustc_middle::bug;
13use rustc_middle::hir::nested_filter;
14use rustc_middle::lint::{
15 LevelAndSource, LintExpectation, LintLevelSource, ShallowLintLevelMap, emit_lint_base,
16 reveal_actual_level,
17};
18use rustc_middle::query::Providers;
19use rustc_middle::ty::{RegisteredTools, TyCtxt};
20use rustc_session::Session;
21use rustc_session::lint::builtin::{
22 self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
23 UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS,
24};
25use rustc_session::lint::{
26 CheckLintNameResult, Level, Lint, LintExpectationId, LintId, TargetLint,
27};
28use rustc_span::{DUMMY_SP, Span, Symbol, sym};
29use tracing::{debug, instrument};
30
31use crate::builtin::MISSING_DOCS;
32use crate::context::LintStore;
33use crate::errors::{
34 CheckNameUnknownTool, OverruledAttribute, OverruledAttributeSub, RequestedLevel,
35 UnsupportedGroup,
36};
37use crate::late::unerased_lint_store;
38use crate::lints::{
39 DeprecatedLintNameFromCommandLine, OverruledAttributeLint, RemovedLintFromCommandLine,
40 RenamedLintFromCommandLine, RenamedLintSuggestion, UnknownLintFromCommandLine,
41 UnknownLintSuggestion,
42};
43
44const ALLOW_LISTED_ATTRS: &[Symbol] = &[
45 sym::allow,
46 sym::deny,
47 sym::expect,
48 sym::forbid,
49 sym::warn,
50 sym::automatically_derived,
51 sym::doc,
52];
53
54#[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)]
58struct LintLevelSets {
59 list: IndexVec<LintStackIndex, LintSet>,
61}
62
63impl ::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! {
64 struct LintStackIndex {
65 const COMMAND_LINE = 0;
66 }
67}
68
69#[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)]
78struct LintSet {
79 specs: FxIndexMap<LintId, LevelAndSource>,
82 parent: LintStackIndex,
83}
84
85impl LintLevelSets {
86 fn new() -> Self {
87 LintLevelSets { list: IndexVec::new() }
88 }
89
90 fn get_lint_level(
91 &self,
92 lint: &'static Lint,
93 idx: LintStackIndex,
94 aux: Option<&FxIndexMap<LintId, LevelAndSource>>,
95 sess: &Session,
96 ) -> LevelAndSource {
97 let lint = LintId::of(lint);
98 let (level, mut src) = self.raw_lint_id_level(lint, idx, aux);
99 let (level, lint_id) = reveal_actual_level(level, &mut src, sess, lint, |id| {
100 self.raw_lint_id_level(id, idx, aux)
101 });
102 LevelAndSource { level, lint_id, src }
103 }
104
105 fn raw_lint_id_level(
106 &self,
107 id: LintId,
108 mut idx: LintStackIndex,
109 aux: Option<&FxIndexMap<LintId, LevelAndSource>>,
110 ) -> (Option<(Level, Option<LintExpectationId>)>, LintLevelSource) {
111 if let Some(specs) = aux
112 && let Some(&LevelAndSource { level, lint_id, src }) = specs.get(&id)
113 {
114 return (Some((level, lint_id)), src);
115 }
116
117 loop {
118 let LintSet { ref specs, parent } = self.list[idx];
119 if let Some(&LevelAndSource { level, lint_id, src }) = specs.get(&id) {
120 return (Some((level, lint_id)), src);
121 }
122 if idx == COMMAND_LINE {
123 return (None, LintLevelSource::Default);
124 }
125 idx = parent;
126 }
127 }
128}
129
130fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> UnordSet<LintId> {
131 let store = unerased_lint_store(&tcx.sess);
132 let root_map = tcx.shallow_lint_levels_on(hir::CRATE_OWNER_ID);
133
134 let mut dont_need_to_run: FxHashSet<LintId> = store
135 .get_lints()
136 .into_iter()
137 .filter(|lint| {
138 let has_future_breakage =
140 lint.future_incompatible.is_some_and(|fut| fut.report_in_deps);
141 !has_future_breakage && !lint.eval_always
142 })
143 .filter(|lint| {
144 let lint_level =
145 root_map.lint_level_id_at_node(tcx, LintId::of(lint), hir::CRATE_HIR_ID);
146 #[allow(non_exhaustive_omitted_patterns)] match lint_level.level {
Level::Allow => true,
_ => false,
}matches!(lint_level.level, Level::Allow)
148 || (#[allow(non_exhaustive_omitted_patterns)] match lint_level.src {
LintLevelSource::Default => true,
_ => false,
}matches!(lint_level.src, LintLevelSource::Default)
149 && lint.default_level(tcx.sess.edition()) == Level::Allow)
150 })
151 .map(|lint| LintId::of(*lint))
152 .collect();
153
154 for owner in tcx.hir_crate_items(()).owners() {
155 let map = tcx.shallow_lint_levels_on(owner);
156
157 for (_, specs) in map.specs.iter() {
159 for (lint, level_and_source) in specs.iter() {
160 if !#[allow(non_exhaustive_omitted_patterns)] match level_and_source.level {
Level::Allow => true,
_ => false,
}matches!(level_and_source.level, Level::Allow) {
161 dont_need_to_run.remove(lint);
162 }
163 }
164 }
165 }
166
167 dont_need_to_run.into()
168}
169
170x;#[instrument(level = "trace", skip(tcx), ret)]
171fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
172 let store = unerased_lint_store(tcx.sess);
173 let attrs = tcx.hir_attr_map(owner);
174
175 let mut levels = LintLevelsBuilder {
176 sess: tcx.sess,
177 features: tcx.features(),
178 provider: LintLevelQueryMap {
179 tcx,
180 cur: owner.into(),
181 specs: ShallowLintLevelMap::default(),
182 empty: FxIndexMap::default(),
183 attrs,
184 },
185 lint_added_lints: false,
186 store,
187 registered_tools: tcx.registered_tools(()),
188 };
189
190 if owner == hir::CRATE_OWNER_ID {
191 levels.add_command_line();
192 }
193
194 match attrs.map.range(..) {
195 [] => {}
197 &[(local_id, _)] => levels.add_id(HirId { owner, local_id }),
199 _ => match tcx.hir_owner_node(owner) {
203 hir::OwnerNode::Item(item) => levels.visit_item(item),
204 hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item),
205 hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item),
206 hir::OwnerNode::ImplItem(item) => levels.visit_impl_item(item),
207 hir::OwnerNode::Crate(mod_) => {
208 levels.add_id(hir::CRATE_HIR_ID);
209 levels.visit_mod(mod_, mod_.spans.inner_span, hir::CRATE_HIR_ID)
210 }
211 hir::OwnerNode::Synthetic => unreachable!(),
212 },
213 }
214
215 let specs = levels.provider.specs;
216
217 #[cfg(debug_assertions)]
218 for (_, v) in specs.specs.iter() {
219 debug_assert!(!v.is_empty());
220 }
221
222 specs
223}
224
225pub struct TopDown {
226 sets: LintLevelSets,
227 cur: LintStackIndex,
228}
229
230pub trait LintLevelsProvider {
231 fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource>;
232 fn insert(&mut self, id: LintId, lvl: LevelAndSource);
233 fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource;
234 fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation);
235}
236
237impl LintLevelsProvider for TopDown {
238 fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource> {
239 &self.sets.list[self.cur].specs
240 }
241
242 fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
243 self.sets.list[self.cur].specs.insert(id, lvl);
244 }
245
246 fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource {
247 self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), sess)
248 }
249
250 fn push_expectation(&mut self, _: LintExpectationId, _: LintExpectation) {}
251}
252
253struct LintLevelQueryMap<'tcx> {
254 tcx: TyCtxt<'tcx>,
255 cur: HirId,
256 specs: ShallowLintLevelMap,
257 empty: FxIndexMap<LintId, LevelAndSource>,
259 attrs: &'tcx hir::AttributeMap<'tcx>,
260}
261
262impl LintLevelsProvider for LintLevelQueryMap<'_> {
263 fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource> {
264 self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
265 }
266 fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
267 self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl);
268 }
269 fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
270 self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
271 }
272 fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) {
273 self.specs.expectations.push((id, expectation))
274 }
275}
276
277impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
278 fn add_id(&mut self, hir_id: HirId) {
279 self.provider.cur = hir_id;
280 self.add(self.provider.attrs.get(hir_id.local_id), Some(hir_id));
281 }
282}
283
284impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
285 type NestedFilter = nested_filter::OnlyBodies;
286
287 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
288 self.provider.tcx
289 }
290
291 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
292 self.add_id(param.hir_id);
293 intravisit::walk_param(self, param);
294 }
295
296 fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
297 self.add_id(it.hir_id());
298 intravisit::walk_item(self, it);
299 }
300
301 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
302 self.add_id(it.hir_id());
303 intravisit::walk_foreign_item(self, it);
304 }
305
306 fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
307 self.add_id(s.hir_id);
308 intravisit::walk_stmt(self, s);
309 }
310
311 fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
312 self.add_id(e.hir_id);
313 intravisit::walk_expr(self, e);
314 }
315
316 fn visit_pat_field(&mut self, f: &'tcx hir::PatField<'tcx>) -> Self::Result {
317 self.add_id(f.hir_id);
318 intravisit::walk_pat_field(self, f);
319 }
320
321 fn visit_expr_field(&mut self, f: &'tcx hir::ExprField<'tcx>) {
322 self.add_id(f.hir_id);
323 intravisit::walk_expr_field(self, f);
324 }
325
326 fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
327 self.add_id(s.hir_id);
328 intravisit::walk_field_def(self, s);
329 }
330
331 fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
332 self.add_id(v.hir_id);
333 intravisit::walk_variant(self, v);
334 }
335
336 fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
337 self.add_id(l.hir_id);
338 intravisit::walk_local(self, l);
339 }
340
341 fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
342 self.add_id(a.hir_id);
343 intravisit::walk_arm(self, a);
344 }
345
346 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
347 self.add_id(trait_item.hir_id());
348 intravisit::walk_trait_item(self, trait_item);
349 }
350
351 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
352 self.add_id(impl_item.hir_id());
353 intravisit::walk_impl_item(self, impl_item);
354 }
355}
356
357pub struct LintLevelsBuilder<'s, P> {
358 sess: &'s Session,
359 features: &'s Features,
360 provider: P,
361 lint_added_lints: bool,
362 store: &'s LintStore,
363 registered_tools: &'s RegisteredTools,
364}
365
366pub(crate) struct BuilderPush {
367 prev: LintStackIndex,
368}
369
370impl<'s> LintLevelsBuilder<'s, TopDown> {
371 pub(crate) fn new(
372 sess: &'s Session,
373 features: &'s Features,
374 lint_added_lints: bool,
375 store: &'s LintStore,
376 registered_tools: &'s RegisteredTools,
377 ) -> Self {
378 let mut builder = LintLevelsBuilder {
379 sess,
380 features,
381 provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE },
382 lint_added_lints,
383 store,
384 registered_tools,
385 };
386 builder.process_command_line();
387 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);
388 builder
389 }
390
391 pub fn crate_root(
392 sess: &'s Session,
393 features: &'s Features,
394 lint_added_lints: bool,
395 store: &'s LintStore,
396 registered_tools: &'s RegisteredTools,
397 crate_attrs: &[ast::Attribute],
398 ) -> Self {
399 let mut builder = Self::new(sess, features, lint_added_lints, store, registered_tools);
400 let parsed_crate_attrs = AttributeParser::parse_limited_all_filtered(
401 sess,
402 crate_attrs,
403 ALLOW_LISTED_ATTRS,
404 Target::Crate,
405 DUMMY_SP,
406 DUMMY_NODE_ID,
407 Some(features),
408 rustc_attr_parsing::ShouldEmit::Nothing,
409 registered_tools,
410 );
411
412 builder.add(&parsed_crate_attrs, None);
413 builder
414 }
415
416 fn process_command_line(&mut self) {
417 self.provider.cur = self
418 .provider
419 .sets
420 .list
421 .push(LintSet { specs: FxIndexMap::default(), parent: COMMAND_LINE });
422 self.add_command_line();
423 }
424
425 pub(crate) fn push(
440 &mut self,
441 attrs: &[ast::Attribute],
442 node_id: NodeId,
443 target_span: Span,
444 ) -> BuilderPush {
445 let prev = self.provider.cur;
446 self.provider.cur =
447 self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev });
448 if !attrs.is_empty() {
449 let attrs = AttributeParser::parse_limited_all_filtered(
450 self.sess,
451 attrs,
452 ALLOW_LISTED_ATTRS,
453 Target::Fn,
454 target_span,
455 node_id,
456 Some(self.features),
457 rustc_attr_parsing::ShouldEmit::Nothing,
458 self.registered_tools,
459 );
460
461 self.add(&attrs, None);
462
463 if self.provider.current_specs().is_empty() {
464 self.provider.sets.list.pop();
465 self.provider.cur = prev;
466 }
467 }
468
469 BuilderPush { prev }
470 }
471
472 pub(crate) fn pop(&mut self, push: BuilderPush) {
474 self.provider.cur = push.prev;
475 std::mem::forget(push);
476 }
477}
478
479#[cfg(debug_assertions)]
480impl Drop for BuilderPush {
481 fn drop(&mut self) {
482 {
::core::panicking::panic_fmt(format_args!("Found a `push` without a `pop`."));
};panic!("Found a `push` without a `pop`.");
483 }
484}
485
486impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
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 current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource> {
496 self.provider.current_specs()
497 }
498
499 fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
500 self.provider.insert(id, lvl)
501 }
502
503 fn add_command_line(&mut self) {
504 for &(ref lint_name, level) in &self.sess.opts.lint_opts {
505 let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
507 if lint_name_only == crate::WARNINGS.name_lower() && #[allow(non_exhaustive_omitted_patterns)] match level {
Level::ForceWarn => true,
_ => false,
}matches!(level, Level::ForceWarn) {
508 self.sess
509 .dcx()
510 .emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
511 }
512 match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) {
513 CheckLintNameResult::Renamed(replace) => {
514 let name = lint_name.as_str();
515 let suggestion = RenamedLintSuggestion::WithoutSpan { replace };
516 let requested_level = RequestedLevel { level, lint_name };
517 let lint =
518 RenamedLintFromCommandLine { name, replace, suggestion, requested_level };
519 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
520 }
521 CheckLintNameResult::Removed(ref reason) => {
522 let name = lint_name.as_str();
523 let requested_level = RequestedLevel { level, lint_name };
524 let lint = RemovedLintFromCommandLine { name, reason, requested_level };
525 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
526 }
527 CheckLintNameResult::NoLint(suggestion) => {
528 let name = lint_name.clone();
529 let suggestion = suggestion.map(|(replace, from_rustc)| {
530 UnknownLintSuggestion::WithoutSpan { replace, from_rustc }
531 });
532 let requested_level = RequestedLevel { level, lint_name };
533 let lint = UnknownLintFromCommandLine { name, suggestion, requested_level };
534 self.emit_lint(UNKNOWN_LINTS, lint);
535 }
536 CheckLintNameResult::Tool(_, Some(ref replace)) => {
537 let name = lint_name.clone();
538 let requested_level = RequestedLevel { level, lint_name };
539 let lint = DeprecatedLintNameFromCommandLine { name, replace, requested_level };
540 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
541 }
542 CheckLintNameResult::NoTool => {
543 self.sess.dcx().emit_err(CheckNameUnknownTool {
544 tool_name: tool_name.unwrap(),
545 sub: RequestedLevel { level, lint_name },
546 });
547 }
548 _ => {}
549 };
550
551 let lint_flag_val = Symbol::intern(lint_name);
552
553 let Some(ids) = self.store.find_lints(lint_name) else {
554 continue;
556 };
557 for &id in ids {
558 if let Some(LevelAndSource { level: Level::ForceWarn | Level::Forbid, .. }) =
560 self.current_specs().get(&id)
561 {
562 continue;
563 }
564
565 if self.check_gated_lint(id, DUMMY_SP, true) {
566 let src = LintLevelSource::CommandLine(lint_flag_val, level);
567 self.insert(id, LevelAndSource { level, lint_id: None, src });
568 }
569 }
570 }
571 }
572
573 fn insert_spec(&mut self, id: LintId, LevelAndSource { level, lint_id, src }: LevelAndSource) {
577 let LevelAndSource { level: old_level, src: old_src, .. } =
578 self.provider.get_lint_level(id.lint, self.sess);
579
580 if self.lint_added_lints && level == Level::Deny && old_level == Level::Forbid {
587 return;
589 } else if self.lint_added_lints && level != Level::Forbid && old_level == Level::Forbid {
590 let id_name = id.lint.name_lower();
597 let fcw_warning = match old_src {
598 LintLevelSource::Default => false,
599 LintLevelSource::Node { name, .. } => self.store.is_lint_group(name),
600 LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
601 };
602 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/levels.rs:602",
"rustc_lint::levels", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(602u32),
::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};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("fcw_warning={0:?}, specs.get(&id) = {1:?}, old_src={2:?}, id_name={3:?}",
fcw_warning, self.current_specs(), old_src, id_name) as
&dyn Value))])
});
} else { ; }
};debug!(
603 "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
604 fcw_warning,
605 self.current_specs(),
606 old_src,
607 id_name
608 );
609 let sub = match old_src {
610 LintLevelSource::Default => {
611 OverruledAttributeSub::DefaultSource { id: id.to_string() }
612 }
613 LintLevelSource::Node { span, reason, .. } => {
614 OverruledAttributeSub::NodeSource { span, reason }
615 }
616 LintLevelSource::CommandLine(name, _) => {
617 OverruledAttributeSub::CommandLineSource { id: name }
618 }
619 };
620 if !fcw_warning {
621 self.sess.dcx().emit_err(OverruledAttribute {
622 span: src.span(),
623 overruled: src.span(),
624 lint_level: level.as_str(),
625 lint_source: src.name(),
626 sub,
627 });
628 } else {
629 self.emit_span_lint(
630 FORBIDDEN_LINT_GROUPS,
631 src.span().into(),
632 OverruledAttributeLint {
633 overruled: src.span(),
634 lint_level: level.as_str(),
635 lint_source: src.name(),
636 sub,
637 },
638 );
639 }
640
641 if !fcw_warning {
645 return;
646 }
647 }
648
649 if let Level::Expect = level
653 && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS)
654 {
655 return;
656 }
657
658 match (old_level, level) {
659 (Level::ForceWarn, Level::Expect) => {
661 self.insert(id, LevelAndSource { level: Level::ForceWarn, lint_id, src: old_src })
662 }
663 (Level::ForceWarn, _) => self.insert(
665 id,
666 LevelAndSource { level: Level::ForceWarn, lint_id: None, src: old_src },
667 ),
668 _ => self.insert(id, LevelAndSource { level, lint_id, src }),
670 };
671 }
672
673 fn simple_add(
674 &mut self,
675 level: Level,
676 lint: &LintInstance,
677 reason: Option<Symbol>,
678 expect_lint_id: Option<LintExpectationId>,
679 ) {
680 let src =
683 LintLevelSource::Node { name: lint.original_lint_name(), span: lint.span(), reason };
684
685 let id = match self.store.get_lint_by_name(lint.full_lint().as_str()) {
686 Some(TargetLint::Id(id)) => id,
687 None | Some(_) => ::rustc_middle::util::bug::bug_fmt(format_args!("guaranteed to find id due to previous parsing, happened while parsing {0:?}",
lint))bug!(
688 "guaranteed to find id due to previous parsing, happened while parsing {:?}",
689 lint,
690 ),
691 };
692
693 if self.check_gated_lint(*id, lint.span(), false) {
694 self.insert_spec(*id, LevelAndSource { level, lint_id: expect_lint_id, src });
695 }
696 }
697
698 fn add(&mut self, attrs: &[hir::Attribute], source_hir_id: Option<HirId>) {
699 if {
{
'done:
{
for i in attrs {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AutomaticallyDerived(..)) => {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}.is_some()
}find_attr!(attrs, AutomaticallyDerived(..)) {
700 self.insert(
701 LintId::of(SINGLE_USE_LIFETIMES),
702 LevelAndSource {
703 level: Level::Allow,
704 lint_id: None,
705 src: LintLevelSource::Default,
706 },
707 );
708 }
709 if {
{
'done:
{
for i in attrs {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(Doc(d)) if d.hidden.is_some()
=> {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}.is_some()
}find_attr!(attrs, Doc(d) if d.hidden.is_some()) {
711 self.insert(
712 LintId::of(MISSING_DOCS),
713 LevelAndSource {
714 level: Level::Allow,
715 lint_id: None,
716 src: LintLevelSource::Default,
717 },
718 );
719 }
720
721 let Some(attrs) = {
'done:
{
for i in attrs {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(LintAttributes(sub_attrs)) => {
break 'done Some(sub_attrs.into_iter());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}find_attr!(attrs, LintAttributes(sub_attrs) => sub_attrs.into_iter())
722 else {
723 return;
724 };
725
726 for (attr_index, LintAttribute { reason, lint_instances, attr_id, kind, .. }) in
727 attrs.enumerate()
728 {
729 let attr_id = attr_id.attr_id;
730 let level = match kind {
731 LintAttributeKind::Allow => Level::Allow,
732 LintAttributeKind::Deny => Level::Deny,
733 LintAttributeKind::Forbid => Level::Forbid,
734 LintAttributeKind::Warn => Level::Warn,
735 LintAttributeKind::Expect => {
736 for lint in lint_instances {
737 let lint_index = lint.lint_index().try_into().unwrap();
738 let attr_index = attr_index.try_into().unwrap();
739 let expectation_id = match source_hir_id {
740 None => LintExpectationId::Unstable { attr_id, lint_index },
741 Some(hir_id) => LintExpectationId::Stable {
742 hir_id,
743 attr_id,
744 lint_index,
745 attr_index,
746 },
747 };
748
749 self.simple_add(Level::Expect, lint, *reason, Some(expectation_id));
750
751 let is_unfulfilled_lint_expectations =
752 lint.lint_name().as_str() == UNFULFILLED_LINT_EXPECTATIONS.name_lower();
753 self.provider.push_expectation(
754 expectation_id,
755 LintExpectation::new(
756 *reason,
757 lint.span(),
758 is_unfulfilled_lint_expectations,
759 lint.tool_name(),
760 ),
761 );
762 }
763
764 continue;
765 }
766 };
767 for lint in lint_instances {
768 self.simple_add(level, lint, *reason, None);
769 }
770 }
771 }
772
773 #[track_caller]
777 fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
778 let feature = if let Some(feature) = lint_id.lint.feature_gate
779 && !self.features.enabled(feature)
780 && !span.allows_unstable(feature)
781 {
782 feature
784 } else {
785 return true;
787 };
788
789 struct UnknownLint<'a> {
790 sess: &'a Session,
791 lint_id: LintId,
792 feature: Symbol,
793 lint_from_cli: bool,
794 }
795
796 impl<'a, 'b> Diagnostic<'a, ()> for UnknownLint<'b> {
797 fn into_diag(
798 self,
799 dcx: DiagCtxtHandle<'a>,
800 level: rustc_errors::Level,
801 ) -> Diag<'a, ()> {
802 let Self { sess, lint_id, feature, lint_from_cli } = self;
803 let mut lint = Diag::new(dcx, level, rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("unknown lint: `{$name}`"))msg!("unknown lint: `{$name}`"))
804 .with_arg("name", lint_id.lint.name_lower())
805 .with_note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the `{$name}` lint is unstable"))msg!("the `{$name}` lint is unstable"));
806 rustc_session::parse::add_feature_diagnostics_for_issue(
807 &mut lint,
808 sess,
809 feature,
810 GateIssue::Language,
811 lint_from_cli,
812 None,
813 );
814 lint
815 }
816 }
817
818 if self.lint_added_lints {
819 let lint = builtin::UNKNOWN_LINTS;
820 let level = self.lint_level(builtin::UNKNOWN_LINTS);
821 emit_lint_base(
822 self.sess,
823 lint,
824 level,
825 Some(span.into()),
826 UnknownLint { sess: &self.sess, lint_id, feature, lint_from_cli },
827 );
828 }
829
830 false
831 }
832
833 pub fn lint_level(&self, lint: &'static Lint) -> LevelAndSource {
835 self.provider.get_lint_level(lint, self.sess)
836 }
837
838 #[track_caller]
841 pub(crate) fn opt_span_lint(
842 &self,
843 lint: &'static Lint,
844 span: Option<MultiSpan>,
845 decorator: impl for<'a> Diagnostic<'a, ()>,
846 ) {
847 let level = self.lint_level(lint);
848 emit_lint_base(self.sess, lint, level, span, decorator)
849 }
850
851 #[track_caller]
852 pub fn emit_span_lint(
853 &self,
854 lint: &'static Lint,
855 span: MultiSpan,
856 decorator: impl for<'a> Diagnostic<'a, ()>,
857 ) {
858 let level = self.lint_level(lint);
859 emit_lint_base(self.sess, lint, level, Some(span), decorator);
860 }
861
862 #[track_caller]
863 pub fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a, ()>) {
864 let level = self.lint_level(lint);
865 emit_lint_base(self.sess, lint, level, None, decorator);
866 }
867}
868
869pub(crate) fn provide(providers: &mut Providers) {
870 *providers = Providers { shallow_lint_levels_on, lints_that_dont_need_to_run, ..*providers };
871}
872
873pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
874 match lint_name.split_once("::") {
875 Some((tool_name, lint_name)) => {
876 let tool_name = Symbol::intern(tool_name);
877
878 (Some(tool_name), lint_name)
879 }
880 None => (None, lint_name),
881 }
882}