From a7e2641b9aba10d6eabf6978d3b5506d99ae633c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 31 Dec 2019 10:51:58 +0100 Subject: [PATCH 1/9] Move dep_graph to new crate librustc_query_system. --- .../dep_graph/README.md | 0 .../dep_graph/debug.rs | 0 .../dep_graph/dep_node.rs | 520 ++++++++++++++++++ .../dep_graph/graph.rs | 0 .../dep_graph/mod.rs | 0 .../dep_graph/prev.rs | 0 .../dep_graph/query.rs | 0 .../dep_graph/safe.rs | 0 .../dep_graph/serialized.rs | 0 9 files changed, 520 insertions(+) rename src/{librustc => librustc_query_system}/dep_graph/README.md (100%) rename src/{librustc => librustc_query_system}/dep_graph/debug.rs (100%) create mode 100644 src/librustc_query_system/dep_graph/dep_node.rs rename src/{librustc => librustc_query_system}/dep_graph/graph.rs (100%) rename src/{librustc => librustc_query_system}/dep_graph/mod.rs (100%) rename src/{librustc => librustc_query_system}/dep_graph/prev.rs (100%) rename src/{librustc => librustc_query_system}/dep_graph/query.rs (100%) rename src/{librustc => librustc_query_system}/dep_graph/safe.rs (100%) rename src/{librustc => librustc_query_system}/dep_graph/serialized.rs (100%) diff --git a/src/librustc/dep_graph/README.md b/src/librustc_query_system/dep_graph/README.md similarity index 100% rename from src/librustc/dep_graph/README.md rename to src/librustc_query_system/dep_graph/README.md diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc_query_system/dep_graph/debug.rs similarity index 100% rename from src/librustc/dep_graph/debug.rs rename to src/librustc_query_system/dep_graph/debug.rs diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs new file mode 100644 index 0000000000000..e3df9d5d04be1 --- /dev/null +++ b/src/librustc_query_system/dep_graph/dep_node.rs @@ -0,0 +1,520 @@ +//! This module defines the `DepNode` type which the compiler uses to represent +//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which +//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc) +//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which +//! depends on the node's `DepKind`. Together, the kind and the fingerprint +//! fully identify a dependency node, even across multiple compilation sessions. +//! In other words, the value of the fingerprint does not depend on anything +//! that is specific to a given compilation session, like an unpredictable +//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a +//! pointer. The concept behind this could be compared to how git commit hashes +//! uniquely identify a given commit and has a few advantages: +//! +//! * A `DepNode` can simply be serialized to disk and loaded in another session +//! without the need to do any "rebasing (like we have to do for Spans and +//! NodeIds) or "retracing" like we had to do for `DefId` in earlier +//! implementations of the dependency graph. +//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to +//! implement `Copy`, `Sync`, `Send`, `Freeze`, etc. +//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into +//! memory without any post-processing (e.g., "abomination-style" pointer +//! reconstruction). +//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that +//! refer to things that do not exist anymore. In previous implementations +//! `DepNode` contained a `DefId`. A `DepNode` referring to something that +//! had been removed between the previous and the current compilation session +//! could not be instantiated because the current compilation session +//! contained no `DefId` for thing that had been removed. +//! +//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro +//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The +//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at +//! runtime in order to construct a valid `DepNode` fingerprint. +//! +//! Because the macro sees what parameters a given `DepKind` requires, it can +//! "infer" some properties for each kind of `DepNode`: +//! +//! * Whether a `DepNode` of a given kind has any parameters at all. Some +//! `DepNode`s could represent global concepts with only one value. +//! * Whether it is possible, in principle, to reconstruct a query key from a +//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter, +//! in which case it is possible to map the node's fingerprint back to the +//! `DefId` it was computed from. In other cases, too much information gets +//! lost during fingerprint computation. +//! +//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only +//! valid `DepNode` instances can be constructed. For example, the API does not +//! allow for constructing parameterless `DepNode`s with anything other +//! than a zeroed out fingerprint. More generally speaking, it relieves the +//! user of the `DepNode` API of having to know how to compute the expected +//! fingerprint for a given set of node parameters. + +use crate::hir::map::DefPathHash; +use crate::ich::{Fingerprint, StableHashingContext}; +use crate::mir; +use crate::mir::interpret::{GlobalId, LitToConstInput}; +use crate::traits; +use crate::traits::query::{ + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, +}; +use crate::ty::subst::SubstsRef; +use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc_hir::HirId; +use rustc_span::symbol::Symbol; +use std::fmt; +use std::hash::Hash; + +// erase!() just makes tokens go away. It's used to specify which macro argument +// is repeated (i.e., which sub-expression of the macro we are in) but don't need +// to actually use any of the arguments. +macro_rules! erase { + ($x:tt) => {{}}; +} + +macro_rules! is_anon_attr { + (anon) => { + true + }; + ($attr:ident) => { + false + }; +} + +macro_rules! is_eval_always_attr { + (eval_always) => { + true + }; + ($attr:ident) => { + false + }; +} + +macro_rules! contains_anon_attr { + ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false}); +} + +macro_rules! contains_eval_always_attr { + ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false}); +} + +macro_rules! define_dep_nodes { + (<$tcx:tt> + $( + [$($attrs:tt)*] + $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* + ,)* + ) => ( + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, + RustcEncodable, RustcDecodable)] + #[allow(non_camel_case_types)] + pub enum DepKind { + $($variant),* + } + + impl DepKind { + #[allow(unreachable_code)] + pub fn can_reconstruct_query_key<$tcx>(&self) -> bool { + match *self { + $( + DepKind :: $variant => { + if contains_anon_attr!($($attrs)*) { + return false; + } + + // tuple args + $({ + return <$tuple_arg_ty as DepNodeParams> + ::CAN_RECONSTRUCT_QUERY_KEY; + })* + + true + } + )* + } + } + + pub fn is_anon(&self) -> bool { + match *self { + $( + DepKind :: $variant => { contains_anon_attr!($($attrs)*) } + )* + } + } + + pub fn is_eval_always(&self) -> bool { + match *self { + $( + DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) } + )* + } + } + + #[allow(unreachable_code)] + pub fn has_params(&self) -> bool { + match *self { + $( + DepKind :: $variant => { + // tuple args + $({ + erase!($tuple_arg_ty); + return true; + })* + + false + } + )* + } + } + } + + pub struct DepConstructor; + + #[allow(non_camel_case_types)] + impl DepConstructor { + $( + #[inline(always)] + #[allow(unreachable_code, non_snake_case)] + pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode { + // tuple args + $({ + erase!($tuple_arg_ty); + let hash = DepNodeParams::to_fingerprint(&arg, _tcx); + let dep_node = DepNode { + kind: DepKind::$variant, + hash + }; + + #[cfg(debug_assertions)] + { + if !dep_node.kind.can_reconstruct_query_key() && + (_tcx.sess.opts.debugging_opts.incremental_info || + _tcx.sess.opts.debugging_opts.query_dep_graph) + { + _tcx.dep_graph.register_dep_node_debug_str(dep_node, || { + arg.to_debug_str(_tcx) + }); + } + } + + return dep_node; + })* + + DepNode { + kind: DepKind::$variant, + hash: Fingerprint::ZERO, + } + } + )* + } + + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, + RustcEncodable, RustcDecodable)] + pub struct DepNode { + pub kind: DepKind, + pub hash: Fingerprint, + } + + impl DepNode { + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + pub fn from_def_path_hash(def_path_hash: DefPathHash, + kind: DepKind) + -> DepNode { + debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); + DepNode { + kind, + hash: def_path_hash.0, + } + } + + /// Creates a new, parameterless DepNode. This method will assert + /// that the DepNode corresponding to the given DepKind actually + /// does not require any parameters. + pub fn new_no_params(kind: DepKind) -> DepNode { + debug_assert!(!kind.has_params()); + DepNode { + kind, + hash: Fingerprint::ZERO, + } + } + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option { + if self.kind.can_reconstruct_query_key() { + let def_path_hash = DefPathHash(self.hash); + tcx.def_path_hash_to_def_id.as_ref()? + .get(&def_path_hash).cloned() + } else { + None + } + } + + /// Used in testing + pub fn from_label_string(label: &str, + def_path_hash: DefPathHash) + -> Result { + let kind = match label { + $( + stringify!($variant) => DepKind::$variant, + )* + _ => return Err(()), + }; + + if !kind.can_reconstruct_query_key() { + return Err(()); + } + + if kind.has_params() { + Ok(DepNode::from_def_path_hash(def_path_hash, kind)) + } else { + Ok(DepNode::new_no_params(kind)) + } + } + + /// Used in testing + pub fn has_label_string(label: &str) -> bool { + match label { + $( + stringify!($variant) => true, + )* + _ => false, + } + } + } + + /// Contains variant => str representations for constructing + /// DepNode groups for tests. + #[allow(dead_code, non_upper_case_globals)] + pub mod label_strs { + $( + pub const $variant: &str = stringify!($variant); + )* + } + ); +} + +impl fmt::Debug for DepNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind)?; + + if !self.kind.has_params() && !self.kind.is_anon() { + return Ok(()); + } + + write!(f, "(")?; + + crate::ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_id) = self.extract_def_id(tcx) { + write!(f, "{}", tcx.def_path_debug_str(def_id))?; + } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { + write!(f, "{}", s)?; + } else { + write!(f, "{}", self.hash)?; + } + } else { + write!(f, "{}", self.hash)?; + } + Ok(()) + })?; + + write!(f, ")") + } +} + +rustc_dep_node_append!([define_dep_nodes!][ <'tcx> + // We use this for most things when incr. comp. is turned off. + [] Null, + + // Represents metadata from an extern crate. + [eval_always] CrateMetadata(CrateNum), + + [anon] TraitSelect, + + [] CompileCodegenUnit(Symbol), +]); + +pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized { + const CAN_RECONSTRUCT_QUERY_KEY: bool; + + /// This method turns the parameters of a DepNodeConstructor into an opaque + /// Fingerprint to be used in DepNode. + /// Not all DepNodeParams support being turned into a Fingerprint (they + /// don't need to if the corresponding DepNode is anonymous). + fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { + panic!("Not implemented. Accidentally called on anonymous node?") + } + + fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + format!("{:?}", self) + } + + /// This method tries to recover the query key from the given `DepNode`, + /// something which is needed when forcing `DepNode`s during red-green + /// evaluation. The query system will only call this method if + /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`. + /// It is always valid to return `None` here, in which case incremental + /// compilation will treat the query as having changed instead of forcing it. + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option; +} + +impl<'tcx, T> DepNodeParams<'tcx> for T +where + T: HashStable> + fmt::Debug, +{ + default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + + default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { + let mut hcx = tcx.create_stable_hashing_context(); + let mut hasher = StableHasher::new(); + + self.hash_stable(&mut hcx, &mut hasher); + + hasher.finish() + } + + default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + format!("{:?}", *self) + } + + default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option { + None + } +} + +impl<'tcx> DepNodeParams<'tcx> for DefId { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + tcx.def_path_hash(*self).0 + } + + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + tcx.def_path_str(*self) + } + + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { + dep_node.extract_def_id(tcx) + } +} + +impl<'tcx> DepNodeParams<'tcx> for DefIndex { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + tcx.hir().definitions().def_path_hash(*self).0 + } + + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + tcx.def_path_str(DefId::local(*self)) + } + + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { + dep_node.extract_def_id(tcx).map(|id| id.index) + } +} + +impl<'tcx> DepNodeParams<'tcx> for CrateNum { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; + tcx.def_path_hash(def_id).0 + } + + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + tcx.crate_name(*self).to_string() + } + + fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { + dep_node.extract_def_id(tcx).map(|id| id.krate) + } +} + +impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { + const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + + // We actually would not need to specialize the implementation of this + // method but it's faster to combine the hashes than to instantiate a full + // hashing context and stable-hashing state. + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + let (def_id_0, def_id_1) = *self; + + let def_path_hash_0 = tcx.def_path_hash(def_id_0); + let def_path_hash_1 = tcx.def_path_hash(def_id_1); + + def_path_hash_0.0.combine(def_path_hash_1.0) + } + + fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { + let (def_id_0, def_id_1) = *self; + + format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1)) + } +} + +impl<'tcx> DepNodeParams<'tcx> for HirId { + const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + + // We actually would not need to specialize the implementation of this + // method but it's faster to combine the hashes than to instantiate a full + // hashing context and stable-hashing state. + fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + let HirId { owner, local_id } = *self; + + let def_path_hash = tcx.def_path_hash(DefId::local(owner)); + let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into()); + + def_path_hash.0.combine(local_id) + } +} + +/// A "work product" corresponds to a `.o` (or other) file that we +/// save in between runs. These IDs do not have a `DefId` but rather +/// some independent path or string that persists between runs without +/// the need to be mapped or unmapped. (This ensures we can serialize +/// them even in the absence of a tcx.) +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + RustcEncodable, + RustcDecodable, + HashStable +)] +pub struct WorkProductId { + hash: Fingerprint, +} + +impl WorkProductId { + pub fn from_cgu_name(cgu_name: &str) -> WorkProductId { + let mut hasher = StableHasher::new(); + cgu_name.len().hash(&mut hasher); + cgu_name.hash(&mut hasher); + WorkProductId { hash: hasher.finish() } + } + + pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId { + WorkProductId { hash: fingerprint } + } +} diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs similarity index 100% rename from src/librustc/dep_graph/graph.rs rename to src/librustc_query_system/dep_graph/graph.rs diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs similarity index 100% rename from src/librustc/dep_graph/mod.rs rename to src/librustc_query_system/dep_graph/mod.rs diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc_query_system/dep_graph/prev.rs similarity index 100% rename from src/librustc/dep_graph/prev.rs rename to src/librustc_query_system/dep_graph/prev.rs diff --git a/src/librustc/dep_graph/query.rs b/src/librustc_query_system/dep_graph/query.rs similarity index 100% rename from src/librustc/dep_graph/query.rs rename to src/librustc_query_system/dep_graph/query.rs diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc_query_system/dep_graph/safe.rs similarity index 100% rename from src/librustc/dep_graph/safe.rs rename to src/librustc_query_system/dep_graph/safe.rs diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc_query_system/dep_graph/serialized.rs similarity index 100% rename from src/librustc/dep_graph/serialized.rs rename to src/librustc_query_system/dep_graph/serialized.rs From 6624dc4045505e942ce219dcc374061cef50e3f1 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 18 Mar 2020 10:25:22 +0100 Subject: [PATCH 2/9] Make librustc_query_system compile. --- Cargo.lock | 17 + src/librustc/Cargo.toml | 1 + src/librustc_query_system/Cargo.toml | 22 + src/librustc_query_system/dep_graph/debug.rs | 6 +- .../dep_graph/dep_node.rs | 427 ++---------------- src/librustc_query_system/dep_graph/graph.rs | 272 +++++------ src/librustc_query_system/dep_graph/mod.rs | 100 +++- src/librustc_query_system/dep_graph/prev.rs | 30 +- src/librustc_query_system/dep_graph/query.rs | 26 +- src/librustc_query_system/dep_graph/safe.rs | 6 - .../dep_graph/serialized.rs | 23 +- src/librustc_query_system/lib.rs | 32 ++ 12 files changed, 358 insertions(+), 604 deletions(-) create mode 100644 src/librustc_query_system/Cargo.toml create mode 100644 src/librustc_query_system/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c65c3a45ec28b..22a06151353ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3116,6 +3116,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_macros", + "rustc_query_system", "rustc_session", "rustc_span", "rustc_target", @@ -4021,6 +4022,22 @@ dependencies = [ "rustc_typeck", ] +[[package]] +name = "rustc_query_system" +version = "0.0.0" +dependencies = [ + "log", + "parking_lot 0.9.0", + "rustc_ast", + "rustc_data_structures", + "rustc_errors", + "rustc_hir", + "rustc_index", + "rustc_macros", + "serialize", + "smallvec 1.0.0", +] + [[package]] name = "rustc_resolve" version = "0.0.0" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 481d691b8e9b2..47b94a2f1a4b4 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -25,6 +25,7 @@ rustc_hir = { path = "../librustc_hir" } rustc_target = { path = "../librustc_target" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_query_system = { path = "../librustc_query_system" } rustc_errors = { path = "../librustc_errors" } rustc_index = { path = "../librustc_index" } rustc_serialize = { path = "../libserialize", package = "serialize" } diff --git a/src/librustc_query_system/Cargo.toml b/src/librustc_query_system/Cargo.toml new file mode 100644 index 0000000000000..a01bb5e5ea30d --- /dev/null +++ b/src/librustc_query_system/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_query_system" +version = "0.0.0" +edition = "2018" + +[lib] +name = "rustc_query_system" +path = "lib.rs" +doctest = false + +[dependencies] +log = { version = "0.4", features = ["release_max_level_info", "std"] } +rustc_ast = { path = "../librustc_ast" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_errors = { path = "../librustc_errors" } +rustc_hir = { path = "../librustc_hir" } +rustc_index = { path = "../librustc_index" } +rustc_macros = { path = "../librustc_macros" } +rustc_serialize = { path = "../libserialize", package = "serialize" } +parking_lot = "0.9" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_query_system/dep_graph/debug.rs b/src/librustc_query_system/dep_graph/debug.rs index d44c54593a627..718a2f1039a4d 100644 --- a/src/librustc_query_system/dep_graph/debug.rs +++ b/src/librustc_query_system/dep_graph/debug.rs @@ -1,6 +1,6 @@ //! Code for debugging the dep-graph. -use super::dep_node::DepNode; +use super::{DepKind, DepNode}; use std::error::Error; /// A dep-node filter goes from a user-defined string to a query over @@ -26,7 +26,7 @@ impl DepNodeFilter { } /// Tests whether `node` meets the filter, returning true if so. - pub fn test(&self, node: &DepNode) -> bool { + pub fn test(&self, node: &DepNode) -> bool { let debug_str = format!("{:?}", node); self.text.split('&').map(|s| s.trim()).all(|f| debug_str.contains(f)) } @@ -52,7 +52,7 @@ impl EdgeFilter { } } - pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { + pub fn test(&self, source: &DepNode, target: &DepNode) -> bool { self.source.test(source) && self.target.test(target) } } diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs index e3df9d5d04be1..9dcba30300f06 100644 --- a/src/librustc_query_system/dep_graph/dep_node.rs +++ b/src/librustc_query_system/dep_graph/dep_node.rs @@ -26,10 +26,10 @@ //! could not be instantiated because the current compilation session //! contained no `DefId` for thing that had been removed. //! -//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro -//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The -//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at -//! runtime in order to construct a valid `DepNode` fingerprint. +//! `DepNode` definition happens in `librustc` with the `define_dep_nodes!()` macro. +//! This macro defines the `DepKind` enum and a corresponding `DepConstructor` enum. The +//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at runtime in order +//! to construct a valid `DepNode` fingerprint. //! //! Because the macro sees what parameters a given `DepKind` requires, it can //! "infer" some properties for each kind of `DepNode`: @@ -41,326 +41,50 @@ //! in which case it is possible to map the node's fingerprint back to the //! `DefId` it was computed from. In other cases, too much information gets //! lost during fingerprint computation. -//! -//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only -//! valid `DepNode` instances can be constructed. For example, the API does not -//! allow for constructing parameterless `DepNode`s with anything other -//! than a zeroed out fingerprint. More generally speaking, it relieves the -//! user of the `DepNode` API of having to know how to compute the expected -//! fingerprint for a given set of node parameters. -use crate::hir::map::DefPathHash; -use crate::ich::{Fingerprint, StableHashingContext}; -use crate::mir; -use crate::mir::interpret::{GlobalId, LitToConstInput}; -use crate::traits; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, -}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use super::{DepContext, DepKind}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; -use rustc_hir::HirId; -use rustc_span::symbol::Symbol; +use rustc_macros::HashStable_Generic; + use std::fmt; use std::hash::Hash; -// erase!() just makes tokens go away. It's used to specify which macro argument -// is repeated (i.e., which sub-expression of the macro we are in) but don't need -// to actually use any of the arguments. -macro_rules! erase { - ($x:tt) => {{}}; -} - -macro_rules! is_anon_attr { - (anon) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! is_eval_always_attr { - (eval_always) => { - true - }; - ($attr:ident) => { - false - }; -} - -macro_rules! contains_anon_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false}); -} - -macro_rules! contains_eval_always_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false}); +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +pub struct DepNode { + pub kind: K, + pub hash: Fingerprint, } -macro_rules! define_dep_nodes { - (<$tcx:tt> - $( - [$($attrs:tt)*] - $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* - ,)* - ) => ( - #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, - RustcEncodable, RustcDecodable)] - #[allow(non_camel_case_types)] - pub enum DepKind { - $($variant),* - } - - impl DepKind { - #[allow(unreachable_code)] - pub fn can_reconstruct_query_key<$tcx>(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - if contains_anon_attr!($($attrs)*) { - return false; - } - - // tuple args - $({ - return <$tuple_arg_ty as DepNodeParams> - ::CAN_RECONSTRUCT_QUERY_KEY; - })* - - true - } - )* - } - } - - pub fn is_anon(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_anon_attr!($($attrs)*) } - )* - } - } - - pub fn is_eval_always(&self) -> bool { - match *self { - $( - DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) } - )* - } - } - - #[allow(unreachable_code)] - pub fn has_params(&self) -> bool { - match *self { - $( - DepKind :: $variant => { - // tuple args - $({ - erase!($tuple_arg_ty); - return true; - })* - - false - } - )* - } - } - } - - pub struct DepConstructor; - - #[allow(non_camel_case_types)] - impl DepConstructor { - $( - #[inline(always)] - #[allow(unreachable_code, non_snake_case)] - pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode { - // tuple args - $({ - erase!($tuple_arg_ty); - let hash = DepNodeParams::to_fingerprint(&arg, _tcx); - let dep_node = DepNode { - kind: DepKind::$variant, - hash - }; - - #[cfg(debug_assertions)] - { - if !dep_node.kind.can_reconstruct_query_key() && - (_tcx.sess.opts.debugging_opts.incremental_info || - _tcx.sess.opts.debugging_opts.query_dep_graph) - { - _tcx.dep_graph.register_dep_node_debug_str(dep_node, || { - arg.to_debug_str(_tcx) - }); - } - } - - return dep_node; - })* - - DepNode { - kind: DepKind::$variant, - hash: Fingerprint::ZERO, - } - } - )* - } - - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, - RustcEncodable, RustcDecodable)] - pub struct DepNode { - pub kind: DepKind, - pub hash: Fingerprint, - } - - impl DepNode { - /// Construct a DepNode from the given DepKind and DefPathHash. This - /// method will assert that the given DepKind actually requires a - /// single DefId/DefPathHash parameter. - pub fn from_def_path_hash(def_path_hash: DefPathHash, - kind: DepKind) - -> DepNode { - debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); - DepNode { - kind, - hash: def_path_hash.0, - } - } - - /// Creates a new, parameterless DepNode. This method will assert - /// that the DepNode corresponding to the given DepKind actually - /// does not require any parameters. - pub fn new_no_params(kind: DepKind) -> DepNode { - debug_assert!(!kind.has_params()); - DepNode { - kind, - hash: Fingerprint::ZERO, - } - } - - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option { - if self.kind.can_reconstruct_query_key() { - let def_path_hash = DefPathHash(self.hash); - tcx.def_path_hash_to_def_id.as_ref()? - .get(&def_path_hash).cloned() - } else { - None - } - } - - /// Used in testing - pub fn from_label_string(label: &str, - def_path_hash: DefPathHash) - -> Result { - let kind = match label { - $( - stringify!($variant) => DepKind::$variant, - )* - _ => return Err(()), - }; - - if !kind.can_reconstruct_query_key() { - return Err(()); - } - - if kind.has_params() { - Ok(DepNode::from_def_path_hash(def_path_hash, kind)) - } else { - Ok(DepNode::new_no_params(kind)) - } - } - - /// Used in testing - pub fn has_label_string(label: &str) -> bool { - match label { - $( - stringify!($variant) => true, - )* - _ => false, - } - } - } - - /// Contains variant => str representations for constructing - /// DepNode groups for tests. - #[allow(dead_code, non_upper_case_globals)] - pub mod label_strs { - $( - pub const $variant: &str = stringify!($variant); - )* - } - ); +impl DepNode { + /// Creates a new, parameterless DepNode. This method will assert + /// that the DepNode corresponding to the given DepKind actually + /// does not require any parameters. + pub fn new_no_params(kind: K) -> DepNode { + debug_assert!(!kind.has_params()); + DepNode { kind, hash: Fingerprint::ZERO } + } } -impl fmt::Debug for DepNode { +impl fmt::Debug for DepNode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.kind)?; - - if !self.kind.has_params() && !self.kind.is_anon() { - return Ok(()); - } - - write!(f, "(")?; - - crate::ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - if let Some(def_id) = self.extract_def_id(tcx) { - write!(f, "{}", tcx.def_path_debug_str(def_id))?; - } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { - write!(f, "{}", s)?; - } else { - write!(f, "{}", self.hash)?; - } - } else { - write!(f, "{}", self.hash)?; - } - Ok(()) - })?; - - write!(f, ")") + K::debug_node(self, f) } } -rustc_dep_node_append!([define_dep_nodes!][ <'tcx> - // We use this for most things when incr. comp. is turned off. - [] Null, - - // Represents metadata from an extern crate. - [eval_always] CrateMetadata(CrateNum), - - [anon] TraitSelect, - - [] CompileCodegenUnit(Symbol), -]); - -pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized { +pub trait DepNodeParams: fmt::Debug + Sized { const CAN_RECONSTRUCT_QUERY_KEY: bool; /// This method turns the parameters of a DepNodeConstructor into an opaque /// Fingerprint to be used in DepNode. /// Not all DepNodeParams support being turned into a Fingerprint (they /// don't need to if the corresponding DepNode is anonymous). - fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { + fn to_fingerprint(&self, _: Ctxt) -> Fingerprint { panic!("Not implemented. Accidentally called on anonymous node?") } - fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + fn to_debug_str(&self, _: Ctxt) -> String { format!("{:?}", self) } @@ -370,16 +94,16 @@ pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized { /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`. /// It is always valid to return `None` here, in which case incremental /// compilation will treat the query as having changed instead of forcing it. - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option; + fn recover(tcx: Ctxt, dep_node: &DepNode) -> Option; } -impl<'tcx, T> DepNodeParams<'tcx> for T +impl DepNodeParams for T where - T: HashStable> + fmt::Debug, + T: HashStable + fmt::Debug, { default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { + default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint { let mut hcx = tcx.create_stable_hashing_context(); let mut hasher = StableHasher::new(); @@ -388,102 +112,15 @@ where hasher.finish() } - default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + default fn to_debug_str(&self, _: Ctxt) -> String { format!("{:?}", *self) } - default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option { + default fn recover(_: Ctxt, _: &DepNode) -> Option { None } } -impl<'tcx> DepNodeParams<'tcx> for DefId { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - tcx.def_path_hash(*self).0 - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - tcx.def_path_str(*self) - } - - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx) - } -} - -impl<'tcx> DepNodeParams<'tcx> for DefIndex { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - tcx.hir().definitions().def_path_hash(*self).0 - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - tcx.def_path_str(DefId::local(*self)) - } - - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.index) - } -} - -impl<'tcx> DepNodeParams<'tcx> for CrateNum { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; - tcx.def_path_hash(def_id).0 - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - tcx.crate_name(*self).to_string() - } - - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.krate) - } -} - -impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { - const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - - // We actually would not need to specialize the implementation of this - // method but it's faster to combine the hashes than to instantiate a full - // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - let (def_id_0, def_id_1) = *self; - - let def_path_hash_0 = tcx.def_path_hash(def_id_0); - let def_path_hash_1 = tcx.def_path_hash(def_id_1); - - def_path_hash_0.0.combine(def_path_hash_1.0) - } - - fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String { - let (def_id_0, def_id_1) = *self; - - format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1)) - } -} - -impl<'tcx> DepNodeParams<'tcx> for HirId { - const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - - // We actually would not need to specialize the implementation of this - // method but it's faster to combine the hashes than to instantiate a full - // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { - let HirId { owner, local_id } = *self; - - let def_path_hash = tcx.def_path_hash(DefId::local(owner)); - let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into()); - - def_path_hash.0.combine(local_id) - } -} - /// A "work product" corresponds to a `.o` (or other) file that we /// save in between runs. These IDs do not have a `DefId` but rather /// some independent path or string that persists between runs without @@ -500,7 +137,7 @@ impl<'tcx> DepNodeParams<'tcx> for HirId { Hash, RustcEncodable, RustcDecodable, - HashStable + HashStable_Generic )] pub struct WorkProductId { hash: Fingerprint, diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index 36edf0f0fc26a..5e004c5428ad2 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -1,32 +1,33 @@ -use crate::ty::{self, TyCtxt}; -use parking_lot::{Condvar, Mutex}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::QueryInvocationId; use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; +use rustc_data_structures::unlikely; use rustc_errors::Diagnostic; -use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; -use smallvec::SmallVec; + +use parking_lot::{Condvar, Mutex}; +use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; use std::env; use std::hash::Hash; use std::mem; +use std::panic as bug; use std::sync::atomic::Ordering::Relaxed; -use crate::ich::{Fingerprint, StableHashingContext, StableHashingContextProvider}; - use super::debug::EdgeFilter; -use super::dep_node::{DepKind, DepNode, WorkProductId}; use super::prev::PreviousDepGraph; use super::query::DepGraphQuery; use super::safe::DepGraphSafe; use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; +use super::{DepContext, DepKind, DepNode, WorkProductId}; +use crate::{HashStableContext, HashStableContextProvider}; #[derive(Clone)] -pub struct DepGraph { - data: Option>, +pub struct DepGraph { + data: Option>>, /// This field is used for assigning DepNodeIndices when running in /// non-incremental mode. Even in non-incremental mode we make sure that @@ -65,16 +66,16 @@ impl DepNodeColor { } } -struct DepGraphData { +struct DepGraphData { /// The new encoding of the dependency graph, optimized for red/green /// tracking. The `current` field is the dependency graph of only the /// current compilation session: We don't merge the previous dep-graph into /// current one anymore. - current: CurrentDepGraph, + current: CurrentDepGraph, /// The dep-graph from the previous compilation session. It contains all /// nodes and edges as well as all fingerprints of nodes that have them. - previous: PreviousDepGraph, + previous: PreviousDepGraph, colors: DepNodeColorMap, @@ -90,12 +91,12 @@ struct DepGraphData { /// this map. We can later look for and extract that data. previous_work_products: FxHashMap, - dep_node_debug: Lock>, + dep_node_debug: Lock, String>>, } -pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option +pub fn hash_result(hcx: &mut HashCtxt, result: &R) -> Option where - R: for<'a> HashStable>, + R: HashStable, { let mut stable_hasher = StableHasher::new(); result.hash_stable(hcx, &mut stable_hasher); @@ -103,11 +104,11 @@ where Some(stable_hasher.finish()) } -impl DepGraph { +impl DepGraph { pub fn new( - prev_graph: PreviousDepGraph, + prev_graph: PreviousDepGraph, prev_work_products: FxHashMap, - ) -> DepGraph { + ) -> DepGraph { let prev_graph_node_count = prev_graph.node_count(); DepGraph { @@ -124,7 +125,7 @@ impl DepGraph { } } - pub fn new_disabled() -> DepGraph { + pub fn new_disabled() -> DepGraph { DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) } } @@ -134,7 +135,7 @@ impl DepGraph { self.data.is_some() } - pub fn query(&self) -> DepGraphQuery { + pub fn query(&self) -> DepGraphQuery { let data = self.data.as_ref().unwrap().current.data.lock(); let nodes: Vec<_> = data.iter().map(|n| n.node).collect(); let mut edges = Vec::new(); @@ -150,10 +151,7 @@ impl DepGraph { pub fn assert_ignored(&self) { if let Some(..) = self.data { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); - }) + K::assert_ignored(); } } @@ -161,11 +159,7 @@ impl DepGraph { where OP: FnOnce() -> R, { - ty::tls::with_context(|icx| { - let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| op()) - }) + K::with_ignore_deps(op) } /// Starts a new dep-graph task. Dep-graph tasks are specified @@ -195,16 +189,17 @@ impl DepGraph { /// `arg` parameter. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html - pub fn with_task<'a, C, A, R>( + pub fn with_task( &self, - key: DepNode, + key: DepNode, cx: C, arg: A, task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: impl FnOnce(&mut H, &R) -> Option, ) -> (R, DepNodeIndex) where - C: DepGraphSafe + StableHashingContextProvider<'a>, + C: DepGraphSafe + HashStableContextProvider, + H: HashStableContext, { self.with_task_impl( key, @@ -218,6 +213,7 @@ impl DepGraph { node: Some(_key), reads: SmallVec::new(), read_set: Default::default(), + phantom_data: std::marker::PhantomData, }) }, |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint), @@ -225,24 +221,25 @@ impl DepGraph { ) } - fn with_task_impl<'a, C, A, R>( + fn with_task_impl( &self, - key: DepNode, + key: DepNode, cx: C, arg: A, no_tcx: bool, task: fn(C, A) -> R, - create_task: fn(DepNode) -> Option, + create_task: fn(DepNode) -> Option>, finish_task_and_alloc_depnode: fn( - &CurrentDepGraph, - DepNode, + &CurrentDepGraph, + DepNode, Fingerprint, - Option, + Option>, ) -> DepNodeIndex, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: impl FnOnce(&mut H, &R) -> Option, ) -> (R, DepNodeIndex) where - C: DepGraphSafe + StableHashingContextProvider<'a>, + C: DepGraphSafe + HashStableContextProvider, + H: HashStableContext, { if let Some(ref data) = self.data { let task_deps = create_task(key).map(Lock::new); @@ -257,12 +254,7 @@ impl DepGraph { let result = if no_tcx { task(cx, arg) } else { - ty::tls::with_context(|icx| { - let icx = - ty::tls::ImplicitCtxt { task_deps: task_deps.as_ref(), ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| task(cx, arg)) - }) + K::with_deps(task_deps.as_ref(), || task(cx, arg)) }; let current_fingerprint = hash_result(&mut hcx, &result); @@ -274,7 +266,7 @@ impl DepGraph { task_deps.map(|lock| lock.into_inner()), ); - let print_status = cfg!(debug_assertions) && hcx.sess().opts.debugging_opts.dep_tasks; + let print_status = cfg!(debug_assertions) && hcx.debug_dep_tasks(); // Determine the color of the new DepNode. if let Some(prev_index) = data.previous.node_to_index_opt(&key) { @@ -322,22 +314,16 @@ impl DepGraph { /// Executes something within an "anonymous" task, that is, a task the /// `DepNode` of which is determined by the list of inputs it read from. - pub fn with_anon_task(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex) + pub fn with_anon_task(&self, dep_kind: K, op: OP) -> (R, DepNodeIndex) where OP: FnOnce() -> R, { if let Some(ref data) = self.data { - let (result, task_deps) = ty::tls::with_context(|icx| { - let task_deps = Lock::new(TaskDeps::default()); - - let r = { - let icx = ty::tls::ImplicitCtxt { task_deps: Some(&task_deps), ..icx.clone() }; + let task_deps = Lock::new(TaskDeps::default()); - ty::tls::enter_context(&icx, |_| op()) - }; + let result = K::with_deps(Some(&task_deps), op); + let task_deps = task_deps.into_inner(); - (r, task_deps.into_inner()) - }); let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps); (result, dep_node_index) } else { @@ -347,16 +333,17 @@ impl DepGraph { /// Executes something within an "eval-always" task which is a task /// that runs whenever anything changes. - pub fn with_eval_always_task<'a, C, A, R>( + pub fn with_eval_always_task( &self, - key: DepNode, + key: DepNode, cx: C, arg: A, task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: impl FnOnce(&mut H, &R) -> Option, ) -> (R, DepNodeIndex) where - C: DepGraphSafe + StableHashingContextProvider<'a>, + C: DepGraphSafe + HashStableContextProvider, + H: HashStableContext, { self.with_task_impl( key, @@ -371,7 +358,7 @@ impl DepGraph { } #[inline] - pub fn read(&self, v: DepNode) { + pub fn read(&self, v: DepNode) { if let Some(ref data) = self.data { let map = data.current.node_to_node_index.get_shard_by_value(&v).lock(); if let Some(dep_node_index) = map.get(&v).copied() { @@ -391,7 +378,7 @@ impl DepGraph { } #[inline] - pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { + pub fn dep_node_index_of(&self, dep_node: &DepNode) -> DepNodeIndex { self.data .as_ref() .unwrap() @@ -405,7 +392,7 @@ impl DepGraph { } #[inline] - pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { if let Some(ref data) = self.data { data.current .node_to_node_index @@ -423,12 +410,12 @@ impl DepGraph { data[dep_node_index].fingerprint } - pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { + pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option { self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) } #[inline] - pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { + pub fn prev_dep_node_index_of(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { self.data.as_ref().unwrap().previous.node_to_index(dep_node) } @@ -445,7 +432,7 @@ impl DepGraph { } #[inline(always)] - pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) + pub fn register_dep_node_debug_str(&self, dep_node: DepNode, debug_str_gen: F) where F: FnOnce() -> String, { @@ -458,7 +445,7 @@ impl DepGraph { dep_node_debug.borrow_mut().insert(dep_node, debug_str); } - pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { + pub fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() } @@ -475,7 +462,7 @@ impl DepGraph { } } - pub fn serialize(&self) -> SerializedDepGraph { + pub fn serialize(&self) -> SerializedDepGraph { let data = self.data.as_ref().unwrap().current.data.lock(); let fingerprints: IndexVec = @@ -503,7 +490,7 @@ impl DepGraph { SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data } } - pub fn node_color(&self, dep_node: &DepNode) -> Option { + pub fn node_color(&self, dep_node: &DepNode) -> Option { if let Some(ref data) = self.data { if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { return data.colors.get(prev_index); @@ -521,10 +508,10 @@ impl DepGraph { /// A node will have an index, when it's already been marked green, or when we can mark it /// green. This function will mark the current task as a reader of the specified node, when /// a node index can be found for that node. - pub fn try_mark_green_and_read( + pub fn try_mark_green_and_read>( &self, - tcx: TyCtxt<'_>, - dep_node: &DepNode, + tcx: Ctxt, + dep_node: &DepNode, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| { debug_assert!(self.is_green(&dep_node)); @@ -533,10 +520,10 @@ impl DepGraph { }) } - pub fn try_mark_green( + pub fn try_mark_green>( &self, - tcx: TyCtxt<'_>, - dep_node: &DepNode, + tcx: Ctxt, + dep_node: &DepNode, ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { debug_assert!(!dep_node.kind.is_eval_always()); @@ -561,12 +548,12 @@ impl DepGraph { } /// Try to mark a dep-node which existed in the previous compilation session as green. - fn try_mark_previous_green<'tcx>( + fn try_mark_previous_green>( &self, - tcx: TyCtxt<'tcx>, - data: &DepGraphData, + tcx: Ctxt, + data: &DepGraphData, prev_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode, + dep_node: &DepNode, ) -> Option { debug!("try_mark_previous_green({:?}) - BEGIN", dep_node); @@ -649,49 +636,7 @@ impl DepGraph { continue; } } else { - // FIXME: This match is just a workaround for incremental bugs and should - // be removed. https://github.com/rust-lang/rust/issues/62649 is one such - // bug that must be fixed before removing this. - match dep_dep_node.kind { - DepKind::hir_owner - | DepKind::hir_owner_nodes - | DepKind::CrateMetadata => { - if let Some(def_id) = dep_dep_node.extract_def_id(tcx) { - if def_id_corresponds_to_hir_dep_node(tcx, def_id) { - if dep_dep_node.kind == DepKind::CrateMetadata { - // The `DefPath` has corresponding node, - // and that node should have been marked - // either red or green in `data.colors`. - bug!( - "DepNode {:?} should have been \ - pre-marked as red or green but wasn't.", - dep_dep_node - ); - } - } else { - // This `DefPath` does not have a - // corresponding `DepNode` (e.g. a - // struct field), and the ` DefPath` - // collided with the `DefPath` of a - // proper item that existed in the - // previous compilation session. - // - // Since the given `DefPath` does not - // denote the item that previously - // existed, we just fail to mark green. - return None; - } - } else { - // If the node does not exist anymore, we - // just fail to mark green. - return None; - } - } - _ => { - // For other kinds of nodes it's OK to be - // forced. - } - } + tcx.ensure_node_can_be_forced(dep_dep_node)?; } // We failed to mark it green, so we try to force the query. @@ -700,7 +645,7 @@ impl DepGraph { dependency {:?}", dep_node, dep_dep_node ); - if crate::ty::query::force_from_dep_node(tcx, dep_dep_node) { + if tcx.force_from_dep_node(dep_dep_node) { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { @@ -721,7 +666,7 @@ impl DepGraph { return None; } None => { - if !tcx.sess.has_errors_or_delayed_span_bugs() { + if !tcx.has_errors_or_delayed_span_bugs() { bug!( "try_mark_previous_green() - Forcing the DepNode \ should have set its color" @@ -779,7 +724,7 @@ impl DepGraph { // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere // Maybe store a list on disk and encode this fact in the DepNodeState - let diagnostics = tcx.queries.on_disk_cache.load_diagnostics(tcx, prev_dep_node_index); + let diagnostics = tcx.load_diagnostics(prev_dep_node_index); #[cfg(not(parallel_compiler))] debug_assert!( @@ -805,10 +750,10 @@ impl DepGraph { /// This may be called concurrently on multiple threads for the same dep node. #[cold] #[inline(never)] - fn emit_diagnostics<'tcx>( + fn emit_diagnostics>( &self, - tcx: TyCtxt<'tcx>, - data: &DepGraphData, + tcx: Ctxt, + data: &DepGraphData, dep_node_index: DepNodeIndex, prev_dep_node_index: SerializedDepNodeIndex, diagnostics: Vec, @@ -827,9 +772,9 @@ impl DepGraph { mem::drop(emitting); // Promote the previous diagnostics to the current session. - tcx.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics.clone().into()); + tcx.store_diagnostics(dep_node_index, diagnostics.clone().into()); - let handle = tcx.sess.diagnostic(); + let handle = tcx.diagnostic(); for diagnostic in diagnostics { handle.emit_diagnostic(&diagnostic); @@ -858,7 +803,7 @@ impl DepGraph { // Returns true if the given node has been marked as green during the // current compilation session. Used in various assertions - pub fn is_green(&self, dep_node: &DepNode) -> bool { + pub fn is_green(&self, dep_node: &DepNode) -> bool { self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) } @@ -870,15 +815,15 @@ impl DepGraph { // // This method will only load queries that will end up in the disk cache. // Other queries will not be executed. - pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) { - let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion"); + pub fn exec_cache_promotions>(&self, tcx: Ctxt) { + let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion"); let data = self.data.as_ref().unwrap(); for prev_index in data.colors.values.indices() { match data.colors.get(prev_index) { Some(DepNodeColor::Green(_)) => { let dep_node = data.previous.index_to_node(prev_index); - dep_node.try_load_from_on_disk_cache(tcx); + tcx.try_load_from_on_disk_cache(&dep_node); } None | Some(DepNodeColor::Red) => { // We can skip red nodes because a node can only be marked @@ -895,11 +840,6 @@ impl DepGraph { } } -fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - def_id.index == hir_id.owner.local_def_index -} - /// A "work product" is an intermediate result that we save into the /// incremental directory for later re-use. The primary example are /// the object files that we save for each partition at code @@ -946,8 +886,8 @@ pub enum WorkProductFileKind { } #[derive(Clone)] -struct DepNodeData { - node: DepNode, +struct DepNodeData { + node: DepNode, edges: EdgesVec, fingerprint: Fingerprint, } @@ -967,9 +907,9 @@ struct DepNodeData { /// The only operation that must manipulate both locks is adding new nodes, in which case /// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted, /// acquire the lock on `data.` -pub(super) struct CurrentDepGraph { - data: Lock>, - node_to_node_index: Sharded>, +pub(super) struct CurrentDepGraph { + data: Lock>>, + node_to_node_index: Sharded, DepNodeIndex>>, /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. @@ -995,8 +935,8 @@ pub(super) struct CurrentDepGraph { total_duplicate_read_count: AtomicU64, } -impl CurrentDepGraph { - fn new(prev_graph_node_count: usize) -> CurrentDepGraph { +impl CurrentDepGraph { + fn new(prev_graph_node_count: usize) -> CurrentDepGraph { use std::time::{SystemTime, UNIX_EPOCH}; let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); @@ -1039,14 +979,14 @@ impl CurrentDepGraph { fn complete_task( &self, - node: DepNode, - task_deps: TaskDeps, + node: DepNode, + task_deps: TaskDeps, fingerprint: Fingerprint, ) -> DepNodeIndex { self.alloc_node(node, task_deps.reads, fingerprint) } - fn complete_anon_task(&self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex { + fn complete_anon_task(&self, kind: K, task_deps: TaskDeps) -> DepNodeIndex { debug_assert!(!kind.is_eval_always()); let mut hasher = StableHasher::new(); @@ -1072,7 +1012,7 @@ impl CurrentDepGraph { fn alloc_node( &self, - dep_node: DepNode, + dep_node: DepNode, edges: EdgesVec, fingerprint: Fingerprint, ) -> DepNodeIndex { @@ -1084,7 +1024,7 @@ impl CurrentDepGraph { fn intern_node( &self, - dep_node: DepNode, + dep_node: DepNode, edges: EdgesVec, fingerprint: Fingerprint, ) -> DepNodeIndex { @@ -1101,12 +1041,11 @@ impl CurrentDepGraph { } } -impl DepGraphData { +impl DepGraphData { #[inline(never)] fn read_index(&self, source: DepNodeIndex) { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - if let Some(task_deps) = icx.task_deps { + K::read_deps(|task_deps| { + if let Some(task_deps) = task_deps { let mut task_deps = task_deps.lock(); let task_deps = &mut *task_deps; if cfg!(debug_assertions) { @@ -1151,12 +1090,25 @@ impl DepGraphData { /// The capacity of the `reads` field `SmallVec` const TASK_DEPS_READS_CAP: usize = 8; type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; -#[derive(Default)] -pub struct TaskDeps { + +pub struct TaskDeps { #[cfg(debug_assertions)] - node: Option, + node: Option>, reads: EdgesVec, read_set: FxHashSet, + phantom_data: std::marker::PhantomData>, +} + +impl Default for TaskDeps { + fn default() -> Self { + Self { + #[cfg(debug_assertions)] + node: None, + reads: EdgesVec::new(), + read_set: FxHashSet::default(), + phantom_data: std::marker::PhantomData, + } + } } // A data structure that stores Option values as a contiguous diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index 1fbd90743f402..77bc8f612932f 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -6,12 +6,94 @@ mod query; mod safe; mod serialized; -pub(crate) use self::dep_node::DepNodeParams; -pub use self::dep_node::{label_strs, DepConstructor, DepKind, DepNode, WorkProductId}; -pub use self::graph::WorkProductFileKind; -pub use self::graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; -pub use self::prev::PreviousDepGraph; -pub use self::query::DepGraphQuery; -pub use self::safe::AssertDepGraphSafe; -pub use self::safe::DepGraphSafe; -pub use self::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; +pub use dep_node::{DepNode, DepNodeParams, WorkProductId}; +pub use graph::WorkProductFileKind; +pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; +pub use prev::PreviousDepGraph; +pub use query::DepGraphQuery; +pub use safe::AssertDepGraphSafe; +pub use safe::DepGraphSafe; +pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; + +use rustc_data_structures::profiling::SelfProfilerRef; +use rustc_data_structures::sync::Lock; +use rustc_data_structures::thin_vec::ThinVec; +use rustc_errors::Diagnostic; +use rustc_hir::def_id::DefId; + +use std::fmt; +use std::hash::Hash; + +pub trait DepContext: Copy { + type DepKind: self::DepKind; + type StableHashingContext: crate::HashStableContext; + + /// Create a hashing context for hashing new results. + fn create_stable_hashing_context(&self) -> Self::StableHashingContext; + + /// Force the execution of a query given the associated `DepNode`. + fn force_from_dep_node(&self, node: &DepNode) -> bool; + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + fn extract_def_id(&self, node: &DepNode) -> Option; + + /// Check the legality of forcing this node. + fn ensure_node_can_be_forced(&self, dep_dep_node: &DepNode) -> Option<()>; + + /// Return whether the current session is tainted by errors. + fn has_errors_or_delayed_span_bugs(&self) -> bool; + + /// Return the diagnostic handler. + fn diagnostic(&self) -> &rustc_errors::Handler; + + /// Load data from the on-disk cache. + fn try_load_from_on_disk_cache(&self, dep_node: &DepNode); + + /// Load diagnostics associated to the node in the previous session. + fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec; + + /// Register diagnostics for the given node, for use in next session. + fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec); + + /// Access the profiler. + fn profiler(&self) -> &SelfProfilerRef; +} + +/// Describe the different families of dependency nodes. +pub trait DepKind: Copy + fmt::Debug + Eq + Ord + Hash { + /// Return whether this kind always require evaluation. + fn is_eval_always(&self) -> bool; + + /// Return whether this kind requires additional parameters to be executed. + fn has_params(&self) -> bool; + + /// Implementation of `std::fmt::Debug` for `DepNode`. + fn debug_node(node: &DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result; + + /// Assert the current implicit context does not track any dependency. + fn assert_ignored(); + + /// Execute the operation ignoring the dependencies. + fn with_ignore_deps(op: OP) -> R + where + OP: FnOnce() -> R; + + /// Execute the operation with provided dependencies. + fn with_deps(deps: Option<&Lock>>, op: OP) -> R + where + OP: FnOnce() -> R; + + /// Access dependencies from current implicit context. + fn read_deps(op: OP) -> () + where + OP: for<'a> FnOnce(Option<&'a Lock>>) -> (); +} diff --git a/src/librustc_query_system/dep_graph/prev.rs b/src/librustc_query_system/dep_graph/prev.rs index fbc8f7bc997e0..5cba64cac4b34 100644 --- a/src/librustc_query_system/dep_graph/prev.rs +++ b/src/librustc_query_system/dep_graph/prev.rs @@ -1,16 +1,22 @@ -use super::dep_node::DepNode; use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; -use crate::ich::Fingerprint; +use super::{DepKind, DepNode}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -#[derive(Debug, RustcEncodable, RustcDecodable, Default)] -pub struct PreviousDepGraph { - data: SerializedDepGraph, - index: FxHashMap, +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct PreviousDepGraph { + data: SerializedDepGraph, + index: FxHashMap, SerializedDepNodeIndex>, } -impl PreviousDepGraph { - pub fn new(data: SerializedDepGraph) -> PreviousDepGraph { +impl Default for PreviousDepGraph { + fn default() -> Self { + PreviousDepGraph { data: Default::default(), index: Default::default() } + } +} + +impl PreviousDepGraph { + pub fn new(data: SerializedDepGraph) -> PreviousDepGraph { let index: FxHashMap<_, _> = data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); PreviousDepGraph { data, index } @@ -25,22 +31,22 @@ impl PreviousDepGraph { } #[inline] - pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { + pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { self.data.nodes[dep_node_index] } #[inline] - pub fn node_to_index(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { + pub fn node_to_index(&self, dep_node: &DepNode) -> SerializedDepNodeIndex { self.index[dep_node] } #[inline] - pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { + pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { self.index.get(dep_node).cloned() } #[inline] - pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { + pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index]) } diff --git a/src/librustc_query_system/dep_graph/query.rs b/src/librustc_query_system/dep_graph/query.rs index c71c11ed0ebdf..4a4283b2a0cbb 100644 --- a/src/librustc_query_system/dep_graph/query.rs +++ b/src/librustc_query_system/dep_graph/query.rs @@ -3,15 +3,15 @@ use rustc_data_structures::graph::implementation::{ Direction, Graph, NodeIndex, INCOMING, OUTGOING, }; -use super::DepNode; +use super::{DepKind, DepNode}; -pub struct DepGraphQuery { - pub graph: Graph, - pub indices: FxHashMap, +pub struct DepGraphQuery { + pub graph: Graph, ()>, + pub indices: FxHashMap, NodeIndex>, } -impl DepGraphQuery { - pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { +impl DepGraphQuery { + pub fn new(nodes: &[DepNode], edges: &[(DepNode, DepNode)]) -> DepGraphQuery { let mut graph = Graph::with_capacity(nodes.len(), edges.len()); let mut indices = FxHashMap::default(); for node in nodes { @@ -27,15 +27,15 @@ impl DepGraphQuery { DepGraphQuery { graph, indices } } - pub fn contains_node(&self, node: &DepNode) -> bool { + pub fn contains_node(&self, node: &DepNode) -> bool { self.indices.contains_key(&node) } - pub fn nodes(&self) -> Vec<&DepNode> { + pub fn nodes(&self) -> Vec<&DepNode> { self.graph.all_nodes().iter().map(|n| &n.data).collect() } - pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { + pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> { self.graph .all_edges() .iter() @@ -44,7 +44,7 @@ impl DepGraphQuery { .collect() } - fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { + fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { if let Some(&index) = self.indices.get(node) { self.graph.depth_traverse(index, direction).map(|s| self.graph.node_data(s)).collect() } else { @@ -54,17 +54,17 @@ impl DepGraphQuery { /// All nodes reachable from `node`. In other words, things that /// will have to be recomputed if `node` changes. - pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> { self.reachable_nodes(node, OUTGOING) } /// All nodes that can reach `node`. - pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { self.reachable_nodes(node, INCOMING) } /// Just the outgoing edges from `node`. - pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> { if let Some(&index) = self.indices.get(&node) { self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect() } else { diff --git a/src/librustc_query_system/dep_graph/safe.rs b/src/librustc_query_system/dep_graph/safe.rs index 74e32867cdec1..7bba348f8841f 100644 --- a/src/librustc_query_system/dep_graph/safe.rs +++ b/src/librustc_query_system/dep_graph/safe.rs @@ -1,7 +1,5 @@ //! The `DepGraphSafe` trait -use crate::ty::TyCtxt; - use rustc_ast::ast::NodeId; use rustc_hir::def_id::DefId; use rustc_hir::BodyId; @@ -28,10 +26,6 @@ impl DepGraphSafe for NodeId {} /// on-demand queries, all of which create reads. impl DepGraphSafe for DefId {} -/// The type context itself can be used to access all kinds of tracked -/// state, but those accesses should always generate read events. -impl<'tcx> DepGraphSafe for TyCtxt<'tcx> {} - /// Tuples make it easy to build up state. impl DepGraphSafe for (A, B) where diff --git a/src/librustc_query_system/dep_graph/serialized.rs b/src/librustc_query_system/dep_graph/serialized.rs index 45ef52dbf39c2..4a89da23ea6a5 100644 --- a/src/librustc_query_system/dep_graph/serialized.rs +++ b/src/librustc_query_system/dep_graph/serialized.rs @@ -1,7 +1,7 @@ //! The data that we will serialize and deserialize. -use crate::dep_graph::DepNode; -use crate::ich::Fingerprint; +use super::{DepKind, DepNode}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_index::vec::IndexVec; rustc_index::newtype_index! { @@ -9,10 +9,10 @@ rustc_index::newtype_index! { } /// Data for use when recompiling the **current crate**. -#[derive(Debug, RustcEncodable, RustcDecodable, Default)] -pub struct SerializedDepGraph { +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct SerializedDepGraph { /// The set of all DepNodes in the graph - pub nodes: IndexVec, + pub nodes: IndexVec>, /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to /// the DepNode at the same index in the nodes vector. pub fingerprints: IndexVec, @@ -25,7 +25,18 @@ pub struct SerializedDepGraph { pub edge_list_data: Vec, } -impl SerializedDepGraph { +impl Default for SerializedDepGraph { + fn default() -> Self { + SerializedDepGraph { + nodes: Default::default(), + fingerprints: Default::default(), + edge_list_indices: Default::default(), + edge_list_data: Default::default(), + } + } +} + +impl SerializedDepGraph { #[inline] pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedDepNodeIndex] { let targets = self.edge_list_indices[source]; diff --git a/src/librustc_query_system/lib.rs b/src/librustc_query_system/lib.rs new file mode 100644 index 0000000000000..ef4886828c411 --- /dev/null +++ b/src/librustc_query_system/lib.rs @@ -0,0 +1,32 @@ +#![feature(const_fn)] +#![feature(const_if_match)] +#![feature(const_panic)] +#![feature(core_intrinsics)] +#![feature(specialization)] +#![feature(stmt_expr_attributes)] + +#[macro_use] +extern crate log; + +pub mod dep_graph; + +pub trait HashStableContext { + fn debug_dep_tasks(&self) -> bool; +} + +/// Something that can provide a stable hashing context. +pub trait HashStableContextProvider { + fn get_stable_hashing_context(&self) -> Ctxt; +} + +impl> HashStableContextProvider for &T { + fn get_stable_hashing_context(&self) -> Ctxt { + (**self).get_stable_hashing_context() + } +} + +impl> HashStableContextProvider for &mut T { + fn get_stable_hashing_context(&self) -> Ctxt { + (**self).get_stable_hashing_context() + } +} From db7bd5f828faa85880fc3cbac0c7b679e2225321 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 18 Mar 2020 10:32:58 +0100 Subject: [PATCH 3/9] Fallout in other crates. --- src/librustc/dep_graph/dep_node.rs | 187 +++----------- src/librustc/dep_graph/mod.rs | 233 ++++++++++++++++++ src/librustc/dep_graph/safe.rs | 9 + src/librustc/ty/query/mod.rs | 13 - src/librustc_incremental/assert_dep_graph.rs | 2 +- .../persist/dirty_clean.rs | 4 +- src/librustc_macros/src/query.rs | 8 +- src/librustc_metadata/rmeta/decoder.rs | 2 +- .../dep_graph/dep_node.rs | 15 +- 9 files changed, 287 insertions(+), 186 deletions(-) create mode 100644 src/librustc/dep_graph/mod.rs create mode 100644 src/librustc/dep_graph/safe.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 7cde57e1f13f6..ee44c07d3a917 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -50,7 +50,7 @@ //! fingerprint for a given set of node parameters. use crate::hir::map::DefPathHash; -use crate::ich::{Fingerprint, StableHashingContext}; +use crate::ich::Fingerprint; use crate::mir; use crate::mir::interpret::{GlobalId, LitToConstInput}; use crate::traits; @@ -62,13 +62,13 @@ use crate::traits::query::{ use crate::ty::subst::SubstsRef; use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::HirId; use rustc_span::symbol::Symbol; -use std::fmt; use std::hash::Hash; +pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; + // erase!() just makes tokens go away. It's used to specify which macro argument // is repeated (i.e., which sub-expression of the macro we are in) but don't need // to actually use any of the arguments. @@ -128,7 +128,7 @@ macro_rules! define_dep_nodes { // tuple args $({ - return <$tuple_arg_ty as DepNodeParams> + return <$tuple_arg_ty as DepNodeParams>> ::CAN_RECONSTRUCT_QUERY_KEY; })* @@ -212,20 +212,27 @@ macro_rules! define_dep_nodes { )* } - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, - RustcEncodable, RustcDecodable)] - pub struct DepNode { - pub kind: DepKind, - pub hash: Fingerprint, + pub type DepNode = rustc_query_system::dep_graph::DepNode; + + pub trait DepNodeExt: Sized { + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self; + + /// Used in testing + fn from_label_string(label: &str, def_path_hash: DefPathHash) + -> Result; + + /// Used in testing + fn has_label_string(label: &str) -> bool; } - impl DepNode { + impl DepNodeExt for DepNode { /// Construct a DepNode from the given DepKind and DefPathHash. This /// method will assert that the given DepKind actually requires a /// single DefId/DefPathHash parameter. - pub fn from_def_path_hash(def_path_hash: DefPathHash, - kind: DepKind) - -> DepNode { + fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode { debug_assert!(kind.can_reconstruct_query_key() && kind.has_params()); DepNode { kind, @@ -233,17 +240,6 @@ macro_rules! define_dep_nodes { } } - /// Creates a new, parameterless DepNode. This method will assert - /// that the DepNode corresponding to the given DepKind actually - /// does not require any parameters. - pub fn new_no_params(kind: DepKind) -> DepNode { - debug_assert!(!kind.has_params()); - DepNode { - kind, - hash: Fingerprint::ZERO, - } - } - /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: /// @@ -254,20 +250,8 @@ macro_rules! define_dep_nodes { /// DepNode. Condition (2) might not be fulfilled if a DepNode /// refers to something from the previous compilation session that /// has been removed. - pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option { - if self.kind.can_reconstruct_query_key() { - let def_path_hash = DefPathHash(self.hash); - tcx.def_path_hash_to_def_id.as_ref()? - .get(&def_path_hash).cloned() - } else { - None - } - } - /// Used in testing - pub fn from_label_string(label: &str, - def_path_hash: DefPathHash) - -> Result { + fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result { let kind = match label { $( stringify!($variant) => DepKind::$variant, @@ -287,7 +271,7 @@ macro_rules! define_dep_nodes { } /// Used in testing - pub fn has_label_string(label: &str) -> bool { + fn has_label_string(label: &str) -> bool { match label { $( stringify!($variant) => true, @@ -308,35 +292,6 @@ macro_rules! define_dep_nodes { ); } -impl fmt::Debug for DepNode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.kind)?; - - if !self.kind.has_params() && !self.kind.is_anon() { - return Ok(()); - } - - write!(f, "(")?; - - crate::ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - if let Some(def_id) = self.extract_def_id(tcx) { - write!(f, "{}", tcx.def_path_debug_str(def_id))?; - } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { - write!(f, "{}", s)?; - } else { - write!(f, "{}", self.hash)?; - } - } else { - write!(f, "{}", self.hash)?; - } - Ok(()) - })?; - - write!(f, ")") - } -} - rustc_dep_node_append!([define_dep_nodes!][ <'tcx> // We use this for most things when incr. comp. is turned off. [] Null, @@ -349,58 +304,10 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> [] CompileCodegenUnit(Symbol), ]); -pub(crate) trait DepNodeParams<'tcx>: fmt::Debug + Sized { - const CAN_RECONSTRUCT_QUERY_KEY: bool; - - /// This method turns the parameters of a DepNodeConstructor into an opaque - /// Fingerprint to be used in DepNode. - /// Not all DepNodeParams support being turned into a Fingerprint (they - /// don't need to if the corresponding DepNode is anonymous). - fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint { - panic!("Not implemented. Accidentally called on anonymous node?") - } - - fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { - format!("{:?}", self) - } - - /// This method tries to recover the query key from the given `DepNode`, - /// something which is needed when forcing `DepNode`s during red-green - /// evaluation. The query system will only call this method if - /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`. - /// It is always valid to return `None` here, in which case incremental - /// compilation will treat the query as having changed instead of forcing it. - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option; -} - -impl<'tcx, T> DepNodeParams<'tcx> for T -where - T: HashStable> + fmt::Debug, -{ - default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - - default fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { - let mut hcx = tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - - self.hash_stable(&mut hcx, &mut hasher); - - hasher.finish() - } - - default fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { - format!("{:?}", *self) - } - - default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option { - None - } -} - -impl<'tcx> DepNodeParams<'tcx> for DefId { +impl<'tcx> DepNodeParams> for DefId { const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { tcx.def_path_hash(*self).0 } @@ -409,14 +316,14 @@ impl<'tcx> DepNodeParams<'tcx> for DefId { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx) + tcx.extract_def_id(dep_node) } } -impl<'tcx> DepNodeParams<'tcx> for LocalDefId { +impl<'tcx> DepNodeParams> for LocalDefId { const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { self.to_def_id().to_fingerprint(tcx) } @@ -425,14 +332,14 @@ impl<'tcx> DepNodeParams<'tcx> for LocalDefId { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.expect_local()) + tcx.extract_def_id(dep_node).map(|id| id.expect_local()) } } -impl<'tcx> DepNodeParams<'tcx> for CrateNum { +impl<'tcx> DepNodeParams> for CrateNum { const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; tcx.def_path_hash(def_id).0 } @@ -442,17 +349,17 @@ impl<'tcx> DepNodeParams<'tcx> for CrateNum { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.krate) + tcx.extract_def_id(dep_node).map(|id| id.krate) } } -impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { +impl<'tcx> DepNodeParams> for (DefId, DefId) { const CAN_RECONSTRUCT_QUERY_KEY: bool = false; // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let (def_id_0, def_id_1) = *self; let def_path_hash_0 = tcx.def_path_hash(def_id_0); @@ -468,13 +375,13 @@ impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { } } -impl<'tcx> DepNodeParams<'tcx> for HirId { +impl<'tcx> DepNodeParams> for HirId { const CAN_RECONSTRUCT_QUERY_KEY: bool = false; // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full // hashing context and stable-hashing state. - fn to_fingerprint(&self, tcx: TyCtxt<'_>) -> Fingerprint { + fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let HirId { owner, local_id } = *self; let def_path_hash = tcx.def_path_hash(owner.to_def_id()); @@ -483,27 +390,3 @@ impl<'tcx> DepNodeParams<'tcx> for HirId { def_path_hash.0.combine(local_id) } } - -/// A "work product" corresponds to a `.o` (or other) file that we -/// save in between runs. These IDs do not have a `DefId` but rather -/// some independent path or string that persists between runs without -/// the need to be mapped or unmapped. (This ensures we can serialize -/// them even in the absence of a tcx.) -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -#[derive(HashStable)] -pub struct WorkProductId { - hash: Fingerprint, -} - -impl WorkProductId { - pub fn from_cgu_name(cgu_name: &str) -> WorkProductId { - let mut hasher = StableHasher::new(); - cgu_name.len().hash(&mut hasher); - cgu_name.hash(&mut hasher); - WorkProductId { hash: hasher.finish() } - } - - pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId { - WorkProductId { hash: fingerprint } - } -} diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs new file mode 100644 index 0000000000000..79295b2f82767 --- /dev/null +++ b/src/librustc/dep_graph/mod.rs @@ -0,0 +1,233 @@ +use crate::hir::map::definitions::DefPathHash; +use crate::ich::StableHashingContext; +use crate::ty::{self, TyCtxt}; +use rustc_data_structures::profiling::SelfProfilerRef; +use rustc_data_structures::sync::Lock; +use rustc_data_structures::thin_vec::ThinVec; +use rustc_errors::Diagnostic; +use rustc_hir::def_id::DefId; + +mod dep_node; +mod safe; + +pub(crate) use rustc_query_system::dep_graph::DepNodeParams; +pub use rustc_query_system::dep_graph::{ + debug, hash_result, DepContext, DepNodeColor, DepNodeIndex, SerializedDepNodeIndex, + WorkProduct, WorkProductFileKind, WorkProductId, +}; + +pub use dep_node::{label_strs, DepConstructor, DepKind, DepNode, DepNodeExt}; +pub use safe::AssertDepGraphSafe; +pub use safe::DepGraphSafe; + +pub type DepGraph = rustc_query_system::dep_graph::DepGraph; +pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps; +pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery; +pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph; +pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph; + +impl rustc_query_system::dep_graph::DepKind for DepKind { + fn is_eval_always(&self) -> bool { + DepKind::is_eval_always(self) + } + + fn has_params(&self) -> bool { + DepKind::has_params(self) + } + + fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", node.kind)?; + + if !node.kind.has_params() && !node.kind.is_anon() { + return Ok(()); + } + + write!(f, "(")?; + + ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_id) = tcx.extract_def_id(node) { + write!(f, "{}", tcx.def_path_debug_str(def_id))?; + } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) { + write!(f, "{}", s)?; + } else { + write!(f, "{}", node.hash)?; + } + } else { + write!(f, "{}", node.hash)?; + } + Ok(()) + })?; + + write!(f, ")") + } + + fn assert_ignored() { + ty::tls::with_context_opt(|icx| { + let icx = if let Some(icx) = icx { icx } else { return }; + assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); + }) + } + + fn with_ignore_deps(op: OP) -> R + where + OP: FnOnce() -> R, + { + ty::tls::with_context(|icx| { + let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() }; + + ty::tls::enter_context(&icx, |_| op()) + }) + } + + fn with_deps(task_deps: Option<&Lock>, op: OP) -> R + where + OP: FnOnce() -> R, + { + ty::tls::with_context(|icx| { + let icx = ty::tls::ImplicitCtxt { task_deps, ..icx.clone() }; + + ty::tls::enter_context(&icx, |_| op()) + }) + } + + fn read_deps(op: OP) -> () + where + OP: for<'a> FnOnce(Option<&'a Lock>) -> (), + { + ty::tls::with_context_opt(|icx| { + let icx = if let Some(icx) = icx { icx } else { return }; + op(icx.task_deps) + }) + } +} + +impl<'tcx> DepContext for TyCtxt<'tcx> { + type DepKind = DepKind; + type StableHashingContext = StableHashingContext<'tcx>; + + fn create_stable_hashing_context(&self) -> Self::StableHashingContext { + TyCtxt::create_stable_hashing_context(*self) + } + + fn force_from_dep_node(&self, node: &DepNode) -> bool { + ty::query::force_from_dep_node(*self, node) + } + + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + fn extract_def_id(&self, node: &DepNode) -> Option { + if node.kind.can_reconstruct_query_key() { + let def_path_hash = DefPathHash(node.hash); + self.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned() + } else { + None + } + } + + fn ensure_node_can_be_forced(&self, dep_dep_node: &DepNode) -> Option<()> { + // FIXME: This match is just a workaround for incremental bugs and should + // be removed. https://github.com/rust-lang/rust/issues/62649 is one such + // bug that must be fixed before removing this. + match dep_dep_node.kind { + DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => { + if let Some(def_id) = self.extract_def_id(dep_dep_node) { + if def_id_corresponds_to_hir_dep_node(*self, def_id) { + if dep_dep_node.kind == DepKind::CrateMetadata { + // The `DefPath` has corresponding node, + // and that node should have been marked + // either red or green in `data.colors`. + bug!( + "DepNode {:?} should have been \ + pre-marked as red or green but wasn't.", + dep_dep_node + ); + } + } else { + // This `DefPath` does not have a + // corresponding `DepNode` (e.g. a + // struct field), and the ` DefPath` + // collided with the `DefPath` of a + // proper item that existed in the + // previous compilation session. + // + // Since the given `DefPath` does not + // denote the item that previously + // existed, we just fail to mark green. + return None; + } + } else { + // If the node does not exist anymore, we + // just fail to mark green. + return None; + } + } + _ => { + // For other kinds of nodes it's OK to be + // forced. + } + } + Some(()) + } + + fn has_errors_or_delayed_span_bugs(&self) -> bool { + self.sess.has_errors_or_delayed_span_bugs() + } + + fn diagnostic(&self) -> &rustc_errors::Handler { + self.sess.diagnostic() + } + + // Interactions with on_disk_cache + fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { + use crate::mir::interpret::GlobalId; + use crate::ty::query::queries; + use crate::ty::query::QueryDescription; + rustc_dep_node_try_load_from_on_disk_cache!(dep_node, *self) + } + + fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec { + self.queries.on_disk_cache.load_diagnostics(*self, prev_dep_node_index) + } + + fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec) { + self.queries.on_disk_cache.store_diagnostics(dep_node_index, diagnostics) + } + + fn profiler(&self) -> &SelfProfilerRef { + &self.prof + } +} + +fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + def_id.index == hir_id.owner.local_def_index +} + +impl rustc_query_system::HashStableContext for StableHashingContext<'_> { + fn debug_dep_tasks(&self) -> bool { + self.sess().opts.debugging_opts.dep_tasks + } +} + +impl rustc_query_system::HashStableContextProvider> for TyCtxt<'tcx> { + fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> { + self.create_stable_hashing_context() + } +} + +impl rustc_query_system::HashStableContextProvider> + for StableHashingContext<'a> +{ + fn get_stable_hashing_context(&self) -> Self { + self.clone() + } +} diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs new file mode 100644 index 0000000000000..47a1c09672ff6 --- /dev/null +++ b/src/librustc/dep_graph/safe.rs @@ -0,0 +1,9 @@ +//! The `DepGraphSafe` trait + +use crate::ty::TyCtxt; + +pub use rustc_query_system::dep_graph::{AssertDepGraphSafe, DepGraphSafe}; + +/// The type context itself can be used to access all kinds of tracked +/// state, but those accesses should always generate read events. +impl<'tcx> DepGraphSafe for TyCtxt<'tcx> {} diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 32ba13b1dbe9a..4cfd1f8f3c4d9 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -191,16 +191,3 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool false } - -impl DepNode { - /// Check whether the query invocation corresponding to the given - /// DepNode is eligible for on-disk-caching. If so, this is method - /// will execute the query corresponding to the given DepNode. - /// Also, as a sanity check, it expects that the corresponding query - /// invocation has been marked as green already. - pub fn try_load_from_on_disk_cache<'tcx>(&self, tcx: TyCtxt<'tcx>) { - use crate::dep_graph::DepKind; - - rustc_dep_node_try_load_from_on_disk_cache!(self, tcx) - } -} diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index a7dccaf974b82..305e0fcc383ad 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -35,7 +35,7 @@ use graphviz as dot; use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; -use rustc::dep_graph::{DepGraphQuery, DepKind, DepNode}; +use rustc::dep_graph::{DepGraphQuery, DepKind, DepNode, DepNodeExt}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; use rustc_ast::ast; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index a7a272654f7f9..4fe23a9f7aeef 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -13,7 +13,7 @@ //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. -use rustc::dep_graph::{label_strs, DepNode}; +use rustc::dep_graph::{label_strs, DepContext, DepNode, DepNodeExt}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; use rustc_ast::ast::{self, Attribute, NestedMetaItem}; @@ -382,7 +382,7 @@ impl DirtyCleanVisitor<'tcx> { } fn dep_node_str(&self, dep_node: &DepNode) -> String { - if let Some(def_id) = dep_node.extract_def_id(self.tcx) { + if let Some(def_id) = self.tcx.extract_def_id(dep_node) { format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id)) } else { format!("{:?}({:?})", dep_node.kind, dep_node.hash) diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index 56b7be2f7e2d5..4474543466312 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -430,13 +430,13 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { try_load_from_on_disk_cache_stream.extend(quote! { DepKind::#name => { - if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY { + if <#arg as DepNodeParams>>::CAN_RECONSTRUCT_QUERY_KEY { debug_assert!($tcx.dep_graph .node_color($dep_node) .map(|c| c.is_green()) .unwrap_or(false)); - let key = <#arg as DepNodeParams>::recover($tcx, $dep_node).unwrap(); + let key = <#arg as DepNodeParams>>::recover($tcx, $dep_node).unwrap(); if queries::#name::cache_on_disk($tcx, key, None) { let _ = $tcx.#name(key); } @@ -487,8 +487,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { // Add a match arm to force the query given the dep node dep_node_force_stream.extend(quote! { DepKind::#name => { - if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY { - if let Some(key) = <#arg as DepNodeParams>::recover($tcx, $dep_node) { + if <#arg as DepNodeParams>>::CAN_RECONSTRUCT_QUERY_KEY { + if let Some(key) = <#arg as DepNodeParams>>::recover($tcx, $dep_node) { $tcx.force_query::>( key, DUMMY_SP, diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index e7e05097a54f4..4e086bcbb2d92 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -4,7 +4,7 @@ use crate::creader::CrateMetadataRef; use crate::rmeta::table::{FixedSizeEncoding, Table}; use crate::rmeta::*; -use rustc::dep_graph::{self, DepNode, DepNodeIndex}; +use rustc::dep_graph::{self, DepNode, DepNodeExt, DepNodeIndex}; use rustc::hir::exports::Export; use rustc::middle::cstore::{CrateSource, ExternCrate}; use rustc::middle::cstore::{ForeignModule, LinkagePreference, NativeLibrary}; diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs index 9dcba30300f06..c6fff2f01643a 100644 --- a/src/librustc_query_system/dep_graph/dep_node.rs +++ b/src/librustc_query_system/dep_graph/dep_node.rs @@ -126,19 +126,8 @@ where /// some independent path or string that persists between runs without /// the need to be mapped or unmapped. (This ensures we can serialize /// them even in the absence of a tcx.) -#[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - RustcEncodable, - RustcDecodable, - HashStable_Generic -)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(HashStable_Generic)] pub struct WorkProductId { hash: Fingerprint, } From 2326ae39b262169fa853c510aa1bc795a166dc26 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Mar 2020 00:21:57 +0100 Subject: [PATCH 4/9] Merge ensure_node_can_be_forced into force_from_dep_node. --- src/librustc/dep_graph/mod.rs | 14 ++++++-------- src/librustc_query_system/dep_graph/graph.rs | 4 +--- src/librustc_query_system/dep_graph/mod.rs | 7 ++----- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 79295b2f82767..d739223f6cb5e 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -110,10 +110,6 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { TyCtxt::create_stable_hashing_context(*self) } - fn force_from_dep_node(&self, node: &DepNode) -> bool { - ty::query::force_from_dep_node(*self, node) - } - /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: /// @@ -133,7 +129,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } } - fn ensure_node_can_be_forced(&self, dep_dep_node: &DepNode) -> Option<()> { + fn try_force_previous_green(&self, dep_dep_node: &DepNode) -> bool { // FIXME: This match is just a workaround for incremental bugs and should // be removed. https://github.com/rust-lang/rust/issues/62649 is one such // bug that must be fixed before removing this. @@ -162,12 +158,12 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // Since the given `DefPath` does not // denote the item that previously // existed, we just fail to mark green. - return None; + return false; } } else { // If the node does not exist anymore, we // just fail to mark green. - return None; + return false; } } _ => { @@ -175,7 +171,9 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // forced. } } - Some(()) + + debug!("try_force_previous_green({:?}) --- trying to force", dep_dep_node); + ty::query::force_from_dep_node(*self, dep_dep_node) } fn has_errors_or_delayed_span_bugs(&self) -> bool { diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index 5e004c5428ad2..36edf255a775e 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -635,8 +635,6 @@ impl DepGraph { current_deps.push(node_index); continue; } - } else { - tcx.ensure_node_can_be_forced(dep_dep_node)?; } // We failed to mark it green, so we try to force the query. @@ -645,7 +643,7 @@ impl DepGraph { dependency {:?}", dep_node, dep_dep_node ); - if tcx.force_from_dep_node(dep_dep_node) { + if tcx.try_force_previous_green(dep_dep_node) { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index 77bc8f612932f..c9983013d3896 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -31,8 +31,8 @@ pub trait DepContext: Copy { /// Create a hashing context for hashing new results. fn create_stable_hashing_context(&self) -> Self::StableHashingContext; - /// Force the execution of a query given the associated `DepNode`. - fn force_from_dep_node(&self, node: &DepNode) -> bool; + /// Try to force a dep node to execute and see if it's green. + fn try_force_previous_green(&self, node: &DepNode) -> bool; /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: @@ -46,9 +46,6 @@ pub trait DepContext: Copy { /// has been removed. fn extract_def_id(&self, node: &DepNode) -> Option; - /// Check the legality of forcing this node. - fn ensure_node_can_be_forced(&self, dep_dep_node: &DepNode) -> Option<()>; - /// Return whether the current session is tainted by errors. fn has_errors_or_delayed_span_bugs(&self) -> bool; From 3a8bb20230c4bb8f40aeca1d6ca3dea048b9e2e3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Mar 2020 00:27:09 +0100 Subject: [PATCH 5/9] Remove assert_ignored and with_ignore_deps. --- src/librustc/dep_graph/mod.rs | 18 ------------------ src/librustc_query_system/dep_graph/graph.rs | 6 ++++-- src/librustc_query_system/dep_graph/mod.rs | 8 -------- 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index d739223f6cb5e..5ccc0d281db0a 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -62,24 +62,6 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { write!(f, ")") } - fn assert_ignored() { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); - }) - } - - fn with_ignore_deps(op: OP) -> R - where - OP: FnOnce() -> R, - { - ty::tls::with_context(|icx| { - let icx = ty::tls::ImplicitCtxt { task_deps: None, ..icx.clone() }; - - ty::tls::enter_context(&icx, |_| op()) - }) - } - fn with_deps(task_deps: Option<&Lock>, op: OP) -> R where OP: FnOnce() -> R, diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index 36edf255a775e..c012dc687d782 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -151,7 +151,9 @@ impl DepGraph { pub fn assert_ignored(&self) { if let Some(..) = self.data { - K::assert_ignored(); + K::read_deps(|task_deps| { + assert!(task_deps.is_none(), "expected no task dependency tracking"); + }) } } @@ -159,7 +161,7 @@ impl DepGraph { where OP: FnOnce() -> R, { - K::with_ignore_deps(op) + K::with_deps(None, op) } /// Starts a new dep-graph task. Dep-graph tasks are specified diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index c9983013d3896..e6a927c11dde0 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -76,14 +76,6 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Ord + Hash { /// Implementation of `std::fmt::Debug` for `DepNode`. fn debug_node(node: &DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result; - /// Assert the current implicit context does not track any dependency. - fn assert_ignored(); - - /// Execute the operation ignoring the dependencies. - fn with_ignore_deps(op: OP) -> R - where - OP: FnOnce() -> R; - /// Execute the operation with provided dependencies. fn with_deps(deps: Option<&Lock>>, op: OP) -> R where From d08cc0ba67d9989548ae163083b7e3a3dec6b9a2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Mar 2020 09:28:37 +0100 Subject: [PATCH 6/9] Put extract_def_id back on DepNode. --- src/librustc/dep_graph/dep_node.rs | 27 ++++++++++++++++--- src/librustc/dep_graph/mod.rs | 24 ++--------------- .../persist/dirty_clean.rs | 4 +-- src/librustc_query_system/dep_graph/mod.rs | 13 --------- 4 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index ee44c07d3a917..fdcc1a0db0538 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -220,6 +220,18 @@ macro_rules! define_dep_nodes { /// single DefId/DefPathHash parameter. fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self; + /// Extracts the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option; + /// Used in testing fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result; @@ -250,6 +262,15 @@ macro_rules! define_dep_nodes { /// DepNode. Condition (2) might not be fulfilled if a DepNode /// refers to something from the previous compilation session that /// has been removed. + fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option { + if self.kind.can_reconstruct_query_key() { + let def_path_hash = DefPathHash(self.hash); + tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned() + } else { + None + } + } + /// Used in testing fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result { let kind = match label { @@ -316,7 +337,7 @@ impl<'tcx> DepNodeParams> for DefId { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - tcx.extract_def_id(dep_node) + dep_node.extract_def_id(tcx) } } @@ -332,7 +353,7 @@ impl<'tcx> DepNodeParams> for LocalDefId { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - tcx.extract_def_id(dep_node).map(|id| id.expect_local()) + dep_node.extract_def_id(tcx).map(|id| id.expect_local()) } } @@ -349,7 +370,7 @@ impl<'tcx> DepNodeParams> for CrateNum { } fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - tcx.extract_def_id(dep_node).map(|id| id.krate) + dep_node.extract_def_id(tcx).map(|id| id.krate) } } diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 5ccc0d281db0a..47cc5f58559df 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -1,4 +1,3 @@ -use crate::hir::map::definitions::DefPathHash; use crate::ich::StableHashingContext; use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; @@ -46,7 +45,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { ty::tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { - if let Some(def_id) = tcx.extract_def_id(node) { + if let Some(def_id) = node.extract_def_id(tcx) { write!(f, "{}", tcx.def_path_debug_str(def_id))?; } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) { write!(f, "{}", s)?; @@ -92,32 +91,13 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { TyCtxt::create_stable_hashing_context(*self) } - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - fn extract_def_id(&self, node: &DepNode) -> Option { - if node.kind.can_reconstruct_query_key() { - let def_path_hash = DefPathHash(node.hash); - self.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned() - } else { - None - } - } - fn try_force_previous_green(&self, dep_dep_node: &DepNode) -> bool { // FIXME: This match is just a workaround for incremental bugs and should // be removed. https://github.com/rust-lang/rust/issues/62649 is one such // bug that must be fixed before removing this. match dep_dep_node.kind { DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => { - if let Some(def_id) = self.extract_def_id(dep_dep_node) { + if let Some(def_id) = dep_dep_node.extract_def_id(*self) { if def_id_corresponds_to_hir_dep_node(*self, def_id) { if dep_dep_node.kind == DepKind::CrateMetadata { // The `DefPath` has corresponding node, diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 4fe23a9f7aeef..9ddd238afff2b 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -13,7 +13,7 @@ //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. -use rustc::dep_graph::{label_strs, DepContext, DepNode, DepNodeExt}; +use rustc::dep_graph::{label_strs, DepNode, DepNodeExt}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; use rustc_ast::ast::{self, Attribute, NestedMetaItem}; @@ -382,7 +382,7 @@ impl DirtyCleanVisitor<'tcx> { } fn dep_node_str(&self, dep_node: &DepNode) -> String { - if let Some(def_id) = self.tcx.extract_def_id(dep_node) { + if let Some(def_id) = dep_node.extract_def_id(self.tcx) { format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id)) } else { format!("{:?}({:?})", dep_node.kind, dep_node.hash) diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index e6a927c11dde0..a54b8497fdef6 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -19,7 +19,6 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; -use rustc_hir::def_id::DefId; use std::fmt; use std::hash::Hash; @@ -34,18 +33,6 @@ pub trait DepContext: Copy { /// Try to force a dep node to execute and see if it's green. fn try_force_previous_green(&self, node: &DepNode) -> bool; - /// Extracts the DefId corresponding to this DepNode. This will work - /// if two conditions are met: - /// - /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and - /// 2. the item that the DefPath refers to exists in the current tcx. - /// - /// Condition (1) is determined by the DepKind variant of the - /// DepNode. Condition (2) might not be fulfilled if a DepNode - /// refers to something from the previous compilation session that - /// has been removed. - fn extract_def_id(&self, node: &DepNode) -> Option; - /// Return whether the current session is tainted by errors. fn has_errors_or_delayed_span_bugs(&self) -> bool; From e0f7b897bad6e5ff4a011cccc0326bdc886e9e73 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 22 Mar 2020 20:47:30 +0100 Subject: [PATCH 7/9] Address review. --- src/librustc/dep_graph/mod.rs | 20 +++++++++----------- src/librustc/ty/query/mod.rs | 6 ++++++ src/librustc_query_system/dep_graph/graph.rs | 18 +++++++++--------- src/librustc_query_system/dep_graph/mod.rs | 2 +- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 47cc5f58559df..4ed2d32c23bea 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -91,22 +91,22 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { TyCtxt::create_stable_hashing_context(*self) } - fn try_force_previous_green(&self, dep_dep_node: &DepNode) -> bool { + fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool { // FIXME: This match is just a workaround for incremental bugs and should // be removed. https://github.com/rust-lang/rust/issues/62649 is one such // bug that must be fixed before removing this. - match dep_dep_node.kind { + match dep_node.kind { DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => { - if let Some(def_id) = dep_dep_node.extract_def_id(*self) { + if let Some(def_id) = dep_node.extract_def_id(*self) { if def_id_corresponds_to_hir_dep_node(*self, def_id) { - if dep_dep_node.kind == DepKind::CrateMetadata { + if dep_node.kind == DepKind::CrateMetadata { // The `DefPath` has corresponding node, // and that node should have been marked // either red or green in `data.colors`. bug!( "DepNode {:?} should have been \ pre-marked as red or green but wasn't.", - dep_dep_node + dep_node ); } } else { @@ -134,8 +134,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } } - debug!("try_force_previous_green({:?}) --- trying to force", dep_dep_node); - ty::query::force_from_dep_node(*self, dep_dep_node) + debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node); + ty::query::force_from_dep_node(*self, dep_node) } fn has_errors_or_delayed_span_bugs(&self) -> bool { @@ -148,10 +148,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // Interactions with on_disk_cache fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { - use crate::mir::interpret::GlobalId; - use crate::ty::query::queries; - use crate::ty::query::QueryDescription; - rustc_dep_node_try_load_from_on_disk_cache!(dep_node, *self) + use crate::ty::query::try_load_from_on_disk_cache; + try_load_from_on_disk_cache(*self, dep_node) } fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec { diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 4cfd1f8f3c4d9..a59824f684d89 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -191,3 +191,9 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool false } + +pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) { + use crate::dep_graph::DepKind; + + rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx) +} diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index c012dc687d782..7352551559cf4 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -13,8 +13,8 @@ use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; use std::env; use std::hash::Hash; +use std::marker::PhantomData; use std::mem; -use std::panic as bug; use std::sync::atomic::Ordering::Relaxed; use super::debug::EdgeFilter; @@ -215,7 +215,7 @@ impl DepGraph { node: Some(_key), reads: SmallVec::new(), read_set: Default::default(), - phantom_data: std::marker::PhantomData, + phantom_data: PhantomData, }) }, |data, key, fingerprint, task| data.complete_task(key, task.unwrap(), fingerprint), @@ -367,7 +367,7 @@ impl DepGraph { std::mem::drop(map); data.read_index(dep_node_index); } else { - bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind) + panic!("DepKind {:?} should be pre-allocated but isn't.", v.kind) } } } @@ -645,7 +645,7 @@ impl DepGraph { dependency {:?}", dep_node, dep_dep_node ); - if tcx.try_force_previous_green(dep_dep_node) { + if tcx.try_force_from_dep_node(dep_dep_node) { let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { @@ -667,7 +667,7 @@ impl DepGraph { } None => { if !tcx.has_errors_or_delayed_span_bugs() { - bug!( + panic!( "try_mark_previous_green() - Forcing the DepNode \ should have set its color" ) @@ -948,7 +948,7 @@ impl CurrentDepGraph { match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { Ok(s) => match EdgeFilter::new(&s) { Ok(f) => Some(f), - Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), + Err(err) => panic!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), }, Err(_) => None, } @@ -1074,7 +1074,7 @@ impl DepGraphData { if let Some(ref forbidden_edge) = self.current.forbidden_edge { let source = data[source].node; if forbidden_edge.test(&source, &target) { - bug!("forbidden edge {:?} -> {:?} created", source, target) + panic!("forbidden edge {:?} -> {:?} created", source, target) } } } @@ -1096,7 +1096,7 @@ pub struct TaskDeps { node: Option>, reads: EdgesVec, read_set: FxHashSet, - phantom_data: std::marker::PhantomData>, + phantom_data: PhantomData>, } impl Default for TaskDeps { @@ -1106,7 +1106,7 @@ impl Default for TaskDeps { node: None, reads: EdgesVec::new(), read_set: FxHashSet::default(), - phantom_data: std::marker::PhantomData, + phantom_data: PhantomData, } } } diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index a54b8497fdef6..825b341cd146d 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -31,7 +31,7 @@ pub trait DepContext: Copy { fn create_stable_hashing_context(&self) -> Self::StableHashingContext; /// Try to force a dep node to execute and see if it's green. - fn try_force_previous_green(&self, node: &DepNode) -> bool; + fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool; /// Return whether the current session is tainted by errors. fn has_errors_or_delayed_span_bugs(&self) -> bool; From 9f4c8889e51cf60641b42b7e43bfdf048dbd692d Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 23 Mar 2020 00:16:00 +0100 Subject: [PATCH 8/9] Fully qualify the path to DepKind. This is needed since `middle::cstore` defines another type named `DepKind`, and we should not rely on shadowing to get the right one. --- src/librustc/ty/query/mod.rs | 12 ++++-------- src/librustc_macros/src/query.rs | 6 +++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index a59824f684d89..b45b3b3f539ea 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -150,8 +150,6 @@ rustc_query_append! { [define_queries!][<'tcx>] } /// add it to the "We don't have enough information to reconstruct..." group in /// the match below. pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool { - use crate::dep_graph::DepKind; - // We must avoid ever having to call `force_from_dep_node()` for a // `DepNode::codegen_unit`: // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we @@ -166,7 +164,7 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool // hit the cache instead of having to go through `force_from_dep_node`. // This assertion makes sure, we actually keep applying the solution above. debug_assert!( - dep_node.kind != DepKind::codegen_unit, + dep_node.kind != crate::dep_graph::DepKind::codegen_unit, "calling force_from_dep_node() on DepKind::codegen_unit" ); @@ -177,14 +175,14 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool rustc_dep_node_force!([dep_node, tcx] // These are inputs that are expected to be pre-allocated and that // should therefore always be red or green already. - DepKind::CrateMetadata | + crate::dep_graph::DepKind::CrateMetadata | // These are anonymous nodes. - DepKind::TraitSelect | + crate::dep_graph::DepKind::TraitSelect | // We don't have enough information to reconstruct the query key of // these. - DepKind::CompileCodegenUnit => { + crate::dep_graph::DepKind::CompileCodegenUnit => { bug!("force_from_dep_node: encountered {:?}", dep_node) } ); @@ -193,7 +191,5 @@ pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool } pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) { - use crate::dep_graph::DepKind; - rustc_dep_node_try_load_from_on_disk_cache!(dep_node, tcx) } diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index 4474543466312..e7005f2f5ba77 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -429,7 +429,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { }); try_load_from_on_disk_cache_stream.extend(quote! { - DepKind::#name => { + ::rustc::dep_graph::DepKind::#name => { if <#arg as DepNodeParams>>::CAN_RECONSTRUCT_QUERY_KEY { debug_assert!($tcx.dep_graph .node_color($dep_node) @@ -486,7 +486,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { // Add a match arm to force the query given the dep node dep_node_force_stream.extend(quote! { - DepKind::#name => { + ::rustc::dep_graph::DepKind::#name => { if <#arg as DepNodeParams>>::CAN_RECONSTRUCT_QUERY_KEY { if let Some(key) = <#arg as DepNodeParams>>::recover($tcx, $dep_node) { $tcx.force_query::>( @@ -509,7 +509,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { } dep_node_force_stream.extend(quote! { - DepKind::Null => { + ::rustc::dep_graph::DepKind::Null => { bug!("Cannot force dep node: {:?}", $dep_node) } }); From 0f918cba3ff48216a140db4fd06e2ea13abc78c9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 23 Mar 2020 07:28:53 +0100 Subject: [PATCH 9/9] Move import. --- src/librustc/dep_graph/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 4ed2d32c23bea..3c39597584df5 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -1,4 +1,5 @@ use crate::ich::StableHashingContext; +use crate::ty::query::try_load_from_on_disk_cache; use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; @@ -148,7 +149,6 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { // Interactions with on_disk_cache fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) { - use crate::ty::query::try_load_from_on_disk_cache; try_load_from_on_disk_cache(*self, dep_node) }