Skip to content

Commit 5c08747

Browse files
Auto merge of #142711 - cjgillot:query-create-def, r=<try>
Make `create_def` a query Creating a new definition using `create_def` currently behaves as a red node for incremental compilation: the caller query must be recomputed at the next run. This is suboptimal. If a query's dependencies have not changed, we'd like the query engine to re-create the definitions and continue replaying the dependency graph and load cached data. This idea falls short with a subtle global state dependency: when creating definitions, we must ensure that `DefPathHash` are globally unique, and carry a disambiguator global state around. Because of this, a call to `create_def` may change its result `DefPathHash` due to global state, and force the caller query to be recomputed. If that happens, the caller query would need to be recomputed, but must not re-create the definitions that the query engine created for it. This PR attempts to solve this issue by using a `create_def_raw` query. This query is `eval_always`, so it can safely read global state. The query engine sees its return value as the `DefPathHash`, so will detect if it unexpectedly changed. We benefit from the caching queries do. However, we want multiple successive calls to `create_def` from the same queries to result in a new definition each time. For instance when creating anonymous definitions that are only identified by their parent and a disambiguator. To allow this, we add 2 extra parameters to `create_def_raw` that are unique to each call by the caller query: the query's `DepNode` and a counter of calls from within that query. Consider this example. Some query A calls create_def twice, we generate calls to: 1. `create_def(CRATE_DEF_ID, Use) = create_def_raw(CRATE_DEF_ID, Use, A, 0)` This returns `::{use#0}`. 2. `create_def(CRATE_DEF_ID, Use) = create_def_raw(CRATE_DEF_ID, Use, A, 1)` The query has different arguments, so returns a brand new `::{use::1}`. 3. `create_def(CRATE_DEF_ID, Impl) = create_def_raw(CRATE_DEF_ID, Impl, A, 2)` This returns `::{impl#0}`. When replaying, if nothing changed, the query engine will call `create_def_raw` thrice, and `A` will be green. If another query created a definition with `(CRATE_DEF_ID, Impl)`, `::{impl#0}` is taken. The 3rd call to `create_def` needs to use another disambiguator, that call to `create_def_raw` returns `::{impl#1}` and be correctly red. `A` needs to be re-computed. The definitions for `use`s have already been created when walking the dep-graph. The re-computation calls use the results in `create_def_raw` cache, aka `::{use#0}`, `::{use#1}` and `::{impl#1}`, and we do not have duplicate definitions. r? `@oli-obk` cc `@Zoxc` <!-- homu-ignore:start --> <!-- If this PR is related to an unstable feature or an otherwise tracked effort, please link to the relevant tracking issue here. If you don't know of a related tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using r? <reviewer name> --> <!-- homu-ignore:end -->
2 parents 70e2b4a + 31b00c7 commit 5c08747

File tree

14 files changed

+169
-117
lines changed

14 files changed

+169
-117
lines changed

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -532,11 +532,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
532532
self.tcx.hir_def_key(self.local_def_id(node_id)),
533533
);
534534

535-
let def_id = self
536-
.tcx
537-
.at(span)
538-
.create_def(parent, name, def_kind, None, &mut self.resolver.disambiguator)
539-
.def_id();
535+
let def_id = self.tcx.at(span).create_def(parent, name, def_kind, None).def_id();
540536

541537
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
542538
self.resolver.node_id_to_def_id.insert(node_id, def_id);

