From db58395a6b79f373595ebe26d6a130583c54fce8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 16 Feb 2026 10:54:52 +1100 Subject: [PATCH] Don't use `HasDepContext` in `DepGraph::with_task` The need for a `HasDepContext` impl on tuples can be avoided by passing the query vtable as part of an argument tuple instead. --- compiler/rustc_middle/src/dep_graph/graph.rs | 72 ++++++++------------ compiler/rustc_middle/src/dep_graph/mod.rs | 6 -- compiler/rustc_query_impl/src/execution.rs | 6 +- compiler/rustc_query_impl/src/lib.rs | 15 ++++ 4 files changed, 46 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index 6a19c02bb81b..265ee76b31b0 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -268,17 +268,17 @@ impl DepGraph { } #[inline(always)] - pub fn with_task<'tcx, Ctxt: HasDepContext<'tcx>, A: Debug, R>( + pub fn with_task<'tcx, A: Debug, R>( &self, - key: DepNode, - cx: Ctxt, - arg: A, - task: fn(Ctxt, A) -> R, + dep_node: DepNode, + tcx: TyCtxt<'tcx>, + task_arg: A, + task_fn: fn(tcx: TyCtxt<'tcx>, task_arg: A) -> R, hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) { match self.data() { - Some(data) => data.with_task(key, cx, arg, task, hash_result), - None => (task(cx, arg), self.next_virtual_depnode_index()), + Some(data) => data.with_task(dep_node, tcx, task_arg, task_fn, hash_result), + None => (task_fn(tcx, task_arg), self.next_virtual_depnode_index()), } } @@ -310,33 +310,21 @@ impl DepGraphData { /// prevent implicit 'leaks' of tracked state into the task (which /// could then be read without generating correct edges in the /// dep-graph -- see the [rustc dev guide] for more details on - /// the dep-graph). To this end, the task function gets exactly two - /// pieces of state: the context `cx` and an argument `arg`. Both - /// of these bits of state must be of some type that implements - /// `DepGraphSafe` and hence does not leak. + /// the dep-graph). /// - /// The choice of two arguments is not fundamental. One argument - /// would work just as well, since multiple values can be - /// collected using tuples. However, using two arguments works out - /// to be quite convenient, since it is common to need a context - /// (`cx`) and some argument (e.g., a `DefId` identifying what - /// item to process). - /// - /// For cases where you need some other number of arguments: - /// - /// - If you only need one argument, just use `()` for the `arg` - /// parameter. - /// - If you need 3+ arguments, use a tuple for the - /// `arg` parameter. + /// Therefore, the task function takes a `TyCtxt`, plus exactly one + /// additional argument, `task_arg`. The additional argument type can be + /// `()` if no argument is needed, or a tuple if multiple arguments are + /// needed. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation.html #[inline(always)] - pub fn with_task<'tcx, Ctxt: HasDepContext<'tcx>, A: Debug, R>( + pub fn with_task<'tcx, A: Debug, R>( &self, - key: DepNode, - cx: Ctxt, - arg: A, - task: fn(Ctxt, A) -> R, + dep_node: DepNode, + tcx: TyCtxt<'tcx>, + task_arg: A, + task_fn: fn(tcx: TyCtxt<'tcx>, task_arg: A) -> R, hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) { // If the following assertion triggers, it can have two reasons: @@ -344,32 +332,28 @@ impl DepGraphData { // in `DepGraph::try_mark_green()`. // 2. Two distinct query keys get mapped to the same `DepNode` // (see for example #48923). - self.assert_dep_node_not_yet_allocated_in_current_session( - cx.dep_context().sess, - &key, - || { - format!( - "forcing query with already existing `DepNode`\n\ - - query-key: {arg:?}\n\ - - dep-node: {key:?}" - ) - }, - ); + self.assert_dep_node_not_yet_allocated_in_current_session(tcx.sess, &dep_node, || { + format!( + "forcing query with already existing `DepNode`\n\ + - query-key: {task_arg:?}\n\ + - dep-node: {dep_node:?}" + ) + }); - let with_deps = |task_deps| with_deps(task_deps, || task(cx, arg)); - let (result, edges) = if cx.dep_context().is_eval_always(key.kind) { + let with_deps = |task_deps| with_deps(task_deps, || task_fn(tcx, task_arg)); + let (result, edges) = if tcx.is_eval_always(dep_node.kind) { (with_deps(TaskDepsRef::EvalAlways), EdgesVec::new()) } else { let task_deps = Lock::new(TaskDeps::new( #[cfg(debug_assertions)] - Some(key), + Some(dep_node), 0, )); (with_deps(TaskDepsRef::Allow(&task_deps)), task_deps.into_inner().reads) }; let dep_node_index = - self.hash_result_and_alloc_node(cx.dep_context(), key, edges, &result, hash_result); + self.hash_result_and_alloc_node(tcx, dep_node, edges, &result, hash_result); (result, dep_node_index) } diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index e8b2f86e5718..3815158c66f1 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -35,12 +35,6 @@ impl<'tcx> HasDepContext<'tcx> for TyCtxt<'tcx> { } } -impl<'tcx, T: HasDepContext<'tcx>, Q: Copy> HasDepContext<'tcx> for (T, Q) { - fn dep_context(&self) -> TyCtxt<'tcx> { - self.0.dep_context() - } -} - /// Describes the contents of the fingerprint generated by a given query. /// /// This is mainly for determining whether and how we can reconstruct a key diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index e9996054211b..80bdc5626ec8 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -475,9 +475,9 @@ fn execute_job_incr<'tcx, C: QueryCache, const FLAGS: QueryFlags>( // Call the query provider. dep_graph_data.with_task( dep_node, - (tcx, query), - key, - |(tcx, query), key| query.invoke_provider(tcx, key), + tcx, + (query, key), + |tcx, (query, key)| query.invoke_provider(tcx, key), query.hash_result(), ) }); diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 8731414eb04e..b4a64686728f 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -9,6 +9,7 @@ #![feature(try_blocks)] // tidy-alphabetical-end +use std::fmt; use std::marker::ConstParamTy; use rustc_data_structures::sync::AtomicU64; @@ -76,6 +77,20 @@ impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> Clone } } +impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> fmt::Debug + for SemiDynamicQueryDispatcher<'tcx, C, FLAGS> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // When debug-printing a query dispatcher (e.g. for ICE or tracing), + // just print the query name to know what query we're dealing with. + // The other fields and flags are probably just unhelpful noise. + // + // If there is need for a more detailed dump of all flags and fields, + // consider writing a separate dump method and calling it explicitly. + f.write_str(self.name()) + } +} + impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> SemiDynamicQueryDispatcher<'tcx, C, FLAGS> { #[inline(always)] fn name(self) -> &'static str {