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! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, 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 String {
41 #[inline]
42 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
43 self[..].abi_hash(tcx, hasher);
44 }
45}
46
47impl<'tcx> AbiHashStable<'tcx> for Symbol {
48 #[inline]
49 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
50 self.as_str().abi_hash(tcx, hasher);
51 }
52}
53
54impl<'tcx, T: AbiHashStable<'tcx>> AbiHashStable<'tcx> for [T] {
55 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
56 self.len().abi_hash(tcx, hasher);
57 for item in self {
58 item.abi_hash(tcx, hasher);
59 }
60 }
61}
62
63impl<'tcx> AbiHashStable<'tcx> for Ty<'tcx> {
64 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
65 match self.kind() {
66 ty::Bool => sym::bool.abi_hash(tcx, hasher),
67 ty::Char => sym::char.abi_hash(tcx, hasher),
68 ty::Int(int_ty) => int_ty.name_str().abi_hash(tcx, hasher),
69 ty::Uint(uint_ty) => uint_ty.name_str().abi_hash(tcx, hasher),
70 ty::Float(float_ty) => float_ty.name_str().abi_hash(tcx, hasher),
71
72 ty::Adt(adt_def, args) => {
73 adt_def.is_struct().abi_hash(tcx, hasher);
74 adt_def.is_enum().abi_hash(tcx, hasher);
75 adt_def.is_union().abi_hash(tcx, hasher);
76
77 if let Some(align) = adt_def.repr().align {
78 align.bits().abi_hash(tcx, hasher);
79 }
80
81 if let Some(integer) = adt_def.repr().int {
82 match integer {
83 IntegerType::Pointer(sign) => sign.abi_hash(tcx, hasher),
84 IntegerType::Fixed(integer, sign) => {
85 integer.int_ty_str().abi_hash(tcx, hasher);
86 sign.abi_hash(tcx, hasher);
87 }
88 }
89 }
90
91 if let Some(pack) = adt_def.repr().pack {
92 pack.bits().abi_hash(tcx, hasher);
93 }
94
95 adt_def.repr().c().abi_hash(tcx, hasher);
96
97 for variant in adt_def.variants() {
98 variant.name.abi_hash(tcx, hasher);
99 for field in &variant.fields {
100 field.name.abi_hash(tcx, hasher);
101 let field_ty = tcx.type_of(field.did).instantiate_identity();
102 field_ty.abi_hash(tcx, hasher);
103 }
104 }
105 args.abi_hash(tcx, hasher);
106 }
107
108 ty::Tuple(args) if args.len() == 0 => {}
109
110 ty::Foreign(_)
112 | ty::Ref(_, _, _)
113 | ty::Str
114 | ty::Array(_, _)
115 | ty::Pat(_, _)
116 | ty::Slice(_)
117 | ty::RawPtr(_, _)
118 | ty::FnDef(_, _)
119 | ty::FnPtr(_, _)
120 | ty::Dynamic(_, _, _)
121 | ty::Closure(_, _)
122 | ty::CoroutineClosure(_, _)
123 | ty::Coroutine(_, _)
124 | ty::CoroutineWitness(_, _)
125 | ty::Never
126 | ty::Tuple(_)
127 | ty::Alias(_, _)
128 | ty::Param(_)
129 | ty::Bound(_, _)
130 | ty::Placeholder(_)
131 | ty::Infer(_)
132 | ty::UnsafeBinder(_) => unreachable!(),
133
134 ty::Error(_) => {}
135 }
136 }
137}
138
139impl<'tcx> AbiHashStable<'tcx> for ty::FnSig<'tcx> {
140 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
141 for ty in self.inputs_and_output {
142 ty.abi_hash(tcx, hasher);
143 }
144 self.safety.is_safe().abi_hash(tcx, hasher);
145 }
146}
147
148impl<'tcx> AbiHashStable<'tcx> for ty::GenericArg<'tcx> {
149 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
150 self.unpack().abi_hash(tcx, hasher);
151 }
152}
153
154impl<'tcx> AbiHashStable<'tcx> for ty::GenericArgKind<'tcx> {
155 fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
156 match self {
157 ty::GenericArgKind::Type(t) => t.abi_hash(tcx, hasher),
158 ty::GenericArgKind::Lifetime(_) | ty::GenericArgKind::Const(_) => unimplemented!(),
159 }
160 }
161}
162
163pub(crate) fn compute_hash_of_export_fn<'tcx>(
164 tcx: TyCtxt<'tcx>,
165 instance: Instance<'tcx>,
166) -> String {
167 let def_id = instance.def_id();
168 debug_assert_matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
169
170 let args = instance.args;
171 let sig_ty = tcx.fn_sig(def_id).instantiate(tcx, args);
172 let sig_ty = tcx.instantiate_bound_regions_with_erased(sig_ty);
173
174 let hash = {
175 let mut hasher = StableHasher::new();
176 sig_ty.abi_hash(tcx, &mut hasher);
177 hasher.finish::<Hash128>()
178 };
179
180 hash.as_u128().to_string()
181}