Skip to content

Assert redundant incremental check#156599

Open
zetanumbers wants to merge 2 commits into
rust-lang:mainfrom
zetanumbers:assert_loadable_from_disk
Open

Assert redundant incremental check#156599
zetanumbers wants to merge 2 commits into
rust-lang:mainfrom
zetanumbers:assert_loadable_from_disk

Conversation

@zetanumbers
Copy link
Copy Markdown
Contributor

So to incrementally execute tcx.ensure_done().query() we first do query graph coloring to determine if nothing has changed and maybe color our query green. In that case for ensure_ok we skip further execution and return. However for ensure_done we do this check:

// In ensure-done mode, we can only skip execution for this key
// if there's a disk-cached value available to load later if
// needed, which guarantees the query provider will never run
// for this key.
EnsureMode::Done => {
(query.will_cache_on_disk_for_key_fn)(key)
&& loadable_from_disk(tcx, serialized_dep_node_index)
}

Which in turn looks up a serialized query value:

/// Returns true if there is a disk-cached query return value for the given node.
#[inline]
pub fn loadable_from_disk(&self, dep_node_index: SerializedDepNodeIndex) -> bool {
self.query_values_index.contains_key(&dep_node_index)
// with_decoder is infallible, so we can stop here
}

However, we only serialize query values if the pure (I've checked) function will_cache_on_disk_for_key_fn from above returns true:

query.cache.for_each(&mut |key, value, dep_node| {
if (query.will_cache_on_disk_for_key_fn)(*key) {
encoder.encode_query_value::<V>(dep_node, &erase::restore_val::<V>(*value));
}
});

As such loadable_from_disk should be able to simply check if tcx.query_system.on_disk_cache is loaded and assume query value is present, assuming that will_cache_on_disk_for_key_fn returned true.

@rustbot rustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 15, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented May 15, 2026

r? @chenyukang

rustbot has assigned @chenyukang.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler, query-system
  • compiler, query-system expanded to 73 candidates
  • Random selection from 17 candidates

@zetanumbers
Copy link
Copy Markdown
Contributor Author

I think we can clarify this change with a comment or by outright inlining that function. Not sure what to pick tho.

@zetanumbers
Copy link
Copy Markdown
Contributor Author

zetanumbers commented May 15, 2026

Also that check is covered by tests, so I making it unconditionally panic would trigger following incremental tests failures:

  • change_crate_dep_kind.rs
  • const-generics/change-const-param-type.rs
  • const-generics/change-const-param-gat.rs
  • hashes/consts.rs
  • define-opaques.rs
  • hashes/closure_expressions.rs
  • feature_gate.rs
  • commandline-args.rs
  • hashes/call_expressions.rs
  • hashes/enum_constructors.rs
  • hashes/if_expressions.rs
  • hashes/loop_expressions.rs
  • hashes/function_interfaces.rs
  • hashes/for_loops.rs
  • hashes/inherent_impls.rs
  • hashes/struct_constructors.rs
  • hashes/while_loops.rs
  • hashes/statics.rs
  • hashes/while_let_loops.rs
  • hashes/trait_impls.rs
  • ich_nested_items.rs
  • issue-100521-change-struct-name-assocty.rs
  • issue-49595/issue-49595.rs
  • reorder_vtable.rs
  • spans_significant_w_panic.rs
  • spans_significant_w_debuginfo.rs
  • issue-110457-same-span-closures/main.rs
  • static_cycle/b.rs
  • static_refering_to_other_static2/issue.rs
  • static_refering_to_other_static3/issue.rs
  • thinlto/cgu_keeps_identical_fn.rs
  • static_stable_hash/issue-49301.rs
  • thinlto/cgu_invalidated_when_export_added.rs
  • unrecoverable_query.rs

@zetanumbers
Copy link
Copy Markdown
Contributor Author

I think we could change it to debug_assert and check if perf is affected.

@chenyukang
Copy link
Copy Markdown
Member

@rustbot reroll

@rustbot rustbot assigned TaKO8Ki and unassigned chenyukang May 18, 2026
@Zalathar
Copy link
Copy Markdown
Member

I think we can clarify this change with a comment or by outright inlining that function. Not sure what to pick tho.

Making the existing helper function assert seems like a hazard if any other code starts calling it, so I think it's clearer to inline and remove the function.

After inlining I think we can also get rid of the else arm and call on_disk_cache.as_ref().unwrap(), because the disk-cache struct should always be present in incremental sessions, even if no previous session was loaded.

@zetanumbers zetanumbers force-pushed the assert_loadable_from_disk branch from 7a4bd2e to ef2fa8a Compare May 25, 2026 12:04
@rustbot

This comment has been minimized.

@cjgillot
Copy link
Copy Markdown
Contributor

What if we restart an incremental compilation with a working dep-graph, but the on-disk cache has been deleted?

@zetanumbers
Copy link
Copy Markdown
Contributor Author

What if we restart an incremental compilation with a working dep-graph, but the on-disk cache has been deleted?

I think that shouldn't matter:

// The on-disk cache struct is always present in incremental mode,
// even if there was no previous session.
let on_disk_cache = tcx.query_system.on_disk_cache.as_ref().unwrap();

@Zalathar
Copy link
Copy Markdown
Member

Indeed, here is where the OnDiskCache gets created:

/// Attempts to load the query result cache from disk
///
/// If we are not in incremental compilation mode, returns `None`.
/// Otherwise, tries to load the query result cache from disk,
/// creating an empty cache if it could not be loaded.
pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache> {
if sess.opts.incremental.is_none() {
return None;
}
let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
let path = query_cache_path(sess);
match file_format::open_incremental_file(sess, &path) {
Ok(OpenFile { mmap, start_pos }) => {
let cache = OnDiskCache::new(sess, mmap, start_pos).unwrap_or_else(|()| {
sess.dcx().emit_warn(errors::CorruptFile { path: &path });
OnDiskCache::new_empty()
});
Some(cache)
}
Err(OpenFileError::NotFoundOrHeaderMismatch | OpenFileError::IoError { .. }) => {
Some(OnDiskCache::new_empty())
}
}
}

As long as we're in incremental mode, we fall back to creating an empty disk-cache struct if nothing could be loaded. So the field is only None in non-incremental mode.

@zetanumbers
Copy link
Copy Markdown
Contributor Author

Should be good now I think.

@Zalathar
Copy link
Copy Markdown
Member

Oh wait, I think I misunderstood the concern.

If the disk-cache was deleted since the last session, the OnDiskCache will be present but empty ... so even values that should be in the disk-cache will be absent, violating the assertion.

So removing the check might be wrong after all.

@zetanumbers
Copy link
Copy Markdown
Contributor Author

Oh wait, I think I misunderstood the concern.

If the disk-cache was deleted since the last session, the OnDiskCache will be present but empty ... so even values that should be in the disk-cache will be absent, violating the assertion.

So removing the check might be wrong after all.

Right, I forgot about that. So can we make it a None for that case, just like I've assumed it in the beginning?

@zetanumbers zetanumbers force-pushed the assert_loadable_from_disk branch from 2667e56 to c23ce2e Compare May 26, 2026 08:17
@zetanumbers
Copy link
Copy Markdown
Contributor Author

Like that it should be ok, right?

@rust-bors

This comment has been minimized.

@zetanumbers zetanumbers force-pushed the assert_loadable_from_disk branch from c23ce2e to 7bb4f71 Compare June 2, 2026 10:25
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 2, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants