diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index eb7e2871bfcd8..156f412e0902e 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -360,33 +360,9 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> [anon] TraitSelect, [] CompileCodegenUnit(Symbol), - - [eval_always] Analysis(CrateNum), ]); -pub trait RecoverKey<'tcx>: Sized { - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option; -} - -impl RecoverKey<'tcx> for CrateNum { - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.krate) - } -} - -impl RecoverKey<'tcx> for DefId { - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx) - } -} - -impl RecoverKey<'tcx> for DefIndex { - fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { - dep_node.extract_def_id(tcx).map(|id| id.index) - } -} - -trait DepNodeParams<'tcx>: fmt::Debug { +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 @@ -400,6 +376,14 @@ trait DepNodeParams<'tcx>: fmt::Debug { 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 @@ -420,6 +404,10 @@ where 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 { @@ -432,6 +420,10 @@ impl<'tcx> DepNodeParams<'tcx> for DefId { 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 { @@ -444,6 +436,10 @@ impl<'tcx> DepNodeParams<'tcx> for DefIndex { 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 { @@ -457,6 +453,10 @@ impl<'tcx> DepNodeParams<'tcx> for CrateNum { 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) { diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index eb377d20f5963..1fbd90743f402 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -6,7 +6,8 @@ mod query; mod safe; mod serialized; -pub use self::dep_node::{label_strs, DepConstructor, DepKind, DepNode, RecoverKey, WorkProductId}; +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; diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index b7f4f432838be..11e9acf3a3912 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{DepKind, DepNode, RecoverKey, SerializedDepNodeIndex}; +use crate::dep_graph::SerializedDepNodeIndex; use crate::mir; use crate::mir::interpret::{GlobalId, LitToConstInput}; use crate::traits; @@ -60,6 +60,11 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } + query analysis(key: CrateNum) -> Result<(), ErrorReported> { + eval_always + desc { "running analysis passes on this crate" } + } + /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its /// associated generics. query generics_of(key: DefId) -> &'tcx ty::Generics { @@ -195,7 +200,6 @@ rustc_queries! { // queries). Making it anonymous avoids hashing the result, which // may save a bit of time. anon - no_force desc { "erasing regions from `{:?}`", ty } } @@ -204,7 +208,6 @@ rustc_queries! { } query program_clauses_for_env(_: traits::Environment<'tcx>) -> Clauses<'tcx> { - no_force desc { "generating chalk-style clauses for environment" } } @@ -247,7 +250,6 @@ rustc_queries! { /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. query type_param_predicates(key: (DefId, DefId)) -> ty::GenericPredicates<'tcx> { - no_force desc { |tcx| "computing the bounds for type parameter `{}`", { let id = tcx.hir().as_local_hir_id(key.1).unwrap(); tcx.hir().ty_param_name(id) @@ -503,7 +505,6 @@ rustc_queries! { /// form to be used outside of const eval. query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> ConstEvalRawResult<'tcx> { - no_force desc { |tcx| "const-evaluating `{}`", tcx.def_path_str(key.value.instance.def.def_id()) @@ -520,7 +521,6 @@ rustc_queries! { /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> ConstEvalResult<'tcx> { - no_force desc { |tcx| "const-evaluating + checking `{}`", tcx.def_path_str(key.value.instance.def.def_id()) @@ -535,7 +535,6 @@ rustc_queries! { query const_field( key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)> ) -> ConstValue<'tcx> { - no_force desc { "extract field of const" } } @@ -544,19 +543,16 @@ rustc_queries! { query destructure_const( key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> ) -> mir::DestructuredConst<'tcx> { - no_force desc { "destructure constant" } } query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { - no_force desc { "get a &core::panic::Location referring to a span" } } query lit_to_const( key: LitToConstInput<'tcx> ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { - no_force desc { "converting literal to const" } } } @@ -587,7 +583,6 @@ rustc_queries! { query region_scope_tree(_: DefId) -> &'tcx region::ScopeTree {} query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::BodyAndCache<'tcx> { - no_force desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } } @@ -595,7 +590,6 @@ rustc_queries! { /// given instance from the local crate. In particular, it will also /// look up the correct symbol name of instances from upstream crates. query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName { - no_force desc { "computing the symbol for `{}`", key } cache_on_disk_if { true } } @@ -642,7 +636,6 @@ rustc_queries! { Other { query vtable_methods(key: ty::PolyTraitRef<'tcx>) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { - no_force desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) } } } @@ -651,7 +644,6 @@ rustc_queries! { query codegen_fulfill_obligation( key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) ) -> Option> { - no_force cache_on_disk_if { true } desc { |tcx| "checking if `{}` fulfills its obligations", @@ -683,22 +675,18 @@ rustc_queries! { /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, /// `ty.is_copy()`, etc, since that will prune the environment where possible. query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - no_force desc { "computing whether `{}` is `Copy`", env.value } } /// Query backing `TyS::is_sized`. query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - no_force desc { "computing whether `{}` is `Sized`", env.value } } /// Query backing `TyS::is_freeze`. query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - no_force desc { "computing whether `{}` is freeze", env.value } } /// Query backing `TyS::needs_drop`. query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - no_force desc { "computing whether `{}` needs drop", env.value } } @@ -712,7 +700,6 @@ rustc_queries! { query layout_raw( env: ty::ParamEnvAnd<'tcx, Ty<'tcx>> ) -> Result<&'tcx ty::layout::LayoutDetails, ty::layout::LayoutError<'tcx>> { - no_force desc { "computing layout of `{}`", env.value } } } @@ -768,7 +755,6 @@ rustc_queries! { TypeChecking { query specializes(_: (DefId, DefId)) -> bool { - no_force desc { "computing whether impls specialize one another" } } query in_scope_traits_map(_: DefIndex) @@ -853,7 +839,6 @@ rustc_queries! { /// (like `Clone::clone` for example). query upstream_drop_glue_for(substs: SubstsRef<'tcx>) -> Option { desc { "available upstream drop-glue for `{:?}`", substs } - no_force } } @@ -898,7 +883,6 @@ rustc_queries! { TypeChecking { query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [DefId] { - no_force desc { "looking up implementations of a trait in a crate" } } query all_trait_implementations(_: CrateNum) @@ -1065,7 +1049,6 @@ rustc_queries! { } query is_codegened_item(_: DefId) -> bool {} query codegen_unit(_: Symbol) -> Arc> { - no_force desc { "codegen_unit" } } query backend_optimization_level(_: CrateNum) -> OptLevel { @@ -1088,7 +1071,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution, > { - no_force desc { "normalizing `{:?}`", goal } } @@ -1096,7 +1078,6 @@ rustc_queries! { query normalize_ty_after_erasing_regions( goal: ParamEnvAnd<'tcx, Ty<'tcx>> ) -> Ty<'tcx> { - no_force desc { "normalizing `{:?}`", goal } } @@ -1106,7 +1087,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>, NoSolution, > { - no_force desc { "computing implied outlives bounds for `{:?}`", goal } } @@ -1117,7 +1097,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution, > { - no_force desc { "computing dropck types for `{:?}`", goal } } @@ -1126,7 +1105,6 @@ rustc_queries! { query evaluate_obligation( goal: CanonicalPredicateGoal<'tcx> ) -> Result { - no_force desc { "evaluating trait selection obligation `{}`", goal.value.value } } @@ -1137,7 +1115,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution, > { - no_force desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal } } @@ -1148,7 +1125,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution, > { - no_force desc { "evaluating `type_op_eq` `{:?}`", goal } } @@ -1159,7 +1135,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution, > { - no_force desc { "evaluating `type_op_subtype` `{:?}`", goal } } @@ -1170,7 +1145,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution, > { - no_force desc { "evaluating `type_op_prove_predicate` `{:?}`", goal } } @@ -1181,7 +1155,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>, NoSolution, > { - no_force desc { "normalizing `{:?}`", goal } } @@ -1192,7 +1165,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>, NoSolution, > { - no_force desc { "normalizing `{:?}`", goal } } @@ -1203,7 +1175,6 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>, NoSolution, > { - no_force desc { "normalizing `{:?}`", goal } } @@ -1214,12 +1185,10 @@ rustc_queries! { &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>, NoSolution, > { - no_force desc { "normalizing `{:?}`", goal } } query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { - no_force desc { |tcx| "testing substituted normalized predicates:`{}`", tcx.def_path_str(key.0) @@ -1229,7 +1198,6 @@ rustc_queries! { query method_autoderef_steps( goal: CanonicalTyGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { - no_force desc { "computing autoderef types for `{:?}`", goal } } } @@ -1243,7 +1211,6 @@ rustc_queries! { // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) -> usize { - no_force desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } } diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index e0e1ca374d9ae..178c2362def6e 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -2,11 +2,10 @@ use crate::dep_graph::SerializedDepNodeIndex; use crate::dep_graph::{DepKind, DepNode}; use crate::ty::query::caches::QueryCache; use crate::ty::query::plumbing::CycleError; -use crate::ty::query::queries; use crate::ty::query::{Query, QueryState}; use crate::ty::TyCtxt; use rustc_data_structures::profiling::ProfileCategory; -use rustc_hir::def_id::{CrateNum, DefId}; +use rustc_hir::def_id::DefId; use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::Fingerprint; @@ -87,9 +86,3 @@ where bug!("QueryDescription::load_from_disk() called for an unsupported query.") } } - -impl<'tcx> QueryDescription<'tcx> for queries::analysis<'tcx> { - fn describe(_tcx: TyCtxt<'_>, _: CrateNum) -> Cow<'static, str> { - "running analysis passes on this crate".into() - } -} diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 8614fd5cdca9a..8adb828fbebc4 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{self, DepConstructor, DepNode}; +use crate::dep_graph::{self, DepConstructor, DepNode, DepNodeParams}; use crate::hir::exports::Export; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintLevelMap; @@ -60,8 +60,8 @@ use std::sync::Arc; #[macro_use] mod plumbing; +pub use self::plumbing::CycleError; use self::plumbing::*; -pub use self::plumbing::{force_from_dep_node, CycleError}; mod stats; pub use self::stats::print_stats; @@ -104,9 +104,105 @@ pub use self::profiling_support::{IntoSelfProfilingString, QueryKeyStringBuilder // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. -rustc_query_append! { [define_queries!][ <'tcx> - Other { - /// Runs analysis passes on the crate. - [eval_always] fn analysis: Analysis(CrateNum) -> Result<(), ErrorReported>, - }, -]} +rustc_query_append! { [define_queries!][<'tcx>] } + +/// The red/green evaluation system will try to mark a specific DepNode in the +/// dependency graph as green by recursively trying to mark the dependencies of +/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` +/// where we don't know if it is red or green and we therefore actually have +/// to recompute its value in order to find out. Since the only piece of +/// information that we have at that point is the `DepNode` we are trying to +/// re-evaluate, we need some way to re-run a query from just that. This is what +/// `force_from_dep_node()` implements. +/// +/// In the general case, a `DepNode` consists of a `DepKind` and an opaque +/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint +/// is usually constructed by computing a stable hash of the query-key that the +/// `DepNode` corresponds to. Consequently, it is not in general possible to go +/// back from hash to query-key (since hash functions are not reversible). For +/// this reason `force_from_dep_node()` is expected to fail from time to time +/// because we just cannot find out, from the `DepNode` alone, what the +/// corresponding query-key is and therefore cannot re-run the query. +/// +/// The system deals with this case letting `try_mark_green` fail which forces +/// the root query to be re-evaluated. +/// +/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. +/// Fortunately, we can use some contextual information that will allow us to +/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we +/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a +/// valid `DefPathHash`. Since we also always build a huge table that maps every +/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have +/// everything we need to re-run the query. +/// +/// Take the `mir_validated` query as an example. Like many other queries, it +/// just has a single parameter: the `DefId` of the item it will compute the +/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` +/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` +/// is actually a `DefPathHash`, and can therefore just look up the corresponding +/// `DefId` in `tcx.def_path_hash_to_def_id`. +/// +/// When you implement a new query, it will likely have a corresponding new +/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As +/// a rule of thumb, if your query takes a `DefId` or `DefIndex` as sole parameter, +/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just +/// 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 + // would always end up having to evaluate the first caller of the + // `codegen_unit` query that *is* reconstructible. This might very well be + // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just + // to re-trigger calling the `codegen_unit` query with the right key. At + // that point we would already have re-done all the work we are trying to + // avoid doing in the first place. + // The solution is simple: Just explicitly call the `codegen_unit` query for + // each CGU, right after partitioning. This way `try_mark_green` will always + // 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, + "calling force_from_dep_node() on DepKind::codegen_unit" + ); + + if !dep_node.kind.can_reconstruct_query_key() { + return false; + } + + 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::AllLocalTraitImpls | + DepKind::CrateMetadata | + DepKind::HirBody | + DepKind::Hir | + + // These are anonymous nodes. + DepKind::TraitSelect | + + // We don't have enough information to reconstruct the query key of + // these. + DepKind::CompileCodegenUnit => { + bug!("force_from_dep_node: encountered {:?}", dep_node) + } + ); + + 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/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index c94909549df22..acf67f52dceaa 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -2,7 +2,7 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; +use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; use crate::ty::query::caches::QueryCache; use crate::ty::query::config::{QueryAccessors, QueryDescription}; use crate::ty::query::job::{QueryInfo, QueryJob, QueryJobId, QueryShardJobId}; @@ -720,7 +720,7 @@ impl<'tcx> TyCtxt<'tcx> { } #[allow(dead_code)] - fn force_query + 'tcx>( + pub(super) fn force_query + 'tcx>( self, key: Q::Key, span: Span, @@ -1162,105 +1162,3 @@ macro_rules! define_provider_struct { } }; } - -/// The red/green evaluation system will try to mark a specific DepNode in the -/// dependency graph as green by recursively trying to mark the dependencies of -/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` -/// where we don't know if it is red or green and we therefore actually have -/// to recompute its value in order to find out. Since the only piece of -/// information that we have at that point is the `DepNode` we are trying to -/// re-evaluate, we need some way to re-run a query from just that. This is what -/// `force_from_dep_node()` implements. -/// -/// In the general case, a `DepNode` consists of a `DepKind` and an opaque -/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint -/// is usually constructed by computing a stable hash of the query-key that the -/// `DepNode` corresponds to. Consequently, it is not in general possible to go -/// back from hash to query-key (since hash functions are not reversible). For -/// this reason `force_from_dep_node()` is expected to fail from time to time -/// because we just cannot find out, from the `DepNode` alone, what the -/// corresponding query-key is and therefore cannot re-run the query. -/// -/// The system deals with this case letting `try_mark_green` fail which forces -/// the root query to be re-evaluated. -/// -/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. -/// Fortunately, we can use some contextual information that will allow us to -/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we -/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a -/// valid `DefPathHash`. Since we also always build a huge table that maps every -/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have -/// everything we need to re-run the query. -/// -/// Take the `mir_validated` query as an example. Like many other queries, it -/// just has a single parameter: the `DefId` of the item it will compute the -/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` -/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` -/// is actually a `DefPathHash`, and can therefore just look up the corresponding -/// `DefId` in `tcx.def_path_hash_to_def_id`. -/// -/// When you implement a new query, it will likely have a corresponding new -/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As -/// a rule of thumb, if your query takes a `DefId` or `DefIndex` as sole parameter, -/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just -/// add it to the "We don't have enough information to reconstruct..." group in -/// the match below. -pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool { - use crate::dep_graph::RecoverKey; - - // 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 - // would always end up having to evaluate the first caller of the - // `codegen_unit` query that *is* reconstructible. This might very well be - // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just - // to re-trigger calling the `codegen_unit` query with the right key. At - // that point we would already have re-done all the work we are trying to - // avoid doing in the first place. - // The solution is simple: Just explicitly call the `codegen_unit` query for - // each CGU, right after partitioning. This way `try_mark_green` will always - // 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, - "calling force_from_dep_node() on DepKind::codegen_unit" - ); - - if !dep_node.kind.can_reconstruct_query_key() { - return false; - } - - 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::AllLocalTraitImpls | - DepKind::CrateMetadata | - DepKind::HirBody | - DepKind::Hir | - - // These are anonymous nodes. - DepKind::TraitSelect | - - // We don't have enough information to reconstruct the query key of - // these. - DepKind::CompileCodegenUnit => { - bug!("force_from_dep_node: encountered {:?}", dep_node) - } - - DepKind::Analysis => { - let def_id = if let Some(def_id) = dep_node.extract_def_id(tcx) { - def_id - } else { - // Return from the whole function. - return false - }; - tcx.force_query::>( - def_id.krate, - DUMMY_SP, - *dep_node - ); - } - ); - - true -} diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index 97b800decc59b..56b7be2f7e2d5 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -51,9 +51,6 @@ enum QueryModifier { /// Don't hash the result, instead just mark a query red if it runs NoHash, - /// Don't force the query - NoForce, - /// Generate a dep node based on the dependencies of the query Anon, @@ -118,8 +115,6 @@ impl Parse for QueryModifier { Ok(QueryModifier::CycleDelayBug) } else if modifier == "no_hash" { Ok(QueryModifier::NoHash) - } else if modifier == "no_force" { - Ok(QueryModifier::NoForce) } else if modifier == "anon" { Ok(QueryModifier::Anon) } else if modifier == "eval_always" { @@ -222,9 +217,6 @@ struct QueryModifiers { /// Don't hash the result, instead just mark a query red if it runs no_hash: bool, - /// Don't force the query - no_force: bool, - /// Generate a dep node based on the dependencies of the query anon: bool, @@ -241,7 +233,6 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { let mut fatal_cycle = false; let mut cycle_delay_bug = false; let mut no_hash = false; - let mut no_force = false; let mut anon = false; let mut eval_always = false; for modifier in query.modifiers.0.drain(..) { @@ -288,12 +279,6 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { } no_hash = true; } - QueryModifier::NoForce => { - if no_force { - panic!("duplicate modifier `no_force` for query `{}`", query.name); - } - no_force = true; - } QueryModifier::Anon => { if anon { panic!("duplicate modifier `anon` for query `{}`", query.name); @@ -316,7 +301,6 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { fatal_cycle, cycle_delay_bug, no_hash, - no_force, anon, eval_always, } @@ -425,7 +409,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut dep_node_def_stream = quote! {}; let mut dep_node_force_stream = quote! {}; let mut try_load_from_on_disk_cache_stream = quote! {}; - let mut no_force_queries = Vec::new(); let mut cached_queries = quote! {}; for group in groups.0 { @@ -444,19 +427,19 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { cached_queries.extend(quote! { #name, }); - } - if modifiers.cache.is_some() && !modifiers.no_force { try_load_from_on_disk_cache_stream.extend(quote! { DepKind::#name => { - debug_assert!(tcx.dep_graph - .node_color(self) - .map(|c| c.is_green()) - .unwrap_or(false)); - - let key = RecoverKey::recover(tcx, self).unwrap(); - if queries::#name::cache_on_disk(tcx, key, None) { - let _ = tcx.#name(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(); + if queries::#name::cache_on_disk($tcx, key, None) { + let _ = $tcx.#name(key); + } } } }); @@ -501,24 +484,21 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { [#attribute_stream] #name(#arg), }); - if modifiers.no_force { - no_force_queries.push(name.clone()); - } else { - // Add a match arm to force the query given the dep node - dep_node_force_stream.extend(quote! { - DepKind::#name => { - if let Some(key) = RecoverKey::recover($tcx, $dep_node) { + // 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) { $tcx.force_query::>( key, DUMMY_SP, *$dep_node ); - } else { - return false; + return true; } } - }); - } + } + }); add_query_description_impl(&query, modifiers, &mut query_description_stream); } @@ -528,12 +508,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { }); } - // Add an arm for the no force queries to panic when trying to force them - for query in no_force_queries { - dep_node_force_stream.extend(quote! { - DepKind::#query | - }); - } dep_node_force_stream.extend(quote! { DepKind::Null => { bug!("Cannot force dep node: {:?}", $dep_node) @@ -577,14 +551,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { #query_description_stream - 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(&self, tcx: TyCtxt<'_>) { - match self.kind { + macro_rules! rustc_dep_node_try_load_from_on_disk_cache { + ($dep_node:expr, $tcx:expr) => { + match $dep_node.kind { #try_load_from_on_disk_cache_stream _ => (), }