Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions compiler/rustc_attr_ir/src/lint.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use rustc_macros::{Decodable, Encodable, PrintAttribute, StableHash};
use rustc_span::{Ident, Span, Symbol, sym};
use rustc_span::{Span, Symbol, sym};
use rustc_structures::LintName;

use crate::{HashIgnoredAttrId, PrintAttribute};

#[derive(Clone, Copy, Debug, StableHash, Encodable, Decodable, PrintAttribute)]
pub enum LintCheckKind {
Allow,
Expand Down Expand Up @@ -43,21 +45,7 @@ impl LintCheckKind {
/// ```
#[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute)]
pub struct LintCheck {
/// The lint's tool name, if present.
pub tool: Option<Ident>,
/// The lint's name, minus the tool name if any.
///
/// For example:
/// - `clippy::blah` -> `blah`
/// - `unstable_imports` -> `unstable_imports`
/// - `custom_tool::blah::bleh` -> `blah::bleh`
pub lint_name: Symbol,
/// The span of the lint name.
///
/// For example `#[deny(foo, bar, reason = "reason")]`
/// produces multiple `LintCheck`s, one with a span pointing to `foo`
/// and another pointing to `bar`.
pub lint_span: Span,
pub lint_name: LintName,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put this inside LintName as well, as it seems pretty related?

@JonathanBrouwer JonathanBrouwer Oct 25, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My dream solution would be to get anLintId here instead of syms.
I'm gonna do a quick experiment to see how realistic that is

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First exploration seems to show potential here, I think this should be possible! (with a few minor hacks)
I'm going to try this in depth tomorrow

@mejrs mejrs Oct 25, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how realistic that is

there are some reasons to not do this:

  • how do you represent a lint that doesn't exist, because e.g. the input is wrong or it belongs to a tool that isn't currently running
  • you'd need to move Lint and LintId far down in the crate graph to do this
  • it would be incompatible with implementing lint resolution for proc/decl macro lints, because we'd likely need to run queries to retrieve the lint information

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do you represent a lint that doesn't exist, because e.g. the input is wrong or it belongs to a tool that isn't currently running

I think that could either stay in the HIR by name if it's useful, and if it's not useful removed entirely.

you'd need to move Lint and LintId far down in the crate graph to do this

rustc_attr_ir can depend directly on rustc_lint_defs. It already does transitively so it doesn't even worsen bootstrap times.

it would be incompatible with implementing lint resolution for proc/decl macro lints, because we'd likely need to run queries to retrieve the lint information

The only information we'd need is from the LintStore, which is available very early through the DynLintStore in Session


The only significant problem I've encountered so far is that LintIds are not encodable, so can't be part of the HIR. I was thinking to encode the index of the lint in LintStore::lints (field) instead.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got nerd-sniped too hard so this is part 1 of this approach: #164918

@JonathanBrouwer JonathanBrouwer Oct 25, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw, I think our approaches are actually mostly compatible. It's still possible to introduce a LintName type and use it in most places that your PR does, and I think that would be good. It's just that it shouldn't be what's stored in the LintCheck type

@JonathanBrouwer JonathanBrouwer Oct 25, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR also has better perf than #164918 (tho both are improvements) so doing both definitely makes sense

pub kind: LintCheckKind,
pub reason: Option<Symbol>,
/// Needed by `LintExpectationId` to track fulfilled expectations
Expand All @@ -68,4 +56,10 @@ pub struct LintCheck {
/// inside one attribute are all smooshed and flattened together, so
/// multiple `LintCheck`s can have the same `attr_span`.
pub attr_span: Span,
/// The span of the entire lint name.
///
/// #[deny(foo::bar::baz)]
/// ^^^^^^^^^^^^^
pub lint_span: Span,
pub tool_span: Option<Span>,
}
5 changes: 4 additions & 1 deletion compiler/rustc_attr_ir/src/pretty_printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use rustc_data_structures::fx::FxIndexMap;
use rustc_span::def_id::DefId;
use rustc_span::hygiene::Transparency;
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
use rustc_structures::{CollapseMacroDebuginfo, CrateType, Limit, NativeLibKind, SanitizerSet};
use rustc_structures::{
CollapseMacroDebuginfo, CrateType, Limit, LintName, NativeLibKind, SanitizerSet,
};
use thin_vec::ThinVec;

use crate::HashIgnoredAttrId;
Expand Down Expand Up @@ -223,4 +225,5 @@ print_debug!(
CrateType,
NativeLibKind,
CollapseMacroDebuginfo,
LintName,
);
46 changes: 17 additions & 29 deletions compiler/rustc_attr_parsing/src/attributes/lint.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use rustc_ast::join_path_syms;
use rustc_attr_ir::AttributeKind;
use rustc_attr_ir::lint::{LintCheck, LintCheckKind};
use rustc_attr_ir::target::{AssocCtxt, MethodKind, Target};
use rustc_lint_defs::builtin::UNUSED_ATTRIBUTES;
use rustc_span::{Symbol, sym};
use rustc_span::sym;
use rustc_structures::LintName;
use thin_vec::ThinVec;

use crate::attributes::{AcceptMapping, AttributeParser, AttributeStability};
Expand Down Expand Up @@ -52,33 +52,21 @@ impl LintParser {
match item {
MetaItemOrLitParser::MetaItemParser(p) => {
match p.args() {
ArgParser::NoArgs => {
let (tool, lint_name) = match &*p.path().0.segments {
[] => unreachable!(),
[lint_name] => (None, lint_name.ident.name),
[tool, lint_name] => (Some(tool.ident), lint_name.ident.name),
// Not reachable for any builtin lints,
// but reachable using `register_tool`.
[tool, multi_segment_lint_name @ ..] => (
Some(tool.ident),
Symbol::intern(&join_path_syms(
multi_segment_lint_name
.iter()
.map(|seg| seg.ident.name),
)),
),
};

self.lints.push(LintCheck {
tool,
lint_name,
lint_span: p.span(),
kind,
attr_id,
reason,
attr_span,
})
}
ArgParser::NoArgs => self.lints.push(LintCheck {
lint_name: LintName::new(
p.path().0.segments.iter().map(|s| s.ident.name),
),
kind,
attr_id,
reason,
attr_span,
lint_span: p.span(),
tool_span: if let [tool, _, ..] = &*p.path().0.segments {
Some(tool.span())
} else {
None
},
}),
// We've found a `reason = "reason"` but we're not the last element.
ArgParser::NameValue(nv) if p.path().word_is(sym::reason) => {
cx.emit_err(diagnostics::MalformedAttribute {
Expand Down
14 changes: 6 additions & 8 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use rustc_session::output::invalid_output_for_target;
use rustc_session::{EarlyDiagCtxt, Session, config};
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::{DUMMY_SP, FileName};
use rustc_structures::CrateType;
use rustc_structures::{CrateType, LintName};
use rustc_target::json::ToJson;
use rustc_target::spec::{Target, TargetTuple};
use tracing::trace;
Expand Down Expand Up @@ -990,11 +990,9 @@ Available lint options:
lints
}

fn sort_lint_groups(
lints: Vec<(&'static str, Vec<LintId>, bool)>,
) -> Vec<(&'static str, Vec<LintId>)> {
fn sort_lint_groups(lints: Vec<(LintName, Vec<LintId>, bool)>) -> Vec<(LintName, Vec<LintId>)> {
let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
lints.sort_by_key(|l| l.0);
lints.sort_by(|left, right| Ord::cmp(&left.0, &right.0));
lints
}

Expand Down Expand Up @@ -1041,7 +1039,7 @@ Available lint options:
loaded_groups
.iter()
.chain(&builtin_groups)
.map(|&(s, _)| s.chars().count())
.map(|(s, _)| s.name.as_str().chars().count())
.max()
.unwrap_or(0),
);
Expand All @@ -1054,7 +1052,7 @@ Available lint options:

safe_println!("Lint groups provided by rustc:\n");

let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>, all_warnings| {
let print_lint_groups = |lints: Vec<(LintName, Vec<LintId>)>, all_warnings| {
safe_println!(" {} sub-lints", padded("name"));
safe_println!(" {} ---------", padded("----"));

Expand All @@ -1063,7 +1061,7 @@ Available lint options:
}

for (name, to) in lints {
let name = name.to_lowercase().replace('_', "-");
let name = name.to_string().to_lowercase().replace('_', "-");
let desc = to
.into_iter()
.map(|x| x.to_string().replace('_', "-"))
Expand Down
Loading
Loading