Create a forever red node and use it to force side effects.

This commit is contained in:
Camille GILLOT 2022-04-27 19:18:26 +02:00
parent 682f57656e
commit 15530a1c84
5 changed files with 26 additions and 37 deletions

View File

@ -20,12 +20,6 @@ rustc_queries! {
desc { "trigger a delay span bug" }
}
/// Create a new definition within the incr. comp. engine.
query register_def(_: ty::RawLocalDefId) -> LocalDefId {
eval_always
desc { "register a DefId with the incr. comp. engine" }
}
query resolutions(_: ()) -> &'tcx ty::ResolverOutputs {
eval_always
no_hash

View File

@ -123,9 +123,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type PlaceholderRegion = ty::PlaceholderRegion;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
pub struct RawLocalDefId(LocalDefId);
/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s
/// except through the error-reporting functions on a [`tcx`][TyCtxt].
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
@ -1477,23 +1474,15 @@ impl<'tcx> TyCtxt<'tcx> {
let def_id = self.definitions.write().create_def(parent, data);
// We need to ensure that these side effects are re-run by the incr. comp. engine.
// When the incr. comp. engine considers marking this query as green, eval_always requires
// we run the function to run. To invoke it, the parameter cannot be reconstructed from
// the DepNode, so the caller query is run. Luckily, we are inside the caller query,
// therefore the definition is properly created.
debug_assert!({
use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
self.is_eval_always(crate::dep_graph::DepKind::register_def)
&& !<RawLocalDefId as DepNodeParams<TyCtxt<'_>>>::fingerprint_style()
.reconstructible()
});
use rustc_query_system::dep_graph::DepNodeIndex;
self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
// 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 `register_def`.
// - 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.
self.register_def(RawLocalDefId(def_id))
def_id
}
pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx {
@ -3033,5 +3022,4 @@ pub fn provide(providers: &mut ty::query::Providers) {
// We want to check if the panic handler was defined in this crate
tcx.lang_items().panic_impl().map_or(false, |did| did.is_local())
};
providers.register_def = |_, raw_id| raw_id.0;
}

View File

@ -72,8 +72,8 @@ pub use self::consts::{
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, RawLocalDefId, TyCtxt,
TypeckResults, UserType, UserTypeAnnotationIndex,
GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
UserTypeAnnotationIndex,
};
pub use self::instance::{Instance, InstanceDef};
pub use self::list::List;

View File

@ -39,17 +39,6 @@ impl Key for () {
}
}
impl Key for ty::RawLocalDefId {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
}
impl<'tcx> Key for ty::InstanceDef<'tcx> {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {

View File

@ -43,6 +43,7 @@ rustc_index::newtype_index! {
impl DepNodeIndex {
pub const INVALID: DepNodeIndex = DepNodeIndex::MAX;
pub const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0);
pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1);
}
impl std::convert::From<DepNodeIndex> for QueryInvocationId {
@ -124,6 +125,8 @@ impl<K: DepKind> DepGraph<K> {
record_stats,
);
let colors = DepNodeColorMap::new(prev_graph_node_count);
// Instantiate a dependy-less node only once for anonymous queries.
let _green_node_index = current.intern_new_node(
profiler,
@ -133,6 +136,18 @@ impl<K: DepKind> DepGraph<K> {
);
debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
// Instantiate a dependy-less red node only once for anonymous queries.
let (_red_node_index, _prev_and_index) = current.intern_node(
profiler,
&prev_graph,
DepNode { kind: DepKind::NULL, hash: Fingerprint::ZERO.into() },
smallvec![],
None,
false,
);
debug_assert_eq!(_red_node_index, DepNodeIndex::FOREVER_RED_NODE);
debug_assert!(matches!(_prev_and_index, None | Some((_, DepNodeColor::Red))));
DepGraph {
data: Some(Lrc::new(DepGraphData {
previous_work_products: prev_work_products,
@ -140,7 +155,7 @@ impl<K: DepKind> DepGraph<K> {
current,
processed_side_effects: Default::default(),
previous: prev_graph,
colors: DepNodeColorMap::new(prev_graph_node_count),
colors,
debug_loaded_from_disk: Default::default(),
})),
virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
@ -965,6 +980,9 @@ impl<K: DepKind> CurrentDepGraph<K> {
let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64;
let mut stable_hasher = StableHasher::new();
nanos.hash(&mut stable_hasher);
let anon_id_seed = stable_hasher.finish();
// We rely on the fact that `anon_id_seed` is not zero when creating static nodes.
debug_assert_ne!(anon_id_seed, Fingerprint::ZERO);
#[cfg(debug_assertions)]
let forbidden_edge = match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
@ -1000,7 +1018,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
)
}),
prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)),
anon_id_seed: stable_hasher.finish(),
anon_id_seed,
#[cfg(debug_assertions)]
forbidden_edge,
total_read_count: AtomicU64::new(0),