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 {
/// 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);
/// 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))]
+// Note that the order is essential here, see below why
pub struct DefId {
- pub krate: CrateNum,
pub index: DefIndex,
+ pub krate: CrateNum,
+}
+
+// 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 {
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-orphan.rs:17:1
- |
-LL | impl !Send for Vec<isize> { }
- | ^^^^^^^^^^^^^^^----------
- | | |
- | | `Vec` is not defined in the current crate
- | impl doesn't use only types from inside the current crate
- |
- = note: define and implement a trait or new type instead
-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-orphan.rs:10:1
|
|
= note: define and implement a trait or new type instead
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/coherence-orphan.rs:17:1
+ |
+LL | impl !Send for Vec<isize> { }
+ | ^^^^^^^^^^^^^^^----------
+ | | |
+ | | `Vec` is not defined in the current crate
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0117`.
LL | fn main() { 1_usize.me(); }
| ^^ multiple `me` found
|
-note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize`
+ = note: candidate #1 is defined in an impl of the trait `Me` for the type `usize`
+note: candidate #2 is defined in an impl of the trait `Me2` for the type `usize`
--> $DIR/method-ambig-two-traits-cross-crate.rs:10:22
|
LL | impl Me2 for usize { fn me(&self) -> usize { *self } }
| ^^^^^^^^^^^^^^^^^^^^^
- = note: candidate #2 is defined in an impl of the trait `Me` for the type `usize`
help: disambiguate the associated function for candidate #1
|
-LL | fn main() { Me2::me(&1_usize); }
- | ~~~~~~~~~~~~~~~~~
-help: disambiguate the associated function for candidate #2
- |
LL | fn main() { Me::me(&1_usize); }
| ~~~~~~~~~~~~~~~~
+help: disambiguate the associated function for candidate #2
+ |
+LL | fn main() { Me2::me(&1_usize); }
+ | ~~~~~~~~~~~~~~~~~
error: aborting due to previous error