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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4492,6 +4492,7 @@ version = "0.0.0"
dependencies = [
"measureme",
"rustc_abi",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_hir",
Expand Down
97 changes: 22 additions & 75 deletions compiler/rustc_macros/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,52 +273,6 @@ fn doc_comment_from_desc(list: &Punctuated<Expr, token::Comma>) -> Result<Attrib
Ok(parse_quote! { #[doc = #doc_string] })
}

/// Contains token streams that are used to accumulate per-query helper
/// functions, to be used by the final output of `rustc_queries!`.
///
/// Helper items typically have the same name as the query they relate to,
/// and expect to be interpolated into a dedicated module.
#[derive(Default)]
struct HelperTokenStreams {
description_fns_stream: proc_macro2::TokenStream,
cache_on_disk_if_fns_stream: proc_macro2::TokenStream,
}

fn make_helpers_for_query(query: &Query, streams: &mut HelperTokenStreams) {
let Query { name, key_pat, key_ty, modifiers, .. } = &query;

// Replace span for `name` to make rust-analyzer ignore it.
let mut erased_name = name.clone();
erased_name.set_span(Span::call_site());

// Generate a function to check whether we should cache the query to disk, for some key.
if let Some(CacheOnDiskIf { block, .. }) = modifiers.cache_on_disk_if.as_ref() {
// `pass_by_value`: some keys are marked with `rustc_pass_by_value`, but we take keys by
// reference here.
// FIXME: `pass_by_value` is badly named; `allow(rustc::pass_by_value)` actually means
// "allow pass by reference of `rustc_pass_by_value` types".
streams.cache_on_disk_if_fns_stream.extend(quote! {
#[allow(unused_variables, rustc::pass_by_value)]
#[inline]
pub fn #erased_name<'tcx>(tcx: TyCtxt<'tcx>, #key_pat: &#key_ty) -> bool
#block
});
}

let Desc { expr_list, .. } = &modifiers.desc;

let desc = quote! {
#[allow(unused_variables)]
pub fn #erased_name<'tcx>(tcx: TyCtxt<'tcx>, #key_pat: #key_ty) -> String {
format!(#expr_list)
}
};

streams.description_fns_stream.extend(quote! {
#desc
});
}

/// Add hints for rust-analyzer
fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::TokenStream) {
// Add links to relevant modifiers
Expand Down Expand Up @@ -398,7 +352,6 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
let queries = parse_macro_input!(input as List<Query>);

let mut query_stream = quote! {};
let mut helpers = HelperTokenStreams::default();
let mut analyzer_stream = quote! {};
let mut errors = quote! {};

Expand All @@ -413,7 +366,7 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
}

for query in queries.0 {
let Query { doc_comments, name, key_ty, return_ty, modifiers, .. } = &query;
let Query { doc_comments, name, key_pat, key_ty, return_ty, modifiers, .. } = &query;

// Normalize an absent return type into `-> ()` to make macro-rules parsing easier.
let return_ty = match return_ty {
Expand All @@ -431,6 +384,10 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
}
}

// Put a description closure inside the `desc` modifier: `(desc { <closure> })`.
let expr_list = &modifiers.desc.expr_list;
modifiers_out.push(quote! { (desc { |tcx, #key_pat| format!(#expr_list) }) });

passthrough!(
arena_cache,
cycle_fatal,
Expand All @@ -445,11 +402,23 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
return_result_from_ensure_ok,
);

// If there was a `cache_on_disk_if` modifier in the real input, pass
// on a synthetic `(cache_on_disk)` modifier that can be inspected by
// macro-rules macros.
if modifiers.cache_on_disk_if.is_some() {
modifiers_out.push(quote! { (cache_on_disk) });
// If there was a `cache_on_disk_if` modifier, put a closure inside it:
// `(cache_on_disk { <closure > }`.
if let Some(CacheOnDiskIf { block, .. }) = &modifiers.cache_on_disk_if {
modifiers_out.push(quote! {
(cache_on_disk_if {
// `pass_by_value`: some keys are marked with `rustc_pass_by_value`, but we
// take keys by reference here.
// FIXME: `pass_by_value` is badly named; `allow(rustc::pass_by_value)`
// actually means "allow pass by reference of `rustc_pass_by_value` types".
//
// The type annotations are required to avoid compile errors, which is annoying
// because it necessitates extra `use` items in the file using
// `rustc_with_all_queries!`.
#[allow(rustc::pass_by_value)]
|tcx: TyCtxt<'_>, #key_pat: &#key_ty| #block
})
});
}

// This uses the span of the query definition for the commas,
Expand Down Expand Up @@ -482,11 +451,8 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
}

add_to_analyzer_stream(&query, &mut analyzer_stream);
make_helpers_for_query(&query, &mut helpers);
}

let HelperTokenStreams { description_fns_stream, cache_on_disk_if_fns_stream } = helpers;

TokenStream::from(quote! {
/// Higher-order macro that invokes the specified macro with a prepared
/// list of all query signatures (including modifiers).
Expand Down Expand Up @@ -516,25 +482,6 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
#analyzer_stream
}

/// Functions that format a human-readable description of each query
/// and its key, as specified by the `desc` query modifier.
///
/// (The leading `_` avoids collisions with actual query names when
/// expanded in `rustc_middle::queries`, and makes this macro-generated
/// module easier to search for.)
pub mod _description_fns {
use super::*;
#description_fns_stream
}

// FIXME(Zalathar): Instead of declaring these functions directly, can
// we put them in a macro and then expand that macro downstream in
// `rustc_query_impl`, where the functions are actually used?
pub mod _cache_on_disk_if_fns {
use super::*;
#cache_on_disk_if_fns_stream
}

#errors
})
}
3 changes: 0 additions & 3 deletions compiler/rustc_middle/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ use rustc_session::cstore::{
CrateDepKind, CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib,
};
use rustc_session::lint::LintExpectationId;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::source_map::Spanned;
use rustc_span::{DUMMY_SP, LocalExpnId, Span, Symbol};
use rustc_target::spec::PanicStrategy;
Expand All @@ -120,7 +119,6 @@ use crate::mir::interpret::{
use crate::mir::mono::{
CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono,
};
use crate::query::describe_as_module;
use crate::query::plumbing::CyclePlaceholder;
use crate::traits::query::{
CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal,
Expand All @@ -135,7 +133,6 @@ use crate::traits::{
};
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::layout::ValidityRequirement;
use crate::ty::print::PrintTraitRefExt;
use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::{
self, CrateInherentImpls, GenericArg, GenericArgsRef, LitToConstInput, PseudoCanonicalInput,
Expand Down
63 changes: 11 additions & 52 deletions compiler/rustc_middle/src/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,6 @@ pub enum CycleErrorHandling {
Stash,
}

pub type WillCacheOnDiskForKeyFn<'tcx, Key> = fn(tcx: TyCtxt<'tcx>, key: &Key) -> bool;

pub type TryLoadFromDiskFn<'tcx, Key, Value> = fn(
tcx: TyCtxt<'tcx>,
key: &Key,
prev_index: SerializedDepNodeIndex,
index: DepNodeIndex,
) -> Option<Value>;

pub type IsLoadableFromDiskFn<'tcx, Key> =
fn(tcx: TyCtxt<'tcx>, key: &Key, index: SerializedDepNodeIndex) -> bool;

pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>;

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -129,7 +117,7 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
pub cycle_error_handling: CycleErrorHandling,
pub state: QueryState<'tcx, C::Key>,
pub cache: C,
pub will_cache_on_disk_for_key_fn: Option<WillCacheOnDiskForKeyFn<'tcx, C::Key>>,
pub will_cache_on_disk_for_key_fn: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool,

/// Function pointer that calls `tcx.$query(key)` for this query and
/// discards the returned value.
Expand All @@ -145,8 +133,16 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
/// This should be the only code that calls the provider function.
pub invoke_provider_fn: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value,

pub try_load_from_disk_fn: Option<TryLoadFromDiskFn<'tcx, C::Key, C::Value>>,
pub is_loadable_from_disk_fn: Option<IsLoadableFromDiskFn<'tcx, C::Key>>,
pub try_load_from_disk_fn: fn(
tcx: TyCtxt<'tcx>,
key: &C::Key,
prev_index: SerializedDepNodeIndex,
index: DepNodeIndex,
) -> Option<C::Value>,

pub is_loadable_from_disk_fn:
fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,

pub hash_result: HashResult<C::Value>,
pub value_from_cycle_error:
fn(tcx: TyCtxt<'tcx>, cycle_error: &CycleError, guar: ErrorGuaranteed) -> C::Value,
Expand Down Expand Up @@ -174,43 +170,6 @@ impl<'tcx, C: QueryCache> fmt::Debug for QueryVTable<'tcx, C> {
}

impl<'tcx, C: QueryCache> QueryVTable<'tcx, C> {
#[inline(always)]
pub fn will_cache_on_disk_for_key(&self, tcx: TyCtxt<'tcx>, key: &C::Key) -> bool {
self.will_cache_on_disk_for_key_fn.map_or(false, |f| f(tcx, key))
}

#[inline(always)]
pub fn try_load_from_disk(
&self,
tcx: TyCtxt<'tcx>,
key: &C::Key,
prev_index: SerializedDepNodeIndex,
index: DepNodeIndex,
) -> Option<C::Value> {
// `?` will return None immediately for queries that never cache to disk.
self.try_load_from_disk_fn?(tcx, key, prev_index, index)
}

#[inline]
pub fn is_loadable_from_disk(
&self,
tcx: TyCtxt<'tcx>,
key: &C::Key,
index: SerializedDepNodeIndex,
) -> bool {
self.is_loadable_from_disk_fn.map_or(false, |f| f(tcx, key, index))
}

/// Synthesize an error value to let compilation continue after a cycle.
pub fn value_from_cycle_error(
&self,
tcx: TyCtxt<'tcx>,
cycle_error: &CycleError,
guar: ErrorGuaranteed,
) -> C::Value {
(self.value_from_cycle_error)(tcx, cycle_error, guar)
}

pub fn construct_dep_node(&self, tcx: TyCtxt<'tcx>, key: &C::Key) -> DepNode {
DepNode::construct(tcx, self.dep_kind, key)
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_query_impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2024"
# tidy-alphabetical-start
measureme = "12.0.1"
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
Expand Down
16 changes: 9 additions & 7 deletions compiler/rustc_query_impl/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ fn handle_cycle_error<'tcx, C: QueryCache>(
match query.cycle_error_handling {
CycleErrorHandling::Error => {
let guar = error.emit();
query.value_from_cycle_error(tcx, cycle_error, guar)
(query.value_from_cycle_error)(tcx, cycle_error, guar)
}
CycleErrorHandling::Fatal => {
error.emit();
Expand All @@ -129,7 +129,7 @@ fn handle_cycle_error<'tcx, C: QueryCache>(
}
CycleErrorHandling::DelayBug => {
let guar = error.delay_as_bug();
query.value_from_cycle_error(tcx, cycle_error, guar)
(query.value_from_cycle_error)(tcx, cycle_error, guar)
}
CycleErrorHandling::Stash => {
let guar = if let Some(root) = cycle_error.cycle.first()
Expand All @@ -139,7 +139,7 @@ fn handle_cycle_error<'tcx, C: QueryCache>(
} else {
error.emit()
};
query.value_from_cycle_error(tcx, cycle_error, guar)
(query.value_from_cycle_error)(tcx, cycle_error, guar)
}
}
}
Expand Down Expand Up @@ -506,7 +506,9 @@ fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache>(

// First we try to load the result from the on-disk cache.
// Some things are never cached on disk.
if let Some(result) = query.try_load_from_disk(tcx, key, prev_dep_node_index, dep_node_index) {
if let Some(result) =
(query.try_load_from_disk_fn)(tcx, key, prev_dep_node_index, dep_node_index)
{
if std::intrinsics::unlikely(tcx.sess.opts.unstable_opts.query_dep_graph) {
dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
}
Expand Down Expand Up @@ -539,15 +541,15 @@ fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache>(
// We always expect to find a cached result for things that
// can be forced from `DepNode`.
debug_assert!(
!query.will_cache_on_disk_for_key(tcx, key)
!(query.will_cache_on_disk_for_key_fn)(tcx, key)
|| !tcx.key_fingerprint_style(dep_node.kind).reconstructible(),
"missing on-disk cache entry for {dep_node:?}"
);

// Sanity check for the logic in `ensure`: if the node is green and the result loadable,
// we should actually be able to load it.
debug_assert!(
!query.is_loadable_from_disk(tcx, key, prev_dep_node_index),
!(query.is_loadable_from_disk_fn)(tcx, key, prev_dep_node_index),
"missing on-disk cache entry for loadable {dep_node:?}"
);

Expand Down Expand Up @@ -644,7 +646,7 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>(
// 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(tcx, key, serialized_dep_node_index);
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) }
}
}
Expand Down
14 changes: 11 additions & 3 deletions compiler/rustc_query_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@
#![feature(core_intrinsics)]
#![feature(min_specialization)]
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
#![feature(try_blocks)]
// tidy-alphabetical-end

use rustc_ast::tokenstream::TokenStream;
Copy link
Contributor

Choose a reason for hiding this comment

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

It's a bit weird to see TokenStream here, where is it used? I don't see any uses of in in rustc_query_impl.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TokenStream is used in some query keys. The generated closure had to type-annotate its arguments, unfortunately. And rustc_middle::rustc_with_all_queries! { define_queries! } appears in this file.

use rustc_data_structures::sync::AtomicU64;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::dep_graph;
use rustc_middle::mir::interpret::GlobalId;
use rustc_middle::mir::mono::CollectionMode;
use rustc_middle::queries::{self, ExternProviders, Providers};
use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
use rustc_middle::query::plumbing::{QuerySystem, QuerySystemFns, QueryVTable};
use rustc_middle::query::{AsLocalKey, QueryCache, QueryMode};
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
use rustc_middle::query::{AsLocalKey, QueryCache, QueryMode, describe_as_module};
use rustc_middle::ty::print::PrintTraitRefExt;
use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt};
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId};
use rustc_span::{LocalExpnId, Span};

pub use crate::dep_kind_vtables::make_dep_kind_vtables;
pub use crate::job::{QueryJobMap, break_query_cycles, print_query_stack};
Expand Down
Loading
Loading