Skip to content

Commit b5eeded

Browse files
committed
Auto merge of rust-lang#115613 - oli-obk:create_def_forever_red, r=<try>
Make create_def a side effect instead of marking the entire query as always red Before this PR: * query A creates def id D * query A is marked as depending on the always-red node, meaning it will always get re-run * in the next run of rustc: query A is not loaded from the incremental cache, but rerun After this PR: * query A creates def id D * query system registers this a side effect (just like we collect diagnostics to re-emit them without running a query) * in the next run of rustc: query A is loaded from the incremental cache and its side effect is run (thus re-creating def id D without running query A) r? `@cjgillot` TODO: * [ ] need to make feeding queries a side effect, too. At least ones that aren't written to disk. * [ ] need to re-feed the `def_span` query * [ ] many more tests
2 parents 8f43b85 + c65f83e commit b5eeded

File tree

12 files changed

+191
-37
lines changed

12 files changed

+191
-37
lines changed

compiler/rustc_hir/src/definitions.rs

+25-6
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use std::hash::Hash;
1010
use rustc_data_structures::stable_hasher::StableHasher;
1111
use rustc_data_structures::unord::UnordMap;
1212
use rustc_hashes::Hash64;
13-
use rustc_index::IndexVec;
14-
use rustc_macros::{Decodable, Encodable};
13+
use rustc_index::{IndexVec, static_assert_size};
14+
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
1515
use rustc_span::{Symbol, kw, sym};
1616
use tracing::{debug, instrument};
1717

@@ -252,7 +252,7 @@ impl DefPath {
252252
}
253253

