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