Skip to main content

rustc_middle/hooks/
mod.rs

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.
5
6use rustc_hir::def_id::{DefId, DefPathHash};
7use rustc_session::StableCrateId;
8use rustc_span::def_id::{CrateNum, LocalDefId};
9use rustc_span::{ExpnHash, ExpnId};
10
11use crate::mir;
12use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex};
13use crate::ty::{Ty, TyCtxt};
14
15macro_rules! declare_hooks {
16    ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => {
17
18        impl<'tcx> TyCtxt<'tcx> {
19            $(
20            $(#[$attr])*
21            #[inline(always)]
22            pub fn $name(self, $($arg: $K,)*) -> $V
23            {
24                (self.hooks.$name)(self, $($arg,)*)
25            }
26            )*
27        }
28
29        pub struct Providers {
30            $(pub $name: for<'tcx> fn(
31                TyCtxt<'tcx>,
32                $($arg: $K,)*
33            ) -> $V,)*
34        }
35
36        impl Default for Providers {
37            fn default() -> Self {
38                Providers {
39                    $($name: |_, $($arg,)*| default_hook(stringify!($name), &($($arg,)*))),*
40                }
41            }
42        }
43
44        impl Copy for Providers {}
45        impl Clone for Providers {
46            fn clone(&self) -> Self { *self }
47        }
48    };
49}
50
51impl<'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 query_key_hash_verify_all(self) -> () {
        (self.hooks.query_key_hash_verify_all)(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)
    }
    #[inline(always)]
    pub fn try_mark_green(self, dep_node: &crate::dep_graph::DepNode)
        -> bool {
        (self.hooks.try_mark_green)(self, dep_node)
    }
    #[inline(always)]
    pub fn encode_all_query_results(self,
        encoder: &mut CacheEncoder<'_, 'tcx>,
        query_result_index: &mut EncodedDepNodeIndex) -> () {
        (self.hooks.encode_all_query_results)(self, encoder,
            query_result_index)
    }
}
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 query_key_hash_verify_all: 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 try_mark_green: for<'tcx> fn(TyCtxt<'tcx>,
        dep_node: &crate::dep_graph::DepNode) -> bool,
    pub encode_all_query_results: for<'tcx> fn(TyCtxt<'tcx>,
        encoder: &mut CacheEncoder<'_, 'tcx>,
        query_result_index: &mut EncodedDepNodeIndex) -> (),
}
impl Default for Providers {
    fn default() -> Self {
        Providers {
            try_destructure_mir_constant_for_user_output: |_, val, ty|
                default_hook("try_destructure_mir_constant_for_user_output",
                    &(val, ty)),
            const_caller_location: |_, file, line, col|
                default_hook("const_caller_location", &(file, line, col)),
            is_eligible_for_coverage: |_, key|
                default_hook("is_eligible_for_coverage", &(key,)),
            import_source_files: |_, key|
                default_hook("import_source_files", &(key,)),
            expn_hash_to_expn_id: |_, cnum, index_guess, hash|
                default_hook("expn_hash_to_expn_id",
                    &(cnum, index_guess, hash)),
            def_path_hash_to_def_id_extern: |_, hash, stable_crate_id|
                default_hook("def_path_hash_to_def_id_extern",
                    &(hash, stable_crate_id)),
            should_codegen_locally: |_, instance|
                default_hook("should_codegen_locally", &(instance,)),
            alloc_self_profile_query_strings: |_|
                default_hook("alloc_self_profile_query_strings", &()),
            save_dep_graph: |_| default_hook("save_dep_graph", &()),
            query_key_hash_verify_all: |_|
                default_hook("query_key_hash_verify_all", &()),
            validate_scalar_in_layout: |_, scalar, ty|
                default_hook("validate_scalar_in_layout", &(scalar, ty)),
            build_mir_inner_impl: |_, def|
                default_hook("build_mir_inner_impl", &(def,)),
            try_mark_green: |_, dep_node|
                default_hook("try_mark_green", &(dep_node,)),
            encode_all_query_results: |_, encoder, query_result_index|
                default_hook("encode_all_query_results",
                    &(encoder, query_result_index)),
        }
    }
}
impl Copy for Providers {}
impl Clone for Providers {
    fn clone(&self) -> Self { *self }
}declare_hooks! {
52    /// Tries to destructure an `mir::Const` ADT or array into its variant index
53    /// and its field values. This should only be used for pretty printing.
54    hook try_destructure_mir_constant_for_user_output(val: mir::ConstValue, ty: Ty<'tcx>) -> Option<mir::DestructuredConstant<'tcx>>;
55
56    /// Getting a &core::panic::Location referring to a span.
57    hook const_caller_location(file: rustc_span::Symbol, line: u32, col: u32) -> mir::ConstValue;
58
59    /// Returns `true` if this def is a function-like thing that is eligible for
60    /// coverage instrumentation under `-Cinstrument-coverage`.
61    ///
62    /// (Eligible functions might nevertheless be skipped for other reasons.)
63    hook is_eligible_for_coverage(key: LocalDefId) -> bool;
64
65    /// Imports all `SourceFile`s from the given crate into the current session.
66    /// This normally happens automatically when we decode a `Span` from
67    /// that crate's metadata - however, the incr comp cache needs
68    /// to trigger this manually when decoding a foreign `Span`
69    hook import_source_files(key: CrateNum) -> ();
70
71    hook expn_hash_to_expn_id(
72        cnum: CrateNum,
73        index_guess: u32,
74        hash: ExpnHash
75    ) -> ExpnId;
76
77    /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
78    /// session, if it still exists. This is used during incremental compilation to
79    /// turn a deserialized `DefPathHash` into its current `DefId`.
80    /// Will fetch a DefId from a DefPathHash for a foreign crate.
81    hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> Option<DefId>;
82
83    /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
84    /// can just link to the upstream crate and therefore don't need a mono item.
85    ///
86    /// Note: this hook isn't called within `rustc_middle` but #127779 suggests it's a hook instead
87    /// of a normal function because external tools might want to override it.
88    hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool;
89
90    hook alloc_self_profile_query_strings() -> ();
91
92    /// Saves and writes the DepGraph to the file system.
93    ///
94    /// This function saves both the dep-graph and the query result cache,
95    /// and drops the result cache.
96    ///
97    /// This function should only run after all queries have completed.
98    /// Trying to execute a query afterwards would attempt to read the result cache we just dropped.
99    hook save_dep_graph() -> ();
100
101    hook query_key_hash_verify_all() -> ();
102
103    /// Ensure the given scalar is valid for the given type.
104    /// This checks non-recursive runtime validity.
105    hook validate_scalar_in_layout(scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool;
106
107    /// **Do not call this directly; call the `mir_built` query instead.**
108    ///
109    /// Creates the MIR for a given `DefId`, including unreachable code.
110    hook build_mir_inner_impl(def: LocalDefId) -> mir::Body<'tcx>;
111
112    hook try_mark_green(dep_node: &crate::dep_graph::DepNode) -> bool;
113
114    hook encode_all_query_results(
115        encoder: &mut CacheEncoder<'_, 'tcx>,
116        query_result_index: &mut EncodedDepNodeIndex
117    ) -> ();
118}
119
120#[cold]
121fn default_hook(name: &str, args: &dyn std::fmt::Debug) -> ! {
122    crate::util::bug::bug_fmt(format_args!("`tcx.{0}{1:?}` cannot be called as `{0}` was never assigned to a provider function",
        name, args))bug!(
123        "`tcx.{name}{args:?}` cannot be called as `{name}` was never assigned to a provider function"
124    )
125}