254254
/// New variants should only be added in synchronization with `enum DefKind`.
255-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
255+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
256256
pub enum DefPathData {
257257
// Root: these should only be used for the root nodes, because
258258
// they are treated specially by the `def_path` function.
@@ -293,6 +293,8 @@ pub enum DefPathData {
293293
SyntheticCoroutineBody,
294294
}
295295

296+
static_assert_size!(DefPathData, 8);
297+
296298
impl Definitions {
297299
pub fn def_path_table(&self) -> &DefPathTable {
298300
&self.table
@@ -346,7 +348,12 @@ impl Definitions {
346348
}
347349

348350
/// Adds a definition with a parent definition.
349-
pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId {
351+
pub fn create_def(
352+
&mut self,
353+
parent: LocalDefId,
354+
data: DefPathData,
355+
query_local_disambiguator: Option<u32>,
356+
) -> LocalDefId {
350357
// We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a
351358
// reference to `Definitions` and we're already holding a mutable reference.
352359
debug!(
@@ -361,8 +368,20 @@ impl Definitions {
361368
let disambiguator = {
362369
let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0);
363370
let disambiguator = *next_disamb;
364-
*next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
365-
disambiguator
371+
// The disambiguator number space is split into the ones counting from 0 upwards,
372+
match query_local_disambiguator {
373+
None => {
374+
assert!(disambiguator < u32::MAX / 2);
375+
*next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
376+
disambiguator
377+
}
378+
// and the ones counting from MAX downwards.
379+
Some(local) => {
380+
// Ensure these two number spaces do not collide. 2^31 disambiguators should be enough for everyone.
381+
assert!(local < u32::MAX / 2);
382+
u32::MAX - local
383+
}
384+
}
366385
};
367386
let key = DefKey {
368387
parent: Some(parent.local_def_index),

compiler/rustc_hir_analysis/src/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,15 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
225225
}
226226
});
227227

228+
// Make sure we actually have a value for static items, as they aren't cached in incremental.
229+
// While we could just wait for codegen to invoke this, the definitions freeze below will cause
230+
// that to ICE, because evaluating statics can create more items.
231+
tcx.par_hir_body_owners(|item_def_id| {
232+
if let DefKind::Static { .. } = tcx.def_kind(item_def_id) {
233+
let _ = tcx.eval_static_initializer(item_def_id);
234+
}
235+
});
236+
228237
tcx.par_hir_body_owners(|item_def_id| {
229238
let def_kind = tcx.def_kind(item_def_id);
230239
// Skip `AnonConst`s because we feed their `type_of`.

compiler/rustc_interface/src/callbacks.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
2525
// Skip doing anything if we aren't tracking dependencies.
2626
let tracks_deps = match icx.task_deps {
2727
TaskDepsRef::Allow(..) => true,
28-
TaskDepsRef::EvalAlways | TaskDepsRef::Ignore | TaskDepsRef::Forbid => false,
28+
TaskDepsRef::Replay { .. }
29+
| TaskDepsRef::EvalAlways
30+
| TaskDepsRef::Ignore
31+
| TaskDepsRef::Forbid => false,
2932
};
3033
if tracks_deps {
3134
let _span = icx.tcx.source_span(def_id);

compiler/rustc_middle/src/hir/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,11 @@ pub fn provide(providers: &mut Providers) {
239239
providers.in_scope_traits_map = |tcx, id| {
240240
tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
241241
};
242+
providers.create_def_raw = |tcx, (parent, data, query_local_disambiguator)| {
243+
tcx.untracked().definitions.write().create_def(
244+
parent,
245+
data,
246+
Some(query_local_disambiguator),
247+
)
248+
}
242249
}

compiler/rustc_middle/src/query/keys.rs

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::ffi::OsStr;
44

55
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId};
6+
use rustc_hir::definitions::DefPathData;
67
use rustc_hir::hir_id::{HirId, OwnerId};
78
use rustc_query_system::dep_graph::DepNodeIndex;
89
use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache};
@@ -265,6 +266,14 @@ impl Key for (LocalDefId, LocalDefId) {
265266
}
266267
}
267268

269+
impl Key for (LocalDefId, DefPathData, u32) {
270+
type Cache<V> = DefaultCache<Self, V>;
271+
272+
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
273+
self.0.default_span(tcx)
274+
}
275+
}
276+
268277
impl Key for (DefId, Ident) {
269278
type Cache<V> = DefaultCache<Self, V>;
270279

compiler/rustc_middle/src/query/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ rustc_queries! {
159159
desc { "getting the source span" }
160160
}
161161

162+
/// Used to handle incremental replays of [`TyCtxt::create_def`] invocations from tracked queries.
163+
query create_def_raw(key: (LocalDefId, rustc_hir::definitions::DefPathData, u32)) -> LocalDefId {
164+
// Accesses untracked data
165+
eval_always
166+
desc { "generating a new def id" }
167+
}
168+
162169
/// Represents crate as a whole (as distinct from the top-level crate module).
163170
///
164171
/// If you call `tcx.hir_crate(())` we will have to assume that any change
@@ -1276,7 +1283,6 @@ rustc_queries! {
12761283
"evaluating initializer of static `{}`",
12771284
tcx.def_path_str(key)
12781285
}
1279-
cache_on_disk_if { key.is_local() }
12801286
separate_provide_extern
12811287
feedable
12821288
}

compiler/rustc_middle/src/ty/context.rs

+32-22
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate};
4141
use rustc_index::IndexVec;
4242
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
4343
use rustc_query_system::cache::WithDepNode;
44-
use rustc_query_system::dep_graph::DepNodeIndex;
44+
use rustc_query_system::dep_graph::{DepNodeIndex, TaskDepsRef};
4545
use rustc_query_system::ich::StableHashingContext;
4646
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
4747
use rustc_session::config::CrateType;
@@ -1970,27 +1970,37 @@ impl<'tcx> TyCtxt<'tcx> {
19701970
def_kind: DefKind,
19711971
) -> TyCtxtFeed<'tcx, LocalDefId> {
19721972
let data = def_kind.def_path_data(name);
1973-
// The following call has the side effect of modifying the tables inside `definitions`.
1974-
// These very tables are relied on by the incr. comp. engine to decode DepNodes and to
1975-
// decode the on-disk cache.
1976-
//
1977-
// Any LocalDefId which is used within queries, either as key or result, either:
1978-
// - has been created before the construction of the TyCtxt;
1979-
// - has been created by this call to `create_def`.
1980-
// As a consequence, this LocalDefId is always re-created before it is needed by the incr.
1981-
// comp. engine itself.
1982-
//
1983-
// This call also writes to the value of the `source_span` query.
1984-
// This is fine because:
1985-
// - that query is `eval_always` so we won't miss its result changing;
1986-
// - this write will have happened before that query is called.
1987-
let def_id = self.untracked.definitions.write().create_def(parent, data);
1988-
1989-
// This function modifies `self.definitions` using a side-effect.
1990-
// We need to ensure that these side effects are re-run by the incr. comp. engine.
1991-
// Depending on the forever-red node will tell the graph that the calling query
1992-
// needs to be re-evaluated.
1993-
self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
1973+
1974+
let def_id = tls::with_context(|icx| {
1975+
match icx.task_deps {
1976+
// Always gets rerun anyway, so nothing to replay
1977+
TaskDepsRef::EvalAlways |
1978+
// Top-level queries like the resolver get rerun every time anyway
1979+
TaskDepsRef::Ignore => {
1980+
// The following call has the side effect of modifying the tables inside `definitions`.
1981+
// These very tables are relied on by the incr. comp. engine to decode DepNodes and to
1982+
// decode the on-disk cache.
1983+
//
1984+
// Any LocalDefId which is used within queries, either as key or result, either:
1985+
// - has been created before the construction of the TyCtxt;
1986+
// - has been created by this call to `create_def`.
1987+
// As a consequence, this LocalDefId is always re-created before it is needed by the incr.
1988+
// comp. engine itself.
1989+
self.untracked.definitions.write().create_def(parent, data, None)
1990+
}
1991+
TaskDepsRef::Forbid => bug!(
1992+
"cannot create definition {parent:?} {data:?} without being able to register task dependencies"
1993+
),
1994+
TaskDepsRef::Allow(deps) => {
1995+
let idx = deps.lock().next_def_id_idx();
1996+
self.create_def_raw((parent, data, idx))
1997+
}
1998+
TaskDepsRef::Replay { created_def_ids } => {
1999+
let idx = created_def_ids.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
2000+
self.create_def_raw((parent, data, idx))
2001+
}
2002+
}
2003+
});
19942004

19952005
let feed = TyCtxtFeed { tcx: self, key: def_id };
19962006
feed.def_kind(def_kind);

compiler/rustc_query_system/src/dep_graph/graph.rs

+38-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::assert_matches::assert_matches;
22
use std::fmt::Debug;
33
use std::hash::Hash;
4-
use std::marker::PhantomData;
54
use std::sync::Arc;
65
use std::sync::atomic::{AtomicU32, Ordering};
76

@@ -208,6 +207,10 @@ impl<D: Deps> DepGraph<D> {
208207
}
209208
}
210209

210+
pub(crate) fn with_replay<R>(&self, created_def_ids: &AtomicU32, op: impl FnOnce() -> R) -> R {
211+
D::with_deps(TaskDepsRef::Replay { created_def_ids }, op)
212+
}
213+
211214
pub fn with_ignore<OP, R>(&self, op: OP) -> R
212215
where
213216
OP: FnOnce() -> R,
@@ -362,7 +365,7 @@ impl<D: Deps> DepGraphData<D> {
362365
node: Some(key),
363366
reads: EdgesVec::new(),
364367
read_set: Default::default(),
365-
phantom_data: PhantomData,
368+
created_def_ids: 0,
366369
});
367370
(with_deps(TaskDepsRef::Allow(&task_deps)), task_deps.into_inner().reads)
368371
};
@@ -478,6 +481,12 @@ impl<D: Deps> DepGraph<D> {
478481
return;
479482
}
480483
TaskDepsRef::Ignore => return,
484+
// We don't need to record dependencies when rerunning a query
485+
// because we have no disk cache entry to load. The dependencies
486+
// are preserved.
487+
// FIXME: assert that the dependencies don't change instead of
488+
// recording them.
489+
TaskDepsRef::Replay { .. } => return,
481490
TaskDepsRef::Forbid => {
482491
// Reading is forbidden in this context. ICE with a useful error message.
483492
panic_on_forbidden_read(data, dep_node_index)
@@ -528,7 +537,9 @@ impl<D: Deps> DepGraph<D> {
528537
pub fn record_diagnostic<Qcx: QueryContext>(&self, qcx: Qcx, diagnostic: &DiagInner) {
529538
if let Some(ref data) = self.data {
530539
D::read_deps(|task_deps| match task_deps {
531-
TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return,
540+
TaskDepsRef::EvalAlways | TaskDepsRef::Ignore | TaskDepsRef::Replay { .. } => {
541+
return;
542+
}
532543
TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => {
533544
self.read_index(data.encode_diagnostic(qcx, diagnostic));
534545
}
@@ -609,7 +620,7 @@ impl<D: Deps> DepGraph<D> {
609620
edges.push(DepNodeIndex::FOREVER_RED_NODE);
610621
}
611622
TaskDepsRef::Ignore => {}
612-
TaskDepsRef::Forbid => {
623+
TaskDepsRef::Replay { .. } | TaskDepsRef::Forbid => {
613624
panic!("Cannot summarize when dependencies are not recorded.")
614625
}
615626
});
@@ -1319,6 +1330,17 @@ pub enum TaskDepsRef<'a> {
13191330
/// to ensure that the decoding process doesn't itself
13201331
/// require the execution of any queries.
13211332
Forbid,
1333+
/// Side effects from the previous run made available to
1334+
/// queries when they are reexecuted because their result was not
1335+
/// available in the cache. Whenever the query creates a new `DefId`,
1336+
/// it is checked against the entries in `QuerySideEffects::definitions`
1337+
/// to ensure that the new `DefId`s are the same as the ones that were
1338+
/// created the last time the query was executed.
1339+
Replay {
1340+
/// Every new `DefId` created increases this counter so that we produce the same ones
1341+
/// as the original execution created.
1342+
created_def_ids: &'a AtomicU32,
1343+
},
13221344
}
13231345

13241346
#[derive(Debug)]
@@ -1327,7 +1349,8 @@ pub struct TaskDeps {
13271349
node: Option<DepNode>,
13281350
reads: EdgesVec,
13291351
read_set: FxHashSet<DepNodeIndex>,
1330-
phantom_data: PhantomData<DepNode>,
1352+
/// Every new `DefId` created increases this counter so that they can be replayed.
1353+
created_def_ids: u32,
13311354
}
13321355

13331356
impl Default for TaskDeps {
@@ -1337,10 +1360,19 @@ impl Default for TaskDeps {
13371360
node: None,
13381361
reads: EdgesVec::new(),
13391362
read_set: FxHashSet::with_capacity_and_hasher(128, Default::default()),
1340-
phantom_data: PhantomData,
1363+
created_def_ids: 0,
13411364
}
13421365
}
13431366
}
1367+
1368+
impl TaskDeps {
1369+
pub fn next_def_id_idx(&mut self) -> u32 {
1370+
let idx = self.created_def_ids;
1371+
self.created_def_ids += 1;
1372+
idx
1373+
}
1374+
}
1375+
13441376
// A data structure that stores Option<DepNodeColor> values as a contiguous
13451377
// array, using one u32 per entry.
13461378
pub(super) struct DepNodeColorMap {

compiler/rustc_query_system/src/query/plumbing.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::cell::Cell;
66
use std::fmt::Debug;
77
use std::hash::Hash;
88
use std::mem;
9+
use std::sync::atomic::AtomicU32;
910

1011
use hashbrown::hash_table::Entry;
1112
use rustc_data_structures::fingerprint::Fingerprint;
@@ -633,8 +634,10 @@ where
633634
// recompute.
634635
let prof_timer = qcx.dep_context().profiler().query_provider();
635636

637+
let created_def_ids = AtomicU32::new(0);
636638
// The dep-graph for this computation is already in-place.
637-
let result = qcx.dep_context().dep_graph().with_ignore(|| query.compute(qcx, *key));
639+
let result =
640+
qcx.dep_context().dep_graph().with_replay(&created_def_ids, || query.compute(qcx, *key));
638641

639642
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
640643

tests/incremental/rpitit-feeding.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//@ revisions: cpass cpass2 cpass3
2+
3+
// This test checks that creating a new `DefId` from within a query `A`
4+
// recreates that `DefId` before reexecuting queries that depend on query `A`.
5+
// Otherwise we'd end up referring to a `DefId` that doesn't exist.
6+
// At present this is handled by always marking all queries as red if they create
7+
// a new `DefId` and thus subsequently rerunning the query.
8+
9+
trait Foo {
10+
fn foo() -> impl Sized;
11+
}
12+
13+
#[cfg(any(cpass, cpass3))]
14+
impl Foo for String {
15+
fn foo() -> i32 {
16+
22
17+
}
18+
}
19+
20+
#[cfg(cpass2)]
21+
impl Foo for String {
22+
fn foo() -> u32 {
23+
22
24+
}
25+
}
26+
27+
fn main() {}

0 commit comments

Comments
 (0)