Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
88ed708
core: generalize `BorrowedCursor::ensure_init`
joboet Aug 3, 2026
0100285
core: add `slice::write_default`
joboet Aug 4, 2026
e52a10e
use `static` instead of `const` for derive(Debug)
makai410 Aug 10, 2026
c02de72
Update books
rustbot Aug 10, 2026
34b02c6
implement <OnceCell,OnceLock>::new_init
malezjaa Aug 10, 2026
0bcefa1
Add back homu-ignore markers around the PR template
steffahn Aug 10, 2026
0f7dbc0
Fix a `use` item
nnethercote Aug 10, 2026
9e2147f
Move `create_cycle_error` to `mod handle_cycle_error`
nnethercote Aug 10, 2026
9e37f39
Rename `query_impl.rs` as `query_vtables.rs`
nnethercote Aug 10, 2026
c0b0065
Move four functions from `plumbing.rs` to `execution.rs`
nnethercote Aug 10, 2026
04df355
Rename `plumbing.rs` as `incremental.rs`
nnethercote Aug 10, 2026
b99843c
Move `GetQueryVTable` into `query_vtables.rs`
nnethercote Aug 10, 2026
ae1b655
Move some job-related stuff into `job.rs`
nnethercote Aug 10, 2026
d6c5503
Rename `profiling_support.rs` as `self_profile.rs`
nnethercote Aug 10, 2026
86c2ea0
Remove the crate's doc comment
nnethercote Aug 10, 2026
98ce159
Rollup merge of #160872 - steffahn:put_back_homu-ignore, r=jieyouxu
jhpratt Aug 11, 2026
4510909
Rollup merge of #160432 - joboet:ensure_init_generic, r=clarfonthey
jhpratt Aug 11, 2026
20b2fd7
Rollup merge of #160843 - nnethercote:overhaul-rustc_query_impl, r=Za…
jhpratt Aug 11, 2026
9b7bae2
Rollup merge of #160865 - makai410:debug-static, r=nnethercote
jhpratt Aug 11, 2026
4da59a3
Rollup merge of #160866 - rustbot:docs-update, r=traviscross
jhpratt Aug 11, 2026
80fdf73
Rollup merge of #160881 - malezjaa:implement_new_init, r=clarfonthey
jhpratt Aug 11, 2026
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
7 changes: 6 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!-- homu-ignore:start -->
<!--
Please read our [LLM policy] before opening a PR,
If you used an LLM to generate any part of this PR, including the PR description, please disclose that according to our [guidelines][disclosure guidelines].
LLM contributions are not banned, but are held to a higher standard of review and correctness.
If you do not want your disclosure to be part of the permanent git history, add `<!-- homu-ignore:start` before it.

[LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html
[disclosure guidelines]: https://rustc-dev-guide.rust-lang.org/llm-guidance/writing.html#disclosure-guidelines
Expand All @@ -15,4 +15,9 @@ This PR will get automatically assigned to a reviewer. In case you would like
a specific user to review your work, you can assign it to them by using

r? <reviewer name>

When merged, your PR's description becomes part of the commit message of a merge commit.
If you do not want certain parts of it (such as your LLM disclosure) to show up in the permanent git history,
surround them with a pair of HTML comments containing `homu-ignore:start` and `homu-ignore:end`.
-->
<!-- homu-ignore:end -->
18 changes: 9 additions & 9 deletions compiler/rustc_builtin_macros/src/deriving/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ fn show_fieldless_enum(
/// ```text
/// impl ::core::fmt::Debug for A {
/// fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
/// const __NAMES: &str = "ABBBCC";
/// const __OFFSET: [usize; 4] =[0, 1, 4, 6];
/// static __NAMES: &str = "ABBBCC";
/// static __OFFSET: [usize; 4] =[0, 1, 4, 6];
/// let __d = ::core::intrinsics::discriminant_value(self) as usize;
/// ::core::fmt::Formatter::debug_c_like_enums_write_str(f, __NAMES, &__OFFSET, __d)
/// }
Expand Down Expand Up @@ -314,8 +314,8 @@ fn show_fieldless_enum_concat_str(
),
);
let names_str_body = cx.expr_str(span, Symbol::intern(&concatenated_names));
let names_const_item =
cx.item_const(span, names_ident, str_ty, Some(names_str_body), ast::ConstItemKind::Body);
let names_static_item =
cx.item_static(span, names_ident, str_ty, ast::Mutability::Not, names_str_body);

// Create the constant offset array
let offset_ident = Ident::from_str_and_span("__OFFSET", span);
Expand All @@ -332,12 +332,12 @@ fn show_fieldless_enum_concat_str(
None,
)),
);
let offset_const_item = cx.item_const(
let offset_static_item = cx.item_static(
span,
offset_ident,
cx.ty(span, TyKind::Array(usize_ty, offset_array_len_expr)),
Some(starts_array_body),
ast::ConstItemKind::Body,
ast::Mutability::Not,
starts_array_body,
);

// let __d = ::core::intrinsics::discriminant_value(self) as usize;
Expand Down Expand Up @@ -372,8 +372,8 @@ fn show_fieldless_enum_concat_str(

Some((
thin_vec![
cx.stmt_item(span, names_const_item),
cx.stmt_item(span, offset_const_item),
cx.stmt_item(span, names_static_item),
cx.stmt_item(span, offset_static_item),
discriminant_let_stmt,
],
call_expr,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_query_impl/src/dep_kind_vtables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use rustc_middle::bug;
use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, KeyFingerprintStyle};
use rustc_middle::query::QueryCache;

use crate::GetQueryVTable;
use crate::plumbing::promote_from_disk_inner;
use crate::incremental::promote_from_disk_inner;
use crate::query_vtables::GetQueryVTable;

/// [`DepKindVTable`] constructors for special dep kinds that aren't queries.
#[expect(non_snake_case, reason = "use non-snake case to avoid collision with query names")]
Expand Down Expand Up @@ -166,7 +166,7 @@ macro_rules! define_dep_kind_vtables {
let q_vtables: [DepKindVTable<'tcx>; _] = [
$(
$crate::dep_kind_vtables::make_dep_kind_vtable_for_query::<
$crate::query_impl::$name::VTableGetter,
$crate::query_vtables::$name::VTableGetter,
>(
$cache_on_disk,
$eval_always,
Expand Down
187 changes: 66 additions & 121 deletions compiler/rustc_query_impl/src/execution.rs
Original file line number Diff line number Diff line change
@@ -1,117 +1,35 @@
use std::hash::Hash;
use std::mem::ManuallyDrop;
use std::num::NonZero;

use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
use rustc_data_structures::hash_table::{Entry, HashTable};
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_data_structures::{defer, outline, sharded, sync};
use rustc_data_structures::hash_table::Entry;
use rustc_data_structures::{Limit, defer, outline, sharded, sync};
use rustc_errors::FatalError;
use rustc_middle::dep_graph::{DepGraphData, DepNodeKey, SerializedDepNodeIndex};
use rustc_middle::dep_graph::{
DepGraphData, DepNode, DepNodeIndex, DepNodeKey, SerializedDepNodeIndex,
};
use rustc_middle::query::{
ActiveKeyStatus, Cycle, QueryCache, QueryJob, QueryJobId, QueryKey, QueryLatch, QueryMode,
QueryState, QueryVTable,
ActiveKeyStatus, Cycle, QueryCache, QueryJob, QueryJobId, QueryLatch, QueryMode, QueryState,
QueryVTable,
};
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::tls::{self, ImplicitCtxt};
use rustc_middle::verify_ich::incremental_verify_ich;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::{DUMMY_SP, Span};
use tracing::debug;

use crate::dep_graph::{DepNode, DepNodeIndex};
use crate::diagnostics::{QueryOverflow, QueryOverflowNote};
use crate::handle_cycle_error;
use crate::job::{QueryJobInfo, QueryJobMap, create_cycle_error, find_cycle_in_stack};
use crate::plumbing::{current_query_job, next_job_id, start_query};
use crate::query_impl::for_each_query_vtable;
use crate::incremental::should_verify_loaded_value;
use crate::job::{
CollectActiveJobsKind, collect_active_query_jobs, find_cycle_in_stack, find_dep_kind_root,
};

#[inline]
fn equivalent_key<K: Eq, V>(k: K) -> impl Fn(&(K, V)) -> bool {
move |x| x.0 == k
}

pub(crate) fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool {
state.active.lock_shards().all(|shard| shard.is_empty())
}

#[derive(Clone, Copy)]
pub enum CollectActiveJobsKind {
/// We need the full query job map, and we are willing to wait to obtain the query state
/// shard lock(s).
Full,

/// We need the full query job map, and we shouldn't need to wait to obtain the shard lock(s),
/// because we are in a place where nothing else could hold the shard lock(s).
FullNoContention,

/// We can get by without the full query job map, so we won't bother waiting to obtain the
/// shard lock(s) if they're not already unlocked.
PartialAllowed,
}

/// Returns a map of currently active query jobs, collected from all queries.
pub fn collect_active_query_jobs<'tcx>(
tcx: TyCtxt<'tcx>,
collect_kind: CollectActiveJobsKind,
) -> QueryJobMap<'tcx> {
let mut job_map = QueryJobMap::default();

for_each_query_vtable!(ALL, tcx, |query| {
collect_active_query_jobs_inner(query, collect_kind, &mut job_map);
});

job_map
}

/// Internal plumbing for collecting the set of active jobs for this query.
///
/// Aborts if jobs can't be gathered as specified by `collect_kind`.
fn collect_active_query_jobs_inner<'tcx, C>(
query: &'tcx QueryVTable<'tcx, C>,
collect_kind: CollectActiveJobsKind,
job_map: &mut QueryJobMap<'tcx>,
) where
C: QueryCache<Key: QueryKey + DynSend + DynSync>,
QueryVTable<'tcx, C>: DynSync,
{
let mut collect_shard_jobs = |shard: &HashTable<(C::Key, ActiveKeyStatus<'tcx>)>| {
for (key, status) in shard.iter() {
if let ActiveKeyStatus::Started(job) = status {
// It's fine to call `create_tagged_key` with the shard locked,
// because it's just a `TaggedQueryKey` variant constructor.
let tagged_key = (query.create_tagged_key)(*key);
job_map.insert(job.id, QueryJobInfo { tagged_key, job: job.clone() });
}
}
};

match collect_kind {
CollectActiveJobsKind::Full => {
for shard in query.state.active.lock_shards() {
collect_shard_jobs(&shard);
}
}
CollectActiveJobsKind::FullNoContention => {
for shard in query.state.active.try_lock_shards() {
match shard {
Some(shard) => collect_shard_jobs(&shard),
None => panic!("Failed to collect active jobs for query `{}`!", query.name),
}
}
}
CollectActiveJobsKind::PartialAllowed => {
for shard in query.state.active.try_lock_shards() {
match shard {
Some(shard) => collect_shard_jobs(&shard),
// This collection is best-effort (it is only used to print the query
// stack on panic), so a contended shard is expected and fine to skip.
// Emitting this at `warn!` would leak nondeterministically into the
// panic output under the parallel front-end, where another thread may
// still hold a shard lock, so keep it at `debug!`.
None => debug!("Failed to collect active jobs for query `{}`!", query.name),
}
}
}
}
}

#[cold]
#[inline(never)]
fn handle_cycle<'tcx, C: QueryCache>(
Expand All @@ -135,7 +53,7 @@ fn handle_cycle<'tcx, C: QueryCache>(
}
let _guard = defer(|| *tcx.query_system.cycle_handler_nesting.lock() -= 1);

let error = create_cycle_error(tcx, &cycle, nested);
let error = handle_cycle_error::create_cycle_error(tcx, &cycle, nested);

if nested {
// Avoid custom handlers and only use the robust `create_cycle_error` for nested cycle errors
Expand Down Expand Up @@ -281,6 +199,19 @@ fn wait_for_query<'tcx, C: QueryCache>(
}
}

#[inline]
fn next_job_id<'tcx>(tcx: TyCtxt<'tcx>) -> QueryJobId {
QueryJobId(
NonZero::new(tcx.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
.unwrap(),
)
}

#[inline]
fn current_query_job() -> Option<QueryJobId> {
tls::with_context(|icx| icx.query)
}

/// Shared main part of both [`execute_query_incr_inner`] and [`execute_query_non_incr_inner`].
#[inline(never)]
fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>(
Expand Down Expand Up @@ -407,6 +338,43 @@ fn check_feedable_consistency<'tcx, C: QueryCache>(
}
}

fn depth_limit_error<'tcx>(tcx: TyCtxt<'tcx>, job: QueryJobId) {
let job_map = collect_active_query_jobs(tcx, CollectActiveJobsKind::Full);
let (span, desc, depth) = find_dep_kind_root(tcx, job, job_map);

let suggested_limit = match tcx.recursion_limit() {
Limit(0) => Limit(2),
limit => limit * 2,
};

tcx.dcx().emit_fatal(QueryOverflow {
span,
note: QueryOverflowNote { desc, depth },
suggested_limit,
crate_name: tcx.crate_name(LOCAL_CRATE),
});
}