compiler/rustc_const_eval/src/interpret/intern.rs

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use hir::def::DefKind;
1717
use rustc_ast::Mutability;
1818
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
1919
use rustc_hir as hir;
20-
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
20+
use rustc_hir::definitions::DefPathData;
2121
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
2222
use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult};
2323
use rustc_middle::query::TyCtxtAt;
@@ -66,7 +66,6 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
6666
ecx: &mut InterpCx<'tcx, M>,
6767
alloc_id: AllocId,
6868
mutability: Mutability,
69-
disambiguator: Option<&mut DisambiguatorState>,
7069
) -> Result<impl Iterator<Item = CtfeProvenance> + 'tcx, ()> {
7170
trace!("intern_shallow {:?}", alloc_id);
7271
// remove allocation
@@ -89,13 +88,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
8988
// link the alloc id to the actual allocation
9089
let alloc = ecx.tcx.mk_const_alloc(alloc);
9190
if let Some(static_id) = ecx.machine.static_def_id() {
92-
intern_as_new_static(
93-
ecx.tcx,
94-
static_id,
95-
alloc_id,
96-
alloc,
97-
disambiguator.expect("disambiguator needed"),
98-
);
91+
intern_as_new_static(ecx.tcx, static_id, alloc_id, alloc);
9992
} else {
10093
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
10194
}
@@ -109,18 +102,16 @@ fn intern_as_new_static<'tcx>(
109102
static_id: LocalDefId,
110103
alloc_id: AllocId,
111104
alloc: ConstAllocation<'tcx>,
112-
disambiguator: &mut DisambiguatorState,
113105
) {
114-
// `intern_const_alloc_recursive` is called once per static and it contains the `DisambiguatorState`.
115-
// The `<static_id>::{{nested}}` path is thus unique to `intern_const_alloc_recursive` and the
116-
// `DisambiguatorState` ensures the generated path is unique for this call as we generate
117-
// `<static_id>::{{nested#n}}` where `n` is the `n`th `intern_as_new_static` call.
106+
// `intern_const_alloc_recursive` is called once per static. The `<static_id>::{{nested}}` path
107+
// is thus unique to `intern_const_alloc_recursive`. If there are several calls to
108+
// `intern_as_new_static`, `create_def` generates a path that is unique for this call as
109+
// generate `<static_id>::{{nested#n}}` where `n` is the `n`th `intern_as_new_static` call.
118110
let feed = tcx.create_def(
119111
static_id,
120112
None,
121113
DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true },
122114
Some(DefPathData::NestedStatic),
123-
disambiguator,
124115
);
125116
tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
126117

