Make rustc_hir_analysis not depend on rustc_lint.

`rustc_hir_analysis` depends on `rustc_lint` in just a single function:
`emit_delayed_lint`, which is used by the
"emit_ast_lowering_delayed_lints" checking section within
`rustc_hir_analysis::check_crate`.

This commit moves that function and section to out of
`rustc_hir_analysis::check_crate`, into `rustc_interface`, eliminating
the dependency. This seems reasonable because the delayed lint errors
aren't really related to HIR analysis. They were in there just because
HIR analysis follows AST lowering.

This means `rustc_hir_analysis` and `rustc_lint` can both start
compiling as soon as `rustc_trait_selection` finishes. This also changes
the error order in one test, which doesn't matter.

The commit also changes `emit_delayed_lint` to `emit_delayed_lints`,
factoring out some code duplicated in rustdoc.
This commit is contained in:
Nicholas Nethercote
2026-03-25 06:58:13 +11:00
parent 80d0e4be6f
commit a733192980
6 changed files with 62 additions and 73 deletions
-1
View File
@@ -4021,7 +4021,6 @@ dependencies = [
"rustc_hir",
"rustc_index",
"rustc_infer",
"rustc_lint",
"rustc_lint_defs",
"rustc_macros",
"rustc_middle",
-1
View File
@@ -19,7 +19,6 @@ rustc_feature = { path = "../rustc_feature" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_lint = { path = "../rustc_lint" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
-55
View File
@@ -85,8 +85,6 @@
use rustc_abi::{CVariadicStatus, ExternAbi};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::lints::DelayedLint;
use rustc_lint::DecorateAttrLint;
use rustc_middle::mir::interpret::GlobalId;
use rustc_middle::query::Providers;
use rustc_middle::ty::{Const, Ty, TyCtxt};
@@ -147,23 +145,6 @@ pub fn provide(providers: &mut Providers) {
};
}
pub fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) {
match lint {
DelayedLint::AttributeParsing(attribute_lint) => {
tcx.emit_node_span_lint(
attribute_lint.lint_id.lint,
attribute_lint.id,
attribute_lint.span,
DecorateAttrLint {
sess: tcx.sess,
tcx: Some(tcx),
diagnostic: &attribute_lint.kind,
},
);
}
}
}
pub fn check_crate(tcx: TyCtxt<'_>) {
let _prof_timer = tcx.sess.timer("type_check_crate");
@@ -182,42 +163,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
let _: R = tcx.ensure_result().crate_inherent_impls_overlap_check(());
});
tcx.sess.time("emit_ast_lowering_delayed_lints", || {
// sanity check in debug mode that all lints are really noticed
// and we really will emit them all in the loop right below.
//
// during ast lowering, when creating items, foreign items, trait items and impl items
// we store in them whether they have any lints in their owner node that should be
// picked up by `hir_crate_items`. However, theoretically code can run between that
// boolean being inserted into the item and the owner node being created.
// We don't want any new lints to be emitted there
// (though honestly, you have to really try to manage to do that but still),
// but this check is there to catch that.
#[cfg(debug_assertions)]
{
// iterate over all owners
for owner_id in tcx.hir_crate_items(()).owners() {
// if it has delayed lints
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
if !delayed_lints.lints.is_empty() {
// assert that delayed_lint_items also picked up this item to have lints
assert!(
tcx.hir_crate_items(()).delayed_lint_items().any(|i| i == owner_id)
);
}
}
}
}
for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
for lint in &delayed_lints.lints {
emit_delayed_lint(lint, tcx);
}
}
}
});
tcx.par_hir_body_owners(|item_def_id| {
let def_kind = tcx.def_kind(item_def_id);
// Make sure we evaluate all static and (non-associated) const items, even if unused.
+53 -1
View File
@@ -21,9 +21,12 @@
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
use rustc_hir::definitions::Definitions;
use rustc_hir::limit::Limit;
use rustc_hir::lints::DelayedLint;
use rustc_hir::{Attribute, MaybeOwner, find_attr};
use rustc_incremental::setup_dep_graph;
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
use rustc_lint::{
BufferedEarlyLint, DecorateAttrLint, EarlyCheckNode, LintStore, unerased_lint_store,
};
use rustc_metadata::EncodedMetadata;
use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena;
@@ -1025,6 +1028,29 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
)
}
pub fn emit_delayed_lints(tcx: TyCtxt<'_>) {
for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
for lint in &delayed_lints.lints {
match lint {
DelayedLint::AttributeParsing(attribute_lint) => {
tcx.emit_node_span_lint(
attribute_lint.lint_id.lint,
attribute_lint.id,
attribute_lint.span,
DecorateAttrLint {
sess: tcx.sess,
tcx: Some(tcx),
diagnostic: &attribute_lint.kind,
},
);
}
}
}
}
}
}
/// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses.
/// This function never fails.
fn run_required_analyses(tcx: TyCtxt<'_>) {
@@ -1074,6 +1100,32 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
]);
});
sess.time("emit_ast_lowering_delayed_lints", || {
// Sanity check in debug mode that all lints are really noticed and we really will emit
// them all in the loop right below.
//
// During ast lowering, when creating items, foreign items, trait items and impl items,
// we store in them whether they have any lints in their owner node that should be
// picked up by `hir_crate_items`. However, theoretically code can run between that
// boolean being inserted into the item and the owner node being created. We don't want
// any new lints to be emitted there (you have to really try to manage that but still),
// but this check is there to catch that.
#[cfg(debug_assertions)]
{
let hir_items = tcx.hir_crate_items(());
for owner_id in hir_items.owners() {
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
if !delayed_lints.lints.is_empty() {
// Assert that delayed_lint_items also picked up this item to have lints.
assert!(hir_items.delayed_lint_items().any(|i| i == owner_id));
}
}
}
}
emit_delayed_lints(tcx);
});
rustc_hir_analysis::check_crate(tcx);
// Freeze definitions as we don't add new ones at this point.
// We need to wait until now since we synthesize a by-move body
+1 -7
View File
@@ -904,13 +904,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
return;
}
for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
for lint in &delayed_lints.lints {
rustc_hir_analysis::emit_delayed_lint(lint, tcx);
}
}
}
rustc_interface::passes::emit_delayed_lints(tcx);
if render_opts.dep_info().is_some() {
rustc_interface::passes::write_dep_info(tcx);
@@ -38,14 +38,6 @@ LL | #[inline]
|
= help: `#[inline]` can only be applied to functions
error: unconstrained opaque type
--> $DIR/inline-trait-and-foreign-items.rs:26:14
|
LL | type U = impl Trait;
| ^^^^^^^^^^
|
= note: `U` must be used in combination with a concrete type within the same impl
warning: `#[inline]` attribute cannot be used on associated consts
--> $DIR/inline-trait-and-foreign-items.rs:7:5
|
@@ -69,5 +61,13 @@ LL | #[inline]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= help: `#[inline]` can only be applied to functions
error: unconstrained opaque type
--> $DIR/inline-trait-and-foreign-items.rs:26:14
|
LL | type U = impl Trait;
| ^^^^^^^^^^
|
= note: `U` must be used in combination with a concrete type within the same impl
error: aborting due to 6 previous errors; 2 warnings emitted