diff options
Diffstat (limited to 'compiler/rustc_query_impl/src/plumbing.rs')
-rw-r--r-- | compiler/rustc_query_impl/src/plumbing.rs | 447 |
1 files changed, 255 insertions, 192 deletions
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index eda4401c8..6f39bbfc0 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -2,19 +2,28 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. +use crate::keys::Key; +use crate::on_disk_cache::CacheDecoder; use crate::{on_disk_cache, Queries}; -use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; -use rustc_middle::ty::tls::{self, ImplicitCtxt}; -use rustc_middle::ty::TyCtxt; -use rustc_query_system::dep_graph::HasDepContext; -use rustc_query_system::query::{QueryContext, QueryJobId, QueryMap, QuerySideEffects}; - -use rustc_data_structures::sync::Lock; -use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_errors::{Diagnostic, Handler}; - +use rustc_middle::dep_graph::{ + self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex, +}; +use rustc_middle::ty::tls::{self, ImplicitCtxt}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; +use rustc_query_system::ich::StableHashingContext; +use rustc_query_system::query::{ + force_query, QueryConfig, QueryContext, QueryDescription, QueryJobId, QueryMap, + QuerySideEffects, QueryStackFrame, +}; +use rustc_query_system::Value; +use rustc_serialize::Decodable; use std::any::Any; use std::num::NonZeroU64; +use thin_vec::ThinVec; #[derive(Copy, Clone)] pub struct QueryCtxt<'tcx> { @@ -91,6 +100,7 @@ impl QueryContext for QueryCtxt<'_> { fn start_query<R>( &self, token: QueryJobId, + depth_limit: bool, diagnostics: Option<&Lock<ThinVec<Diagnostic>>>, compute: impl FnOnce() -> R, ) -> R { @@ -98,12 +108,16 @@ impl QueryContext for QueryCtxt<'_> { // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes // when accessing the `ImplicitCtxt`. tls::with_related_context(**self, move |current_icx| { + if depth_limit && !self.recursion_limit().value_within_limit(current_icx.query_depth) { + self.depth_limit_error(); + } + // Update the `ImplicitCtxt` to point to our new query job. let new_icx = ImplicitCtxt { tcx: **self, query: Some(token), diagnostics, - layout_depth: current_icx.layout_depth, + query_depth: current_icx.query_depth + depth_limit as usize, task_deps: current_icx.task_deps, }; @@ -137,19 +151,31 @@ impl<'tcx> QueryCtxt<'tcx> { encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx>, query_result_index: &mut on_disk_cache::EncodedDepNodeIndex, ) { + macro_rules! expand_if_cached { + ([] $encode:expr) => {}; + ([(cache) $($rest:tt)*] $encode:expr) => { + $encode + }; + ([$other:tt $($modifiers:tt)*] $encode:expr) => { + expand_if_cached!([$($modifiers)*] $encode) + }; + } + macro_rules! encode_queries { - ($($query:ident,)*) => { + ( + $($(#[$attr:meta])* + [$($modifiers:tt)*] fn $query:ident($($K:tt)*) -> $V:ty,)*) => { $( - on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>( + expand_if_cached!([$($modifiers)*] on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>( self, encoder, query_result_index - ); + )); )* } } - rustc_cached_queries!(encode_queries!); + rustc_query_append!(encode_queries!); } pub fn try_print_query_stack( @@ -163,21 +189,17 @@ impl<'tcx> QueryCtxt<'tcx> { } macro_rules! handle_cycle_error { - ([][$tcx: expr, $error:expr]) => {{ - $error.emit(); - Value::from_cycle_error($tcx) + ([]) => {{ + rustc_query_system::HandleCycleError::Error }}; - ([(fatal_cycle) $($rest:tt)*][$tcx:expr, $error:expr]) => {{ - $error.emit(); - $tcx.sess.abort_if_errors(); - unreachable!() + ([(fatal_cycle) $($rest:tt)*]) => {{ + rustc_query_system::HandleCycleError::Fatal }}; - ([(cycle_delay_bug) $($rest:tt)*][$tcx:expr, $error:expr]) => {{ - $error.delay_as_bug(); - Value::from_cycle_error($tcx) + ([(cycle_delay_bug) $($rest:tt)*]) => {{ + rustc_query_system::HandleCycleError::DelayBug }}; - ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - handle_cycle_error!([$($modifiers)*][$($args)*]) + ([$other:tt $($modifiers:tt)*]) => { + handle_cycle_error!([$($modifiers)*]) }; } @@ -205,6 +227,18 @@ macro_rules! is_eval_always { }; } +macro_rules! depth_limit { + ([]) => {{ + false + }}; + ([(depth_limit) $($rest:tt)*]) => {{ + true + }}; + ([$other:tt $($modifiers:tt)*]) => { + depth_limit!([$($modifiers)*]) + }; +} + macro_rules! hash_result { ([]) => {{ Some(dep_graph::hash_result) @@ -233,106 +267,174 @@ macro_rules! get_provider { }; } -macro_rules! opt_remap_env_constness { - ([][$name:ident]) => {}; - ([(remap_env_constness) $($rest:tt)*][$name:ident]) => { - let $name = $name.without_const(); +macro_rules! should_ever_cache_on_disk { + ([]) => {{ + None + }}; + ([(cache) $($rest:tt)*]) => {{ + Some($crate::plumbing::try_load_from_disk::<Self::Value>) + }}; + ([$other:tt $($modifiers:tt)*]) => { + should_ever_cache_on_disk!([$($modifiers)*]) }; - ([$other:tt $($modifiers:tt)*][$name:ident]) => { - opt_remap_env_constness!([$($modifiers)*][$name]) +} + +pub(crate) fn create_query_frame< + 'tcx, + K: Copy + Key + for<'a> HashStable<StableHashingContext<'a>>, +>( + tcx: QueryCtxt<'tcx>, + do_describe: fn(QueryCtxt<'tcx>, K) -> String, + key: K, + kind: DepKind, + name: &'static str, +) -> QueryStackFrame { + // Disable visible paths printing for performance reasons. + // Showing visible path instead of any path is not that important in production. + let description = ty::print::with_no_visible_paths!( + // Force filename-line mode to avoid invoking `type_of` query. + ty::print::with_forced_impl_filename_line!(do_describe(tcx, key)) + ); + let description = + if tcx.sess.verbose() { format!("{} [{}]", description, name) } else { description }; + let span = if kind == dep_graph::DepKind::def_span { + // The `def_span` query is used to calculate `default_span`, + // so exit to avoid infinite recursion. + None + } else { + Some(key.default_span(*tcx)) }; + let def_kind = if kind == dep_graph::DepKind::opt_def_kind { + // Try to avoid infinite recursion. + None + } else { + key.key_as_def_id() + .and_then(|def_id| def_id.as_local()) + .and_then(|def_id| tcx.opt_def_kind(def_id)) + }; + let hash = || { + tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher); + key.hash_stable(&mut hcx, &mut hasher); + hasher.finish::<u64>() + }) + }; + + QueryStackFrame::new(name, description, span, def_kind, hash) +} + +fn try_load_from_on_disk_cache<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) +where + Q: QueryDescription<QueryCtxt<'tcx>>, + Q::Key: DepNodeParams<TyCtxt<'tcx>>, +{ + debug_assert!(tcx.dep_graph.is_green(&dep_node)); + + let key = Q::Key::recover(tcx, &dep_node).unwrap_or_else(|| { + panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash) + }); + if Q::cache_on_disk(tcx, &key) { + let _ = Q::execute_query(tcx, key); + } +} + +pub(crate) fn try_load_from_disk<'tcx, V>( + tcx: QueryCtxt<'tcx>, + id: SerializedDepNodeIndex, +) -> Option<V> +where + V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>, +{ + tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id) +} + +fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool +where + Q: QueryDescription<QueryCtxt<'tcx>>, + Q::Key: DepNodeParams<TyCtxt<'tcx>>, + Q::Value: Value<TyCtxt<'tcx>>, +{ + if let Some(key) = Q::Key::recover(tcx, &dep_node) { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); + let tcx = QueryCtxt::from_tcx(tcx); + force_query::<Q, _>(tcx, key, dep_node); + true + } else { + false + } +} + +pub(crate) fn query_callback<'tcx, Q: QueryConfig>( + is_anon: bool, + is_eval_always: bool, +) -> DepKindStruct<'tcx> +where + Q: QueryDescription<QueryCtxt<'tcx>>, + Q::Key: DepNodeParams<TyCtxt<'tcx>>, +{ + let fingerprint_style = Q::Key::fingerprint_style(); + + if is_anon || !fingerprint_style.reconstructible() { + return DepKindStruct { + is_anon, + is_eval_always, + fingerprint_style, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + }; + } + + DepKindStruct { + is_anon, + is_eval_always, + fingerprint_style, + force_from_dep_node: Some(force_from_dep_node::<Q>), + try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache::<Q>), + } } +// NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros +// invoked by `rustc_query_append`. macro_rules! define_queries { - (<$tcx:tt> + ( $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { - define_queries_struct! { - tcx: $tcx, input: ($(([$($modifiers)*] [$($attr)*] [$name]))*) } - mod make_query { - use super::*; - - // Create an eponymous constructor for each query. - $(#[allow(nonstandard_style)] $(#[$attr])* - pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame { - opt_remap_env_constness!([$($modifiers)*][key]); - let kind = dep_graph::DepKind::$name; - let name = stringify!($name); - // Disable visible paths printing for performance reasons. - // Showing visible path instead of any path is not that important in production. - let description = ty::print::with_no_visible_paths!( - // Force filename-line mode to avoid invoking `type_of` query. - ty::print::with_forced_impl_filename_line!( - queries::$name::describe(tcx, key) - ) - ); - let description = if tcx.sess.verbose() { - format!("{} [{}]", description, name) - } else { - description - }; - let span = if kind == dep_graph::DepKind::def_span { - // The `def_span` query is used to calculate `default_span`, - // so exit to avoid infinite recursion. - None - } else { - Some(key.default_span(*tcx)) - }; - let def_kind = if kind == dep_graph::DepKind::opt_def_kind { - // Try to avoid infinite recursion. - None - } else { - key.key_as_def_id() - .and_then(|def_id| def_id.as_local()) - .and_then(|def_id| tcx.opt_def_kind(def_id)) - }; - let hash = || { - tcx.with_stable_hashing_context(|mut hcx|{ - let mut hasher = StableHasher::new(); - std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher); - key.hash_stable(&mut hcx, &mut hasher); - hasher.finish::<u64>() - }) - }; - - QueryStackFrame::new(name, description, span, def_kind, hash) - })* - } - #[allow(nonstandard_style)] mod queries { use std::marker::PhantomData; - $(pub struct $name<$tcx> { - data: PhantomData<&$tcx ()> + $(pub struct $name<'tcx> { + data: PhantomData<&'tcx ()> })* } - $(impl<$tcx> QueryConfig for queries::$name<$tcx> { - type Key = query_keys::$name<$tcx>; - type Value = query_values::$name<$tcx>; - type Stored = query_stored::$name<$tcx>; + $(impl<'tcx> QueryConfig for queries::$name<'tcx> { + type Key = query_keys::$name<'tcx>; + type Value = query_values::$name<'tcx>; + type Stored = query_stored::$name<'tcx>; const NAME: &'static str = stringify!($name); } - impl<$tcx> QueryDescription<QueryCtxt<$tcx>> for queries::$name<$tcx> { - rustc_query_description! { $name<$tcx> } + impl<'tcx> QueryDescription<QueryCtxt<'tcx>> for queries::$name<'tcx> { + rustc_query_description! { $name } - type Cache = query_storage::$name<$tcx>; + type Cache = query_storage::$name<'tcx>; #[inline(always)] - fn query_state<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryState<Self::Key> - where QueryCtxt<$tcx>: 'a + fn query_state<'a>(tcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key> + where QueryCtxt<'tcx>: 'a { &tcx.queries.$name } #[inline(always)] - fn query_cache<'a>(tcx: QueryCtxt<$tcx>) -> &'a Self::Cache + fn query_cache<'a>(tcx: QueryCtxt<'tcx>) -> &'a Self::Cache where 'tcx:'a { &tcx.query_caches.$name @@ -340,34 +442,34 @@ macro_rules! define_queries { #[inline] fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) -> - QueryVTable<QueryCtxt<$tcx>, Self::Key, Self::Value> + QueryVTable<QueryCtxt<'tcx>, Self::Key, Self::Value> { let compute = get_provider!([$($modifiers)*][tcx, $name, key]); let cache_on_disk = Self::cache_on_disk(tcx.tcx, key); QueryVTable { anon: is_anon!([$($modifiers)*]), eval_always: is_eval_always!([$($modifiers)*]), + depth_limit: depth_limit!([$($modifiers)*]), dep_kind: dep_graph::DepKind::$name, hash_result: hash_result!([$($modifiers)*]), - handle_cycle_error: |tcx, mut error| handle_cycle_error!([$($modifiers)*][tcx, error]), + handle_cycle_error: handle_cycle_error!([$($modifiers)*]), compute, - cache_on_disk, - try_load_from_disk: Self::TRY_LOAD_FROM_DISK, + try_load_from_disk: if cache_on_disk { should_ever_cache_on_disk!([$($modifiers)*]) } else { None }, } } + + fn execute_query(tcx: TyCtxt<'tcx>, k: Self::Key) -> Self::Stored { + tcx.$name(k) + } })* #[allow(nonstandard_style)] mod query_callbacks { use super::*; - use rustc_middle::dep_graph::DepNode; - use rustc_middle::ty::query::query_keys; - use rustc_query_system::dep_graph::DepNodeParams; - use rustc_query_system::query::{force_query, QueryDescription}; use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. - pub fn Null() -> DepKindStruct { + pub fn Null<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: false, is_eval_always: false, @@ -378,7 +480,7 @@ macro_rules! define_queries { } // We use this for the forever-red node. - pub fn Red() -> DepKindStruct { + pub fn Red<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: false, is_eval_always: false, @@ -388,7 +490,7 @@ macro_rules! define_queries { } } - pub fn TraitSelect() -> DepKindStruct { + pub fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: true, is_eval_always: false, @@ -398,7 +500,7 @@ macro_rules! define_queries { } } - pub fn CompileCodegenUnit() -> DepKindStruct { + pub fn CompileCodegenUnit<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: false, is_eval_always: false, @@ -408,7 +510,7 @@ macro_rules! define_queries { } } - pub fn CompileMonoItem() -> DepKindStruct { + pub fn CompileMonoItem<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: false, is_eval_always: false, @@ -418,108 +520,70 @@ macro_rules! define_queries { } } - $(pub(crate) fn $name()-> DepKindStruct { - let is_anon = is_anon!([$($modifiers)*]); - let is_eval_always = is_eval_always!([$($modifiers)*]); - - let fingerprint_style = - <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::fingerprint_style(); - - if is_anon || !fingerprint_style.reconstructible() { - return DepKindStruct { - is_anon, - is_eval_always, - fingerprint_style, - force_from_dep_node: None, - try_load_from_on_disk_cache: None, - } - } - - #[inline(always)] - fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option<query_keys::$name<'tcx>> { - <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, &dep_node) - } - - fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool { - if let Some(key) = recover(tcx, dep_node) { - #[cfg(debug_assertions)] - let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); - let tcx = QueryCtxt::from_tcx(tcx); - force_query::<queries::$name<'_>, _>(tcx, key, dep_node); - true - } else { - false - } - } - - fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) { - debug_assert!(tcx.dep_graph.is_green(&dep_node)); - - let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); - if queries::$name::cache_on_disk(tcx, &key) { - let _ = tcx.$name(key); - } - } - - DepKindStruct { - is_anon, - is_eval_always, - fingerprint_style, - force_from_dep_node: Some(force_from_dep_node), - try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache), - } + $(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> { + $crate::plumbing::query_callback::<queries::$name<'tcx>>( + is_anon!([$($modifiers)*]), + is_eval_always!([$($modifiers)*]), + ) })* } - pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] { + pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] { arena.alloc_from_iter(make_dep_kind_array!(query_callbacks)) } } } -// FIXME(eddyb) this macro (and others?) use `$tcx` and `'tcx` interchangeably. -// We should either not take `$tcx` at all and use `'tcx` everywhere, or use -// `$tcx` everywhere (even if that isn't necessary due to lack of hygiene). +use crate::{ExternProviders, OnDiskCache, Providers}; + +impl<'tcx> Queries<'tcx> { + pub fn new( + local_providers: Providers, + extern_providers: ExternProviders, + on_disk_cache: Option<OnDiskCache<'tcx>>, + ) -> Self { + Queries { + local_providers: Box::new(local_providers), + extern_providers: Box::new(extern_providers), + on_disk_cache, + jobs: AtomicU64::new(1), + ..Queries::default() + } + } +} + macro_rules! define_queries_struct { - (tcx: $tcx:tt, + ( input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { - pub struct Queries<$tcx> { + #[derive(Default)] + pub struct Queries<'tcx> { local_providers: Box<Providers>, extern_providers: Box<ExternProviders>, - pub on_disk_cache: Option<OnDiskCache<$tcx>>, + pub on_disk_cache: Option<OnDiskCache<'tcx>>, jobs: AtomicU64, - $($(#[$attr])* $name: QueryState<query_keys::$name<$tcx>>,)* + $($(#[$attr])* $name: QueryState<<queries::$name<'tcx> as QueryConfig>::Key>,)* } - impl<$tcx> Queries<$tcx> { - pub fn new( - local_providers: Providers, - extern_providers: ExternProviders, - on_disk_cache: Option<OnDiskCache<$tcx>>, - ) -> Self { - Queries { - local_providers: Box::new(local_providers), - extern_providers: Box::new(extern_providers), - on_disk_cache, - jobs: AtomicU64::new(1), - $($name: Default::default()),* - } - } - + impl<'tcx> Queries<'tcx> { pub(crate) fn try_collect_active_jobs( - &$tcx self, - tcx: TyCtxt<$tcx>, + &'tcx self, + tcx: TyCtxt<'tcx>, ) -> Option<QueryMap> { let tcx = QueryCtxt { tcx, queries: self }; let mut jobs = QueryMap::default(); $( + let make_query = |tcx, key| { + let kind = dep_graph::DepKind::$name; + let name = stringify!($name); + $crate::plumbing::create_query_frame(tcx, queries::$name::describe, key, kind, name) + }; self.$name.try_collect_active_jobs( tcx, - make_query::$name, + make_query, &mut jobs, )?; )* @@ -541,17 +605,16 @@ macro_rules! define_queries_struct { $($(#[$attr])* #[inline(always)] - #[tracing::instrument(level = "trace", skip(self, tcx))] + #[tracing::instrument(level = "trace", skip(self, tcx), ret)] fn $name( &'tcx self, - tcx: TyCtxt<$tcx>, + tcx: TyCtxt<'tcx>, span: Span, - key: query_keys::$name<$tcx>, + key: <queries::$name<'tcx> as QueryConfig>::Key, mode: QueryMode, - ) -> Option<query_stored::$name<$tcx>> { - opt_remap_env_constness!([$($modifiers)*][key]); + ) -> Option<query_stored::$name<'tcx>> { let qcx = QueryCtxt { tcx, queries: self }; - get_query::<queries::$name<$tcx>, _>(qcx, span, key, mode) + get_query::<queries::$name<'tcx>, _>(qcx, span, key, mode) })* } }; |