/// Executes a job by changing the `ImplicitCtxt` to point to the new query job while it executes.
#[inline(always)]
fn start_query<R>(job_id: QueryJobId, depth_limit: bool, compute: impl FnOnce() -> R) -> R {
tls::with_context(move |icx| {
if depth_limit && !icx.tcx.recursion_limit().value_within_limit(icx.query_depth) {
depth_limit_error(icx.tcx, job_id);
}

// Update the `ImplicitCtxt` to point to our new query job.
let icx = ImplicitCtxt {
query: Some(job_id),
query_depth: icx.query_depth + if depth_limit { 1 } else { 0 },
..*icx
};

// Use the `ImplicitCtxt` while we execute the query.
tls::enter_context(&icx, compute)
})
}

// Fast path for when incr. comp. is off.
#[inline(always)]
fn execute_job_non_incr<'tcx, C: QueryCache>(
Expand Down Expand Up @@ -484,29 +452,6 @@ fn execute_job_incr<'tcx, C: QueryCache>(
(result, dep_node_index)
}

/// Whether a value loaded from the on-disk cache should have its fingerprint
/// verified with `incremental_verify_ich`. If `-Zincremental-verify-ich` is
/// specified, re-hash results from the cache and make sure that they have the
/// expected fingerprint.
///
/// If not, we still verify a subset: re-hashing is too expensive to do for
/// every value. The subset rotates with the session count, covering the whole
/// cache every 32 sessions, and is deterministic so that a verification
/// failure reproduces on retry.
///
/// `to_smaller_hash` mixes both fingerprint halves because neither half is
/// evenly distributed on its own (`DefPathHash` keys share the
/// `StableCrateId`, `HirId` keys contain a sequential id).
pub(crate) fn should_verify_loaded_value(
tcx: TyCtxt<'_>,
dep_graph_data: &DepGraphData,
key_fingerprint: PackedFingerprint,
) -> bool {
let hash = Fingerprint::from(key_fingerprint).to_smaller_hash().as_u64();
hash % 32 == dep_graph_data.session_count() % 32
|| tcx.sess.opts.unstable_opts.incremental_verify_ich
}

/// Given that the dep node for this query+key is green, obtain a value for it
/// by loading one from disk if possible, or by invoking its query provider if
/// necessary.
Expand Down
Loading
Loading