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
8 changes: 3 additions & 5 deletions compiler/rustc_incremental/src/assert_dep_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,9 @@ impl<'tcx> IfThisChanged<'tcx> {
for attr in attrs {
if let Attribute::Parsed(AttributeKind::RustcIfThisChanged(span, dep_node)) = *attr {
let dep_node = match dep_node {
None => DepNode::from_def_path_hash(
self.tcx,
def_path_hash,
DepKind::opt_hir_owner_nodes,
),
None => {
DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner)
}
Some(n) => {
match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
Ok(n) => n,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_incremental/src/persist/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ const BASE_FN: &[&str] = &[

/// DepNodes for Hir, which is pretty much everything
const BASE_HIR: &[&str] = &[
// opt_hir_owner_nodes should be computed for all nodes
label_strs::opt_hir_owner_nodes,
// hir_owner should be computed for all nodes
label_strs::hir_owner,
];

/// `impl` implementation of struct/trait
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -879,9 +879,9 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
providers.queries.analysis = analysis;
providers.queries.hir_crate = rustc_ast_lowering::lower_to_hir;
providers.queries.lower_delayed_owner = rustc_ast_lowering::lower_delayed_owner;
// `delayed_owner` is fed during `lower_delayed_owner`, by default it returns phantom,
// `hir_delayed_owner` is fed during `lower_delayed_owner`, by default it returns phantom,
// as if this query was not fed it means that `MaybeOwner` does not exist for provided LocalDefId.
providers.queries.delayed_owner = |_, _| MaybeOwner::Phantom;
providers.queries.hir_delayed_owner = |_, _| MaybeOwner::Phantom;
providers.queries.resolver_for_lowering_raw = resolver_for_lowering_raw;
providers.queries.stripped_cfg_items = |tcx, _| &tcx.resolutions(()).stripped_cfg_items[..];
providers.queries.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1;
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ macro_rules! arena_types {
[] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls,
[] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>,
[decode] token_stream: rustc_ast::tokenstream::TokenStream,
[] maybe_owner: rustc_middle::hir::ProjectedMaybeOwner<'tcx>,
[] owner_info: rustc_middle::hir::ProjectedOwnerInfo<'tcx>,
[] parenting: rustc_hir::def_id::LocalDefIdMap<rustc_hir::ItemLocalId>,
[] trait_candidates: rustc_hir::ItemLocalMap<&'tcx [rustc_hir::TraitCandidate<'tcx>]>,
[] delayed_lints: rustc_data_structures::steal::Steal<rustc_hir::lints::DelayedLints>,
]);
)
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ impl DepGraph {
}
}

pub fn assert_eval_always(&self) {
self.data.as_ref().inspect(|_| {
read_deps(|deps| {
assert_matches!(deps, TaskDepsRef::EvalAlways, "expected eval always context")
});
});
}

pub fn with_ignore<OP, R>(&self, op: OP) -> R
where
OP: FnOnce() -> R,
Expand Down
37 changes: 35 additions & 2 deletions compiler/rustc_middle/src/hir/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@ use rustc_abi::ExternAbi;
use rustc_ast::visit::{VisitorResult, walk_list};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hash::{StableHash, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, spawn, try_par_for_each_in};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lints::DelayedLints;
use rustc_hir::*;
use rustc_hir_pretty as pprust_hir;
use rustc_span::def_id::StableCrateId;
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, with_metavar_spans};

use crate::hir::{ModuleItems, nested_filter};
use crate::hir::{ModuleItems, ProjectedMaybeOwner, nested_filter};
use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
use crate::query::LocalCrate;
use crate::query::{IntoQueryKey, LocalCrate};
use crate::ty::TyCtxt;

/// An iterator that walks up the ancestor tree of a given `HirId`.
Expand Down Expand Up @@ -101,6 +103,37 @@ impl<'tcx> Iterator for ParentOwnerIterator<'tcx> {
}

impl<'tcx> TyCtxt<'tcx> {
#[inline]
pub fn local_def_id_to_hir_id(self, def_id: impl IntoQueryKey<LocalDefId>) -> HirId {
let def_id = def_id.into_query_key();
match self.hir_owner(def_id) {
ProjectedMaybeOwner::Owner(_) => HirId::make_owner(def_id),
ProjectedMaybeOwner::NonOwner(hir_id) => hir_id,
}
}

/// This function is used only inside eval-always query `analysis`
/// (`analysis -> run_required_analysis` -> `emit_delayed_lints`), so it is safe
/// to obtain delayed lints from non-eval-always `owner` query.
#[inline]
pub fn opt_ast_lowering_delayed_lints(self, id: OwnerId) -> Option<&'tcx Steal<DelayedLints>> {
self.dep_graph.assert_eval_always();
self.hir_owner(id.def_id).as_owner().map(|o| o.delayed_lints)
}

#[inline]
pub fn in_scope_traits_map(
self,
id: OwnerId,
) -> Option<&'tcx ItemLocalMap<&'tcx [TraitCandidate<'tcx>]>> {
self.hir_owner(id.def_id).as_owner().map(|o| o.trait_map)
}

#[inline]
pub fn opt_hir_owner_nodes(self, def_id: LocalDefId) -> Option<&'tcx OwnerNodes<'tcx>> {
self.hir_owner(def_id).as_owner().map(|o| o.nodes)
}

#[inline]
fn expect_hir_owner_nodes(self, def_id: LocalDefId) -> &'tcx OwnerNodes<'tcx> {
self.opt_hir_owner_nodes(def_id)
Expand Down
72 changes: 55 additions & 17 deletions compiler/rustc_middle/src/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHashe
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap, LocalModDefId};
use rustc_hir::lints::DelayedLints;
use rustc_hir::*;
use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, StableHash};
Expand Down Expand Up @@ -72,7 +73,7 @@ impl<'hir> Crate<'hir> {
tcx.ensure_done().lower_delayed_owner(def_id);
}

tcx.delayed_owner(def_id)
tcx.hir_delayed_owner(def_id)
}
}

Expand Down Expand Up @@ -422,8 +423,7 @@ impl<'tcx> TyCtxt<'tcx> {
HirId {
owner: parent_owner_id,
local_id: self
.hir_crate(())
.owner(self, parent_owner_id.def_id)
.hir_owner(parent_owner_id.def_id)
.unwrap()
.parenting
.get(&owner_id.def_id)
Expand Down Expand Up @@ -452,23 +452,64 @@ pub struct Hashes {
pub attrs_hash: Option<Fingerprint>,
}

/// Unites some of `OwnerInfo`'s fields into same struct that is used by `hir_owner` query.
/// `AttributeMap` is handled separately as placing it in this struct led to perf regressions:
/// <https://github.com/rust-lang/rust/pull/155678#issuecomment-4304597871>.
/// This struct is created mainly for uniting/splitting fields of `OwnerInfo` so they are
/// stored/invalidated together in incremental compilation.
/// For comments about each field see `OwnerInfo` struct.
#[derive(Clone, Copy, Debug, StableHash)]
pub struct ProjectedOwnerInfo<'tcx> {
pub nodes: &'tcx OwnerNodes<'tcx>,
pub parenting: &'tcx LocalDefIdMap<ItemLocalId>,
pub trait_map: &'tcx ItemLocalMap<&'tcx [TraitCandidate<'tcx>]>,

#[stable_hash(ignore)]
pub delayed_lints: &'tcx Steal<DelayedLints>,
}

#[derive(Clone, Copy, Debug, StableHash)]
pub enum ProjectedMaybeOwner<'tcx> {
Owner(ProjectedOwnerInfo<'tcx>),
NonOwner(HirId),
}

impl<'tcx> ProjectedMaybeOwner<'tcx> {
pub fn new(value: MaybeOwner<'tcx>, def_id: LocalDefId) -> Self {
match value {
MaybeOwner::Owner(o) => ProjectedMaybeOwner::Owner(ProjectedOwnerInfo {
nodes: &o.nodes,
parenting: &o.parenting,
trait_map: &o.trait_map,
delayed_lints: &o.delayed_lints,
}),
MaybeOwner::NonOwner(hir_id) => ProjectedMaybeOwner::NonOwner(hir_id),
MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
}
}

pub fn as_owner(&self) -> Option<&ProjectedOwnerInfo<'tcx>> {
match self {
ProjectedMaybeOwner::Owner(i) => Some(i),
ProjectedMaybeOwner::NonOwner(_) => None,
}
}

pub fn unwrap(&'tcx self) -> &'tcx ProjectedOwnerInfo<'tcx> {
self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner"))
}
}

pub fn provide(providers: &mut Providers) {
providers.hir_crate_items = map::hir_crate_items;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = map::hir_module_items;
providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owner(tcx, def_id) {
MaybeOwner::Owner(_) => HirId::make_owner(def_id),
MaybeOwner::NonOwner(hir_id) => hir_id,
MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
};
providers.opt_hir_owner_nodes =
|tcx, id| tcx.hir_crate(()).owner(tcx, id).as_owner().map(|i| &i.nodes);
providers.hir_owner_parent_q = |tcx, owner_id| tcx.hir_owner_parent_impl(owner_id);
providers.hir_attr_map = |tcx, id| {
tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
};
providers.opt_ast_lowering_delayed_lints =
|tcx, id| tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|o| &o.delayed_lints);
providers.hir_owner =
|tcx, def_id| ProjectedMaybeOwner::new(tcx.hir_crate(()).owner(tcx, def_id), def_id);
providers.hir_owner_parent_q = |tcx, owner_id| tcx.hir_owner_parent_impl(owner_id);
providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id));
providers.def_ident_span = |tcx, def_id| {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
Expand Down Expand Up @@ -508,7 +549,4 @@ pub fn provide(providers: &mut Providers) {
|tcx, trait_id| tcx.resolutions(()).trait_impls.get(&trait_id).map_or(&[], |xs| &xs[..]);
providers.expn_that_defined =
|tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root());
providers.in_scope_traits_map = |tcx, id| {
tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|owner_info| &owner_info.trait_map)
};
}
40 changes: 7 additions & 33 deletions compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem};
use rustc_hir::def::{DefKind, DocLinkResMap};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdSet, LocalModDefId};
use rustc_hir::lang_items::{LangItem, LanguageItems};
use rustc_hir::{ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate};
use rustc_hir::{ItemLocalId, PreciseCapturingArgKind};
use rustc_index::IndexVec;
use rustc_lint_defs::LintId;
use rustc_macros::rustc_queries;
Expand Down Expand Up @@ -215,7 +215,12 @@ rustc_queries! {
desc { "lowering the delayed AST owner `{}`", tcx.def_path_str(def_id) }
}

