diff --git a/compiler/rustc_middle/src/query/inner.rs b/compiler/rustc_middle/src/query/inner.rs index c2525d26d4c67..9b9e2abbc857f 100644 --- a/compiler/rustc_middle/src/query/inner.rs +++ b/compiler/rustc_middle/src/query/inner.rs @@ -79,21 +79,26 @@ where { match try_get_cached(tcx, &query.cache, key) { Some(value) => erase::restore_val(value).map(drop), - None => (query.execute_query_fn)( - tcx, - DUMMY_SP, - key, - QueryMode::Ensure { ensure_mode: EnsureMode::Ok }, - ) - .map(erase::restore_val) - .map(|value| value.map(drop)) - // Either we actually executed the query, which means we got a full `Result`, - // or we can just assume the query succeeded, because it was green in the - // incremental cache. If it is green, that means that the previous compilation - // that wrote to the incremental cache compiles successfully. That is only - // possible if the cache entry was `Ok(())`, so we emit that here, without - // actually encoding the `Result` in the cache or loading it from there. - .unwrap_or(Ok(())), + None => { + match (query.execute_query_fn)( + tcx, + DUMMY_SP, + key, + QueryMode::Ensure { ensure_mode: EnsureMode::Ok }, + ) { + // We executed the query. If the restored result is `Ok(_)`, dropping it converts + // it to `Ok(())`. If the restored result is `Err(guar)`, we pass that along. + Some(res) => erase::restore_val(res).map(drop), + + // Reaching here means we didn't execute the query, but we can just assume the + // query succeeded, because it was green in the incremental cache. If it is green, + // that means that the previous compilation that wrote to the incremental cache + // compiles successfully. That is only possible if the cache entry was `Ok(())`, so + // we emit that here, without actually encoding the `Result` in the cache or + // loading it from there. + None => Ok(()), + } + } } } diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 1224ec0706cf0..a9bacd78a3f26 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -572,14 +572,12 @@ fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>( value } -/// Return value struct for [`check_if_ensure_can_skip_execution`]. -struct EnsureCanSkip { - /// If true, the current `tcx.ensure_ok()` or `tcx.ensure_done()` query - /// can return early without actually trying to execute. - skip_execution: bool, - /// A dep node that was prepared while checking whether execution can be - /// skipped, to be reused by execution itself if _not_ skipped. - dep_node: Option, +/// Can a `tcx.ensure_ok()` or `tcx.ensure_done()` query return early without +/// actually trying to execute? +enum EnsureCanSkip { + Yes, + // We may have created a `DepNode` while determining whether we can skip. + No(Option), } /// Checks whether a `tcx.ensure_ok()` or `tcx.ensure_done()` query call can @@ -597,7 +595,7 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>( ) -> EnsureCanSkip { // Queries with `eval_always` should never skip execution. if query.eval_always { - return EnsureCanSkip { skip_execution: false, dep_node: None }; + return EnsureCanSkip::No(None); } // Ensuring an anonymous query makes no sense @@ -613,7 +611,7 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>( // DepNodeIndex. We must invoke the query itself. The performance cost // this introduces should be negligible as we'll immediately hit the // in-memory cache, or another query down the line will. - return EnsureCanSkip { skip_execution: false, dep_node: Some(dep_node) }; + return EnsureCanSkip::No(Some(dep_node)); } Some((serialized_dep_node_index, dep_node_index)) => { tcx.dep_graph.read_index(dep_node_index); @@ -627,14 +625,17 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>( // In ensure-ok mode, we can skip execution for this key if the node // is green. It must have succeeded in the previous session, and // therefore would succeed in the current session if executed. - EnsureCanSkip { skip_execution: true, dep_node: None } + EnsureCanSkip::Yes } EnsureMode::Done => { // 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. - let is_loadable = (query.is_loadable_from_disk_fn)(tcx, key, serialized_dep_node_index); - EnsureCanSkip { skip_execution: is_loadable, dep_node: Some(dep_node) } + if (query.is_loadable_from_disk_fn)(tcx, key, serialized_dep_node_index) { + EnsureCanSkip::Yes + } else { + EnsureCanSkip::No(Some(dep_node)) + } } } } @@ -669,16 +670,13 @@ pub(super) fn execute_query_incr_inner<'tcx, C: QueryCache>( // This might have the side-effect of creating a suitable DepNode, which // we should reuse for execution instead of creating a new one. let dep_node: Option = match mode { + QueryMode::Get => None, QueryMode::Ensure { ensure_mode } => { - let EnsureCanSkip { skip_execution, dep_node } = - check_if_ensure_can_skip_execution(query, tcx, key, ensure_mode); - if skip_execution { - // Return early to skip execution. - return None; + match check_if_ensure_can_skip_execution(query, tcx, key, ensure_mode) { + EnsureCanSkip::Yes => return None, + EnsureCanSkip::No(dep_node) => dep_node, } - dep_node } - QueryMode::Get => None, }; let (result, dep_node_index) =