about summary refs log tree commit diff
path: root/compiler/rustc_span/src/def_id.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_span/src/def_id.rs')
-rw-r--r--compiler/rustc_span/src/def_id.rs106
1 files changed, 79 insertions, 27 deletions
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 64baf94cc00..147c1f9e043 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -7,6 +7,7 @@ use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::borrow::Borrow;
 use std::fmt;
+use std::hash::{Hash, Hasher};
 
 rustc_index::newtype_index! {
     pub struct CrateNum {
@@ -46,8 +47,8 @@ impl<E: Encoder> Encodable<E> for CrateNum {
 }
 
 impl<D: Decoder> Decodable<D> for CrateNum {
-    default fn decode(d: &mut D) -> Result<CrateNum, D::Error> {
-        Ok(CrateNum::from_u32(d.read_u32()?))
+    default fn decode(d: &mut D) -> CrateNum {
+        CrateNum::from_u32(d.read_u32())
     }
 }
 
@@ -126,14 +127,17 @@ impl Borrow<Fingerprint> for DefPathHash {
     }
 }
 
-/// A [StableCrateId] is a 64 bit hash of the crate name combined with all
-/// `-Cmetadata` arguments. It is to [CrateNum] what [DefPathHash] is to
-/// [DefId]. It is stable across compilation sessions.
+/// A [`StableCrateId`] is a 64-bit hash of a crate name, together with all
+/// `-Cmetadata` arguments, and some other data. It is to [`CrateNum`] what [`DefPathHash`] is to
+/// [`DefId`]. It is stable across compilation sessions.
 ///
-/// Since the ID is a hash value there is a (very small) chance that two crates
-/// end up with the same [StableCrateId]. The compiler will check for such
+/// Since the ID is a hash value, there is a small chance that two crates
+/// end up with the same [`StableCrateId`]. The compiler will check for such
 /// collisions when loading crates and abort compilation in order to avoid
 /// further trouble.
+///
+/// For more information on the possibility of hash collisions in rustc,
+/// see the discussion in [`DefId`].
 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub struct StableCrateId(pub(crate) u64);
@@ -146,13 +150,10 @@ impl StableCrateId {
     /// Computes the stable ID for a crate with the given name and
     /// `-Cmetadata` arguments.
     pub fn new(crate_name: &str, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId {
-        use std::hash::Hash;
-        use std::hash::Hasher;
-
         let mut hasher = StableHasher::new();
         crate_name.hash(&mut hasher);
 
-        // We don't want the stable crate id to dependent on the order
+        // We don't want the stable crate ID to depend on the order of
         // -C metadata arguments, so sort them:
         metadata.sort();
         // Every distinct -C metadata value is only incorporated once:
@@ -171,6 +172,18 @@ impl StableCrateId {
         // linking against a library of the same name, if this is an executable.
         hasher.write(if is_exe { b"exe" } else { b"lib" });
 
+        // Also incorporate the rustc version. Otherwise, with -Zsymbol-mangling-version=v0
+        // and no -Cmetadata, symbols from the same crate compiled with different versions of
+        // rustc are named the same.
+        //
+        // RUSTC_FORCE_RUSTC_VERSION is used to inject rustc version information
+        // during testing.
+        if let Some(val) = std::env::var_os("RUSTC_FORCE_RUSTC_VERSION") {
+            hasher.write(val.to_string_lossy().into_owned().as_bytes())
+        } else {
+            hasher.write(option_env!("CFG_VERSION").unwrap_or("unknown version").as_bytes());
+        }
+
         StableCrateId(hasher.finish())
     }
 }
@@ -196,7 +209,7 @@ impl<E: Encoder> Encodable<E> for DefIndex {
 }
 
 impl<D: Decoder> Decodable<D> for DefIndex {
-    default fn decode(_: &mut D) -> Result<DefIndex, D::Error> {
+    default fn decode(_: &mut D) -> DefIndex {
         panic!("cannot decode `DefIndex` with `{}`", std::any::type_name::<D>());
     }
 }
@@ -205,12 +218,47 @@ impl<D: Decoder> Decodable<D> for DefIndex {
 /// index and a def index.
 ///
 /// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
+// On below-64 bit systems we can simply use the derived `Hash` impl
+#[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
+#[repr(C)]
+// We guarantee field order. Note that the order is essential here, see below why.
 pub struct DefId {
+    // cfg-ing the order of fields so that the `DefIndex` which is high entropy always ends up in
+    // the lower bits no matter the endianness. This allows the compiler to turn that `Hash` impl
+    // into a direct call to 'u64::hash(_)`.
+    #[cfg(not(all(target_pointer_width = "64", target_endian = "big")))]
+    pub index: DefIndex,
     pub krate: CrateNum,
+    #[cfg(all(target_pointer_width = "64", target_endian = "big"))]
     pub index: DefIndex,
 }
 
+// On 64-bit systems, we can hash the whole `DefId` as one `u64` instead of two `u32`s. This
+// improves performance without impairing `FxHash` quality. So the below code gets compiled to a
+// noop on little endian systems because the memory layout of `DefId` is as follows:
+//
+// ```
+//     +-1--------------31-+-32-------------63-+
+//     ! index             ! krate             !
+//     +-------------------+-------------------+
+// ```
+//
+// The order here has direct impact on `FxHash` quality because we have far more `DefIndex` per
+// crate than we have `Crate`s within one compilation. Or in other words, this arrangement puts
+// more entropy in the low bits than the high bits. The reason this matters is that `FxHash`, which
+// is used throughout rustc, has problems distributing the entropy from the high bits, so reversing
+// the order would lead to a large number of collisions and thus far worse performance.
+//
+// On 64-bit big-endian systems, this compiles to a 64-bit rotation by 32 bits, which is still
+// faster than another `FxHash` round.
+#[cfg(target_pointer_width = "64")]
+impl Hash for DefId {
+    fn hash<H: Hasher>(&self, h: &mut H) {
+        (((self.krate.as_u32() as u64) << 32) | (self.index.as_u32() as u64)).hash(h)
+    }
+}
+
 impl DefId {
     /// Makes a local `DefId` from the given `DefIndex`.
     #[inline]
@@ -250,12 +298,10 @@ impl<E: Encoder> Encodable<E> for DefId {
 }
 
 impl<D: Decoder> Decodable<D> for DefId {
-    default fn decode(d: &mut D) -> Result<DefId, D::Error> {
-        d.read_struct(|d| {
-            Ok(DefId {
-                krate: d.read_struct_field("krate", Decodable::decode)?,
-                index: d.read_struct_field("index", Decodable::decode)?,
-            })
+    default fn decode(d: &mut D) -> DefId {
+        d.read_struct(|d| DefId {
+            krate: d.read_struct_field("krate", Decodable::decode),
+            index: d.read_struct_field("index", Decodable::decode),
         })
     }
 }
@@ -275,17 +321,23 @@ impl fmt::Debug for DefId {
 
 rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId);
 
-/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
+/// A `LocalDefId` is equivalent to a `DefId` with `krate == LOCAL_CRATE`. Since
 /// we encode this information in the type, we can ensure at compile time that
-/// no DefIds from upstream crates get thrown into the mix. There are quite a
-/// few cases where we know that only DefIds from the local crate are expected
-/// and a DefId from a different crate would signify a bug somewhere. This
-/// is when LocalDefId comes in handy.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+/// no `DefId`s from upstream crates get thrown into the mix. There are quite a
+/// few cases where we know that only `DefId`s from the local crate are expected;
+/// a `DefId` from a different crate would signify a bug somewhere. This
+/// is when `LocalDefId` comes in handy.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct LocalDefId {
     pub local_def_index: DefIndex,
 }
 
+// To ensure correctness of incremental compilation,
+// `LocalDefId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for LocalDefId {}
+impl !PartialOrd for LocalDefId {}
+
 pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX };
 
 impl Idx for LocalDefId {
@@ -324,8 +376,8 @@ impl<E: Encoder> Encodable<E> for LocalDefId {
 }
 
 impl<D: Decoder> Decodable<D> for LocalDefId {
-    fn decode(d: &mut D) -> Result<LocalDefId, D::Error> {
-        DefId::decode(d).map(|d| d.expect_local())
+    fn decode(d: &mut D) -> LocalDefId {
+        DefId::decode(d).expect_local()
     }
 }