query delayed_owner(def_id: LocalDefId) -> hir::MaybeOwner<'tcx> {
query hir_owner(def_id: LocalDefId) -> rustc_middle::hir::ProjectedMaybeOwner<'tcx> {
desc { "getting owner for `{}`", tcx.def_path_str(def_id) }
feedable
}

query hir_delayed_owner(def_id: LocalDefId) -> hir::MaybeOwner<'tcx> {
feedable
desc { "getting child of lowered delayed AST owner `{}`", tcx.def_path_str(def_id) }
}
Expand All @@ -237,12 +242,6 @@ rustc_queries! {
cache_on_disk
}

/// Returns HIR ID for the given `LocalDefId`.
query local_def_id_to_hir_id(key: LocalDefId) -> hir::HirId {
desc { "getting HIR ID of `{}`", tcx.def_path_str(key) }
feedable
}

/// Gives access to the HIR node's parent for the HIR owner `key`.
///
/// This can be conveniently accessed by `tcx.hir_*` methods.
Expand All @@ -251,15 +250,6 @@ rustc_queries! {
desc { "getting HIR parent of `{}`", tcx.def_path_str(key) }
}

/// Gives access to the HIR nodes and bodies inside `key` if it's a HIR owner.
///
/// This can be conveniently accessed by `tcx.hir_*` methods.
/// Avoid calling this query directly.
query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
desc { "getting HIR owner items in `{}`", tcx.def_path_str(key) }
feedable
}

/// Gives access to the HIR attributes inside the HIR owner `key`.
///
/// This can be conveniently accessed by `tcx.hir_*` methods.
Expand All @@ -269,18 +259,6 @@ rustc_queries! {
feedable
}

/// Gives access to lints emitted during ast lowering.
///
/// This can be conveniently accessed by `tcx.hir_*` methods.
/// Avoid calling this query directly.
query opt_ast_lowering_delayed_lints(key: hir::OwnerId) -> Option<&'tcx Steal<hir::lints::DelayedLints>> {
desc { "getting AST lowering delayed lints in `{}`", tcx.def_path_str(key) }
// This query has to be `no_hash` and `eval_always`,
// because it accesses `delayed_lints` which is not hashed as part of the HIR
no_hash
eval_always
Copy link
Copy Markdown
Contributor

