diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index f93b9e5af5345..97a7256a4a8dc 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -10,8 +10,8 @@ use std::hash::Hash; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash64; -use rustc_index::IndexVec; -use rustc_macros::{Decodable, Encodable}; +use rustc_index::{IndexVec, static_assert_size}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::{Symbol, kw, sym}; use tracing::{debug, instrument}; @@ -67,7 +67,8 @@ impl DefPathTable { // being used. // // See the documentation for DefPathHash for more information. - panic!( + assert_eq!( + def_path1, def_path2, "found DefPathHash collision between {def_path1:#?} and {def_path2:#?}. \ Compilation cannot continue." ); @@ -114,6 +115,13 @@ impl DisambiguatorState { this.next.insert((def_id, data), index); this } + + pub fn next(&mut self, parent: LocalDefId, data: DefPathData) -> u32 { + let next_disamb = self.next.entry((parent, data)).or_insert(0); + let disambiguator = *next_disamb; + *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow"); + disambiguator + } } /// The definition table containing node definitions. @@ -207,7 +215,7 @@ impl fmt::Display for DisambiguatedDefPathData { } } -#[derive(Clone, Debug, Encodable, Decodable)] +#[derive(Clone, Debug, Encodable, Decodable, PartialEq)] pub struct DefPath { /// The path leading from the crate root to the item. pub data: Vec, @@ -274,7 +282,7 @@ impl DefPath { } /// New variants should only be added in synchronization with `enum DefKind`. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] pub enum DefPathData { // Root: these should only be used for the root nodes, because // they are treated specially by the `def_path` function. @@ -320,6 +328,8 @@ pub enum DefPathData { NestedStatic, } +static_assert_size!(DefPathData, 8); + impl Definitions { pub fn def_path_table(&self) -> &DefPathTable { &self.table @@ -381,25 +391,18 @@ impl Definitions { &mut self, parent: LocalDefId, data: DefPathData, - disambiguator: &mut DisambiguatorState, - ) -> LocalDefId { + disambiguator: u32, + ) -> (LocalDefId, DefPathHash) { // We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a // reference to `Definitions` and we're already holding a mutable reference. debug!( - "create_def(parent={}, data={data:?})", + "create_def(parent={}, data={data:?}, disambiguator: {disambiguator})", self.def_path(parent).to_string_no_crate_verbose(), ); // The root node must be created in `new()`. assert!(data != DefPathData::CrateRoot); - // Find the next free disambiguator for this key. - let disambiguator = { - let next_disamb = disambiguator.next.entry((parent, data)).or_insert(0); - let disambiguator = *next_disamb; - *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow"); - disambiguator - }; let key = DefKey { parent: Some(parent.local_def_index), disambiguated_data: DisambiguatedDefPathData { data, disambiguator }, @@ -411,7 +414,7 @@ impl Definitions { debug!("create_def: after disambiguation, key = {:?}", key); // Create the definition. - LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) } + (LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) }, def_path_hash) } #[inline(always)] diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 7c6b7157f71a5..745926ecb4194 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -14,9 +14,11 @@ use std::fmt; use rustc_errors::{DiagInner, TRACK_DIAGNOSTIC}; use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef}; use rustc_middle::ty::tls; +use rustc_middle::util::Providers; use rustc_query_impl::QueryCtxt; use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug; use rustc_query_system::dep_graph::{DepContext, DepKind, DepNode}; +use rustc_query_system::query::DefIdInfo; fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { tls::with_context_opt(|icx| { @@ -113,3 +115,14 @@ pub fn setup_callbacks() { .swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _)); } + +pub fn provide(providers: &mut Providers) { + providers.create_def_raw = |tcx, (parent, data, disambiguator)| { + let (def_id, hash) = + tcx.untracked().definitions.write().create_def(parent, data, disambiguator); + + tcx.dep_graph + .record_def(QueryCtxt::new(tcx), DefIdInfo { parent, data, hash, disambiguator }); + def_id + } +} diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index f4d11a7c0be2d..26bcfb00a86ce 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -799,6 +799,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { rustc_lint::provide(providers); rustc_symbol_mangling::provide(providers); rustc_codegen_ssa::provide(providers); + crate::callbacks::provide(providers); *providers }); diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 931d67087acab..f1529d842b909 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -1,5 +1,6 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_query_system::ich::StableHashingContext; +use rustc_query_system::query::DefIdInfo; use rustc_session::Session; use crate::ty::{self, TyCtxt}; @@ -80,6 +81,11 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { self.sess } + fn create_def(&self, &DefIdInfo { parent, data, disambiguator: index, hash }: &DefIdInfo) { + let (_, h) = self.untracked().definitions.write().create_def(parent, data, index); + assert_eq!(hash, h); + } + #[inline] fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> { &self.query_kinds[dk.as_usize()] diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 9ed1f10455ad3..50346eda8073c 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -3,6 +3,7 @@ use std::ffi::OsStr; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId}; +use rustc_hir::definitions::DefPathData; use rustc_hir::hir_id::{HirId, OwnerId}; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache}; @@ -265,6 +266,14 @@ impl Key for (LocalDefId, LocalDefId) { } } +impl Key for (LocalDefId, DefPathData, u32) { + type Cache = DefaultCache; + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.0.default_span(tcx) + } +} + impl Key for (DefId, Ident) { type Cache = DefaultCache; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b2133fea08cc3..77aa1a62ac5dc 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -159,6 +159,11 @@ rustc_queries! { desc { "getting the source span" } } + /// Used to handle incremental replays of [`TyCtxt::create_def`] invocations from tracked queries. + query create_def_raw(key: (LocalDefId, rustc_hir::definitions::DefPathData, u32)) -> LocalDefId { + desc { "generating a new def id" } + } + /// Represents crate as a whole (as distinct from the top-level crate module). /// /// If you call `tcx.hir_crate(())` we will have to assume that any change @@ -2054,6 +2059,7 @@ rustc_queries! { desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } separate_provide_extern feedable + cache_on_disk_if { def_id.is_local() } } query inhabited_predicate_adt(key: DefId) -> ty::inhabitedness::InhabitedPredicate<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0759fa3da428a..18aad62fa0a04 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -41,7 +41,7 @@ use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate}; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::cache::WithDepNode; -use rustc_query_system::dep_graph::DepNodeIndex; +use rustc_query_system::dep_graph::{DepNodeIndex, TaskDepsRef}; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::CrateType; @@ -1992,6 +1992,7 @@ impl<'tcx> TyCtxtAt<'tcx> { impl<'tcx> TyCtxt<'tcx> { /// `tcx`-dependent operations performed for every created definition. + #[instrument(level = "trace", skip(self))] pub fn create_def( self, parent: LocalDefId, @@ -2001,22 +2002,26 @@ impl<'tcx> TyCtxt<'tcx> { disambiguator: &mut DisambiguatorState, ) -> TyCtxtFeed<'tcx, LocalDefId> { let data = override_def_path_data.unwrap_or_else(|| def_kind.def_path_data(name)); - // The following call has the side effect of modifying the tables inside `definitions`. - // These very tables are relied on by the incr. comp. engine to decode DepNodes and to - // decode the on-disk cache. - // - // Any LocalDefId which is used within queries, either as key or result, either: - // - has been created before the construction of the TyCtxt; - // - has been created by this call to `create_def`. - // As a consequence, this LocalDefId is always re-created before it is needed by the incr. - // comp. engine itself. - let def_id = self.untracked.definitions.write().create_def(parent, data, disambiguator); - - // This function modifies `self.definitions` using a side-effect. - // We need to ensure that these side effects are re-run by the incr. comp. engine. - // Depending on the forever-red node will tell the graph that the calling query - // needs to be re-evaluated. - self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); + + let def_id = tls::with_context(|icx| { + match icx.task_deps { + // Always gets rerun anyway, so nothing to replay + TaskDepsRef::EvalAlways | + // Top-level queries like the resolver get rerun every time anyway + TaskDepsRef::Ignore => { + // The following call has the side effect of modifying the tables inside `definitions`. + // These very tables are relied on by the incr. comp. engine to decode DepNodes and to + // decode the on-disk cache. + self.untracked.definitions.write().create_def(parent, data, disambiguator.next(parent, data)).0 + } + TaskDepsRef::Forbid => bug!( + "cannot create definition {parent:?} {data:?} without being able to register task dependencies" + ), + TaskDepsRef::Allow(_) => { + self.create_def_raw((parent, data, disambiguator.next(parent, data))) + } + } + }); let feed = TyCtxtFeed { tcx: self, key: def_id }; feed.def_kind(def_kind); diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 9fbbcdc755691..8f474482c089f 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -871,7 +871,7 @@ macro_rules! define_queries { is_eval_always: false, fingerprint_style: FingerprintStyle::Unit, force_from_dep_node: Some(|tcx, _, prev_index| { - tcx.dep_graph.force_diagnostic_node(QueryCtxt::new(tcx), prev_index); + tcx.dep_graph.force_side_effect_node(QueryCtxt::new(tcx), prev_index); true }), try_load_from_on_disk_cache: None, diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 3ae56cef2c421..ec33a86804e0a 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1,7 +1,6 @@ use std::assert_matches::assert_matches; use std::fmt::Debug; use std::hash::Hash; -use std::marker::PhantomData; use std::sync::Arc; use std::sync::atomic::{AtomicU32, Ordering}; @@ -27,7 +26,7 @@ use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex use super::{DepContext, DepKind, DepNode, Deps, HasDepContext, WorkProductId}; use crate::dep_graph::edges::EdgesVec; use crate::ich::StableHashingContext; -use crate::query::{QueryContext, QuerySideEffect}; +use crate::query::{DefIdInfo, QueryContext, QuerySideEffect}; #[derive(Clone)] pub struct DepGraph { @@ -261,6 +260,7 @@ impl DepGraph { } #[inline(always)] + /// A helper for `codegen_cranelift`. pub fn with_task, A: Debug, R>( &self, key: DepNode, @@ -354,7 +354,6 @@ impl DepGraphData { node: Some(key), reads: EdgesVec::new(), read_set: Default::default(), - phantom_data: PhantomData, }); (with_deps(TaskDepsRef::Allow(&task_deps)), task_deps.into_inner().reads) }; @@ -522,21 +521,38 @@ impl DepGraph { D::read_deps(|task_deps| match task_deps { TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return, TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => { - self.read_index(data.encode_diagnostic(qcx, diagnostic)); + self.read_index( + data.encode_side_effect( + qcx, + QuerySideEffect::Diagnostic(diagnostic.clone()), + ), + ); } }) } } + + pub fn record_def(&self, qcx: Qcx, def: DefIdInfo) { + if let Some(ref data) = self.data { + D::read_deps(|task_deps| match task_deps { + TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return, + TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => { + self.read_index(data.encode_side_effect(qcx, QuerySideEffect::Definition(def))); + } + }) + } + } + /// This forces a diagnostic node green by running its side effect. `prev_index` would - /// refer to a node created used `encode_diagnostic` in the previous session. + /// refer to a node created used [Self::record_diagnostic] in the previous session. #[inline] - pub fn force_diagnostic_node( + pub fn force_side_effect_node( &self, qcx: Qcx, prev_index: SerializedDepNodeIndex, ) { if let Some(ref data) = self.data { - data.force_diagnostic_node(qcx, prev_index); + data.force_side_effect_node(qcx, prev_index); } } @@ -664,13 +680,13 @@ impl DepGraphData { self.debug_loaded_from_disk.lock().insert(dep_node); } - /// This encodes a diagnostic by creating a node with an unique index and assoicating + /// This encodes a diagnostic by creating a node with an unique index and associating /// `diagnostic` with it, for use in the next session. #[inline] - fn encode_diagnostic( + fn encode_side_effect( &self, qcx: Qcx, - diagnostic: &DiagInner, + side_effect: QuerySideEffect, ) -> DepNodeIndex { // Use `send_new` so we get an unique index, even though the dep node is not. let dep_node_index = self.current.encoder.send_new( @@ -679,19 +695,18 @@ impl DepGraphData { hash: PackedFingerprint::from(Fingerprint::ZERO), }, Fingerprint::ZERO, - // We want the side effect node to always be red so it will be forced and emit the - // diagnostic. + // We want the side effect node to always be red so it will be forced and apply + // the side effect std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), ); - let side_effect = QuerySideEffect::Diagnostic(diagnostic.clone()); qcx.store_side_effect(dep_node_index, side_effect); dep_node_index } /// This forces a diagnostic node green by running its side effect. `prev_index` would - /// refer to a node created used `encode_diagnostic` in the previous session. + /// refer to a node created used [Self::encode_side_effect] in the previous session. #[inline] - fn force_diagnostic_node( + fn force_side_effect_node( &self, qcx: Qcx, prev_index: SerializedDepNodeIndex, @@ -703,6 +718,9 @@ impl DepGraphData { QuerySideEffect::Diagnostic(diagnostic) => { qcx.dep_context().sess().dcx().emit_diagnostic(diagnostic.clone()); } + QuerySideEffect::Definition(def_id_info) => { + qcx.dep_context().create_def(def_id_info) + } } // Use `send_and_color` as `promote_node_and_deps_to_current` expects all @@ -1301,7 +1319,6 @@ pub struct TaskDeps { node: Option, reads: EdgesVec, read_set: FxHashSet, - phantom_data: PhantomData, } impl Default for TaskDeps { @@ -1311,7 +1328,6 @@ impl Default for TaskDeps { node: None, reads: EdgesVec::new(), read_set: FxHashSet::with_capacity_and_hasher(128, Default::default()), - phantom_data: PhantomData, } } } diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 89d1db878095f..fe811fcc65cb3 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -19,6 +19,7 @@ use tracing::instrument; use self::graph::{MarkFrame, print_markframe_trace}; use crate::ich::StableHashingContext; +use crate::query::DefIdInfo; pub trait DepContext: Copy { type Deps: Deps; @@ -35,6 +36,8 @@ pub trait DepContext: Copy { /// Access the compiler session. fn sess(&self) -> &Session; + fn create_def(&self, def: &DefIdInfo); + fn dep_kind_info(&self, dep_node: DepKind) -> &DepKindStruct; #[inline(always)] diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 855769dacc3e1..03667561c1d2a 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -21,9 +21,10 @@ use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::DiagInner; use rustc_hashes::Hash64; use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefPathHash; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; pub use self::config::{HashResult, QueryConfig}; use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; @@ -147,6 +148,19 @@ pub enum QuerySideEffect { /// the query as green, as that query will have the side /// effect dep node as a dependency. Diagnostic(DiagInner), + + /// A `DefId` that was created during query execution. + /// These `DefId`s will be re-created when we mark the query as green. + Definition(DefIdInfo), +} + +#[derive(Debug, Clone, Encodable, Decodable, PartialEq)] +pub struct DefIdInfo { + pub parent: LocalDefId, + pub data: rustc_hir::definitions::DefPathData, + pub hash: DefPathHash, + /// Disambiguator + pub disambiguator: u32, } pub trait QueryContext: HasDepContext { diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3c1fc7317848c..949f8abd4722d 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -525,7 +525,7 @@ where let dep_node = dep_node_opt.get_or_insert_with(|| query.construct_dep_node(*qcx.dep_context(), &key)); - // The diagnostics for this query will be promoted to the current session during + // The side_effects for this query will be promoted to the current session during // `try_mark_green()`, so we can ignore them here. if let Some(ret) = qcx.start_query(job_id, false, || { try_load_from_disk_and_cache_in_memory(query, dep_graph_data, qcx, &key, dep_node) diff --git a/tests/incremental/rpitit-feeding.rs b/tests/incremental/rpitit-feeding.rs new file mode 100644 index 0000000000000..0786879808f57 --- /dev/null +++ b/tests/incremental/rpitit-feeding.rs @@ -0,0 +1,27 @@ +//@ revisions: cpass cpass2 cpass3 + +// This test checks that creating a new `DefId` from within a query `A` +// recreates that `DefId` before reexecuting queries that depend on query `A`. +// Otherwise we'd end up referring to a `DefId` that doesn't exist. +// At present this is handled by always marking all queries as red if they create +// a new `DefId` and thus subsequently rerunning the query. + +trait Foo { + fn foo() -> impl Sized; +} + +#[cfg(any(cpass, cpass3))] +impl Foo for String { + fn foo() -> i32 { + 22 + } +} + +#[cfg(cpass2)] +impl Foo for String { + fn foo() -> u32 { + 22 + } +} + +fn main() {} diff --git a/tests/run-make/rustc-crates-on-stable/rmake.rs b/tests/run-make/rustc-crates-on-stable/rmake.rs index cbc1f24b8c16e..a4ae666bcb96d 100644 --- a/tests/run-make/rustc-crates-on-stable/rmake.rs +++ b/tests/run-make/rustc-crates-on-stable/rmake.rs @@ -8,6 +8,8 @@ fn main() { cargo() // Ensure `proc-macro2`'s nightly detection is disabled .env("RUSTC_STAGE", "0") + // Avoid loading stale data from the stage 0 compiler in case that one was incremental + .env("CARGO_INCREMENTAL", "0") .env("RUSTC", rustc_path()) // We want to disallow all nightly features to simulate a stable build .env("RUSTFLAGS", "-Zallow-features=")