1use std::assert_matches::debug_assert_matches;
2
3use rustc_abi::IntegerType;
4use rustc_data_structures::stable_hasher::StableHasher;
5use rustc_hashes::Hash128;
6use rustc_hir::def::DefKind;
7use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
8use rustc_span::symbol::{Symbol, sym};
9
10trait AbiHashStable<'tcx> {
11 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher);
12}
13macro_rules! default_hash_impl {
14 ($($t:ty,)+) => {
15 $(impl<'tcx> AbiHashStable<'tcx> for $t {
16 #[inline]
17 fn abi_hash(&self, _tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
18 ::std::hash::Hash::hash(self, hasher);
19 }
20 })*
21 };
22}
23
24default_hash_impl! { u8, u64, usize, }
25
26impl<'tcx> AbiHashStable<'tcx> for bool {
27 #[inline]
28 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
29 (if *self { 1u8 } else { 0u8 }).abi_hash(tcx, hasher);
30 }
31}
32
33impl<'tcx> AbiHashStable<'tcx> for str {
34 #[inline]
35 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
36 self.as_bytes().abi_hash(tcx, hasher);
37 }
38}
39
40impl<'tcx> AbiHashStable<'tcx> for Symbol {
41 #[inline]
42 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
43 self.as_str().abi_hash(tcx, hasher);
44 }
45}
46
47impl<'tcx, T: AbiHashStable<'tcx>> AbiHashStable<'tcx> for [T] {
48 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
49 self.len().abi_hash(tcx, hasher);
50 for item in self {
51 item.abi_hash(tcx, hasher);
52 }
53 }
54}
55
56impl<'tcx> AbiHashStable<'tcx> for Ty<'tcx> {
57 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
58 match self.kind() {
59 ty::Bool => sym::bool.abi_hash(tcx, hasher),
60 ty::Char => sym::char.abi_hash(tcx, hasher),
61 ty::Int(int_ty) => int_ty.name_str().abi_hash(tcx, hasher),
62 ty::Uint(uint_ty) => uint_ty.name_str().abi_hash(tcx, hasher),
63 ty::Float(float_ty) => float_ty.name_str().abi_hash(tcx, hasher),
64
65 ty::Adt(adt_def, args) => {
66 adt_def.is_struct().abi_hash(tcx, hasher);
67 adt_def.is_enum().abi_hash(tcx, hasher);
68 adt_def.is_union().abi_hash(tcx, hasher);
69
70 if let Some(align) = adt_def.repr().align {
71 align.bits().abi_hash(tcx, hasher);
72 }
73
74 if let Some(integer) = adt_def.repr().int {
75 match integer {
76 IntegerType::Pointer(sign) => sign.abi_hash(tcx, hasher),
77 IntegerType::Fixed(integer, sign) => {
78 integer.int_ty_str().abi_hash(tcx, hasher);
79 sign.abi_hash(tcx, hasher);
80 }
81 }
82 }
83
84 if let Some(pack) = adt_def.repr().pack {
85 pack.bits().abi_hash(tcx, hasher);
86 }
87
88 adt_def.repr().c().abi_hash(tcx, hasher);
89
90 for variant in adt_def.variants() {
91 variant.name.abi_hash(tcx, hasher);
92 for field in &variant.fields {
93 field.name.abi_hash(tcx, hasher);
94 let field_ty = tcx.type_of(field.did).instantiate_identity();
95 field_ty.abi_hash(tcx, hasher);
96 }
97 }
98 args.abi_hash(tcx, hasher);
99 }
100
101 ty::Tuple(args) if args.len() == 0 => {}
102
103 ty::Foreign(_)
105 | ty::Ref(_, _, _)
106 | ty::Str
107 | ty::Array(_, _)
108 | ty::Pat(_, _)
109 | ty::Slice(_)
110 | ty::RawPtr(_, _)
111 | ty::FnDef(_, _)
112 | ty::FnPtr(_, _)
113 | ty::Dynamic(_, _, _)
114 | ty::Closure(_, _)
115 | ty::CoroutineClosure(_, _)
116 | ty::Coroutine(_, _)
117 | ty::CoroutineWitness(_, _)
118 | ty::Never
119 | ty::Tuple(_)
120 | ty::Alias(_, _)
121 | ty::Param(_)
122 | ty::Bound(_, _)
123 | ty::Placeholder(_)
124 | ty::Infer(_)
125 | ty::UnsafeBinder(_) => unreachable!(),
126
127 ty::Error(_) => {}
128 }
129 }
130}
131
132impl<'tcx> AbiHashStable<'tcx> for ty::FnSig<'tcx> {
133 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
134 for ty in self.inputs_and_output {
135 ty.abi_hash(tcx, hasher);
136 }
137 self.safety.is_safe().abi_hash(tcx, hasher);
138 }
139}
140
141impl<'tcx> AbiHashStable<'tcx> for ty::GenericArg<'tcx> {
142 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
143 self.kind().abi_hash(tcx, hasher);
144 }
145}
146
147impl<'tcx> AbiHashStable<'tcx> for ty::GenericArgKind<'tcx> {
148 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
149 match self {
150 ty::GenericArgKind::Type(t) => t.abi_hash(tcx, hasher),
151 ty::GenericArgKind::Lifetime(_) | ty::GenericArgKind::Const(_) => unimplemented!(),
152 }
153 }
154}
155
156pub(crate) fn compute_hash_of_export_fn<'tcx>(
157 tcx: TyCtxt<'tcx>,
158 instance: Instance<'tcx>,
159) -> String {
160 let def_id = instance.def_id();
161 debug_assert_matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
162
163 let args = instance.args;
164 let sig_ty = tcx.fn_sig(def_id).instantiate(tcx, args);
165 let sig_ty = tcx.instantiate_bound_regions_with_erased(sig_ty);
166
167 let hash = {
168 let mut hasher = StableHasher::new();
169 sig_ty.abi_hash(tcx, &mut hasher);
170 hasher.finish::<Hash128>()
171 };
172
173 hash.as_u128().to_string()
174}