@cjgillot cjgillot Apr 25, 2026

Choose a reason for hiding this comment

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

How do we ensure that we are not leaking untracked state ?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've added an assert that we execute opt_ast_lowering_delayed_lints only in EvalAlways context (and we call it only in eval-always analysis query).

}

/// Returns the *default* of the const pararameter given by `DefId`.
///
/// E.g., given `struct Ty<const N: usize = 3>;` this returns `3` for `N`.
Expand Down Expand Up @@ -1881,10 +1859,6 @@ rustc_queries! {
query specializes(_: (DefId, DefId)) -> bool {
desc { "computing whether impls specialize one another" }
}
query in_scope_traits_map(_: hir::OwnerId)
-> Option<&'tcx ItemLocalMap<&'tcx [TraitCandidate<'tcx>]>> {
desc { "getting traits in scope at a block" }
}

/// Returns whether the impl or associated function has the `default` keyword.
/// Note: This will ICE on inherent impl items. Consider using `AssocItem::defaultness`.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/query/erase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ impl_erasable_for_types_with_no_type_params! {
rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>,
rustc_hir::def::DefKind,
rustc_hir::def_id::DefId,
rustc_middle::hir::ProjectedMaybeOwner<'_>,
rustc_middle::middle::codegen_fn_attrs::SanitizerFnAttrs,
rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault,
rustc_middle::mir::ConstQualifs,
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ use tracing::{debug, instrument};
use crate::arena::Arena;
use crate::dep_graph::dep_node::make_metadata;
use crate::dep_graph::{DepGraph, DepKindVTable, DepNodeIndex};
use crate::hir::{ProjectedMaybeOwner, ProjectedOwnerInfo};
use crate::ich::StableHashState;
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind};
use crate::lint::emit_lint_base;
Expand Down Expand Up @@ -585,7 +586,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Feeds the HIR delayed owner during AST -> HIR delayed lowering.
pub fn feed_delayed_owner(self, key: LocalDefId, owner: MaybeOwner<'tcx>) {
self.dep_graph.assert_ignored();
TyCtxtFeed { tcx: self, key }.delayed_owner(owner);
TyCtxtFeed { tcx: self, key }.hir_delayed_owner(owner);
}

// Trait impl item visibility is inherited from its trait when not specified
Expand Down Expand Up @@ -626,8 +627,13 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {

// Fills in all the important parts needed by HIR queries
pub fn feed_hir(&self) {
self.local_def_id_to_hir_id(HirId::make_owner(self.def_id()));
self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes::synthetic())));
self.hir_owner(ProjectedMaybeOwner::Owner(ProjectedOwnerInfo {
nodes: self.tcx.arena.alloc(hir::OwnerNodes::synthetic()),
parenting: self.tcx.arena.alloc(Default::default()),
delayed_lints: self.tcx.arena.alloc(Steal::new(Default::default())),
trait_map: self.tcx.arena.alloc(Default::default()),
}));

self.feed_owner_id().hir_attr_map(hir::AttributeMap::EMPTY);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/incremental/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ mod y {
use x;

#[rustc_clean(
except="opt_hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig",
except="hir_owner,generics_of,predicates_of,type_of,fn_sig",
cfg="bfail2",
)]
pub fn y() {
//[bfail2]~^ ERROR `opt_hir_owner_nodes(y)` should be dirty but is not
//[bfail2]~^ ERROR `hir_owner(y)` should be dirty but is not
//[bfail2]~| ERROR `generics_of(y)` should be dirty but is not
//[bfail2]~| ERROR `predicates_of(y)` should be dirty but is not
//[bfail2]~| ERROR `type_of(y)` should be dirty but is not
Expand Down
4 changes: 2 additions & 2 deletions tests/incremental/hash-module-order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
#![feature(rustc_attrs)]

#[cfg(rpass1)]
#[rustc_clean(cfg="rpass1",except="opt_hir_owner_nodes")]
#[rustc_clean(cfg="rpass1",except="hir_owner")]
mod foo {
struct First;
struct Second;
}

#[cfg(rpass2)]
#[rustc_clean(cfg="rpass2",except="opt_hir_owner_nodes")]
#[rustc_clean(cfg="rpass2",except="hir_owner")]
mod foo {
struct Second;
struct First;
Expand Down
Loading
Loading