@@ -168,8 +159,6 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
168159
intern_kind: InternKind,
169160
ret: &MPlaceTy<'tcx>,
170161
) -> Result<(), InternResult> {
171-
let mut disambiguator = DisambiguatorState::new();
172-
173162
// We are interning recursively, and for mutability we are distinguishing the "root" allocation
174163
// that we are starting in, and all other allocations that we are encountering recursively.
175164
let (base_mutability, inner_mutability, is_static) = match intern_kind {
@@ -213,9 +202,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
213202
alloc.1.mutability = base_mutability;
214203
alloc.1.provenance().ptrs().iter().map(|&(_, prov)| prov).collect()
215204
} else {
216-
intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguator))
217-
.unwrap()
218-
.collect()
205+
intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().collect()
219206
};
220207
// We need to distinguish "has just been interned" from "was already in `tcx`",
221208
// so we track this in a separate set.
@@ -308,7 +295,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
308295
// okay with losing some potential for immutability here. This can anyway only affect
309296
// `static mut`.
310297
just_interned.insert(alloc_id);
311-
match intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator)) {
298+
match intern_shallow(ecx, alloc_id, inner_mutability) {
312299
Ok(nested) => todo.extend(nested),
313300
Err(()) => {
314301
ecx.tcx.dcx().delayed_bug("found dangling pointer during const interning");
@@ -330,9 +317,8 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>
330317
return interp_ok(());
331318
}
332319
// Move allocation to `tcx`.
333-
if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None)
334-
.map_err(|()| err_ub!(DeadLocal))?
335-
.next()
320+
if let Some(_) =
321+
intern_shallow(ecx, alloc_id, Mutability::Not).map_err(|()| err_ub!(DeadLocal))?.next()
336322
{
337323
// We are not doing recursive interning, so we don't currently support provenance.
338324
// (If this assertion ever triggers, we should just implement a
@@ -358,7 +344,7 @@ impl<'tcx> InterpCx<'tcx, DummyMachine> {
358344
let dest = self.allocate(layout, MemoryKind::Stack)?;
359345
f(self, &dest.clone().into())?;
360346
let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance
361-
for prov in intern_shallow(self, alloc_id, Mutability::Not, None).unwrap() {
347+
for prov in intern_shallow(self, alloc_id, Mutability::Not).unwrap() {
362348
// We are not doing recursive interning, so we don't currently support provenance.
363349
// (If this assertion ever triggers, we should just implement a
364350
// proper recursive interning loop -- or just call `intern_const_alloc_recursive`.

compiler/rustc_hir/src/definitions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_data_structures::stable_hasher::StableHasher;
1111
use rustc_data_structures::unord::UnordMap;
1212
use rustc_hashes::Hash64;
1313
use rustc_index::IndexVec;
14-
use rustc_macros::{Decodable, Encodable};
14+
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
1515
use rustc_span::{Symbol, kw, sym};
1616
use tracing::{debug, instrument};
1717

@@ -274,7 +274,7 @@ impl DefPath {
274274
}
275275

276276
/// New variants should only be added in synchronization with `enum DefKind`.
277-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
277+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
278278
pub enum DefPathData {
279279
// Root: these should only be used for the root nodes, because
280280
// they are treated specially by the `def_path` function.

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_ast::visit::walk_list;
1414
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
1515
use rustc_errors::ErrorGuaranteed;
1616
use rustc_hir::def::{DefKind, Res};
17-
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
17+
use rustc_hir::definitions::DefPathData;
1818
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
1919
use rustc_hir::{
2020
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node,
@@ -64,7 +64,6 @@ impl ResolvedArg {
6464
struct BoundVarContext<'a, 'tcx> {
6565
tcx: TyCtxt<'tcx>,
6666
rbv: &'a mut ResolveBoundVars,
67-
disambiguator: &'a mut DisambiguatorState,
6867
scope: ScopeRef<'a>,
6968
}
7069

@@ -247,12 +246,8 @@ pub(crate) fn provide(providers: &mut Providers) {
247246
#[instrument(level = "debug", skip(tcx))]
248247
fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
249248
let mut rbv = ResolveBoundVars::default();
250-
let mut visitor = BoundVarContext {
251-
tcx,
252-
rbv: &mut rbv,
253-
scope: &Scope::Root { opt_parent_item: None },
254-
disambiguator: &mut DisambiguatorState::new(),
255-
};
249+
let mut visitor =
250+
BoundVarContext { tcx, rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None } };
256251
match tcx.hir_owner_node(local_def_id) {
257252
hir::OwnerNode::Item(item) => visitor.visit_item(item),
258253
hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
@@ -1098,8 +1093,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
10981093
where
10991094
F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
11001095
{
1101-
let BoundVarContext { tcx, rbv, disambiguator, .. } = self;
1102-
let mut this = BoundVarContext { tcx: *tcx, rbv, disambiguator, scope: &wrap_scope };
1096+
let BoundVarContext { tcx, rbv, .. } = self;
1097+
let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope };
11031098
let span = debug_span!("scope", scope = ?this.scope.debug_truncated());
11041099
{
11051100
let _enter = span.enter();
@@ -1472,13 +1467,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
14721467
// `opaque_def_id` is unique to the `BoundVarContext` pass which is executed once
14731468
// per `resolve_bound_vars` query. This is the only location that creates
14741469
// `OpaqueLifetime` paths. `<opaque_def_id>::OpaqueLifetime(..)` is thus unique
1475-
// to this query and duplicates within the query are handled by `self.disambiguator`.
1470+
// to this query.
14761471
let feed = self.tcx.create_def(
14771472
opaque_def_id,
14781473
None,
14791474
DefKind::LifetimeParam,
14801475
Some(DefPathData::OpaqueLifetime(ident.name)),
1481-
&mut self.disambiguator,
14821476
);
14831477
feed.def_span(ident.span);
14841478
feed.def_ident_span(Some(ident.span));

compiler/rustc_interface/src/passes.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ use rustc_ast as ast;
99
use rustc_codegen_ssa::traits::CodegenBackend;
1010
use rustc_data_structures::jobserver::Proxy;
1111
use rustc_data_structures::steal::Steal;
12-
use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal};
12+
use rustc_data_structures::sync::WorkerLocal;
1313
use rustc_data_structures::{parallel, thousands};
1414
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
1515
use rustc_feature::Features;
1616
use rustc_fs_util::try_canonicalize;
17-
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
18-
use rustc_hir::definitions::Definitions;
17+
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId};
1918
use rustc_incremental::setup_dep_graph;
2019
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
2120
use rustc_metadata::EncodedMetadata;
@@ -30,7 +29,6 @@ use rustc_parse::{
3029
use rustc_passes::{abi_test, input_stats, layout_test};
3130
use rustc_resolve::Resolver;
3231
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
33-
use rustc_session::cstore::Untracked;
3432
use rustc_session::output::{collect_crate_types, filename_for_input};
3533
use rustc_session::parse::feature_err;
3634
use rustc_session::search_paths::PathKind;
@@ -904,13 +902,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
904902
let dep_type = DepsType { dep_names: rustc_query_impl::dep_kind_names() };
905903
let dep_graph = setup_dep_graph(sess, crate_name, &dep_type);
906904

907-
let cstore =
908-
FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _);
909-
let definitions = FreezeLock::new(Definitions::new(stable_crate_id));
910-
911-
let stable_crate_ids = FreezeLock::new(StableCrateIdMap::default());
912-
let untracked =
913-
Untracked { cstore, source_span: AppendOnlyIndexVec::new(), definitions, stable_crate_ids };
905+
let cstore = Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _;
914906

915907
// We're constructing the HIR here; we don't care what we will
916908
// read, since we haven't even constructed the *input* to
@@ -953,7 +945,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
953945
stable_crate_id,
954946
arena,
955947
hir_arena,
956-
untracked,
948+
cstore,
957949
dep_graph,
958950
rustc_query_impl::query_callbacks(arena),
959951
rustc_query_impl::query_system(

compiler/rustc_middle/src/query/keys.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
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};
910
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
1011

12+
use crate::dep_graph::DepNode;
1113
use crate::infer::canonical::CanonicalQueryInput;
1214
use crate::mir::mono::CollectionMode;
1315
use crate::ty::fast_reject::SimplifiedType;
@@ -640,3 +642,11 @@ impl<'tcx> Key for (ty::Instance<'tcx>, CollectionMode) {
640642
self.0.default_span(tcx)
641643
}
642644
}
645+
646+
impl Key for (LocalDefId, DefPathData, Option<DepNode>, usize) {
647+
type Cache<V> = DefaultCache<Self, V>;
648+
649+
fn default_span(&self, _: TyCtxt<'_>) -> Span {
650+
DUMMY_SP
651+
}
652+
}

compiler/rustc_middle/src/query/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ use rustc_hir::def::{DefKind, DocLinkResMap};
8181
use rustc_hir::def_id::{
8282
CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
8383
};
84+
use rustc_hir::definitions::DefPathData;
8485
use rustc_hir::lang_items::{LangItem, LanguageItems};
8586
use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate};
8687
use rustc_index::IndexVec;
@@ -102,6 +103,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol};
102103
use rustc_target::spec::PanicStrategy;
103104
use {rustc_abi as abi, rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir};
104105

106+
use crate::dep_graph::DepNode;
105107
use crate::infer::canonical::{self, Canonical};
106108
use crate::lint::LintExpectation;
107109
use crate::metadata::ModChild;
@@ -215,6 +217,23 @@ rustc_queries! {
215217
desc { "getting the source span" }
216218
}
217219

220+
/// Create a new definition.
221+
query create_def_raw(key: (
222+
LocalDefId, // parent
223+
DefPathData, // def_path_data
224+
Option<DepNode>, // caller query
225+
usize, // counter of calls to `create_def_raw` by the caller query
226+
)) -> LocalDefId {
227+
// Accesses untracked data
228+
eval_always
229+
desc { |tcx|
230+
"create a new definition for `{}::{:?}`, {}th call",
231+
tcx.def_path_str(key.0),
232+
key.1,
233+
key.3,
234+
}
235+
}
236+
218237
/// Represents crate as a whole (as distinct from the top-level crate module).
219238
///
220239
/// If you call `tcx.hir_crate(())` we will have to assume that any change

0 commit comments

Comments
 (0)