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
6 changes: 1 addition & 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,7 @@ 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::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,
// owner should be computed for all nodes
label_strs::owner,
];

/// `impl` implementation of struct/trait
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
36 changes: 34 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,36 @@ 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.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
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.

Assert (or debug assert that it's invoked from an eval-always query

/// (`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.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.owner(id.def_id).as_owner().map(|owner_info| owner_info.trait_map)
}

#[inline]
pub fn opt_hir_owner_nodes(self, def_id: LocalDefId) -> Option<&'tcx OwnerNodes<'tcx>> {
self.owner(def_id).as_owner().map(|i| i.nodes)
Copy link
Copy Markdown
Contributor

@petrochenkov petrochenkov May 15, 2026

Choose a reason for hiding this comment

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

Style nit: 3 owner maps and 3 different names for the same thing (o, i, owner_info) 😄

View changes since the review

}

#[inline]
fn expect_hir_owner_nodes(self, def_id: LocalDefId) -> &'tcx OwnerNodes<'tcx> {
self.opt_hir_owner_nodes(def_id)
Expand Down
71 changes: 55 additions & 16 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 @@ -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)
.owner(parent_owner_id.def_id)
.unwrap()
.parenting
.get(&owner_id.def_id)
Expand Down Expand Up @@ -452,23 +452,65 @@ pub struct Hashes {
pub attrs_hash: Option<Fingerprint>,
}

/// Unites some of `OwnerInfo`'s fields into same struct that is used by 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 create_from(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.owner = |tcx, def_id| {
ProjectedMaybeOwner::create_from(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 +550,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)
};
}
38 changes: 6 additions & 32 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,6 +215,11 @@ rustc_queries! {
desc { "lowering the delayed AST owner `{}`", tcx.def_path_str(def_id) }
}

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

query 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

}

/// 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
10 changes: 8 additions & 2 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 @@ -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.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="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 `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="owner")]
mod foo {
struct First;
struct Second;
}

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