diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 8fe5756a60e..c209503e90e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -12,6 +12,7 @@ use hir::def_id::DefId; use infer::InferCtxt; +use hir::map as ast_map; use hir::pat_util; use traits::{self, Reveal}; use ty::{self, Ty, AdtKind, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; @@ -388,16 +389,77 @@ pub fn is_adt_dtorck(self, adt: ty::AdtDef) -> bool { } } +// When hashing a type this ends up affecting properties like symbol names. We +// want these symbol names to be calculated independent of other factors like +// what architecture you're compiling *from*. +// +// The hashing just uses the standard `Hash` trait, but the implementations of +// `Hash` for the `usize` and `isize` types are *not* architecture independent +// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and +// `isize` completely when hashing. To ensure that these don't leak in we use a +// custom hasher implementation here which inflates the size of these to a `u64` +// and `i64`. +struct WidenUsizeHasher { + inner: H, +} + +impl WidenUsizeHasher { + fn new(inner: H) -> WidenUsizeHasher { + WidenUsizeHasher { inner: inner } + } +} + +impl Hasher for WidenUsizeHasher { + fn write(&mut self, bytes: &[u8]) { + self.inner.write(bytes) + } + + fn finish(&self) -> u64 { + self.inner.finish() + } + + fn write_u8(&mut self, i: u8) { + self.inner.write_u8(i) + } + fn write_u16(&mut self, i: u16) { + self.inner.write_u16(i) + } + fn write_u32(&mut self, i: u32) { + self.inner.write_u32(i) + } + fn write_u64(&mut self, i: u64) { + self.inner.write_u64(i) + } + fn write_usize(&mut self, i: usize) { + self.inner.write_u64(i as u64) + } + fn write_i8(&mut self, i: i8) { + self.inner.write_i8(i) + } + fn write_i16(&mut self, i: i16) { + self.inner.write_i16(i) + } + fn write_i32(&mut self, i: i32) { + self.inner.write_i32(i) + } + fn write_i64(&mut self, i: i64) { + self.inner.write_i64(i) + } + fn write_isize(&mut self, i: isize) { + self.inner.write_i64(i as i64) + } +} + pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, H> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - state: H + state: WidenUsizeHasher, } impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> { pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, state: H) -> Self { TypeIdHasher { tcx: tcx, - state: state + state: WidenUsizeHasher::new(state), } } @@ -421,9 +483,12 @@ fn hash_discriminant_u8(&mut self, x: &T) { fn def_id(&mut self, did: DefId) { // Hash the DefPath corresponding to the DefId, which is independent // of compiler internal state. - let tcx = self.tcx; - let def_path = tcx.def_path(did); - def_path.deterministic_hash_to(tcx, &mut self.state); + let path = self.tcx.def_path(did); + self.def_path(&path) + } + + pub fn def_path(&mut self, def_path: &ast_map::DefPath) { + def_path.deterministic_hash_to(self.tcx, &mut self.state); } } @@ -436,7 +501,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { TyInt(i) => self.hash(i), TyUint(u) => self.hash(u), TyFloat(f) => self.hash(f), - TyArray(_, n) => self.hash(n as u64), + TyArray(_, n) => self.hash(n), TyRawPtr(m) | TyRef(_, m) => self.hash(m.mutbl), TyClosure(def_id, _) | @@ -447,14 +512,14 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { self.hash(f.unsafety); self.hash(f.abi); self.hash(f.sig.variadic()); - self.hash(f.sig.inputs().skip_binder().len() as u64); + self.hash(f.sig.inputs().skip_binder().len()); } TyTrait(ref data) => { self.def_id(data.principal.def_id()); self.hash(data.builtin_bounds); } TyTuple(tys) => { - self.hash(tys.len() as u64); + self.hash(tys.len()); } TyParam(p) => { self.hash(p.idx); diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 0a668db0690..f0661e03bc8 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -152,17 +152,17 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, let mut hash_state = scx.symbol_hasher().borrow_mut(); record_time(&tcx.sess.perf_stats.symbol_hash_time, || { hash_state.reset(); - let mut hasher = Sha256Hasher(&mut hash_state); + let hasher = Sha256Hasher(&mut hash_state); + let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher); // the main symbol name is not necessarily unique; hash in the // compiler's internal def-path, guaranteeing each symbol has a // truly unique path - def_path.deterministic_hash_to(tcx, &mut hasher); + hasher.def_path(def_path); // Include the main item-type. Note that, in this case, the // assertions about `needs_subst` may not hold, but this item-type // ought to be the same for every reference anyway. - let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher); assert!(!item_type.has_erasable_regions()); hasher.visit_ty(item_type);