Skip to content
Open
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_middle/src/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub enum ActiveKeyStatus<'tcx> {
Poisoned,
}

#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct CycleError<'tcx> {
/// The query and related span that uses the cycle.
pub usage: Option<Spanned<QueryStackFrame<'tcx>>>,
Expand Down Expand Up @@ -505,7 +505,7 @@ macro_rules! define_callbacks {

/// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a number.
#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TaggedQueryKey<'tcx> {
$(
$name($name::Key<'tcx>),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::queries::TaggedQueryKey;
/// Description of a frame in the query stack.
///
/// This is mostly used in case of cycles for error reporting.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct QueryStackFrame<'tcx> {
pub tagged_key: TaggedQueryKey<'tcx>,
pub dep_kind: DepKind,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_query_impl/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ fn cycle_error<'tcx, C: QueryCache>(
let job_map =
collect_active_jobs_from_all_queries(tcx, CollectActiveJobsKind::FullNoContention);

let error = find_cycle_in_stack(try_execute, job_map, &current_query_job(), span);
let error = find_cycle_in_stack(try_execute, &job_map, current_query_job(), span)
.expect("did not find a cycle");
(mk_cycle(query, tcx, key, error), None)
}

Expand Down
27 changes: 21 additions & 6 deletions compiler/rustc_query_impl/src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,12 @@ pub(crate) struct QueryJobInfo<'tcx> {

pub(crate) fn find_cycle_in_stack<'tcx>(
id: QueryJobId,
job_map: QueryJobMap<'tcx>,
current_job: &Option<QueryJobId>,
job_map: &QueryJobMap<'tcx>,
mut current_job: Option<QueryJobId>,
span: Span,
) -> CycleError<'tcx> {
) -> Option<CycleError<'tcx>> {
// Find the waitee amongst `current_job` parents
let mut cycle = Vec::new();
let mut current_job = Option::clone(current_job);

while let Some(job) = current_job {
let info = &job_map.map[&job];
Expand All @@ -79,13 +78,13 @@ pub(crate) fn find_cycle_in_stack<'tcx>(
let parent = info.job.parent?;
respan(info.job.span, job_map.frame_of(parent).clone())
};
return CycleError { usage, cycle };
return Some(CycleError { usage, cycle });
}

current_job = info.job.parent;
}

panic!("did not find a cycle")
None
}

/// Finds the job closest to the root with a `DepKind` matching the `DepKind` of `id` and returns
Expand Down Expand Up @@ -315,6 +314,8 @@ fn remove_cycle<'tcx>(
.query_waiting_on_cycle
.map(|(span, job)| respan(span, job_map.frame_of(job).clone()));

let span = entry_point.query_waiting_on_cycle.map_or(DUMMY_SP, |(s, _)| s);
stack[0].0 = span;
// Create the cycle error
let error = CycleError {
usage,
Expand All @@ -324,6 +325,20 @@ fn remove_cycle<'tcx>(
.collect(),
};

if cfg!(debug_assertions)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no added comments in this commit. An explanatory comment here would be useful. Something like "compare the single-threaded cycle detection against the multi-threaded cycle detection".

&& let Some(expected) = find_cycle_in_stack(
entry_point.query_in_cycle,
job_map,
stack.last().map(|&(_, job)| job),
span,
)
{
if error != expected {
panic!(
"CycleError coherency check failed:\nexpected: {expected:#?}\ngot: {error:#?}"
);
}
}
// We unwrap `resumable` here since there must always be one
// edge which is resumable / waited using a query latch
let (waitee_query, waiter_idx) = resumable.unwrap();
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ where
SESSION_GLOBALS.with(f)
}

#[inline]
pub fn are_session_globals_set() -> bool {
SESSION_GLOBALS.is_set()
}

/// Default edition, no source map.
pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
create_session_globals_then(edition::DEFAULT_EDITION, &[], None, f)
Expand Down
18 changes: 15 additions & 3 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc_data_structures::sync::Lock;
use rustc_macros::{Decodable, Encodable, HashStable_Generic, symbols};

use crate::edit_distance::find_best_match_for_name;
use crate::{DUMMY_SP, Edition, Span, with_session_globals};
use crate::{DUMMY_SP, Edition, Span, are_session_globals_set, with_session_globals};

#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -2545,6 +2545,10 @@ impl Symbol {
})
}

pub fn opt_as_str(&self) -> Option<&str> {
are_session_globals_set().then(|| self.as_str())
}

pub fn as_u32(self) -> u32 {
self.0.as_u32()
}
Expand Down Expand Up @@ -2586,13 +2590,21 @@ impl Symbol {

impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_str(), f)
if let Some(s) = self.opt_as_str() {
Copy link
Contributor

@petrochenkov petrochenkov Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if let Some(s) = self.opt_as_str() {
if are_session_globals_set() {

Together with a comment #153953 (comment) explaining why it's acceptable.
opt_as_str can be removed, it shouldn't be a generally available method.

fmt::Debug::fmt(s, f)
} else {
fmt::Debug::fmt(&self.0, f)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will just print a number, e.g. 123. Printing Symbol(123) would be much better.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Symbols should never be used in contexts in which this path can be triggered, it's better to continue panicking here.
@zetanumbers In which specific context was this encountered?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consult #t-compiler/parallel-rustc > Getting rid of the cycle detection thread

That thread doesn't have anything answering my question.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This context is the cycle detection thread

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment explaining this use?
Using Symbols when the interner is dead is like using dangling pointers, suspicious at least.
If the cycle detection thread is the only such context and it's removed, then it would be better to remove this logic as well.

}
}
}

impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_str(), f)
if let Some(s) = self.opt_as_str() {
fmt::Display::fmt(s, f)
} else {
fmt::Debug::fmt(&self.0, f)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

}
}
}

Expand Down
Loading