//! "Hooks" let you write `tcx` methods in downstream crates and call them in this crate, reducing //! the amount of code that needs to be in this crate (which is already very big). This is somewhat //! similar to queries, but queries come with a lot of machinery for caching and incremental //! compilation, whereas hooks are just plain function pointers without any of the query magic. use rustc_hir::def_id::{DefId, DefPathHash}; use rustc_session::StableCrateId; use rustc_span::def_id::{CrateNum, LocalDefId}; use rustc_span::{ExpnHash, ExpnId}; use crate::mir; use crate::ty::{Ty, TyCtxt}; macro_rules! declare_hooks { ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => { impl<'tcx> TyCtxt<'tcx> { $( $(#[$attr])* #[inline(always)] pub fn $name(self, $($arg: $K,)*) -> $V { (self.hooks.$name)(self, $($arg,)*) } )* } pub struct Providers { $(pub $name: for<'tcx> fn( TyCtxt<'tcx>, $($arg: $K,)* ) -> $V,)* } impl Default for Providers { fn default() -> Self { Providers { $($name: |_, $($arg,)*| default_hook(stringify!($name), &($($arg,)*))),* } } } impl Copy for Providers {} impl Clone for Providers { fn clone(&self) -> Self { *self } } }; } declare_hooks! { /// Tries to destructure an `mir::Const` ADT or array into its variant index /// and its field values. This should only be used for pretty printing. hook try_destructure_mir_constant_for_user_output(val: mir::ConstValue<'tcx>, ty: Ty<'tcx>) -> Option>; /// Getting a &core::panic::Location referring to a span. hook const_caller_location(file: rustc_span::Symbol, line: u32, col: u32) -> mir::ConstValue<'tcx>; /// Returns `true` if this def is a function-like thing that is eligible for /// coverage instrumentation under `-Cinstrument-coverage`. /// /// (Eligible functions might nevertheless be skipped for other reasons.) hook is_eligible_for_coverage(key: LocalDefId) -> bool; /// Imports all `SourceFile`s from the given crate into the current session. /// This normally happens automatically when we decode a `Span` from /// that crate's metadata - however, the incr comp cache needs /// to trigger this manually when decoding a foreign `Span` hook import_source_files(key: CrateNum) -> (); hook expn_hash_to_expn_id( cnum: CrateNum, index_guess: u32, hash: ExpnHash ) -> ExpnId; /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation /// session, if it still exists. This is used during incremental compilation to /// turn a deserialized `DefPathHash` into its current `DefId`. /// Will fetch a DefId from a DefPathHash for a foreign crate. hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId; /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. /// /// Note: this hook isn't called within `rustc_middle` but #127779 suggests it's a hook instead /// of a normal function because external tools might want to override it. hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool; hook alloc_self_profile_query_strings() -> (); /// Saves and writes the DepGraph to the file system. /// /// This function saves both the dep-graph and the query result cache, /// and drops the result cache. /// /// This function should only run after all queries have completed. /// Trying to execute a query afterwards would attempt to read the result cache we just dropped. hook save_dep_graph() -> (); hook query_key_hash_verify_all() -> (); /// Ensure the given scalar is valid for the given type. /// This checks non-recursive runtime validity. hook validate_scalar_in_layout(scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool; } #[cold] fn default_hook(name: &str, args: &dyn std::fmt::Debug) -> ! { bug!( "`tcx.{name}{args:?}` cannot be called as `{name}` was never assigned to a provider function" ) }