1//! "Hooks" let you write `tcx` methods in downstream crates and call them in this crate, reducing
2//! the amount of code that needs to be in this crate (which is already very big). This is somewhat
3//! similar to queries, but queries come with a lot of machinery for caching and incremental
4//! compilation, whereas hooks are just plain function pointers without any of the query magic.
56use rustc_hir::def_id::{DefId, DefPathHash};
7use rustc_session::StableCrateId;
8use rustc_span::def_id::{CrateNum, LocalDefId};
9use rustc_span::{ExpnHash, ExpnId};
1011use crate::mir;
12use crate::query::on_disk_cache::CacheEncoder;
13use crate::ty::{Ty, TyCtxt};
1415macro_rules!declare_hooks {
16 ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => {
1718impl<'tcx> TyCtxt<'tcx> {
19 $(
20 $(#[$attr])*
21#[inline(always)]
22pub fn $name(self, $($arg: $K,)*) -> $V
23{
24 (self.hooks.$name)(self, $($arg,)*)
25 }
26 )*
27 }
2829pub struct Providers {
30 $(pub $name: for<'tcx> fn(
31TyCtxt<'tcx>,
32 $($arg: $K,)*
33 ) -> $V,)*
34 }
3536impl Default for Providers {
37fn default() -> Self {
38#[allow(unused)]
39Providers {
40 $($name:
41 |_, $($arg,)*| default_hook(stringify!($name))),*
42 }
43 }
44 }
4546impl Copy for Providers {}
47impl Clone for Providers {
48fn clone(&self) -> Self { *self }
49 }
50 };
51}
5253impl<'tcx> TyCtxt<'tcx> {
#[doc =
r" Tries to destructure an `mir::Const` ADT or array into its variant index"]
#[doc =
r" and its field values. This should only be used for pretty printing."]
#[inline(always)]
pub fn try_destructure_mir_constant_for_user_output(self,
val: mir::ConstValue, ty: Ty<'tcx>)
-> Option<mir::DestructuredConstant<'tcx>> {
(self.hooks.try_destructure_mir_constant_for_user_output)(self, val,
ty)
}
#[doc = r" Getting a &core::panic::Location referring to a span."]
#[inline(always)]
pub fn const_caller_location(self, file: rustc_span::Symbol, line: u32,
col: u32) -> mir::ConstValue {
(self.hooks.const_caller_location)(self, file, line, col)
}
#[doc =
r" Returns `true` if this def is a function-like thing that is eligible for"]
#[doc = r" coverage instrumentation under `-Cinstrument-coverage`."]
#[doc = r""]
#[doc =
r" (Eligible functions might nevertheless be skipped for other reasons.)"]
#[inline(always)]
pub fn is_eligible_for_coverage(self, key: LocalDefId) -> bool {
(self.hooks.is_eligible_for_coverage)(self, key)
}
#[doc =
r" Imports all `SourceFile`s from the given crate into the current session."]
#[doc =
r" This normally happens automatically when we decode a `Span` from"]
#[doc = r" that crate's metadata - however, the incr comp cache needs"]
#[doc = r" to trigger this manually when decoding a foreign `Span`"]
#[inline(always)]
pub fn import_source_files(self, key: CrateNum) -> () {
(self.hooks.import_source_files)(self, key)
}
#[inline(always)]
pub fn expn_hash_to_expn_id(self, cnum: CrateNum, index_guess: u32,
hash: ExpnHash) -> ExpnId {
(self.hooks.expn_hash_to_expn_id)(self, cnum, index_guess, hash)
}
#[doc =
r" Converts a `DefPathHash` to its corresponding `DefId` in the current compilation"]
#[doc =
r" session, if it still exists. This is used during incremental compilation to"]
#[doc = r" turn a deserialized `DefPathHash` into its current `DefId`."]
#[doc = r" Will fetch a DefId from a DefPathHash for a foreign crate."]
#[inline(always)]
pub fn def_path_hash_to_def_id_extern(self, hash: DefPathHash,
stable_crate_id: StableCrateId) -> Option<DefId> {
(self.hooks.def_path_hash_to_def_id_extern)(self, hash,
stable_crate_id)
}
#[doc =
r" Returns `true` if we should codegen an instance in the local crate, or returns `false` if we"]
#[doc =
r" can just link to the upstream crate and therefore don't need a mono item."]
#[doc = r""]
#[doc =
r" Note: this hook isn't called within `rustc_middle` but #127779 suggests it's a hook instead"]
#[doc =
r" of a normal function because external tools might want to override it."]
#[inline(always)]
pub fn should_codegen_locally(self, instance: crate::ty::Instance<'tcx>)
-> bool {
(self.hooks.should_codegen_locally)(self, instance)
}
#[inline(always)]
pub fn alloc_self_profile_query_strings(self) -> () {
(self.hooks.alloc_self_profile_query_strings)(self)
}
#[doc = r" Saves and writes the DepGraph to the file system."]
#[doc = r""]
#[doc =
r" This function saves both the dep-graph and the query result cache,"]
#[doc = r" and drops the result cache."]
#[doc = r""]
#[doc =
r" This function should only run after all queries have completed."]
#[doc =
r" Trying to execute a query afterwards would attempt to read the result cache we just dropped."]
#[inline(always)]
pub fn save_dep_graph(self) -> () { (self.hooks.save_dep_graph)(self) }
#[inline(always)]
pub fn verify_query_key_hashes(self) -> () {
(self.hooks.verify_query_key_hashes)(self)
}
#[doc = r" Ensure the given scalar is valid for the given type."]
#[doc = r" This checks non-recursive runtime validity."]
#[inline(always)]
pub fn validate_scalar_in_layout(self, scalar: crate::ty::ScalarInt,
ty: Ty<'tcx>) -> bool {
(self.hooks.validate_scalar_in_layout)(self, scalar, ty)
}
#[doc =
r" **Do not call this directly; call the `mir_built` query instead.**"]
#[doc = r""]
#[doc =
r" Creates the MIR for a given `DefId`, including unreachable code."]
#[inline(always)]
pub fn build_mir_inner_impl(self, def: LocalDefId) -> mir::Body<'tcx> {
(self.hooks.build_mir_inner_impl)(self, def)
}
#[doc =
r" Serializes all eligible query return values into the on-disk cache."]
#[inline(always)]
pub fn encode_query_values(self, encoder: &mut CacheEncoder<'_, 'tcx>)
-> () {
(self.hooks.encode_query_values)(self, encoder)
}
}
pub struct Providers {
pub try_destructure_mir_constant_for_user_output: for<'tcx> fn(TyCtxt<'tcx>,
val: mir::ConstValue, ty: Ty<'tcx>)
-> Option<mir::DestructuredConstant<'tcx>>,
pub const_caller_location: for<'tcx> fn(TyCtxt<'tcx>,
file: rustc_span::Symbol, line: u32, col: u32) -> mir::ConstValue,
pub is_eligible_for_coverage: for<'tcx> fn(TyCtxt<'tcx>, key: LocalDefId)
-> bool,
pub import_source_files: for<'tcx> fn(TyCtxt<'tcx>, key: CrateNum) -> (),
pub expn_hash_to_expn_id: for<'tcx> fn(TyCtxt<'tcx>, cnum: CrateNum,
index_guess: u32, hash: ExpnHash) -> ExpnId,
pub def_path_hash_to_def_id_extern: for<'tcx> fn(TyCtxt<'tcx>,
hash: DefPathHash, stable_crate_id: StableCrateId) -> Option<DefId>,
pub should_codegen_locally: for<'tcx> fn(TyCtxt<'tcx>,
instance: crate::ty::Instance<'tcx>) -> bool,
pub alloc_self_profile_query_strings: for<'tcx> fn(TyCtxt<'tcx>) -> (),
pub save_dep_graph: for<'tcx> fn(TyCtxt<'tcx>) -> (),
pub verify_query_key_hashes: for<'tcx> fn(TyCtxt<'tcx>) -> (),
pub validate_scalar_in_layout: for<'tcx> fn(TyCtxt<'tcx>,
scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool,
pub build_mir_inner_impl: for<'tcx> fn(TyCtxt<'tcx>, def: LocalDefId)
-> mir::Body<'tcx>,
pub encode_query_values: for<'tcx> fn(TyCtxt<'tcx>,
encoder: &mut CacheEncoder<'_, 'tcx>) -> (),
}
impl Default for Providers {
fn default() -> Self {
#[allow(unused)]
Providers {
try_destructure_mir_constant_for_user_output: |_, val, ty|
default_hook("try_destructure_mir_constant_for_user_output"),
const_caller_location: |_, file, line, col|
default_hook("const_caller_location"),
is_eligible_for_coverage: |_, key|
default_hook("is_eligible_for_coverage"),
import_source_files: |_, key| default_hook("import_source_files"),
expn_hash_to_expn_id: |_, cnum, index_guess, hash|
default_hook("expn_hash_to_expn_id"),
def_path_hash_to_def_id_extern: |_, hash, stable_crate_id|
default_hook("def_path_hash_to_def_id_extern"),
should_codegen_locally: |_, instance|
default_hook("should_codegen_locally"),
alloc_self_profile_query_strings: |_|
default_hook("alloc_self_profile_query_strings"),
save_dep_graph: |_| default_hook("save_dep_graph"),
verify_query_key_hashes: |_|
default_hook("verify_query_key_hashes"),
validate_scalar_in_layout: |_, scalar, ty|
default_hook("validate_scalar_in_layout"),
build_mir_inner_impl: |_, def|
default_hook("build_mir_inner_impl"),
encode_query_values: |_, encoder|
default_hook("encode_query_values"),
}
}
}
impl Copy for Providers {}
impl Clone for Providers {
fn clone(&self) -> Self { *self }
}declare_hooks! {
54/// Tries to destructure an `mir::Const` ADT or array into its variant index
55 /// and its field values. This should only be used for pretty printing.
56hook try_destructure_mir_constant_for_user_output(val: mir::ConstValue, ty: Ty<'tcx>) -> Option<mir::DestructuredConstant<'tcx>>;
5758/// Getting a &core::panic::Location referring to a span.
59hook const_caller_location(file: rustc_span::Symbol, line: u32, col: u32) -> mir::ConstValue;
6061/// Returns `true` if this def is a function-like thing that is eligible for
62 /// coverage instrumentation under `-Cinstrument-coverage`.
63 ///
64 /// (Eligible functions might nevertheless be skipped for other reasons.)
65hook is_eligible_for_coverage(key: LocalDefId) -> bool;
6667/// Imports all `SourceFile`s from the given crate into the current session.
68 /// This normally happens automatically when we decode a `Span` from
69 /// that crate's metadata - however, the incr comp cache needs
70 /// to trigger this manually when decoding a foreign `Span`
71hook import_source_files(key: CrateNum) -> ();
7273 hook expn_hash_to_expn_id(
74 cnum: CrateNum,
75 index_guess: u32,
76 hash: ExpnHash77 ) -> ExpnId;
7879/// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
80 /// session, if it still exists. This is used during incremental compilation to
81 /// turn a deserialized `DefPathHash` into its current `DefId`.
82 /// Will fetch a DefId from a DefPathHash for a foreign crate.
83hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> Option<DefId>;
8485/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
86 /// can just link to the upstream crate and therefore don't need a mono item.
87 ///
88 /// Note: this hook isn't called within `rustc_middle` but #127779 suggests it's a hook instead
89 /// of a normal function because external tools might want to override it.
90hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool;
9192 hook alloc_self_profile_query_strings() -> ();
9394/// Saves and writes the DepGraph to the file system.
95 ///
96 /// This function saves both the dep-graph and the query result cache,
97 /// and drops the result cache.
98 ///
99 /// This function should only run after all queries have completed.
100 /// Trying to execute a query afterwards would attempt to read the result cache we just dropped.
101hook save_dep_graph() -> ();
102103 hook verify_query_key_hashes() -> ();
104105/// Ensure the given scalar is valid for the given type.
106 /// This checks non-recursive runtime validity.
107hook validate_scalar_in_layout(scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool;
108109/// **Do not call this directly; call the `mir_built` query instead.**
110 ///
111 /// Creates the MIR for a given `DefId`, including unreachable code.
112hook build_mir_inner_impl(def: LocalDefId) -> mir::Body<'tcx>;
113114/// Serializes all eligible query return values into the on-disk cache.
115hook encode_query_values(encoder: &mut CacheEncoder<'_, 'tcx>) -> ();
116}117118#[cold]
119fn default_hook(name: &str) -> ! {
120crate::util::bug::bug_fmt(format_args!("`tcx.{0}` cannot be called as `{0}` was never assigned to a provider function",
name))bug!("`tcx.{name}` cannot be called as `{name}` was never assigned to a provider function")121}