Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_interface/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ pub(crate) fn run_in_thread_pool_with_globals<

use rustc_data_structures::defer;
use rustc_middle::ty::tls;
use rustc_query_impl::break_query_cycles;
use rustc_query_impl::break_query_cycle;

let thread_stack_size = init_stack_size(thread_builder_diag);

Expand Down Expand Up @@ -260,7 +260,7 @@ internal compiler error: query cycle handler thread panicked, aborting process";
)
},
);
break_query_cycles(job_map, &registry);
break_query_cycle(job_map, &registry);
})
})
});
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::ErrorGuaranteed;
use rustc_errors::{ErrorGuaranteed, catch_fatal_errors};
use rustc_hir as hir;
use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem};
use rustc_hir::def::{DefKind, DocLinkResMap};
Expand Down
16 changes: 12 additions & 4 deletions compiler/rustc_middle/src/query/inner.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//! Helper functions that serve as the immediate implementation of
//! `tcx.$query(..)` and its variations.

use std::panic::Location;

use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};

use crate::dep_graph;
use crate::dep_graph::DepNodeKey;
use crate::query::erase::{self, Erasable, Erased};
use crate::query::{EnsureMode, QueryCache, QueryMode, QueryVTable};
use crate::query::{EnsureMode, QueryCache, QueryCallContext, QueryMode, QueryVTable};
use crate::ty::TyCtxt;

/// Checks whether there is already a value for this key in the in-memory
Expand All @@ -31,6 +33,7 @@ where
/// Shared implementation of `tcx.$query(..)` and `tcx.at(span).$query(..)`
/// for all queries.
#[inline(always)]
#[track_caller]
pub(crate) fn query_get_at<'tcx, C>(
tcx: TyCtxt<'tcx>,
span: Span,
Expand All @@ -40,15 +43,17 @@ pub(crate) fn query_get_at<'tcx, C>(
where
C: QueryCache,
{
let call_context = QueryCallContext { span, location: Some(Location::caller()) };
match try_get_cached(tcx, &query.cache, key) {
Some(value) => value,
None => (query.execute_query_fn)(tcx, span, key, QueryMode::Get).unwrap(),
None => (query.execute_query_fn)(tcx, call_context, key, QueryMode::Get).unwrap(),
}
}

/// Shared implementation of `tcx.ensure_ok().$query(..)` and
/// `tcx.ensure_done().$query(..)` for all queries.
#[inline]
#[track_caller]
pub(crate) fn query_ensure_ok_or_done<'tcx, C>(
tcx: TyCtxt<'tcx>,
query: &'tcx QueryVTable<'tcx, C>,
Expand All @@ -57,17 +62,19 @@ pub(crate) fn query_ensure_ok_or_done<'tcx, C>(
) where
C: QueryCache,
{
let call_context = QueryCallContext { span: DUMMY_SP, location: Some(Location::caller()) };
match try_get_cached(tcx, &query.cache, key) {
Some(_value) => {}
None => {
(query.execute_query_fn)(tcx, DUMMY_SP, key, QueryMode::Ensure { ensure_mode });
(query.execute_query_fn)(tcx, call_context, key, QueryMode::Ensure { ensure_mode });
}
}
}

