| use std::debug_assert_matches; | |
| use rustc_abi::IntegerType; | |
| use rustc_data_structures::stable_hash::StableHasher; | |
| use rustc_hashes::Hash128; | |
| use rustc_hir::def::DefKind; | |
| use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; | |
| use rustc_span::symbol::{Symbol, sym}; | |
| trait AbiStableHash<'tcx> { | |
| fn abi_stable_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher); | |
| } | |
| macro_rules! default_hash_impl { | |
| ($($t:ty,)+) => { | |
| $(impl<'tcx> AbiStableHash<'tcx> for $t { | |
| #[inline] | |
| fn abi_stable_hash(&self, _tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { | |
| ::std::hash::Hash::hash(self, hasher); | |
| } | |
| })* | |
| }; | |
| } | |
| default_hash_impl! { u8, u64, usize, } | |
| impl<'tcx> AbiStableHash<'tcx> for bool { | |
| #[inline] | |
| fn abi_stable_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { | |
| (if *self { 1u8 } else { 0u8 }).abi_stable_hash(tcx, hasher); | |
| } | |
| } | |
| impl<'tcx> AbiStableHash<'tcx> for str { | |
| #[inline] | |
| fn abi_stable_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { | |
| self.as_bytes().abi_stable_hash(tcx, hasher); | |
| } | |
| } | |
| impl<'tcx> AbiStableHash<'tcx> for Symbol { | |
| #[inline] | |
| fn abi_stable_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { | |
| self.as_str().abi_stable_hash(tcx, hasher); | |
| } | |
| } | |
| impl<'tcx, T: AbiStableHash<'tcx>> AbiStableHash<'tcx> for [T] { | |
| fn abi_stable_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { | |
| self.len().abi_stable_hash(tcx, hasher); | |
| for item in self { | |
| item.abi_stable_hash(tcx, hasher); | |
| } | |
| } | |
| } | |
| impl<'tcx> AbiStableHash<'tcx> for Ty<'tcx> { | |
| fn abi_stable_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { | |
| match self.kind() { | |
| ty::Bool => sym::bool.abi_stable_hash(tcx, hasher), | |
| ty::Char => sym::char.abi_stable_hash(tcx, hasher), | |
| ty::Int(int_ty) => int_ty.name_str().abi_stable_hash(tcx, hasher), | |
| ty::Uint(uint_ty) => uint_ty.name_str().abi_stable_hash(tcx, hasher), | |
| ty::Float(float_ty) => float_ty.name_str().abi_stable_hash(tcx, hasher), | |
| ty::Adt(adt_def, args) => { | |
| adt_def.is_struct().abi_stable_hash(tcx, hasher); | |
| adt_def.is_enum().abi_stable_hash(tcx, hasher); | |
| adt_def.is_union().abi_stable_hash(tcx, hasher); | |
| if let Some(align) = adt_def.repr().align { | |
| align.bits().abi_stable_hash(tcx, hasher); | |
| } | |
| if let Some(integer) = adt_def.repr().int { | |
| match integer { | |
| IntegerType::Pointer(sign) => sign.abi_stable_hash(tcx, hasher), | |
| IntegerType::Fixed(integer, sign) => { | |
| integer.int_ty_str().abi_stable_hash(tcx, hasher); | |
| sign.abi_stable_hash(tcx, hasher); | |
| } | |
| } | |
| } | |
| if let Some(pack) = adt_def.repr().pack { | |
| pack.bits().abi_stable_hash(tcx, hasher); | |
| } | |
| adt_def.repr().c().abi_stable_hash(tcx, hasher); | |
| for variant in adt_def.variants() { | |
| variant.name.abi_stable_hash(tcx, hasher); | |
| for field in &variant.fields { | |
| field.name.abi_stable_hash(tcx, hasher); | |
| let field_ty = | |
| tcx.type_of(field.did).instantiate_identity().skip_norm_wip(); | |
| field_ty.abi_stable_hash(tcx, hasher); | |
| } | |
| } | |
| args.abi_stable_hash(tcx, hasher); | |
| } | |
| ty::Tuple(args) if args.len() == 0 => {} | |
| // FIXME: Not yet supported. | |
| ty::Foreign(_) | |
| | ty::Ref(_, _, _) | |
| | ty::Str | |
| | ty::Array(_, _) | |
| | ty::Pat(_, _) | |
| | ty::Slice(_) | |
| | ty::RawPtr(_, _) | |
| | ty::FnDef(_, _) | |
| | ty::FnPtr(_, _) | |
| | ty::Dynamic(_, _) | |
| | ty::Closure(_, _) | |
| | ty::CoroutineClosure(_, _) | |
| | ty::Coroutine(_, _) | |
| | ty::CoroutineWitness(_, _) | |
| | ty::Never | |
| | ty::Tuple(_) | |
| | ty::Alias(_, _) | |
| | ty::Param(_) | |
| | ty::Bound(_, _) | |
| | ty::Placeholder(_) | |
| | ty::Infer(_) | |
| | ty::UnsafeBinder(_) => unreachable!(), | |
| ty::Error(_) => {} | |
| } | |
| } | |
| } | |
| impl<'tcx> AbiStableHash<'tcx> for ty::FnSig<'tcx> { | |
| fn abi_stable_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { | |
| for ty in self.inputs_and_output { | |
| ty.abi_stable_hash(tcx, hasher); | |
| } | |
| self.safety().is_safe().abi_stable_hash(tcx, hasher); | |
| } | |
| } | |
| impl<'tcx> AbiStableHash<'tcx> for ty::GenericArg<'tcx> { | |
| fn abi_stable_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { | |
| self.kind().abi_stable_hash(tcx, hasher); | |
| } | |
| } | |
| impl<'tcx> AbiStableHash<'tcx> for ty::GenericArgKind<'tcx> { | |
| fn abi_stable_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { | |
| match self { | |
| ty::GenericArgKind::Type(t) => t.abi_stable_hash(tcx, hasher), | |
| ty::GenericArgKind::Lifetime(_) | ty::GenericArgKind::Const(_) => unimplemented!(), | |
| } | |
| } | |
| } | |
| pub(crate) fn compute_hash_of_export_fn<'tcx>( | |
| tcx: TyCtxt<'tcx>, | |
| instance: Instance<'tcx>, | |
| ) -> String { | |
| let def_id = instance.def_id(); | |
| debug_assert_matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn); | |
| let args = instance.args; | |
| let sig_ty = tcx.fn_sig(def_id).instantiate(tcx, args).skip_norm_wip(); | |
| let sig_ty = tcx.instantiate_bound_regions_with_erased(sig_ty); | |
| let hash = { | |
| let mut hasher = StableHasher::new(); | |
| sig_ty.abi_stable_hash(tcx, &mut hasher); | |
| hasher.finish::<Hash128>() | |
| }; | |
| hash.as_u128().to_string() | |
| } |