From 9f6e7473d6ac3e7e1596bef17cfbfda4e563ffc7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 14:54:14 +1100 Subject: [PATCH 1/5] Fix a typo. --- compiler/rustc_middle/src/query/plumbing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 8d01d9482ed4b..9300c942a525e 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -278,7 +278,7 @@ macro_rules! define_callbacks { ($V) ); - /// This function takes `ProvidedValue` and coverts it to an erased `Value` by + /// This function takes `ProvidedValue` and converts it to an erased `Value` by /// allocating it on an arena if the query has the `arena_cache` modifier. The /// value is then erased and returned. This will happen when computing the query /// using a provider or decoding a stored result. From 4c2e447027399f4ebe98563177c68831898c16e6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 14:54:48 +1100 Subject: [PATCH 2/5] Rename `fatal_cycle` as `cycle_fatal`. To be consistent with the closely related `cycle_stash` and `cycle_delay_bug`. --- compiler/rustc_macros/src/query.rs | 12 ++++----- compiler/rustc_middle/src/query/mod.rs | 28 ++++++++++----------- compiler/rustc_middle/src/query/plumbing.rs | 2 +- compiler/rustc_query_impl/src/plumbing.rs | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 5d32950875adb..104e95277a1a2 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -93,7 +93,7 @@ struct QueryModifiers { cache: Option<(Option, Block)>, /// A cycle error for this query aborting the compilation with a fatal error. - fatal_cycle: Option, + cycle_fatal: Option, /// A cycle error results in a delay_bug call cycle_delay_bug: Option, @@ -136,7 +136,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut arena_cache = None; let mut cache = None; let mut desc = None; - let mut fatal_cycle = None; + let mut cycle_fatal = None; let mut cycle_delay_bug = None; let mut cycle_stash = None; let mut no_hash = None; @@ -189,8 +189,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { try_insert!(cache = (args, block)); } else if modifier == "arena_cache" { try_insert!(arena_cache = modifier); - } else if modifier == "fatal_cycle" { - try_insert!(fatal_cycle = modifier); + } else if modifier == "cycle_fatal" { + try_insert!(cycle_fatal = modifier); } else if modifier == "cycle_delay_bug" { try_insert!(cycle_delay_bug = modifier); } else if modifier == "cycle_stash" { @@ -220,7 +220,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { arena_cache, cache, desc, - fatal_cycle, + cycle_fatal, cycle_delay_bug, cycle_stash, no_hash, @@ -366,8 +366,8 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { } passthrough!( - fatal_cycle, arena_cache, + cycle_fatal, cycle_delay_bug, cycle_stash, no_hash, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5f40c36423b33..fc1bf78c82f35 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -28,7 +28,7 @@ //! - `desc { ... }`: Sets the human-readable description for diagnostics and profiling. Required for every query. //! - `arena_cache`: Use an arena for in-memory caching of the query result. //! - `cache_on_disk_if { ... }`: Cache the query result to disk if the provided block evaluates to true. -//! - `fatal_cycle`: If a dependency cycle is detected, abort compilation with a fatal error. +//! - `cycle_fatal`: If a dependency cycle is detected, abort compilation with a fatal error. //! - `cycle_delay_bug`: If a dependency cycle is detected, emit a delayed bug instead of aborting immediately. //! - `cycle_stash`: If a dependency cycle is detected, stash the error for later handling. //! - `no_hash`: Do not hash the query result for incremental compilation; just mark as dirty if recomputed. @@ -160,7 +160,7 @@ pub mod plumbing; // The result type of each query must implement `Clone`, and additionally // `ty::query::values::Value`, which produces an appropriate placeholder // (error) value if the query resulted in a query cycle. -// Queries marked with `fatal_cycle` do not need the latter implementation, +// Queries marked with `cycle_fatal` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. rustc_queries! { /// This exists purely for testing the interactions between delayed bugs and incremental. @@ -584,7 +584,7 @@ rustc_queries! { } query is_panic_runtime(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "checking if the crate is_panic_runtime" } separate_provide_extern } @@ -1315,7 +1315,7 @@ rustc_queries! { /// Return the set of (transitive) callees that may result in a recursive call to `key`, /// if we were able to walk all callees. query mir_callgraph_cyclic(key: LocalDefId) -> &'tcx Option> { - fatal_cycle + cycle_fatal arena_cache desc { |tcx| "computing (transitive) callees of `{}` that may recurse", @@ -1326,7 +1326,7 @@ rustc_queries! { /// Obtain all the calls into other local functions query mir_inliner_callees(key: ty::InstanceKind<'tcx>) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { - fatal_cycle + cycle_fatal desc { |tcx| "computing all local function calls in `{}`", tcx.def_path_str(key.def_id()), @@ -1822,31 +1822,31 @@ rustc_queries! { } query is_compiler_builtins(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "checking if the crate is_compiler_builtins" } separate_provide_extern } query has_global_allocator(_: CrateNum) -> bool { // This query depends on untracked global state in CStore eval_always - fatal_cycle + cycle_fatal desc { "checking if the crate has_global_allocator" } separate_provide_extern } query has_alloc_error_handler(_: CrateNum) -> bool { // This query depends on untracked global state in CStore eval_always - fatal_cycle + cycle_fatal desc { "checking if the crate has_alloc_error_handler" } separate_provide_extern } query has_panic_handler(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "checking if the crate has_panic_handler" } separate_provide_extern } query is_profiler_runtime(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "checking if a crate is `#![profiler_runtime]`" } separate_provide_extern } @@ -1855,22 +1855,22 @@ rustc_queries! { cache_on_disk_if { true } } query required_panic_strategy(_: CrateNum) -> Option { - fatal_cycle + cycle_fatal desc { "getting a crate's required panic strategy" } separate_provide_extern } query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy { - fatal_cycle + cycle_fatal desc { "getting a crate's configured panic-in-drop strategy" } separate_provide_extern } query is_no_builtins(_: CrateNum) -> bool { - fatal_cycle + cycle_fatal desc { "getting whether a crate has `#![no_builtins]`" } separate_provide_extern } query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion { - fatal_cycle + cycle_fatal desc { "getting a crate's symbol mangling version" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 9300c942a525e..25c9a0a81ab48 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -532,7 +532,7 @@ macro_rules! define_feedable { // The result type of each query must implement `Clone`, and additionally // `ty::query::values::Value`, which produces an appropriate placeholder // (error) value if the query resulted in a query cycle. -// Queries marked with `fatal_cycle` do not need the latter implementation, +// Queries marked with `cycle_fatal` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. mod sealed { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 39b6fac4ebc0b..c98affe0cb198 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -219,7 +219,7 @@ macro_rules! handle_cycle_error { ([]) => {{ rustc_query_system::HandleCycleError::Error }}; - ([(fatal_cycle) $($rest:tt)*]) => {{ + ([(cycle_fatal) $($rest:tt)*]) => {{ rustc_query_system::HandleCycleError::Fatal }}; ([(cycle_stash) $($rest:tt)*]) => {{ From 2e58d05a0a40533914aeaf11cf664ba41d070955 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 15:51:13 +1100 Subject: [PATCH 3/5] Add test from #124901. Issue #124901 was an OOM caused by a query cycle. It was fixed by a complex change in PR #138672, but that PR did not add the test case. Let's add it now, because it's the only known reproducer of the OOM. --- tests/ui/resolve/query-cycle-issue-124901.rs | 24 +++++++++++++++++++ .../resolve/query-cycle-issue-124901.stderr | 9 +++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/ui/resolve/query-cycle-issue-124901.rs create mode 100644 tests/ui/resolve/query-cycle-issue-124901.stderr diff --git a/tests/ui/resolve/query-cycle-issue-124901.rs b/tests/ui/resolve/query-cycle-issue-124901.rs new file mode 100644 index 0000000000000..6cb1e58b6258f --- /dev/null +++ b/tests/ui/resolve/query-cycle-issue-124901.rs @@ -0,0 +1,24 @@ +//~ ERROR: cycle detected when looking up span for `Default` +trait Default { + type Id; + + fn intu(&self) -> &Self::Id; +} + +impl, U: Copy> Default for U { + default type Id = T; + fn intu(&self) -> &Self::Id { + self + } +} + +fn specialization(t: T) -> U { + *t.intu() +} + +use std::num::NonZero; + +fn main() { + let assert_eq = NonZero::>>(0); + assert_eq!(specialization, None); +} diff --git a/tests/ui/resolve/query-cycle-issue-124901.stderr b/tests/ui/resolve/query-cycle-issue-124901.stderr new file mode 100644 index 0000000000000..9c1d7b1de33a5 --- /dev/null +++ b/tests/ui/resolve/query-cycle-issue-124901.stderr @@ -0,0 +1,9 @@ +error[E0391]: cycle detected when looking up span for `Default` + | + = note: ...which immediately requires looking up span for `Default` again + = note: cycle used when perform lints prior to AST lowering + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. From 48bcaf7ed1795ceb8b1e4ad4822e7e85e2cb5de5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 18:34:46 +1100 Subject: [PATCH 4/5] Revert the `QueryStackFrameExtra`/`QueryStackDeferred` split. PR #138672 introduced a complex and invasive split of `QueryStackFrame` to avoid a query cycle. This commit reverts that change because there is a much simpler change that fixes the problem, which will be in the next commit. --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 2 +- compiler/rustc_middle/src/values.rs | 4 +- compiler/rustc_query_impl/src/lib.rs | 11 +- compiler/rustc_query_impl/src/plumbing.rs | 86 ++++-------- .../rustc_query_system/src/query/config.rs | 5 +- compiler/rustc_query_system/src/query/job.rs | 131 ++++++++---------- compiler/rustc_query_system/src/query/mod.rs | 129 ++++------------- .../rustc_query_system/src/query/plumbing.rs | 61 ++++---- 9 files changed, 145 insertions(+), 286 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index fc1bf78c82f35..285097832ba97 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -87,7 +87,7 @@ use rustc_index::IndexVec; use rustc_lint_defs::LintId; use rustc_macros::rustc_queries; use rustc_query_system::ich::StableHashingContext; -use rustc_query_system::query::{QueryMode, QueryStackDeferred, QueryState}; +use rustc_query_system::query::{QueryMode, QueryState}; use rustc_session::Limits; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{ diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 25c9a0a81ab48..df333e68add1a 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -431,7 +431,7 @@ macro_rules! define_callbacks { #[derive(Default)] pub struct QueryStates<'tcx> { $( - pub $name: QueryState<$($K)*, QueryStackDeferred<'tcx>>, + pub $name: QueryState<$($K)*>, )* } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index bc73d36216ef4..8d614a535498f 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -88,7 +88,7 @@ impl<'tcx> Value> for Representability { if info.query.dep_kind == dep_kinds::representability && let Some(field_id) = info.query.def_id && let Some(field_id) = field_id.as_local() - && let Some(DefKind::Field) = info.query.info.def_kind + && let Some(DefKind::Field) = info.query.def_kind { let parent_id = tcx.parent(field_id.to_def_id()); let item_id = match tcx.def_kind(parent_id) { @@ -224,7 +224,7 @@ impl<'tcx, T> Value> for Result> continue; }; let frame_span = - frame.query.info.default_span(cycle[(i + 1) % cycle.len()].span); + frame.query.default_span(cycle[(i + 1) % cycle.len()].span); if frame_span.is_dummy() { continue; } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 6904af771f0cc..f763b707aa234 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -21,8 +21,8 @@ use rustc_middle::ty::TyCtxt; use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryStackDeferred, - QueryState, get_query_incr, get_query_non_incr, + CycleError, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode, QueryState, + get_query_incr, get_query_non_incr, }; use rustc_query_system::{HandleCycleError, Value}; use rustc_span::{ErrorGuaranteed, Span}; @@ -79,10 +79,7 @@ where } #[inline(always)] - fn query_state<'a>( - self, - qcx: QueryCtxt<'tcx>, - ) -> &'a QueryState> + fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState where QueryCtxt<'tcx>: 'a, { @@ -91,7 +88,7 @@ where unsafe { &*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>) .byte_add(self.dynamic.query_state) - .cast::>>() + .cast::>() } } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index c98affe0cb198..ba1a358d24151 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -6,7 +6,6 @@ use std::num::NonZero; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash64; use rustc_hir::limit::Limit; @@ -27,8 +26,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect, - QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra, force_query, + QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect, QueryStackFrame, + force_query, }; use rustc_query_system::{QueryOverflow, QueryOverflowNote}; use rustc_serialize::{Decodable, Encodable}; @@ -67,9 +66,7 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> { } } -impl<'tcx> QueryContext for QueryCtxt<'tcx> { - type QueryInfo = QueryStackDeferred<'tcx>; - +impl QueryContext for QueryCtxt<'_> { #[inline] fn jobserver_proxy(&self) -> &Proxy { &*self.jobserver_proxy @@ -98,10 +95,7 @@ impl<'tcx> QueryContext for QueryCtxt<'tcx> { /// Prefer passing `false` to `require_complete` to avoid potential deadlocks, /// especially when called from within a deadlock handler, unless a /// complete map is needed and no deadlock is possible at this call site. - fn collect_active_jobs( - self, - require_complete: bool, - ) -> Result>, QueryMap>> { + fn collect_active_jobs(self, require_complete: bool) -> Result { let mut jobs = QueryMap::default(); let mut complete = true; @@ -114,13 +108,6 @@ impl<'tcx> QueryContext for QueryCtxt<'tcx> { if complete { Ok(jobs) } else { Err(jobs) } } - fn lift_query_info( - self, - info: &QueryStackDeferred<'tcx>, - ) -> rustc_query_system::query::QueryStackFrameExtra { - info.extract() - } - // Interactions with on_disk_cache fn load_side_effect( self, @@ -181,10 +168,7 @@ impl<'tcx> QueryContext for QueryCtxt<'tcx> { self.sess.dcx().emit_fatal(QueryOverflow { span: info.job.span, - note: QueryOverflowNote { - desc: self.lift_query_info(&info.query.info).description, - depth, - }, + note: QueryOverflowNote { desc: info.query.description, depth }, suggested_limit, crate_name: self.crate_name(LOCAL_CRATE), }); @@ -321,17 +305,16 @@ macro_rules! should_ever_cache_on_disk { }; } -fn create_query_frame_extra<'tcx, K: Key + Copy + 'tcx>( - (tcx, key, kind, name, do_describe): ( - TyCtxt<'tcx>, - K, - DepKind, - &'static str, - fn(TyCtxt<'tcx>, K) -> String, - ), -) -> QueryStackFrameExtra { - let def_id = key.key_as_def_id(); - +pub(crate) fn create_query_frame< + 'tcx, + K: Copy + Key + for<'a> HashStable>, +>( + tcx: TyCtxt<'tcx>, + do_describe: fn(TyCtxt<'tcx>, K) -> String, + key: K, + kind: DepKind, + name: &'static str, +) -> QueryStackFrame { // If reduced queries are requested, we may be printing a query stack due // to a panic. Avoid using `default_span` and `def_kind` in that case. let reduce_queries = with_reduced_queries(); @@ -343,6 +326,7 @@ fn create_query_frame_extra<'tcx, K: Key + Copy + 'tcx>( } else { description }; + let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries { // The `def_span` query is used to calculate `default_span`, // so exit to avoid infinite recursion. @@ -351,41 +335,25 @@ fn create_query_frame_extra<'tcx, K: Key + Copy + 'tcx>( Some(key.default_span(tcx)) }; + let def_id = key.key_as_def_id(); + let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries { // Try to avoid infinite recursion. None } else { def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) }; - QueryStackFrameExtra::new(description, span, def_kind) -} - -pub(crate) fn create_query_frame< - 'tcx, - K: Copy + DynSend + DynSync + Key + for<'a> HashStable> + 'tcx, ->( - tcx: TyCtxt<'tcx>, - do_describe: fn(TyCtxt<'tcx>, K) -> String, - key: K, - kind: DepKind, - name: &'static str, -) -> QueryStackFrame> { - let def_id = key.key_as_def_id(); - let hash = || { - tcx.with_stable_hashing_context(|mut hcx| { - let mut hasher = StableHasher::new(); - kind.as_usize().hash_stable(&mut hcx, &mut hasher); - key.hash_stable(&mut hcx, &mut hasher); - hasher.finish::() - }) - }; let def_id_for_ty_in_cycle = key.def_id_for_ty_in_cycle(); - let info = - QueryStackDeferred::new((tcx, key, kind, name, do_describe), create_query_frame_extra); + let hash = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + kind.as_usize().hash_stable(&mut hcx, &mut hasher); + key.hash_stable(&mut hcx, &mut hasher); + hasher.finish::() + }); - QueryStackFrame::new(info, kind, hash, def_id, def_id_for_ty_in_cycle) + QueryStackFrame::new(description, span, def_id, def_kind, kind, def_id_for_ty_in_cycle, hash) } pub(crate) fn encode_query_results<'a, 'tcx, Q>( @@ -737,7 +705,7 @@ macro_rules! define_queries { pub(crate) fn collect_active_jobs<'tcx>( tcx: TyCtxt<'tcx>, - qmap: &mut QueryMap>, + qmap: &mut QueryMap, require_complete: bool, ) -> Option<()> { let make_query = |tcx, key| { @@ -821,7 +789,7 @@ macro_rules! define_queries { // These arrays are used for iteration and can't be indexed by `DepKind`. const COLLECT_ACTIVE_JOBS: &[ - for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap>, bool) -> Option<()> + for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap, bool) -> Option<()> ] = &[$(query_impl::$name::collect_active_jobs),*]; diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index e508eadb73b0b..371b896400a58 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -6,7 +6,6 @@ use std::hash::Hash; use rustc_data_structures::fingerprint::Fingerprint; use rustc_span::ErrorGuaranteed; -use super::QueryStackFrameExtra; use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex}; use crate::error::HandleCycleError; use crate::ich::StableHashingContext; @@ -28,7 +27,7 @@ pub trait QueryConfig: Copy { fn format_value(self) -> fn(&Self::Value) -> String; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState + fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState where Qcx: 'a; @@ -58,7 +57,7 @@ pub trait QueryConfig: Copy { fn value_from_cycle_error( self, tcx: Qcx::DepContext, - cycle_error: &CycleError, + cycle_error: &CycleError, guar: ErrorGuaranteed, ) -> Self::Value; diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 7d9b594d501ff..4a9b6a0d557cb 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -1,4 +1,3 @@ -use std::fmt::Debug; use std::hash::Hash; use std::io::Write; use std::iter; @@ -12,7 +11,6 @@ use rustc_hir::def::DefKind; use rustc_session::Session; use rustc_span::{DUMMY_SP, Span}; -use super::QueryStackFrameExtra; use crate::dep_graph::DepContext; use crate::error::CycleStack; use crate::query::plumbing::CycleError; @@ -20,54 +18,45 @@ use crate::query::{QueryContext, QueryStackFrame}; /// Represents a span and a query key. #[derive(Clone, Debug)] -pub struct QueryInfo { +pub struct QueryInfo { /// The span corresponding to the reason for which this query was required. pub span: Span, - pub query: QueryStackFrame, + pub query: QueryStackFrame, } -impl QueryInfo { - pub(crate) fn lift>( - &self, - qcx: Qcx, - ) -> QueryInfo { - QueryInfo { span: self.span, query: self.query.lift(qcx) } - } -} - -pub type QueryMap = FxHashMap>; +pub type QueryMap = FxHashMap; /// A value uniquely identifying an active query job. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct QueryJobId(pub NonZero); impl QueryJobId { - fn query(self, map: &QueryMap) -> QueryStackFrame { + fn query(self, map: &QueryMap) -> QueryStackFrame { map.get(&self).unwrap().query.clone() } - fn span(self, map: &QueryMap) -> Span { + fn span(self, map: &QueryMap) -> Span { map.get(&self).unwrap().job.span } - fn parent(self, map: &QueryMap) -> Option { + fn parent(self, map: &QueryMap) -> Option { map.get(&self).unwrap().job.parent } - fn latch(self, map: &QueryMap) -> Option<&QueryLatch> { + fn latch(self, map: &QueryMap) -> Option<&QueryLatch> { map.get(&self).unwrap().job.latch.as_ref() } } #[derive(Clone, Debug)] -pub struct QueryJobInfo { - pub query: QueryStackFrame, - pub job: QueryJob, +pub struct QueryJobInfo { + pub query: QueryStackFrame, + pub job: QueryJob, } /// Represents an active query job. #[derive(Debug)] -pub struct QueryJob { +pub struct QueryJob { pub id: QueryJobId, /// The span corresponding to the reason for which this query was required. @@ -77,23 +66,23 @@ pub struct QueryJob { pub parent: Option, /// The latch that is used to wait on this job. - latch: Option>, + latch: Option, } -impl Clone for QueryJob { +impl Clone for QueryJob { fn clone(&self) -> Self { Self { id: self.id, span: self.span, parent: self.parent, latch: self.latch.clone() } } } -impl QueryJob { +impl QueryJob { /// Creates a new query job. #[inline] pub fn new(id: QueryJobId, span: Span, parent: Option) -> Self { QueryJob { id, span, parent, latch: None } } - pub(super) fn latch(&mut self) -> QueryLatch { + pub(super) fn latch(&mut self) -> QueryLatch { if self.latch.is_none() { self.latch = Some(QueryLatch::new()); } @@ -113,12 +102,12 @@ impl QueryJob { } impl QueryJobId { - pub(super) fn find_cycle_in_stack( + pub(super) fn find_cycle_in_stack( &self, - query_map: QueryMap, + query_map: QueryMap, current_job: &Option, span: Span, - ) -> CycleError { + ) -> CycleError { // Find the waitee amongst `current_job` parents let mut cycle = Vec::new(); let mut current_job = Option::clone(current_job); @@ -152,7 +141,7 @@ impl QueryJobId { #[cold] #[inline(never)] - pub fn find_dep_kind_root(&self, query_map: QueryMap) -> (QueryJobInfo, usize) { + pub fn find_dep_kind_root(&self, query_map: QueryMap) -> (QueryJobInfo, usize) { let mut depth = 1; let info = query_map.get(&self).unwrap(); let dep_kind = info.query.dep_kind; @@ -172,31 +161,31 @@ impl QueryJobId { } #[derive(Debug)] -struct QueryWaiter { +struct QueryWaiter { query: Option, condvar: Condvar, span: Span, - cycle: Mutex>>, + cycle: Mutex>, } #[derive(Debug)] -struct QueryLatchInfo { +struct QueryLatchInfo { complete: bool, - waiters: Vec>>, + waiters: Vec>, } #[derive(Debug)] -pub(super) struct QueryLatch { - info: Arc>>, +pub(super) struct QueryLatch { + info: Arc>, } -impl Clone for QueryLatch { +impl Clone for QueryLatch { fn clone(&self) -> Self { Self { info: Arc::clone(&self.info) } } } -impl QueryLatch { +impl QueryLatch { fn new() -> Self { QueryLatch { info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), @@ -209,7 +198,7 @@ impl QueryLatch { qcx: impl QueryContext, query: Option, span: Span, - ) -> Result<(), CycleError> { + ) -> Result<(), CycleError> { let waiter = Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); self.wait_on_inner(qcx, &waiter); @@ -224,7 +213,7 @@ impl QueryLatch { } /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, qcx: impl QueryContext, waiter: &Arc>) { + fn wait_on_inner(&self, qcx: impl QueryContext, waiter: &Arc) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -260,7 +249,7 @@ impl QueryLatch { /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. - fn extract_waiter(&self, waiter: usize) -> Arc> { + fn extract_waiter(&self, waiter: usize) -> Arc { let mut info = self.info.lock(); debug_assert!(!info.complete); // Remove the waiter from the list of waiters @@ -280,11 +269,7 @@ type Waiter = (QueryJobId, usize); /// For visits of resumable waiters it returns Some(Some(Waiter)) which has the /// required information to resume the waiter. /// If all `visit` calls returns None, this function also returns None. -fn visit_waiters( - query_map: &QueryMap, - query: QueryJobId, - mut visit: F, -) -> Option> +fn visit_waiters(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option> where F: FnMut(Span, QueryJobId) -> Option>, { @@ -314,8 +299,8 @@ where /// `span` is the reason for the `query` to execute. This is initially DUMMY_SP. /// If a cycle is detected, this initial value is replaced with the span causing /// the cycle. -fn cycle_check( - query_map: &QueryMap, +fn cycle_check( + query_map: &QueryMap, query: QueryJobId, span: Span, stack: &mut Vec<(Span, QueryJobId)>, @@ -354,8 +339,8 @@ fn cycle_check( /// Finds out if there's a path to the compiler root (aka. code which isn't in a query) /// from `query` without going through any of the queries in `visited`. /// This is achieved with a depth first search. -fn connected_to_root( - query_map: &QueryMap, +fn connected_to_root( + query_map: &QueryMap, query: QueryJobId, visited: &mut FxHashSet, ) -> bool { @@ -376,7 +361,7 @@ fn connected_to_root( } // Deterministically pick an query from a list -fn pick_query<'a, I: Clone, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T +fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T where F: Fn(&T) -> (Span, QueryJobId), { @@ -401,10 +386,10 @@ where /// the function return true. /// If a cycle was not found, the starting query is removed from `jobs` and /// the function returns false. -fn remove_cycle( - query_map: &QueryMap, +fn remove_cycle( + query_map: &QueryMap, jobs: &mut Vec, - wakelist: &mut Vec>>, + wakelist: &mut Vec>, ) -> bool { let mut visited = FxHashSet::default(); let mut stack = Vec::new(); @@ -505,10 +490,7 @@ fn remove_cycle( /// uses a query latch and then resuming that waiter. /// There may be multiple cycles involved in a deadlock, so this searches /// all active queries for cycles before finally resuming all the waiters at once. -pub fn break_query_cycles( - query_map: QueryMap, - registry: &rustc_thread_pool::Registry, -) { +pub fn break_query_cycles(query_map: QueryMap, registry: &rustc_thread_pool::Registry) { let mut wakelist = Vec::new(); // It is OK per the comments: // - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798854932 @@ -559,7 +541,7 @@ pub fn report_cycle<'a>( ) -> Diag<'a> { assert!(!stack.is_empty()); - let span = stack[0].query.info.default_span(stack[1 % stack.len()].span); + let span = stack[0].query.default_span(stack[1 % stack.len()].span); let mut cycle_stack = Vec::new(); @@ -568,31 +550,31 @@ pub fn report_cycle<'a>( for i in 1..stack.len() { let query = &stack[i].query; - let span = query.info.default_span(stack[(i + 1) % stack.len()].span); - cycle_stack.push(CycleStack { span, desc: query.info.description.to_owned() }); + let span = query.default_span(stack[(i + 1) % stack.len()].span); + cycle_stack.push(CycleStack { span, desc: query.description.to_owned() }); } let mut cycle_usage = None; if let Some((span, ref query)) = *usage { cycle_usage = Some(crate::error::CycleUsage { - span: query.info.default_span(span), - usage: query.info.description.to_string(), + span: query.default_span(span), + usage: query.description.to_string(), }); } - let alias = - if stack.iter().all(|entry| matches!(entry.query.info.def_kind, Some(DefKind::TyAlias))) { - Some(crate::error::Alias::Ty) - } else if stack.iter().all(|entry| entry.query.info.def_kind == Some(DefKind::TraitAlias)) { - Some(crate::error::Alias::Trait) - } else { - None - }; + let alias = if stack.iter().all(|entry| matches!(entry.query.def_kind, Some(DefKind::TyAlias))) + { + Some(crate::error::Alias::Ty) + } else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) { + Some(crate::error::Alias::Trait) + } else { + None + }; let cycle_diag = crate::error::Cycle { span, cycle_stack, - stack_bottom: stack[0].query.info.description.to_owned(), + stack_bottom: stack[0].query.description.to_owned(), alias, cycle_usage, stack_count, @@ -628,7 +610,6 @@ pub fn print_query_stack( let Some(query_info) = query_map.get(&query) else { break; }; - let query_extra = qcx.lift_query_info(&query_info.query.info); if Some(count_printed) < limit_frames || limit_frames.is_none() { // Only print to stderr as many stack frames as `num_frames` when present. // FIXME: needs translation @@ -636,7 +617,7 @@ pub fn print_query_stack( #[allow(rustc::untranslatable_diagnostic)] dcx.struct_failure_note(format!( "#{} [{:?}] {}", - count_printed, query_info.query.dep_kind, query_extra.description + count_printed, query_info.query.dep_kind, query_info.query.description )) .with_span(query_info.job.span) .emit(); @@ -649,7 +630,7 @@ pub fn print_query_stack( "#{} [{}] {}", count_total, qcx.dep_context().dep_kind_info(query_info.query.dep_kind).name, - query_extra.description + query_info.query.description ); } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index ce3456d532e69..b524756d81b61 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -1,23 +1,4 @@ -mod plumbing; -use std::fmt::Debug; -use std::marker::PhantomData; -use std::mem::transmute; -use std::sync::Arc; - -pub use self::plumbing::*; - -mod job; -pub use self::job::{ - QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack, - report_cycle, -}; - -mod caches; -pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; - -mod config; use rustc_data_structures::jobserver::Proxy; -use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::DiagInner; use rustc_hashes::Hash64; use rustc_hir::def::DefKind; @@ -25,66 +6,49 @@ use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; use rustc_span::def_id::DefId; +pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; pub use self::config::{HashResult, QueryConfig}; +pub use self::job::{ + QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack, + report_cycle, +}; +pub use self::plumbing::*; use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; +mod caches; +mod config; +mod job; +mod plumbing; + /// Description of a frame in the query stack. /// /// This is mostly used in case of cycles for error reporting. #[derive(Clone, Debug)] -pub struct QueryStackFrame { - /// This field initially stores a `QueryStackDeferred` during collection, - /// but can later be changed to `QueryStackFrameExtra` containing concrete information - /// by calling `lift`. This is done so that collecting query does not need to invoke - /// queries, instead `lift` will call queries in a more appropriate location. - pub info: I, - +pub struct QueryStackFrame { + pub description: String, + span: Option, + pub def_id: Option, + pub def_kind: Option, + /// A def-id that is extracted from a `Ty` in a query key + pub def_id_for_ty_in_cycle: Option, pub dep_kind: DepKind, /// This hash is used to deterministically pick /// a query to remove cycles in the parallel compiler. hash: Hash64, - pub def_id: Option, - /// A def-id that is extracted from a `Ty` in a query key - pub def_id_for_ty_in_cycle: Option, } -impl QueryStackFrame { +impl QueryStackFrame { #[inline] pub fn new( - info: I, - dep_kind: DepKind, - hash: impl FnOnce() -> Hash64, + description: String, + span: Option, def_id: Option, + def_kind: Option, + dep_kind: DepKind, def_id_for_ty_in_cycle: Option, + hash: Hash64, ) -> Self { - Self { info, def_id, dep_kind, hash: hash(), def_id_for_ty_in_cycle } - } - - fn lift>( - &self, - qcx: Qcx, - ) -> QueryStackFrame { - QueryStackFrame { - info: qcx.lift_query_info(&self.info), - dep_kind: self.dep_kind, - hash: self.hash, - def_id: self.def_id, - def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle, - } - } -} - -#[derive(Clone, Debug)] -pub struct QueryStackFrameExtra { - pub description: String, - span: Option, - pub def_kind: Option, -} - -impl QueryStackFrameExtra { - #[inline] - pub fn new(description: String, span: Option, def_kind: Option) -> Self { - Self { description, span, def_kind } + Self { description, span, def_id, def_kind, def_id_for_ty_in_cycle, dep_kind, hash } } // FIXME(eddyb) Get more valid `Span`s on queries. @@ -97,40 +61,6 @@ impl QueryStackFrameExtra { } } -/// Track a 'side effect' for a particular query. -/// This is used to hold a closure which can create `QueryStackFrameExtra`. -#[derive(Clone)] -pub struct QueryStackDeferred<'tcx> { - _dummy: PhantomData<&'tcx ()>, - - // `extract` may contain references to 'tcx, but we can't tell drop checking that it won't - // access it in the destructor. - extract: Arc QueryStackFrameExtra + DynSync + DynSend>, -} - -impl<'tcx> QueryStackDeferred<'tcx> { - pub fn new( - context: C, - extract: fn(C) -> QueryStackFrameExtra, - ) -> Self { - let extract: Arc QueryStackFrameExtra + DynSync + DynSend + 'tcx> = - Arc::new(move || extract(context)); - // SAFETY: The `extract` closure does not access 'tcx in its destructor as the only - // captured variable is `context` which is Copy and cannot have a destructor. - Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } } - } - - pub fn extract(&self) -> QueryStackFrameExtra { - (self.extract)() - } -} - -impl<'tcx> Debug for QueryStackDeferred<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("QueryStackDeferred") - } -} - /// Tracks 'side effects' for a particular query. /// This struct is saved to disk along with the query result, /// and loaded from disk if we mark the query as green. @@ -150,8 +80,6 @@ pub enum QuerySideEffect { } pub trait QueryContext: HasDepContext { - type QueryInfo: Clone; - /// Gets a jobserver reference which is used to release then acquire /// a token while waiting on a query. fn jobserver_proxy(&self) -> &Proxy; @@ -161,12 +89,7 @@ pub trait QueryContext: HasDepContext { /// Get the query information from the TLS context. fn current_query_job(self) -> Option; - fn collect_active_jobs( - self, - require_complete: bool, - ) -> Result, QueryMap>; - - fn lift_query_info(self, info: &Self::QueryInfo) -> QueryStackFrameExtra; + fn collect_active_jobs(self, require_complete: bool) -> Result; /// Load a side effect associated to the node in the previous session. fn load_side_effect( diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index dea47c8fa787e..fa5a94d651885 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -18,7 +18,7 @@ use rustc_errors::{Diag, FatalError, StashKey}; use rustc_span::{DUMMY_SP, Span}; use tracing::instrument; -use super::{QueryConfig, QueryStackFrameExtra}; +use super::QueryConfig; use crate::HandleCycleError; use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams}; use crate::ich::StableHashingContext; @@ -31,23 +31,23 @@ fn equivalent_key(k: &K) -> impl Fn(&(K, V)) -> bool + '_ { move |x| x.0 == *k } -pub struct QueryState { - active: Sharded)>>, +pub struct QueryState { + active: Sharded>, } /// Indicates the state of a query for a given key in a query map. -enum QueryResult { +enum QueryResult { /// An already executing query. The query job can be used to await for its completion. - Started(QueryJob), + Started(QueryJob), /// The query panicked. Queries trying to wait on this will raise a fatal error which will /// silently panic. Poisoned, } -impl QueryResult { +impl QueryResult { /// Unwraps the query job expecting that it has started. - fn expect_job(self) -> QueryJob { + fn expect_job(self) -> QueryJob { match self { Self::Started(job) => job, Self::Poisoned => { @@ -57,7 +57,7 @@ impl QueryResult { } } -impl QueryState +impl QueryState where K: Eq + Hash + Copy + Debug, { @@ -68,13 +68,13 @@ where pub fn collect_active_jobs( &self, qcx: Qcx, - make_query: fn(Qcx, K) -> QueryStackFrame, - jobs: &mut QueryMap, + make_query: fn(Qcx, K) -> QueryStackFrame, + jobs: &mut QueryMap, require_complete: bool, ) -> Option<()> { let mut active = Vec::new(); - let mut collect = |iter: LockGuard<'_, HashTable<(K, QueryResult)>>| { + let mut collect = |iter: LockGuard<'_, HashTable<(K, QueryResult)>>| { for (k, v) in iter.iter() { if let QueryResult::Started(ref job) = *v { active.push((*k, job.clone())); @@ -105,19 +105,19 @@ where } } -impl Default for QueryState { - fn default() -> QueryState { +impl Default for QueryState { + fn default() -> QueryState { QueryState { active: Default::default() } } } /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. -struct JobOwner<'tcx, K, I> +struct JobOwner<'tcx, K> where K: Eq + Hash + Copy, { - state: &'tcx QueryState, + state: &'tcx QueryState, key: K, } @@ -159,7 +159,7 @@ where } Stash => { let guar = if let Some(root) = cycle_error.cycle.first() - && let Some(span) = root.query.info.span + && let Some(span) = root.query.span { error.stash(span, StashKey::Cycle).unwrap() } else { @@ -170,7 +170,7 @@ where } } -impl<'tcx, K, I> JobOwner<'tcx, K, I> +impl<'tcx, K> JobOwner<'tcx, K> where K: Eq + Hash + Copy, { @@ -207,7 +207,7 @@ where } } -impl<'tcx, K, I> Drop for JobOwner<'tcx, K, I> +impl<'tcx, K> Drop for JobOwner<'tcx, K> where K: Eq + Hash + Copy, { @@ -235,19 +235,10 @@ where } #[derive(Clone, Debug)] -pub struct CycleError { +pub struct CycleError { /// The query and related span that uses the cycle. - pub usage: Option<(Span, QueryStackFrame)>, - pub cycle: Vec>, -} - -impl CycleError { - fn lift>(&self, qcx: Qcx) -> CycleError { - CycleError { - usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift(qcx))), - cycle: self.cycle.iter().map(|info| info.lift(qcx)).collect(), - } - } + pub usage: Option<(Span, QueryStackFrame)>, + pub cycle: Vec, } /// Checks whether there is already a value for this key in the in-memory @@ -284,10 +275,10 @@ where { // Ensure there was no errors collecting all active jobs. // We need the complete map to ensure we find a cycle to break. - let query_map = qcx.collect_active_jobs(false).ok().expect("failed to collect active queries"); + let query_map = qcx.collect_active_jobs(false).expect("failed to collect active queries"); let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span); - (mk_cycle(query, qcx, error.lift(qcx)), None) + (mk_cycle(query, qcx, error), None) } #[inline(always)] @@ -296,7 +287,7 @@ fn wait_for_query( qcx: Qcx, span: Span, key: Q::Key, - latch: QueryLatch, + latch: QueryLatch, current: Option, ) -> (Q::Value, Option) where @@ -336,7 +327,7 @@ where (v, Some(index)) } - Err(cycle) => (mk_cycle(query, qcx, cycle.lift(qcx)), None), + Err(cycle) => (mk_cycle(query, qcx, cycle), None), } } @@ -414,7 +405,7 @@ where fn execute_job( query: Q, qcx: Qcx, - state: &QueryState, + state: &QueryState, key: Q::Key, key_hash: u64, id: QueryJobId, From 90e4a421623ed4e9f8e1985795456f734ec822a1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Jan 2026 19:18:16 +1100 Subject: [PATCH 5/5] Use `with_reduced_queries` to avoid query cycles. This changes the error message of `query-cycle-issue-124901.rs`, which doesn't matter much. --- compiler/rustc_query_impl/src/plumbing.rs | 10 ++++++---- tests/ui/resolve/query-cycle-issue-124901.rs | 2 +- tests/ui/resolve/query-cycle-issue-124901.stderr | 9 ++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index ba1a358d24151..67ab1114af62b 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -327,21 +327,23 @@ pub(crate) fn create_query_frame< description }; - let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries { + let span = if reduce_queries { // The `def_span` query is used to calculate `default_span`, // so exit to avoid infinite recursion. None } else { - Some(key.default_span(tcx)) + Some(tcx.with_reduced_queries(|| key.default_span(tcx))) }; let def_id = key.key_as_def_id(); - let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries { + let def_kind = if reduce_queries { // Try to avoid infinite recursion. None } else { - def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) + def_id + .and_then(|def_id| def_id.as_local()) + .map(|def_id| tcx.with_reduced_queries(|| tcx.def_kind(def_id))) }; let def_id_for_ty_in_cycle = key.def_id_for_ty_in_cycle(); diff --git a/tests/ui/resolve/query-cycle-issue-124901.rs b/tests/ui/resolve/query-cycle-issue-124901.rs index 6cb1e58b6258f..ccaee0e6bc6fd 100644 --- a/tests/ui/resolve/query-cycle-issue-124901.rs +++ b/tests/ui/resolve/query-cycle-issue-124901.rs @@ -1,4 +1,4 @@ -//~ ERROR: cycle detected when looking up span for `Default` +//~ ERROR: cycle detected when getting HIR ID of `Default` trait Default { type Id; diff --git a/tests/ui/resolve/query-cycle-issue-124901.stderr b/tests/ui/resolve/query-cycle-issue-124901.stderr index 9c1d7b1de33a5..3679925c6db42 100644 --- a/tests/ui/resolve/query-cycle-issue-124901.stderr +++ b/tests/ui/resolve/query-cycle-issue-124901.stderr @@ -1,7 +1,10 @@ -error[E0391]: cycle detected when looking up span for `Default` +error[E0391]: cycle detected when getting HIR ID of `Default` | - = note: ...which immediately requires looking up span for `Default` again - = note: cycle used when perform lints prior to AST lowering + = note: ...which requires getting the crate HIR... + = note: ...which requires perform lints prior to AST lowering... + = note: ...which requires looking up span for `Default`... + = note: ...which again requires getting HIR ID of `Default`, completing the cycle + = note: cycle used when getting the resolver for lowering = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error