/// Implementation of `tcx.ensure_result().$query(..)` for queries that
/// return `Result<_, ErrorGuaranteed>`.
#[inline]
#[track_caller]
pub(crate) fn query_ensure_result<'tcx, C, T>(
tcx: TyCtxt<'tcx>,
query: &'tcx QueryVTable<'tcx, C>,
Expand All @@ -77,6 +84,7 @@ where
C: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
Result<T, ErrorGuaranteed>: Erasable,
{
let call_context = QueryCallContext { span: DUMMY_SP, location: Some(Location::caller()) };
let convert = |value: Erased<Result<T, ErrorGuaranteed>>| -> Result<(), ErrorGuaranteed> {
match erase::restore_val(value) {
Ok(_) => Ok(()),
Expand All @@ -89,7 +97,7 @@ where
None => {
match (query.execute_query_fn)(
tcx,
DUMMY_SP,
call_context,
key,
QueryMode::Ensure { ensure_mode: EnsureMode::Ok },
) {
Expand Down
17 changes: 8 additions & 9 deletions compiler/rustc_middle/src/query/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ use std::num::NonZero;
use std::sync::Arc;

use parking_lot::{Condvar, Mutex};
use rustc_span::Span;

use crate::query::Cycle;
use crate::query::{Cycle, QueryCallContext};
use crate::ty::TyCtxt;

/// A value uniquely identifying an active query job.
Expand All @@ -18,8 +17,8 @@ pub struct QueryJobId(pub NonZero<u64>);
pub struct QueryJob<'tcx> {
pub id: QueryJobId,

/// The span corresponding to the reason for which this query was required.
pub span: Span,
/// The span and call site corresponding to why this query was required.
pub call_context: QueryCallContext,

/// The parent query job which created this job and is implicitly waiting on it.
pub parent: Option<QueryJobId>,
Expand All @@ -31,8 +30,8 @@ pub struct QueryJob<'tcx> {
impl<'tcx> QueryJob<'tcx> {
/// Creates a new query job.
#[inline]
pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
QueryJob { id, span, parent, latch: None }
pub fn new(id: QueryJobId, call_context: QueryCallContext, parent: Option<QueryJobId>) -> Self {
QueryJob { id, call_context, parent, latch: None }
}

pub fn latch(&mut self) -> QueryLatch<'tcx> {
Expand All @@ -58,7 +57,7 @@ impl<'tcx> QueryJob<'tcx> {
pub struct QueryWaiter<'tcx> {
pub parent: Option<QueryJobId>,
pub condvar: Condvar,
pub span: Span,
pub call_context: QueryCallContext,
pub cycle: Mutex<Option<Cycle<'tcx>>>,
}

Expand All @@ -78,7 +77,7 @@ impl<'tcx> QueryLatch<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
query: Option<QueryJobId>,
span: Span,
call_context: QueryCallContext,
) -> Result<(), Cycle<'tcx>> {
let mut waiters_guard = self.waiters.lock();
let Some(waiters) = &mut *waiters_guard else {
Expand All @@ -87,7 +86,7 @@ impl<'tcx> QueryLatch<'tcx> {

let waiter = Arc::new(QueryWaiter {
parent: query,
span,
call_context,
cycle: Mutex::new(None),
condvar: Condvar::new(),
});
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub use self::plumbing::{
ActiveKeyStatus, Cycle, EnsureMode, QueryMode, QueryState, QuerySystem, QueryVTable, TyCtxtAt,
TyCtxtEnsureDone, TyCtxtEnsureOk, TyCtxtEnsureResult,
};
pub use self::stack::QueryStackFrame;
pub use self::stack::{QueryCallContext, QueryStackFrame};
pub use crate::queries::Providers;
use crate::ty::TyCtxt;

Expand Down
45 changes: 21 additions & 24 deletions compiler/rustc_middle/src/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::dep_graph::{DepKind, DepNodeIndex, QuerySideEffect, SerializedDepNode
use crate::ich::StableHashingContext;
use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables, TaggedQueryKey};
use crate::query::on_disk_cache::OnDiskCache;
use crate::query::{QueryCache, QueryJob, QueryStackFrame};
use crate::query::{QueryCache, QueryCallContext, QueryJob, QueryStackFrame};
use crate::ty::TyCtxt;

/// For a particular query, keeps track of "active" keys, i.e. keys whose
Expand Down Expand Up @@ -130,7 +130,7 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
/// and putting the obtained value into the in-memory cache.
///
/// [^1]: [`TyCtxt`], [`TyCtxtAt`], [`TyCtxtEnsureOk`], [`TyCtxtEnsureDone`]
pub execute_query_fn: fn(TyCtxt<'tcx>, Span, C::Key, QueryMode) -> Option<C::Value>,
pub execute_query_fn: fn(TyCtxt<'tcx>, QueryCallContext, C::Key, QueryMode) -> Option<C::Value>,
}

impl<'tcx, C: QueryCache> fmt::Debug for QueryVTable<'tcx, C> {
Expand Down Expand Up @@ -166,6 +166,8 @@ pub struct QuerySystem<'tcx> {
pub extern_providers: ExternProviders,

pub jobs: AtomicU64,

pub cycle_handler_nesting: Lock<u8>,
}

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -204,6 +206,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Returns a transparent wrapper for `TyCtxt` which uses
/// `span` as the location of queries performed through it.
#[inline(always)]
#[track_caller]
pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
TyCtxtAt { tcx: self, span }
}
Expand Down Expand Up @@ -231,6 +234,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Therefore, this call mode is not appropriate for callers that want to
/// ensure that the query is _never_ executed in the future.
#[inline(always)]
#[track_caller]
pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> {
TyCtxtEnsureOk { tcx: self }
}
Expand All @@ -241,6 +245,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// but nothing else. As with `ensure_ok`, this can be more efficient than
/// a normal query call.
#[inline(always)]
#[track_caller]
pub fn ensure_result(self) -> TyCtxtEnsureResult<'tcx> {
TyCtxtEnsureResult { tcx: self }
}
Expand All @@ -262,6 +267,7 @@ impl<'tcx> TyCtxt<'tcx> {
///
/// [`Steal`]: rustc_data_structures::steal::Steal
#[inline(always)]
#[track_caller]
pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> {
TyCtxtEnsureDone { tcx: self }
}
Expand Down Expand Up @@ -431,6 +437,11 @@ macro_rules! define_callbacks {
}
}

/// Calls `self.description` or returns a fallback if there was a fatal error
pub fn catch_description(&self, tcx: TyCtxt<'tcx>) -> String {
catch_fatal_errors(|| self.description(tcx)).unwrap_or_else(|_| format!("<error describing {}>", self.query_name()))
}

/// Returns the default span for this query if `span` is a dummy span.
pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
if !span.is_dummy() {
Expand All @@ -449,28 +460,9 @@ macro_rules! define_callbacks {
}
}

pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
// This is used to reduce code generation as it
// can be reused for queries with the same key type.
fn inner<'tcx>(key: &impl $crate::query::QueryKey, tcx: TyCtxt<'tcx>)
-> Option<DefKind>
{
key
.key_as_def_id()
.and_then(|def_id| def_id.as_local())
.map(|def_id| tcx.def_kind(def_id))
}

if let TaggedQueryKey::def_kind(..) = self {
// Try to avoid infinite recursion.
return None
}

match self {
$(
TaggedQueryKey::$name(key) => inner(key, tcx),
)*
}
/// Calls `self.default_span` or returns `DUMMY_SP` if there was a fatal error
pub fn catch_default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
catch_fatal_errors(|| self.default_span(tcx, span)).unwrap_or(DUMMY_SP)
}
}

Expand Down Expand Up @@ -554,6 +546,7 @@ macro_rules! define_callbacks {
$(
$(#[$attr])*
#[inline(always)]
#[track_caller]
#[must_use]
pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
self.at(DUMMY_SP).$name(key)
Expand All @@ -565,6 +558,7 @@ macro_rules! define_callbacks {
$(
$(#[$attr])*
#[inline(always)]
#[track_caller]
pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
use $crate::query::{erase, inner};

Expand All @@ -582,6 +576,7 @@ macro_rules! define_callbacks {
$(
$(#[$attr])*
#[inline(always)]
#[track_caller]
pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
$crate::query::inner::query_ensure_ok_or_done(
self.tcx,
Expand All @@ -599,6 +594,7 @@ macro_rules! define_callbacks {
#[cfg($returns_error_guaranteed)]
$(#[$attr])*
#[inline(always)]
#[track_caller]
pub fn $name(
self,
key: maybe_into_query_key!($($K)*),
Expand All @@ -616,6 +612,7 @@ macro_rules! define_callbacks {
$(
$(#[$attr])*
#[inline(always)]
#[track_caller]
pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
$crate::query::inner::query_ensure_ok_or_done(
self.tcx,
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_middle/src/query/stack.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
use std::panic::Location;

use rustc_span::Span;

use crate::queries::TaggedQueryKey;

#[derive(Clone, Copy, Debug)]
pub struct QueryCallContext {
pub span: Span,
pub location: Option<&'static Location<'static>>,
}

/// Description of a frame in the query stack.
///
/// This is mostly used in case of cycles for error reporting.
#[derive(Debug)]
pub struct QueryStackFrame<'tcx> {
pub span: Span,
pub call_context: QueryCallContext,

/// The query and key of the query method call that this stack frame
/// corresponds to.
Expand Down
32 changes: 32 additions & 0 deletions compiler/rustc_query_impl/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub(crate) struct CycleStack {
#[primary_span]
pub span: Span,
pub desc: String,
#[subdiagnostic]
pub location: Option<QueryLocationNote>,
}

#[derive(Subdiagnostic)]
Expand Down Expand Up @@ -58,6 +60,14 @@ pub(crate) struct CycleUsage {
#[primary_span]
pub span: Span,
pub usage: String,
#[subdiagnostic]
pub location: Option<QueryLocationNote>,
}

#[derive(Subdiagnostic)]
#[note("at {$location}")]
pub(crate) struct QueryLocationNote {
pub location: String,
}

#[derive(Diagnostic)]
Expand All @@ -71,6 +81,8 @@ pub(crate) struct Cycle {
#[subdiagnostic]
pub stack_count: StackCount,
#[subdiagnostic]
pub stack_bottom_location: Option<QueryLocationNote>,
#[subdiagnostic]
pub alias: Option<Alias>,
#[subdiagnostic]
pub cycle_usage: Option<CycleUsage>,
Expand All @@ -79,3 +91,23 @@ pub(crate) struct Cycle {
)]
pub note_span: (),
}

#[derive(Diagnostic)]
#[diag("cycle when printing cycle detected when {$stack_bottom}")]
pub(crate) struct NestedCycle {
#[primary_span]
pub span: Span,
pub stack_bottom: String,
#[subdiagnostic]
pub cycle_stack: Vec<CycleStack>,
#[subdiagnostic]
pub stack_count: StackCount,
#[subdiagnostic]
pub stack_bottom_location: Option<QueryLocationNote>,
#[subdiagnostic]
pub cycle_usage: Option<CycleUsage>,
#[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"
)]
pub note_span: (),
}
Loading
Loading