rustc_symbol_mangling/
export.rs

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            // FIXME: Not yet supported.
104            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}