diff options
146 files changed, 1762 insertions, 1180 deletions
diff --git a/configure b/configure index ea9320c901b..61c737e0fd3 100755 --- a/configure +++ b/configure @@ -599,6 +599,18 @@ then fi putvar CFG_RELEASE_CHANNEL +# A magic value that allows the compiler to use unstable features +# during the bootstrap even when doing so would normally be an error +# because of feature staging or because the build turns on +# warnings-as-errors and unstable features default to warnings. The +# build has to match this key in an env var. Meant to be a mild +# deterrent from users just turning on unstable features on the stable +# channel. +# Basing CFG_BOOTSTRAP_KEY on CFG_BOOTSTRAP_KEY lets it get picked up +# during a Makefile reconfig. +CFG_BOOTSTRAP_KEY="${CFG_BOOTSTRAP_KEY-`date +%N`}" +putvar CFG_BOOTSTRAP_KEY + step_msg "looking for build programs" probe_need CFG_PERL perl diff --git a/mk/main.mk b/mk/main.mk index a97e68af59b..e892286f7fd 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -25,11 +25,13 @@ ifeq ($(CFG_RELEASE_CHANNEL),stable) CFG_RELEASE=$(CFG_RELEASE_NUM) # This is the string used in dist artifact file names, e.g. "0.12.0", "nightly" CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM) +CFG_DISABLE_UNSTABLE_FEATURES=1 endif ifeq ($(CFG_RELEASE_CHANNEL),beta) # The beta channel is temporarily called 'alpha' CFG_RELEASE=$(CFG_RELEASE_NUM)-alpha$(CFG_BETA_CYCLE) CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-alpha$(CFG_BETA_CYCLE) +CFG_DISABLE_UNSTABLE_FEATURES=1 endif ifeq ($(CFG_RELEASE_CHANNEL),nightly) CFG_RELEASE=$(CFG_RELEASE_NUM)-nightly @@ -319,11 +321,20 @@ export CFG_VERSION_WIN export CFG_RELEASE export CFG_PACKAGE_NAME export CFG_BUILD +export CFG_RELEASE_CHANNEL export CFG_LLVM_ROOT export CFG_PREFIX export CFG_LIBDIR export CFG_LIBDIR_RELATIVE export CFG_DISABLE_INJECT_STD_VERSION +ifdef CFG_DISABLE_UNSTABLE_FEATURES +CFG_INFO := $(info cfg: disabling unstable features (CFG_DISABLE_UNSTABLE_FEATURES)) +# Turn on feature-staging +export CFG_DISABLE_UNSTABLE_FEATURES +endif +# Subvert unstable feature lints to do the self-build +export CFG_BOOTSTRAP_KEY +export RUSTC_BOOTSTRAP_KEY:=$(CFG_BOOTSTRAP_KEY) ###################################################################### # Per-stage targets and runner diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index e2420b0a220..ac8cf543a42 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -9,7 +9,7 @@ // except according to those terms. #![crate_type = "bin"] -#![feature(slicing_syntax, unboxed_closures)] +#![feature(slicing_syntax)] #![deny(warnings)] diff --git a/src/doc/footer.inc b/src/doc/footer.inc index 4e7d60586f2..f32f2fd443f 100644 --- a/src/doc/footer.inc +++ b/src/doc/footer.inc @@ -1,5 +1,5 @@ <footer><p> -Copyright © 2011-2014 The Rust Project Developers. Licensed under the +Copyright © 2011-2015 The Rust Project Developers. Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a> or the <a href="http://opensource.org/licenses/MIT">MIT license</a>, at your option. </p><p> diff --git a/src/doc/intro.md b/src/doc/intro.md index fbc96a577a4..ffe33f41bc7 100644 --- a/src/doc/intro.md +++ b/src/doc/intro.md @@ -542,7 +542,7 @@ use std::thread::Thread; fn main() { let vec = vec![1i, 2, 3]; - for i in range(1u, 3) { + for i in range(0u, 3) { Thread::spawn(move || { println!("{}", vec[i]); }).detach(); @@ -558,7 +558,7 @@ a vector: ```{rust} let vec = vec![1i, 2, 3]; -for i in range(1u, vec.len()) { +for i in range(0u, vec.len()) { println!("{}", vec[i]); } ``` diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 5d47602b5e1..636d80e7451 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -67,21 +67,20 @@ //! } //! ``` +use core::prelude::*; + use core::atomic; use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst}; use core::borrow::BorrowFrom; -use core::clone::Clone; use core::fmt::{self, Show}; -use core::cmp::{Eq, Ord, PartialEq, PartialOrd, Ordering}; +use core::cmp::{Ordering}; use core::default::Default; -use core::marker::{Sync, Send}; -use core::mem::{min_align_of, size_of, drop}; +use core::mem::{min_align_of, size_of}; use core::mem; use core::nonzero::NonZero; -use core::ops::{Drop, Deref}; -use core::option::Option; -use core::option::Option::{Some, None}; -use core::ptr::{self, PtrExt}; +use core::ops::Deref; +use core::ptr; +use core::hash::{Hash, Hasher}; use heap::deallocate; /// An atomically reference counted wrapper for shared state. @@ -591,6 +590,12 @@ impl<T: Default + Sync + Send> Default for Arc<T> { fn default() -> Arc<T> { Arc::new(Default::default()) } } +impl<H: Hasher, T: Hash<H>> Hash<H> for Arc<T> { + fn hash(&self, state: &mut H) { + (**self).hash(state) + } +} + #[cfg(test)] #[allow(experimental)] mod tests { diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d46f18abf97..adca8b9cc4c 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -106,12 +106,20 @@ impl<T: ?Sized + Ord> Ord for Box<T> { #[stable]} impl<T: ?Sized + Eq> Eq for Box<T> {} +#[cfg(stage0)] impl<S: hash::Writer, T: ?Sized + Hash<S>> Hash<S> for Box<T> { #[inline] fn hash(&self, state: &mut S) { (**self).hash(state); } } +#[cfg(not(stage0))] +impl<S: hash::Hasher, T: ?Sized + Hash<S>> Hash<S> for Box<T> { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } +} /// Extension methods for an owning `Any` trait object. #[unstable = "post-DST and coherence changes, this will not be a trait but \ diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index c57435cdc8c..439bb6c55dc 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -115,16 +115,20 @@ unsafe fn exchange_free(ptr: *mut u8, old_size: uint, align: uint) { // The minimum alignment guaranteed by the architecture. This value is used to // add fast paths for low alignment values. In practice, the alignment is a // constant at the call site and the branch will be optimized out. -#[cfg(any(target_arch = "arm", - target_arch = "mips", - target_arch = "mipsel"))] +#[cfg(all(not(feature = "external_funcs"), + not(feature = "external_crate"), + any(target_arch = "arm", + target_arch = "mips", + target_arch = "mipsel")))] const MIN_ALIGN: uint = 8; -#[cfg(any(target_arch = "x86", - target_arch = "x86_64", - target_arch = "aarch64"))] +#[cfg(all(not(feature = "external_funcs"), + not(feature = "external_crate"), + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "aarch64"))] const MIN_ALIGN: uint = 16; -#[cfg(external_funcs)] +#[cfg(feature = "external_funcs")] mod imp { extern { fn rust_allocate(size: uint, align: uint) -> *mut u8; @@ -142,14 +146,13 @@ mod imp { } #[inline] - pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint, - align: uint) -> uint { - rust_reallocate_inplace(ptr, old_size, size, align) + pub unsafe fn deallocate(ptr: *mut u8, old_size: uint, align: uint) { + rust_deallocate(ptr, old_size, align) } #[inline] - pub unsafe fn deallocate(ptr: *mut u8, old_size: uint, align: uint) { - rust_deallocate(ptr, old_size, align) + pub unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8 { + rust_reallocate(ptr, old_size, size, align) } #[inline] @@ -169,14 +172,16 @@ mod imp { } } -#[cfg(external_crate)] +#[cfg(feature = "external_crate")] mod imp { extern crate external; pub use self::external::{allocate, deallocate, reallocate_inplace, reallocate}; pub use self::external::{usable_size, stats_print}; } -#[cfg(all(not(external_funcs), not(external_crate), jemalloc))] +#[cfg(all(not(feature = "external_funcs"), + not(feature = "external_crate"), + jemalloc))] mod imp { use core::option::Option; use core::option::Option::None; @@ -253,7 +258,10 @@ mod imp { } } -#[cfg(all(not(external_funcs), not(external_crate), not(jemalloc), unix))] +#[cfg(all(not(feature = "external_funcs"), + not(feature = "external_crate"), + not(jemalloc), + unix))] mod imp { use core::cmp; use core::ptr; @@ -314,7 +322,10 @@ mod imp { pub fn stats_print() {} } -#[cfg(all(not(external_funcs), not(external_crate), not(jemalloc), windows))] +#[cfg(all(not(feature = "external_funcs"), + not(feature = "external_crate"), + not(jemalloc), + windows))] mod imp { use libc::{c_void, size_t}; use libc; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index ba6e89cdd76..dc6037c3c0c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -58,6 +58,7 @@ #![crate_name = "alloc"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", @@ -69,6 +70,8 @@ #[macro_use] extern crate core; + +#[cfg(all(not(feature = "external_funcs"), not(feature = "external_crate")))] extern crate libc; // Allow testing this library diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 67b25427710..83eff71e2b8 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -10,23 +10,26 @@ //! Thread-local reference-counted boxes (the `Rc<T>` type). //! -//! The `Rc<T>` type provides shared ownership of an immutable value. Destruction is deterministic, -//! and will occur as soon as the last owner is gone. It is marked as non-sendable because it -//! avoids the overhead of atomic reference counting. +//! The `Rc<T>` type provides shared ownership of an immutable value. +//! Destruction is deterministic, and will occur as soon as the last owner is +//! gone. It is marked as non-sendable because it avoids the overhead of atomic +//! reference counting. //! -//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer to the box. A -//! `Weak<T>` pointer can be upgraded to an `Rc<T>` pointer, but will return `None` if the value -//! has already been dropped. +//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer +//! to the box. A `Weak<T>` pointer can be upgraded to an `Rc<T>` pointer, but +//! will return `None` if the value has already been dropped. //! -//! For example, a tree with parent pointers can be represented by putting the nodes behind strong -//! `Rc<T>` pointers, and then storing the parent pointers as `Weak<T>` pointers. +//! For example, a tree with parent pointers can be represented by putting the +//! nodes behind strong `Rc<T>` pointers, and then storing the parent pointers +//! as `Weak<T>` pointers. //! //! # Examples //! -//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. We want to have our -//! `Gadget`s point to their `Owner`. We can't do this with unique ownership, because more than one -//! gadget may belong to the same `Owner`. `Rc<T>` allows us to share an `Owner` between multiple -//! `Gadget`s, and have the `Owner` remain allocated as long as any `Gadget` points at it. +//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. +//! We want to have our `Gadget`s point to their `Owner`. We can't do this with +//! unique ownership, because more than one gadget may belong to the same +//! `Owner`. `Rc<T>` allows us to share an `Owner` between multiple `Gadget`s, +//! and have the `Owner` remain allocated as long as any `Gadget` points at it. //! //! ```rust //! use std::rc::Rc; @@ -597,12 +600,20 @@ impl<T: Ord> Ord for Rc<T> { } // FIXME (#18248) Make `T` `Sized?` +#[cfg(stage0)] impl<S: hash::Writer, T: Hash<S>> Hash<S> for Rc<T> { #[inline] fn hash(&self, state: &mut S) { (**self).hash(state); } } +#[cfg(not(stage0))] +impl<S: hash::Hasher, T: Hash<S>> Hash<S> for Rc<T> { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } +} #[experimental = "Show is experimental."] impl<T: fmt::Show> fmt::Show for Rc<T> { diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 423c16bfee8..79e43b9cc64 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -21,6 +21,7 @@ #![crate_name = "arena"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 2154d06377a..f7277d4dfd8 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -982,7 +982,7 @@ impl fmt::Show for Bitv { } #[stable] -impl<S: hash::Writer> hash::Hash<S> for Bitv { +impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Bitv { fn hash(&self, state: &mut S) { self.nbits.hash(state); for elem in self.blocks() { @@ -1742,7 +1742,7 @@ impl fmt::Show for BitvSet { } } -impl<S: hash::Writer> hash::Hash<S> for BitvSet { +impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for BitvSet { fn hash(&self, state: &mut S) { for pos in self.iter() { pos.hash(state); diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 4e44779810b..3e1533dd35f 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -23,7 +23,9 @@ use core::borrow::BorrowFrom; use core::cmp::Ordering; use core::default::Default; use core::fmt::Show; -use core::hash::{Writer, Hash}; +use core::hash::{Hash, Hasher}; +#[cfg(stage0)] +use core::hash::Writer; use core::iter::{Map, FromIterator}; use core::ops::{Index, IndexMut}; use core::{iter, fmt, mem}; @@ -820,6 +822,7 @@ impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> { } #[stable] +#[cfg(stage0)] impl<S: Writer, K: Hash<S>, V: Hash<S>> Hash<S> for BTreeMap<K, V> { fn hash(&self, state: &mut S) { for elt in self.iter() { @@ -827,6 +830,15 @@ impl<S: Writer, K: Hash<S>, V: Hash<S>> Hash<S> for BTreeMap<K, V> { } } } +#[stable] +#[cfg(not(stage0))] +impl<S: Hasher, K: Hash<S>, V: Hash<S>> Hash<S> for BTreeMap<K, V> { + fn hash(&self, state: &mut S) { + for elt in self.iter() { + elt.hash(state); + } + } +} #[stable] impl<K: Ord, V> Default for BTreeMap<K, V> { diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 25df4a3cc2a..812cff6fab7 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -678,7 +678,7 @@ mod test { use prelude::*; use super::BTreeSet; - use std::hash; + use std::hash::{self, SipHasher}; #[test] fn test_clone_eq() { @@ -703,7 +703,7 @@ mod test { y.insert(2); y.insert(1); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y)); } struct Counter<'a, 'b> { diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index 63ea9f7cb43..0b426f6016c 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -27,7 +27,7 @@ use alloc::boxed::Box; use core::cmp::Ordering; use core::default::Default; use core::fmt; -use core::hash::{Writer, Hash}; +use core::hash::{Writer, Hasher, Hash}; use core::iter::{self, FromIterator}; use core::mem; use core::ptr; @@ -675,7 +675,7 @@ impl<A: fmt::Show> fmt::Show for DList<A> { } #[stable] -impl<S: Writer, A: Hash<S>> Hash<S> for DList<A> { +impl<S: Writer + Hasher, A: Hash<S>> Hash<S> for DList<A> { fn hash(&self, state: &mut S) { self.len().hash(state); for elt in self.iter() { @@ -688,7 +688,7 @@ impl<S: Writer, A: Hash<S>> Hash<S> for DList<A> { mod tests { use prelude::*; use std::rand; - use std::hash; + use std::hash::{self, SipHasher}; use std::thread::Thread; use test::Bencher; use test; @@ -951,7 +951,7 @@ mod tests { let mut x = DList::new(); let mut y = DList::new(); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y)); x.push_back(1i); x.push_back(2); @@ -961,7 +961,7 @@ mod tests { y.push_front(2); y.push_front(1); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y)); } #[test] diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index e7f48c291c9..a3adc09b581 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -15,6 +15,7 @@ #![crate_name = "collections"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", @@ -23,8 +24,8 @@ #![allow(unknown_features)] #![feature(unsafe_destructor, slicing_syntax)] -#![feature(old_impl_check)] #![feature(unboxed_closures)] +#![feature(old_impl_check)] #![no_std] #[macro_use] diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 42c17136a08..a35482aa5d3 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -27,7 +27,7 @@ use core::ops::{Index, IndexMut}; use core::ptr; use core::raw::Slice as RawSlice; -use std::hash::{Writer, Hash}; +use std::hash::{Writer, Hash, Hasher}; use std::cmp; use alloc::heap; @@ -1562,7 +1562,7 @@ impl<A: Ord> Ord for RingBuf<A> { } #[stable] -impl<S: Writer, A: Hash<S>> Hash<S> for RingBuf<A> { +impl<S: Writer + Hasher, A: Hash<S>> Hash<S> for RingBuf<A> { fn hash(&self, state: &mut S) { self.len().hash(state); for elt in self.iter() { @@ -1631,7 +1631,7 @@ mod tests { use prelude::*; use core::iter; use std::fmt::Show; - use std::hash; + use std::hash::{self, SipHasher}; use test::Bencher; use test; @@ -2283,7 +2283,7 @@ mod tests { y.push_back(2); y.push_back(3); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y)); } #[test] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 507703c3a90..2d8fd159159 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -820,12 +820,21 @@ impl fmt::Show for String { } #[experimental = "waiting on Hash stabilization"] +#[cfg(stage0)] impl<H: hash::Writer> hash::Hash<H> for String { #[inline] fn hash(&self, hasher: &mut H) { (**self).hash(hasher) } } +#[experimental = "waiting on Hash stabilization"] +#[cfg(not(stage0))] +impl<H: hash::Writer + hash::Hasher> hash::Hash<H> for String { + #[inline] + fn hash(&self, hasher: &mut H) { + (**self).hash(hasher) + } +} #[unstable = "recent addition, needs more experience"] impl<'a> Add<&'a str> for String { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 312d739e3a4..c2de5d24025 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1183,12 +1183,20 @@ impl<T:Clone> Clone for Vec<T> { } } +#[cfg(stage0)] impl<S: hash::Writer, T: Hash<S>> Hash<S> for Vec<T> { #[inline] fn hash(&self, state: &mut S) { self.as_slice().hash(state); } } +#[cfg(not(stage0))] +impl<S: hash::Writer + hash::Hasher, T: Hash<S>> Hash<S> for Vec<T> { + #[inline] + fn hash(&self, state: &mut S) { + self.as_slice().hash(state); + } +} #[experimental = "waiting on Index stability"] impl<T> Index<uint> for Vec<T> { diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 4399a6fec22..d4ce266d3e2 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -18,7 +18,7 @@ use core::prelude::*; use core::cmp::Ordering; use core::default::Default; use core::fmt; -use core::hash::{Hash, Writer}; +use core::hash::{Hash, Writer, Hasher}; use core::iter::{Enumerate, FilterMap, Map, FromIterator}; use core::iter; use core::mem::replace; @@ -85,7 +85,7 @@ impl<V:Clone> Clone for VecMap<V> { } } -impl<S: Writer, V: Hash<S>> Hash<S> for VecMap<V> { +impl<S: Writer + Hasher, V: Hash<S>> Hash<S> for VecMap<V> { fn hash(&self, state: &mut S) { // In order to not traverse the `VecMap` twice, count the elements // during iteration. @@ -712,7 +712,7 @@ impl<V> DoubleEndedIterator for IntoIter<V> { #[cfg(test)] mod test_map { use prelude::*; - use core::hash::hash; + use core::hash::{hash, SipHasher}; use super::VecMap; @@ -1004,7 +1004,7 @@ mod test_map { let mut x = VecMap::new(); let mut y = VecMap::new(); - assert!(hash(&x) == hash(&y)); + assert!(hash::<_, SipHasher>(&x) == hash::<_, SipHasher>(&y)); x.insert(1, 'a'); x.insert(2, 'b'); x.insert(3, 'c'); @@ -1013,12 +1013,12 @@ mod test_map { y.insert(2, 'b'); y.insert(1, 'a'); - assert!(hash(&x) == hash(&y)); + assert!(hash::<_, SipHasher>(&x) == hash::<_, SipHasher>(&y)); x.insert(1000, 'd'); x.remove(&1000); - assert!(hash(&x) == hash(&y)); + assert!(hash::<_, SipHasher>(&x) == hash::<_, SipHasher>(&y)); } #[test] diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index d8b9cf9594d..a82ea009e13 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -16,8 +16,7 @@ //! # Examples //! //! ```rust -//! use std::hash; -//! use std::hash::Hash; +//! use std::hash::{hash, Hash, SipHasher}; //! //! #[derive(Hash)] //! struct Person { @@ -29,16 +28,14 @@ //! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; //! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; //! -//! assert!(hash::hash(&person1) != hash::hash(&person2)); +//! assert!(hash::<_, SipHasher>(&person1) != hash::<_, SipHasher>(&person2)); //! ``` //! //! If you need more control over how a value is hashed, you need to implement //! the trait `Hash`: //! //! ```rust -//! use std::hash; -//! use std::hash::Hash; -//! use std::hash::sip::SipState; +//! use std::hash::{hash, Hash, Hasher, Writer, SipHasher}; //! //! struct Person { //! id: uint, @@ -46,8 +43,8 @@ //! phone: u64, //! } //! -//! impl Hash for Person { -//! fn hash(&self, state: &mut SipState) { +//! impl<H: Hasher + Writer> Hash<H> for Person { +//! fn hash(&self, state: &mut H) { //! self.id.hash(state); //! self.phone.hash(state); //! } @@ -56,186 +53,382 @@ //! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; //! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; //! -//! assert!(hash::hash(&person1) == hash::hash(&person2)); +//! assert_eq!(hash::<_, SipHasher>(&person1), hash::<_, SipHasher>(&person2)); //! ``` -#![allow(unused_must_use)] +#![unstable = "module was recently redesigned"] -use prelude::*; +use default::Default; -use borrow::{Cow, ToOwned}; -use intrinsics::TypeId; -use mem; -use num::Int; +pub use self::sip::SipHasher; -/// Reexport the `sip::hash` function as our default hasher. -pub use self::sip::hash as hash; +mod sip; -pub mod sip; +/// A hashable type. +/// +/// The `H` type parameter is an abstract hash state that is used by the `Hash` +/// to compute the hash. Specific implementations of this trait may specialize +/// for particular instances of `H` in order to be able to optimize the hashing +/// behavior. +#[cfg(stage0)] +pub trait Hash<H> { + /// Feeds this value into the state given, updating the hasher as necessary. + fn hash(&self, state: &mut H); +} -/// A hashable type. The `S` type parameter is an abstract hash state that is -/// used by the `Hash` to compute the hash. It defaults to -/// `std::hash::sip::SipState`. -pub trait Hash<S = sip::SipState> { - /// Computes the hash of a value. - fn hash(&self, state: &mut S); +/// A hashable type. +/// +/// The `H` type parameter is an abstract hash state that is used by the `Hash` +/// to compute the hash. Specific implementations of this trait may specialize +/// for particular instances of `H` in order to be able to optimize the hashing +/// behavior. +#[cfg(not(stage0))] +pub trait Hash<H: Hasher> { + /// Feeds this value into the state given, updating the hasher as necessary. + fn hash(&self, state: &mut H); } -/// A trait that computes a hash for a value. The main users of this trait are -/// containers like `HashMap`, which need a generic way hash multiple types. -pub trait Hasher<S> { - /// Compute the hash of a value. - fn hash<T: ?Sized + Hash<S>>(&self, value: &T) -> u64; +/// A trait which represents the ability to hash an arbitrary stream of bytes. +pub trait Hasher { + /// Result type of one run of hashing generated by this hasher. + type Output; + + /// Resets this hasher back to its initial state (as if it were just + /// created). + fn reset(&mut self); + + /// Completes a round of hashing, producing the output hash generated. + fn finish(&self) -> Self::Output; } +/// A common bound on the `Hasher` parameter to `Hash` implementations in order +/// to generically hash an aggregate. +#[experimental = "this trait will likely be replaced by io::Writer"] #[allow(missing_docs)] pub trait Writer { fn write(&mut self, bytes: &[u8]); } +/// Hash a value with the default SipHasher algorithm (two initial keys of 0). +/// +/// The specified value will be hashed with this hasher and then the resulting +/// hash will be returned. +pub fn hash<T: Hash<H>, H: Hasher + Default>(value: &T) -> H::Output { + let mut h: H = Default::default(); + value.hash(&mut h); + h.finish() +} + ////////////////////////////////////////////////////////////////////////////// -macro_rules! impl_hash { - ($ty:ident, $uty:ident) => { - impl<S: Writer> Hash<S> for $ty { - #[inline] - fn hash(&self, state: &mut S) { - let a: [u8; ::$ty::BYTES] = unsafe { - mem::transmute((*self as $uty).to_le() as $ty) - }; - state.write(a.as_slice()) +#[cfg(stage0)] +mod impls { + use prelude::*; + + use borrow::{Cow, ToOwned}; + use intrinsics::TypeId; + use mem; + use super::{Hash, Writer}; + use num::Int; + + macro_rules! impl_hash { + ($ty:ident, $uty:ident) => { + impl<S: Writer> Hash<S> for $ty { + #[inline] + fn hash(&self, state: &mut S) { + let a: [u8; ::$ty::BYTES] = unsafe { + mem::transmute((*self as $uty).to_le() as $ty) + }; + state.write(a.as_slice()) + } } } } -} -impl_hash! { u8, u8 } -impl_hash! { u16, u16 } -impl_hash! { u32, u32 } -impl_hash! { u64, u64 } -impl_hash! { uint, uint } -impl_hash! { i8, u8 } -impl_hash! { i16, u16 } -impl_hash! { i32, u32 } -impl_hash! { i64, u64 } -impl_hash! { int, uint } - -impl<S: Writer> Hash<S> for bool { - #[inline] - fn hash(&self, state: &mut S) { - (*self as u8).hash(state); + impl_hash! { u8, u8 } + impl_hash! { u16, u16 } + impl_hash! { u32, u32 } + impl_hash! { u64, u64 } + impl_hash! { uint, uint } + impl_hash! { i8, u8 } + impl_hash! { i16, u16 } + impl_hash! { i32, u32 } + impl_hash! { i64, u64 } + impl_hash! { int, uint } + + impl<S: Writer> Hash<S> for bool { + #[inline] + fn hash(&self, state: &mut S) { + (*self as u8).hash(state); + } } -} -impl<S: Writer> Hash<S> for char { - #[inline] - fn hash(&self, state: &mut S) { - (*self as u32).hash(state); + impl<S: Writer> Hash<S> for char { + #[inline] + fn hash(&self, state: &mut S) { + (*self as u32).hash(state); + } } -} -impl<S: Writer> Hash<S> for str { - #[inline] - fn hash(&self, state: &mut S) { - state.write(self.as_bytes()); - 0xffu8.hash(state) + impl<S: Writer> Hash<S> for str { + #[inline] + fn hash(&self, state: &mut S) { + state.write(self.as_bytes()); + 0xffu8.hash(state) + } } -} -macro_rules! impl_hash_tuple { - () => ( - impl<S: Writer> Hash<S> for () { - #[inline] - fn hash(&self, state: &mut S) { - state.write(&[]); + macro_rules! impl_hash_tuple { + () => ( + impl<S> Hash<S> for () { + #[inline] + fn hash(&self, _state: &mut S) {} } - } - ); - - ( $($name:ident)+) => ( - impl<S: Writer, $($name: Hash<S>),*> Hash<S> for ($($name,)*) { - #[inline] - #[allow(non_snake_case)] - fn hash(&self, state: &mut S) { - match *self { - ($(ref $name,)*) => { - $( - $name.hash(state); - )* + ); + + ( $($name:ident)+) => ( + impl<S, $($name: Hash<S>),*> Hash<S> for ($($name,)*) { + #[inline] + #[allow(non_snake_case)] + fn hash(&self, state: &mut S) { + match *self { + ($(ref $name,)*) => { + $( + $name.hash(state); + )* + } } } } + ); + } + + impl_hash_tuple! {} + impl_hash_tuple! { A } + impl_hash_tuple! { A B } + impl_hash_tuple! { A B C } + impl_hash_tuple! { A B C D } + impl_hash_tuple! { A B C D E } + impl_hash_tuple! { A B C D E F } + impl_hash_tuple! { A B C D E F G } + impl_hash_tuple! { A B C D E F G H } + impl_hash_tuple! { A B C D E F G H I } + impl_hash_tuple! { A B C D E F G H I J } + impl_hash_tuple! { A B C D E F G H I J K } + impl_hash_tuple! { A B C D E F G H I J K L } + + impl<S: Writer, T: Hash<S>> Hash<S> for [T] { + #[inline] + fn hash(&self, state: &mut S) { + self.len().hash(state); + for elt in self.iter() { + elt.hash(state); + } } - ); -} + } + -impl_hash_tuple! {} -impl_hash_tuple! { A } -impl_hash_tuple! { A B } -impl_hash_tuple! { A B C } -impl_hash_tuple! { A B C D } -impl_hash_tuple! { A B C D E } -impl_hash_tuple! { A B C D E F } -impl_hash_tuple! { A B C D E F G } -impl_hash_tuple! { A B C D E F G H } -impl_hash_tuple! { A B C D E F G H I } -impl_hash_tuple! { A B C D E F G H I J } -impl_hash_tuple! { A B C D E F G H I J K } -impl_hash_tuple! { A B C D E F G H I J K L } - -impl<S: Writer, T: Hash<S>> Hash<S> for [T] { - #[inline] - fn hash(&self, state: &mut S) { - self.len().hash(state); - for elt in self.iter() { - elt.hash(state); + impl<'a, S, T: ?Sized + Hash<S>> Hash<S> for &'a T { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); } } -} + impl<'a, S, T: ?Sized + Hash<S>> Hash<S> for &'a mut T { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } + } -impl<'a, S: Writer, T: ?Sized + Hash<S>> Hash<S> for &'a T { - #[inline] - fn hash(&self, state: &mut S) { - (**self).hash(state); + impl<S: Writer, T> Hash<S> for *const T { + #[inline] + fn hash(&self, state: &mut S) { + // NB: raw-pointer Hash does _not_ dereference + // to the target; it just gives you the pointer-bytes. + (*self as uint).hash(state); + } } -} -impl<'a, S: Writer, T: ?Sized + Hash<S>> Hash<S> for &'a mut T { - #[inline] - fn hash(&self, state: &mut S) { - (**self).hash(state); + impl<S: Writer, T> Hash<S> for *mut T { + #[inline] + fn hash(&self, state: &mut S) { + // NB: raw-pointer Hash does _not_ dereference + // to the target; it just gives you the pointer-bytes. + (*self as uint).hash(state); + } } -} -impl<S: Writer, T> Hash<S> for *const T { - #[inline] - fn hash(&self, state: &mut S) { - // NB: raw-pointer Hash does _not_ dereference - // to the target; it just gives you the pointer-bytes. - (*self as uint).hash(state); + impl<S: Writer> Hash<S> for TypeId { + #[inline] + fn hash(&self, state: &mut S) { + self.hash().hash(state) + } } -} -impl<S: Writer, T> Hash<S> for *mut T { - #[inline] - fn hash(&self, state: &mut S) { - // NB: raw-pointer Hash does _not_ dereference - // to the target; it just gives you the pointer-bytes. - (*self as uint).hash(state); + impl<'a, T, B: ?Sized, S> Hash<S> for Cow<'a, T, B> + where B: Hash<S> + ToOwned<T> + { + #[inline] + fn hash(&self, state: &mut S) { + Hash::hash(&**self, state) + } } } -impl<S: Writer> Hash<S> for TypeId { - #[inline] - fn hash(&self, state: &mut S) { - self.hash().hash(state) +#[cfg(not(stage0))] +mod impls { + use prelude::*; + + use borrow::{Cow, ToOwned}; + use intrinsics::TypeId; + use mem; + use super::{Hash, Writer, Hasher}; + use num::Int; + + macro_rules! impl_hash { + ($ty:ident, $uty:ident) => { + impl<S: Writer + Hasher> Hash<S> for $ty { + #[inline] + fn hash(&self, state: &mut S) { + let a: [u8; ::$ty::BYTES] = unsafe { + mem::transmute((*self as $uty).to_le() as $ty) + }; + state.write(a.as_slice()) + } + } + } + } + + impl_hash! { u8, u8 } + impl_hash! { u16, u16 } + impl_hash! { u32, u32 } + impl_hash! { u64, u64 } + impl_hash! { uint, uint } + impl_hash! { i8, u8 } + impl_hash! { i16, u16 } + impl_hash! { i32, u32 } + impl_hash! { i64, u64 } + impl_hash! { int, uint } + + impl<S: Writer + Hasher> Hash<S> for bool { + #[inline] + fn hash(&self, state: &mut S) { + (*self as u8).hash(state); + } + } + + impl<S: Writer + Hasher> Hash<S> for char { + #[inline] + fn hash(&self, state: &mut S) { + (*self as u32).hash(state); + } + } + + impl<S: Writer + Hasher> Hash<S> for str { + #[inline] + fn hash(&self, state: &mut S) { + state.write(self.as_bytes()); + 0xffu8.hash(state) + } + } + + macro_rules! impl_hash_tuple { + () => ( + impl<S: Hasher> Hash<S> for () { + #[inline] + fn hash(&self, _state: &mut S) {} + } + ); + + ( $($name:ident)+) => ( + impl<S: Hasher, $($name: Hash<S>),*> Hash<S> for ($($name,)*) { + #[inline] + #[allow(non_snake_case)] + fn hash(&self, state: &mut S) { + match *self { + ($(ref $name,)*) => { + $( + $name.hash(state); + )* + } + } + } + } + ); + } + + impl_hash_tuple! {} + impl_hash_tuple! { A } + impl_hash_tuple! { A B } + impl_hash_tuple! { A B C } + impl_hash_tuple! { A B C D } + impl_hash_tuple! { A B C D E } + impl_hash_tuple! { A B C D E F } + impl_hash_tuple! { A B C D E F G } + impl_hash_tuple! { A B C D E F G H } + impl_hash_tuple! { A B C D E F G H I } + impl_hash_tuple! { A B C D E F G H I J } + impl_hash_tuple! { A B C D E F G H I J K } + impl_hash_tuple! { A B C D E F G H I J K L } + + impl<S: Writer + Hasher, T: Hash<S>> Hash<S> for [T] { + #[inline] + fn hash(&self, state: &mut S) { + self.len().hash(state); + for elt in self.iter() { + elt.hash(state); + } + } + } + + + impl<'a, S: Hasher, T: ?Sized + Hash<S>> Hash<S> for &'a T { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } + } + + impl<'a, S: Hasher, T: ?Sized + Hash<S>> Hash<S> for &'a mut T { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } } -} -impl<'a, T, B: ?Sized, S> Hash<S> for Cow<'a, T, B> where B: Hash<S> + ToOwned<T> { - #[inline] - fn hash(&self, state: &mut S) { - Hash::hash(&**self, state) + impl<S: Writer + Hasher, T> Hash<S> for *const T { + #[inline] + fn hash(&self, state: &mut S) { + // NB: raw-pointer Hash does _not_ dereference + // to the target; it just gives you the pointer-bytes. + (*self as uint).hash(state); + } + } + + impl<S: Writer + Hasher, T> Hash<S> for *mut T { + #[inline] + fn hash(&self, state: &mut S) { + // NB: raw-pointer Hash does _not_ dereference + // to the target; it just gives you the pointer-bytes. + (*self as uint).hash(state); + } + } + + impl<S: Writer + Hasher> Hash<S> for TypeId { + #[inline] + fn hash(&self, state: &mut S) { + self.hash().hash(state) + } + } + + impl<'a, T, B: ?Sized, S: Hasher> Hash<S> for Cow<'a, T, B> + where B: Hash<S> + ToOwned<T> + { + #[inline] + fn hash(&self, state: &mut S) { + Hash::hash(&**self, state) + } } } diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index c4d45e9c2c8..c20fb8457d2 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -11,27 +11,27 @@ // ignore-lexer-test FIXME #15883 //! An implementation of SipHash 2-4. -//! -//! See: http://131002.net/siphash/ -//! -//! Consider this as a main "general-purpose" hash for all hashtables: it -//! runs at good speed (competitive with spooky and city) and permits -//! strong _keyed_ hashing. Key your hashtables from a strong RNG, -//! such as `rand::Rng`. -//! -//! Although the SipHash algorithm is considered to be cryptographically -//! strong, this implementation has not been reviewed for such purposes. -//! As such, all cryptographic uses of this implementation are strongly -//! discouraged. use prelude::*; use default::Default; -use super::{Hash, Hasher, Writer}; - -/// `SipState` computes a SipHash 2-4 hash over a stream of bytes. -#[derive(Copy)] -pub struct SipState { +use super::{Hasher, Writer}; + +/// An implementation of SipHash 2-4. +/// +/// See: http://131002.net/siphash/ +/// +/// Consider this as a main "general-purpose" hash for all hashtables: it +/// runs at good speed (competitive with spooky and city) and permits +/// strong _keyed_ hashing. Key your hashtables from a strong RNG, +/// such as `rand::Rng`. +/// +/// Although the SipHash algorithm is considered to be cryptographically +/// strong, this implementation has not been reviewed for such purposes. +/// As such, all cryptographic uses of this implementation are strongly +/// discouraged. +#[allow(missing_copy_implementations)] +pub struct SipHasher { k0: u64, k1: u64, length: uint, // how many bytes we've processed @@ -86,17 +86,17 @@ macro_rules! compress { }) } -impl SipState { - /// Creates a `SipState` that is keyed off the provided keys. +impl SipHasher { + /// Creates a new `SipHasher` with the two initial keys set to 0. #[inline] - pub fn new() -> SipState { - SipState::new_with_keys(0, 0) + pub fn new() -> SipHasher { + SipHasher::new_with_keys(0, 0) } - /// Creates a `SipState` that is keyed off the provided keys. + /// Creates a `SipHasher` that is keyed off the provided keys. #[inline] - pub fn new_with_keys(key0: u64, key1: u64) -> SipState { - let mut state = SipState { + pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { + let mut state = SipHasher { k0: key0, k1: key1, length: 0, @@ -111,43 +111,12 @@ impl SipState { state } - /// Resets the state to its initial state. - #[inline] - pub fn reset(&mut self) { - self.length = 0; - self.v0 = self.k0 ^ 0x736f6d6570736575; - self.v1 = self.k1 ^ 0x646f72616e646f6d; - self.v2 = self.k0 ^ 0x6c7967656e657261; - self.v3 = self.k1 ^ 0x7465646279746573; - self.ntail = 0; - } - /// Returns the computed hash. - #[inline] - pub fn result(&self) -> u64 { - let mut v0 = self.v0; - let mut v1 = self.v1; - let mut v2 = self.v2; - let mut v3 = self.v3; - - let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail; - - v3 ^= b; - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - v0 ^= b; - - v2 ^= 0xff; - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - - v0 ^ v1 ^ v2 ^ v3 - } + #[deprecated = "renamed to finish"] + pub fn result(&self) -> u64 { self.finish() } } -impl Writer for SipState { +impl Writer for SipHasher { #[inline] fn write(&mut self, msg: &[u8]) { let length = msg.len(); @@ -195,355 +164,60 @@ impl Writer for SipState { } } -#[stable] -impl Clone for SipState { - #[inline] - fn clone(&self) -> SipState { - *self - } -} +impl Hasher for SipHasher { + type Output = u64; -#[stable] -impl Default for SipState { - #[inline] - #[stable] - fn default() -> SipState { - SipState::new() + fn reset(&mut self) { + self.length = 0; + self.v0 = self.k0 ^ 0x736f6d6570736575; + self.v1 = self.k1 ^ 0x646f72616e646f6d; + self.v2 = self.k0 ^ 0x6c7967656e657261; + self.v3 = self.k1 ^ 0x7465646279746573; + self.ntail = 0; } -} -/// `SipHasher` computes the SipHash algorithm from a stream of bytes. -#[derive(Clone)] -#[allow(missing_copy_implementations)] -pub struct SipHasher { - k0: u64, - k1: u64, -} + fn finish(&self) -> u64 { + let mut v0 = self.v0; + let mut v1 = self.v1; + let mut v2 = self.v2; + let mut v3 = self.v3; -impl SipHasher { - /// Creates a `Sip`. - #[inline] - pub fn new() -> SipHasher { - SipHasher::new_with_keys(0, 0) - } + let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail; - /// Creates a `Sip` that is keyed off the provided keys. - #[inline] - pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { - SipHasher { - k0: key0, - k1: key1, - } + v3 ^= b; + compress!(v0, v1, v2, v3); + compress!(v0, v1, v2, v3); + v0 ^= b; + + v2 ^= 0xff; + compress!(v0, v1, v2, v3); + compress!(v0, v1, v2, v3); + compress!(v0, v1, v2, v3); + compress!(v0, v1, v2, v3); + + v0 ^ v1 ^ v2 ^ v3 } } -impl Hasher<SipState> for SipHasher { +impl Clone for SipHasher { #[inline] - fn hash<T: ?Sized + Hash<SipState>>(&self, value: &T) -> u64 { - let mut state = SipState::new_with_keys(self.k0, self.k1); - value.hash(&mut state); - state.result() + fn clone(&self) -> SipHasher { + SipHasher { + k0: self.k0, + k1: self.k1, + length: self.length, + v0: self.v0, + v1: self.v1, + v2: self.v2, + v3: self.v3, + tail: self.tail, + ntail: self.ntail, + } } } impl Default for SipHasher { - #[inline] fn default() -> SipHasher { SipHasher::new() } } - -/// Hashes a value using the SipHash algorithm. -#[inline] -pub fn hash<T: ?Sized + Hash<SipState>>(value: &T) -> u64 { - let mut state = SipState::new(); - value.hash(&mut state); - state.result() -} - -/// Hashes a value with the SipHash algorithm with the provided keys. -#[inline] -pub fn hash_with_keys<T: ?Sized + Hash<SipState>>(k0: u64, k1: u64, value: &T) -> u64 { - let mut state = SipState::new_with_keys(k0, k1); - value.hash(&mut state); - state.result() -} - -#[cfg(test)] -mod tests { - use test::Bencher; - use prelude::*; - use std::fmt; - - use super::super::{Hash, Writer}; - use super::{SipState, hash, hash_with_keys}; - - // Hash just the bytes of the slice, without length prefix - struct Bytes<'a>(&'a [u8]); - - impl<'a, S: Writer> Hash<S> for Bytes<'a> { - #[allow(unused_must_use)] - fn hash(&self, state: &mut S) { - let Bytes(v) = *self; - state.write(v); - } - } - - #[test] - #[allow(unused_must_use)] - fn test_siphash() { - let vecs : [[u8; 8]; 64] = [ - [ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ], - [ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ], - [ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ], - [ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ], - [ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ], - [ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ], - [ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ], - [ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ], - [ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ], - [ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ], - [ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ], - [ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ], - [ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ], - [ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ], - [ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ], - [ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ], - [ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ], - [ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ], - [ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ], - [ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ], - [ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ], - [ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ], - [ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ], - [ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ], - [ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ], - [ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ], - [ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ], - [ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ], - [ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ], - [ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ], - [ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ], - [ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ], - [ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ], - [ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ], - [ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ], - [ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ], - [ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ], - [ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ], - [ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ], - [ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ], - [ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ], - [ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ], - [ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ], - [ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ], - [ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ], - [ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ], - [ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ], - [ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ], - [ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ], - [ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ], - [ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ], - [ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ], - [ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ], - [ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ], - [ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ], - [ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ], - [ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ], - [ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ], - [ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ], - [ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ], - [ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ], - [ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ], - [ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ], - [ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ] - ]; - - let k0 = 0x_07_06_05_04_03_02_01_00_u64; - let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64; - let mut buf = Vec::new(); - let mut t = 0; - let mut state_inc = SipState::new_with_keys(k0, k1); - let mut state_full = SipState::new_with_keys(k0, k1); - - fn to_hex_str(r: &[u8; 8]) -> String { - let mut s = String::new(); - for b in r.iter() { - s.push_str(format!("{}", fmt::radix(*b, 16)).as_slice()); - } - s - } - - fn result_bytes(h: u64) -> Vec<u8> { - vec![(h >> 0) as u8, - (h >> 8) as u8, - (h >> 16) as u8, - (h >> 24) as u8, - (h >> 32) as u8, - (h >> 40) as u8, - (h >> 48) as u8, - (h >> 56) as u8, - ] - } - - fn result_str(h: u64) -> String { - let r = result_bytes(h); - let mut s = String::new(); - for b in r.iter() { - s.push_str(format!("{}", fmt::radix(*b, 16)).as_slice()); - } - s - } - - while t < 64 { - debug!("siphash test {}: {}", t, buf); - let vec = u8to64_le!(vecs[t], 0); - let out = hash_with_keys(k0, k1, &Bytes(buf.as_slice())); - debug!("got {}, expected {}", out, vec); - assert_eq!(vec, out); - - state_full.reset(); - state_full.write(buf.as_slice()); - let f = result_str(state_full.result()); - let i = result_str(state_inc.result()); - let v = to_hex_str(&vecs[t]); - debug!("{}: ({}) => inc={} full={}", t, v, i, f); - - assert_eq!(f, i); - assert_eq!(f, v); - - buf.push(t as u8); - state_inc.write(&[t as u8]); - - t += 1; - } - } - - #[test] #[cfg(target_arch = "aarch64")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as uint))); - assert!(hash(&(val as u32)) != hash(&(val as uint))); - } - #[test] #[cfg(target_arch = "arm")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); - } - #[test] #[cfg(target_arch = "x86_64")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as uint))); - assert!(hash(&(val as u32)) != hash(&(val as uint))); - } - #[test] #[cfg(target_arch = "x86")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); - } - - #[test] - fn test_hash_idempotent() { - let val64 = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&val64), hash(&val64)); - let val32 = 0xdeadbeef_u32; - assert_eq!(hash(&val32), hash(&val32)); - } - - #[test] - fn test_hash_no_bytes_dropped_64() { - let val = 0xdeadbeef_deadbeef_u64; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - assert!(hash(&val) != hash(&zero_byte(val, 4))); - assert!(hash(&val) != hash(&zero_byte(val, 5))); - assert!(hash(&val) != hash(&zero_byte(val, 6))); - assert!(hash(&val) != hash(&zero_byte(val, 7))); - - fn zero_byte(val: u64, byte: uint) -> u64 { - assert!(byte < 8); - val & !(0xff << (byte * 8)) - } - } - - #[test] - fn test_hash_no_bytes_dropped_32() { - let val = 0xdeadbeef_u32; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - - fn zero_byte(val: u32, byte: uint) -> u32 { - assert!(byte < 4); - val & !(0xff << (byte * 8)) - } - } - - #[test] - fn test_hash_no_concat_alias() { - let s = ("aa", "bb"); - let t = ("aabb", ""); - let u = ("a", "abb"); - - assert!(s != t && t != u); - assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - - let v: (&[u8], &[u8], &[u8]) = (&[1u8], &[0u8, 0], &[0u8]); - let w: (&[u8], &[u8], &[u8]) = (&[1u8, 0, 0, 0], &[], &[]); - - assert!(v != w); - assert!(hash(&v) != hash(&w)); - } - - #[bench] - fn bench_str_under_8_bytes(b: &mut Bencher) { - let s = "foo"; - b.iter(|| { - assert_eq!(hash(&s), 16262950014981195938); - }) - } - - #[bench] - fn bench_str_of_8_bytes(b: &mut Bencher) { - let s = "foobar78"; - b.iter(|| { - assert_eq!(hash(&s), 4898293253460910787); - }) - } - - #[bench] - fn bench_str_over_8_bytes(b: &mut Bencher) { - let s = "foobarbaz0"; - b.iter(|| { - assert_eq!(hash(&s), 10581415515220175264); - }) - } - - #[bench] - fn bench_long_str(b: &mut Bencher) { - let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \ -incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \ -exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \ -irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \ -pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \ -officia deserunt mollit anim id est laborum."; - b.iter(|| { - assert_eq!(hash(&s), 17717065544121360093); - }) - } - - #[bench] - fn bench_u64(b: &mut Bencher) { - let u = 16262950014981195938u64; - b.iter(|| { - assert_eq!(hash(&u), 5254097107239593357); - }) - } -} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 822416a387e..bb2bfa95372 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -42,6 +42,8 @@ #![experimental] #![allow(missing_docs)] +use marker::Sized; + pub type GlueFn = extern "Rust" fn(*const i8); #[lang="ty_desc"] @@ -200,6 +202,10 @@ extern "rust-intrinsic" { /// Gets an identifier which is globally unique to the specified type. This /// function will return the same value for a type regardless of whichever /// crate it is invoked in. + #[cfg(not(stage0))] + pub fn type_id<T: ?Sized + 'static>() -> TypeId; + + #[cfg(stage0)] pub fn type_id<T: 'static>() -> TypeId; /// Create a value initialized to zero. @@ -551,8 +557,15 @@ pub struct TypeId { impl TypeId { /// Returns the `TypeId` of the type this generic function has been instantiated with + #[cfg(not(stage0))] + pub fn of<T: ?Sized + 'static>() -> TypeId { + unsafe { type_id::<T>() } + } + + #[cfg(stage0)] pub fn of<T: 'static>() -> TypeId { unsafe { type_id::<T>() } } + pub fn hash(&self) -> u64 { self.t } } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index d30cfc405a1..f0f4a191e4f 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2749,9 +2749,9 @@ macro_rules! step_impl_no_between { } step_impl!(uint u8 u16 u32 int i8 i16 i32); -#[cfg(target_word_size = "64")] +#[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] step_impl!(u64 i64); -#[cfg(target_word_size = "32")] +#[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] step_impl_no_between!(u64 i64); diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 890417b133f..21c25a12730 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -49,6 +49,7 @@ #![crate_name = "core"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", diff --git a/src/libcore/num/int.rs b/src/libcore/num/int.rs index fe68b78b2b6..065763a0d8e 100644 --- a/src/libcore/num/int.rs +++ b/src/libcore/num/int.rs @@ -16,5 +16,8 @@ #![deprecated = "replaced by isize"] -#[cfg(target_word_size = "32")] int_module! { int, 32 } -#[cfg(target_word_size = "64")] int_module! { int, 64 } +#[cfg(stage0)] #[cfg(target_word_size = "32")] int_module! { int, 32 } +#[cfg(stage0)] #[cfg(target_word_size = "64")] int_module! { int, 64 } + +#[cfg(not(stage0))] #[cfg(target_pointer_width = "32")] int_module! { int, 32 } +#[cfg(not(stage0))] #[cfg(target_pointer_width = "64")] int_module! { int, 64 } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 490d8111f46..47da5de5391 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -496,7 +496,7 @@ uint_impl! { u64 = u64, 64, intrinsics::u64_sub_with_overflow, intrinsics::u64_mul_with_overflow } -#[cfg(target_word_size = "32")] +#[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] uint_impl! { uint = u32, 32, intrinsics::ctpop32, intrinsics::ctlz32, @@ -506,7 +506,7 @@ uint_impl! { uint = u32, 32, intrinsics::u32_sub_with_overflow, intrinsics::u32_mul_with_overflow } -#[cfg(target_word_size = "64")] +#[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] uint_impl! { uint = u64, 64, intrinsics::ctpop64, intrinsics::ctlz64, @@ -601,13 +601,13 @@ int_impl! { i64 = i64, u64, 64, intrinsics::i64_sub_with_overflow, intrinsics::i64_mul_with_overflow } -#[cfg(target_word_size = "32")] +#[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] int_impl! { int = i32, u32, 32, intrinsics::i32_add_with_overflow, intrinsics::i32_sub_with_overflow, intrinsics::i32_mul_with_overflow } -#[cfg(target_word_size = "64")] +#[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] int_impl! { int = i64, u64, 64, intrinsics::i64_add_with_overflow, intrinsics::i64_sub_with_overflow, diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 63bf9ec3314..63935894bf5 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -7,27 +7,22 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::marker::Sized; -use std::mem; - -use core::slice::SliceExt; -use core::hash::{Hash, Hasher, Writer}; -struct MyWriterHasher; +use std::mem; +use std::hash::{Hash, Hasher, Writer}; +use std::default::Default; -impl Hasher<MyWriter> for MyWriterHasher { - fn hash<T: ?Sized + Hash<MyWriter>>(&self, value: &T) -> u64 { - let mut state = MyWriter { hash: 0 }; - value.hash(&mut state); - state.hash - } +struct MyHasher { + hash: u64, } -struct MyWriter { - hash: u64, +impl Default for MyHasher { + fn default() -> MyHasher { + MyHasher { hash: 0 } + } } -impl Writer for MyWriter { +impl Writer for MyHasher { // Most things we'll just add up the bytes. fn write(&mut self, buf: &[u8]) { for byte in buf.iter() { @@ -36,66 +31,88 @@ impl Writer for MyWriter { } } +impl Hasher for MyHasher { + type Output = u64; + fn reset(&mut self) { self.hash = 0; } + fn finish(&self) -> u64 { self.hash } +} + + #[test] fn test_writer_hasher() { - let hasher = MyWriterHasher; + fn hash<T: Hash<MyHasher>>(t: &T) -> u64 { + ::std::hash::hash::<_, MyHasher>(t) + } - assert_eq!(hasher.hash(&()), 0); + assert_eq!(hash(&()), 0); - assert_eq!(hasher.hash(&5u8), 5); - assert_eq!(hasher.hash(&5u16), 5); - assert_eq!(hasher.hash(&5u32), 5); - assert_eq!(hasher.hash(&5u64), 5); - assert_eq!(hasher.hash(&5u), 5); + assert_eq!(hash(&5u8), 5); + assert_eq!(hash(&5u16), 5); + assert_eq!(hash(&5u32), 5); + assert_eq!(hash(&5u64), 5); + assert_eq!(hash(&5u), 5); - assert_eq!(hasher.hash(&5i8), 5); - assert_eq!(hasher.hash(&5i16), 5); - assert_eq!(hasher.hash(&5i32), 5); - assert_eq!(hasher.hash(&5i64), 5); - assert_eq!(hasher.hash(&5i), 5); + assert_eq!(hash(&5i8), 5); + assert_eq!(hash(&5i16), 5); + assert_eq!(hash(&5i32), 5); + assert_eq!(hash(&5i64), 5); + assert_eq!(hash(&5i), 5); - assert_eq!(hasher.hash(&false), 0); - assert_eq!(hasher.hash(&true), 1); + assert_eq!(hash(&false), 0); + assert_eq!(hash(&true), 1); - assert_eq!(hasher.hash(&'a'), 97); + assert_eq!(hash(&'a'), 97); let s: &str = "a"; - assert_eq!(hasher.hash(& s), 97 + 0xFF); + assert_eq!(hash(& s), 97 + 0xFF); // FIXME (#18283) Enable test //let s: Box<str> = box "a"; //assert_eq!(hasher.hash(& s), 97 + 0xFF); let cs: &[u8] = &[1u8, 2u8, 3u8]; - assert_eq!(hasher.hash(& cs), 9); + assert_eq!(hash(& cs), 9); let cs: Box<[u8]> = box [1u8, 2u8, 3u8]; - assert_eq!(hasher.hash(& cs), 9); + assert_eq!(hash(& cs), 9); // FIXME (#18248) Add tests for hashing Rc<str> and Rc<[T]> unsafe { let ptr: *const int = mem::transmute(5i); - assert_eq!(hasher.hash(&ptr), 5); + assert_eq!(hash(&ptr), 5); } unsafe { let ptr: *mut int = mem::transmute(5i); - assert_eq!(hasher.hash(&ptr), 5); + assert_eq!(hash(&ptr), 5); } } -struct Custom { - hash: u64 +struct Custom { hash: u64 } +struct CustomHasher { output: u64 } + +impl Hasher for CustomHasher { + type Output = u64; + fn reset(&mut self) { self.output = 0; } + fn finish(&self) -> u64 { self.output } +} + +impl Default for CustomHasher { + fn default() -> CustomHasher { + CustomHasher { output: 0 } + } } -impl Hash<u64> for Custom { - fn hash(&self, state: &mut u64) { - *state = self.hash; +impl Hash<CustomHasher> for Custom { + fn hash(&self, state: &mut CustomHasher) { + state.output = self.hash; } } #[test] fn test_custom_state() { + fn hash<T: Hash<CustomHasher>>(t: &T) -> u64 { + ::std::hash::hash::<_, CustomHasher>(t) + } + let custom = Custom { hash: 5 }; - let mut state = 0; - custom.hash(&mut state); - assert_eq!(state, 5); + assert_eq!(hash(&Custom { hash: 5 }), 5); } diff --git a/src/libcoretest/intrinsics.rs b/src/libcoretest/intrinsics.rs new file mode 100644 index 00000000000..bcf8a6a433b --- /dev/null +++ b/src/libcoretest/intrinsics.rs @@ -0,0 +1,31 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::intrinsics::TypeId; + +#[test] +fn test_typeid_sized_types() { + struct X; struct Y(uint); + + assert_eq!(TypeId::of::<X>(), TypeId::of::<X>()); + assert_eq!(TypeId::of::<Y>(), TypeId::of::<Y>()); + assert!(TypeId::of::<X>() != TypeId::of::<Y>()); +} + +#[test] +fn test_typeid_unsized_types() { + trait Z {} + struct X(str); struct Y(Z + 'static); + + assert_eq!(TypeId::of::<X>(), TypeId::of::<X>()); + assert_eq!(TypeId::of::<Y>(), TypeId::of::<Y>()); + assert!(TypeId::of::<X>() != TypeId::of::<Y>()); +} + diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index f38440d86c6..1896bdd182a 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -16,6 +16,7 @@ #![crate_name = "flate"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 47cc072a636..a703bfbb8fe 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -16,6 +16,7 @@ #![crate_name = "fmt_macros"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index f50e24c6354..0dd6a430a88 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -79,6 +79,7 @@ #![crate_name = "getopts"] #![experimental = "use the crates.io `getopts` library instead"] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 83bad70e7b1..21a8ba03454 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -266,6 +266,7 @@ #![crate_name = "graphviz"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index dff27f800c7..c39fd074387 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -11,6 +11,7 @@ #![crate_name = "libc"] #![crate_type = "rlib"] #![cfg_attr(not(feature = "cargo-build"), experimental)] +#![cfg_attr(not(feature = "cargo-build"), staged_api)] #![no_std] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 08b01e956e1..6bfbbb99fc7 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -157,6 +157,7 @@ #![crate_name = "log"] #![experimental = "use the crates.io `log` library instead"] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 9d33f65cd59..ec34b904a68 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -25,6 +25,7 @@ #![no_std] #![experimental] +#![staged_api] #[macro_use] extern crate core; diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index a66d1dd08c1..66f4f2321fd 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -17,6 +17,7 @@ #![crate_name = "rbml"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libregex/lib.rs b/src/libregex/lib.rs index c039abc9aff..bd376528a0e 100644 --- a/src/libregex/lib.rs +++ b/src/libregex/lib.rs @@ -17,6 +17,7 @@ #![crate_type = "rlib"] #![crate_type = "dylib"] #![experimental = "use the crates.io `regex` library instead"] +#![staged_api] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/", diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a3a041c2497..5525874a614 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -16,6 +16,7 @@ #![crate_name = "rustc"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 1af8e2f29eb..9d7e833e711 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -34,7 +34,7 @@ use middle::{def, pat_util, stability}; use middle::const_eval::{eval_const_expr_partial, const_int, const_uint}; use util::ppaux::{ty_to_string}; use util::nodemap::{FnvHashMap, NodeSet}; -use lint::{Context, LintPass, LintArray}; +use lint::{Context, LintPass, LintArray, Lint}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::num::SignedInt; @@ -1643,6 +1643,13 @@ declare_lint! { "detects use of #[unstable] items (incl. items with no stability attribute)" } +declare_lint!(STAGED_EXPERIMENTAL, Warn, + "detects use of #[experimental] items in staged builds"); + +declare_lint!(STAGED_UNSTABLE, Warn, + "detects use of #[unstable] items (incl. items with no stability attribute) \ + in staged builds"); + /// Checks for use of items with `#[deprecated]`, `#[experimental]` and /// `#[unstable]` attributes, or no stability attribute. #[derive(Copy)] @@ -1650,12 +1657,13 @@ pub struct Stability; impl Stability { fn lint(&self, cx: &Context, id: ast::DefId, span: Span) { - let stability = stability::lookup(cx.tcx, id); + + let ref stability = stability::lookup(cx.tcx, id); let cross_crate = !ast_util::is_local(id); // stability attributes are promises made across crates; only // check DEPRECATED for crate-local usage. - let (lint, label) = match stability { + let (lint, label) = match *stability { // no stability attributes == Unstable None if cross_crate => (UNSTABLE, "unmarked"), Some(attr::Stability { level: attr::Unstable, .. }) if cross_crate => @@ -1667,24 +1675,53 @@ impl Stability { _ => return }; - let msg = match stability { - Some(attr::Stability { text: Some(ref s), .. }) => { - format!("use of {} item: {}", label, *s) + output(cx, span, stability, lint, label); + if cross_crate && stability::is_staged_api(cx.tcx, id) { + if lint.name == UNSTABLE.name { + output(cx, span, stability, STAGED_UNSTABLE, label); + } else if lint.name == EXPERIMENTAL.name { + output(cx, span, stability, STAGED_EXPERIMENTAL, label); } - _ => format!("use of {} item", label) - }; + } - cx.span_lint(lint, span, msg.index(&FullRange)); + fn output(cx: &Context, span: Span, stability: &Option<attr::Stability>, + lint: &'static Lint, label: &'static str) { + let msg = match *stability { + Some(attr::Stability { text: Some(ref s), .. }) => { + format!("use of {} item: {}", label, *s) + } + _ => format!("use of {} item", label) + }; + + cx.span_lint(lint, span, msg.index(&FullRange)); + } } + fn is_internal(&self, cx: &Context, span: Span) -> bool { cx.tcx.sess.codemap().span_is_internal(span) } + } impl LintPass for Stability { fn get_lints(&self) -> LintArray { - lint_array!(DEPRECATED, EXPERIMENTAL, UNSTABLE) + lint_array!(DEPRECATED, EXPERIMENTAL, UNSTABLE, STAGED_EXPERIMENTAL, STAGED_UNSTABLE) + } + + fn check_crate(&mut self, _: &Context, c: &ast::Crate) { + // Just mark the #[staged_api] attribute used, though nothing else is done + // with it during this pass over the source. + for attr in c.attrs.iter() { + if attr.name().get() == "staged_api" { + match attr.node.value.node { + ast::MetaWord(_) => { + attr::mark_used(attr); + } + _ => (/*pass*/) + } + } + } } fn check_view_item(&mut self, cx: &Context, item: &ast::ViewItem) { @@ -1746,6 +1783,7 @@ impl LintPass for Stability { } _ => return }; + self.lint(cx, id, span); } @@ -1878,3 +1916,22 @@ impl LintPass for HardwiredLints { ) } } + +/// Forbids using the `#[feature(...)]` attribute +#[deriving(Copy)] +pub struct UnstableFeatures; + +declare_lint!(UNSTABLE_FEATURES, Allow, + "enabling unstable features"); + +impl LintPass for UnstableFeatures { + fn get_lints(&self) -> LintArray { + lint_array!(UNSTABLE_FEATURES) + } + fn check_attribute(&mut self, ctx: &Context, attr: &ast::Attribute) { + use syntax::attr; + if attr::contains_name(&[attr.node.value.clone()], "feature") { + ctx.span_lint(UNSTABLE_FEATURES, attr.span, "unstable feature"); + } + } +} diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 51998bdbcf2..7d58b04a7f4 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -28,8 +28,9 @@ use self::TargetLint::*; use middle::privacy::ExportedItems; use middle::ty::{self, Ty}; use session::{early_error, Session}; +use session::config::UnstableFeatures; use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject}; -use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}; +use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid, ReleaseChannel}; use lint::builtin; use util::nodemap::FnvHashMap; @@ -210,6 +211,7 @@ impl LintStore { UnusedAllocation, Stability, MissingCopyImplementations, + UnstableFeatures, ); add_builtin_with_new!(sess, @@ -298,6 +300,29 @@ impl LintStore { } } } + + fn maybe_stage_features(&mut self, sess: &Session) { + let lvl = match sess.opts.unstable_features { + UnstableFeatures::Default => return, + UnstableFeatures::Disallow => Warn, + UnstableFeatures::Cheat => Allow + }; + match self.by_name.get("unstable_features") { + Some(&Id(lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)), + Some(&Renamed(_, lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)), + None => unreachable!() + } + match self.by_name.get("staged_unstable") { + Some(&Id(lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)), + Some(&Renamed(_, lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)), + None => unreachable!() + } + match self.by_name.get("staged_experimental") { + Some(&Id(lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)), + Some(&Renamed(_, lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)), + None => unreachable!() + } + } } /// Context for lint checking. @@ -380,6 +405,7 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint, if level == Allow { return } let name = lint.name_lower(); + let mut def = None; let mut note = None; let msg = match source { Default => { @@ -394,7 +420,13 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint, }, name.replace("_", "-")) }, Node(src) => { - note = Some(src); + def = Some(src); + msg.to_string() + } + ReleaseChannel => { + let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); + note = Some(format!("this feature may not be used in the {} release channel", + release_channel)); msg.to_string() } }; @@ -410,7 +442,11 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint, _ => sess.bug("impossible level in raw_emit_lint"), } - for span in note.into_iter() { + for note in note.into_iter() { + sess.note(note.index(&FullRange)); + } + + for span in def.into_iter() { sess.span_note(span, "lint level defined here"); } } @@ -767,6 +803,10 @@ impl LintPass for GatherNodeLevels { /// Consumes the `lint_store` field of the `Session`. pub fn check_crate(tcx: &ty::ctxt, exported_items: &ExportedItems) { + + // If this is a feature-staged build of rustc then flip several lints to 'forbid' + tcx.sess.lint_store.borrow_mut().maybe_stage_features(&tcx.sess); + let krate = tcx.map.krate(); let mut cx = Context::new(tcx, krate, exported_items); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index e9778fa05ff..8a266a2530b 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -186,7 +186,7 @@ impl PartialEq for LintId { impl Eq for LintId { } -impl<S: hash::Writer> hash::Hash<S> for LintId { +impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for LintId { fn hash(&self, state: &mut S) { let ptr = self.lint as *const Lint; ptr.hash(state); @@ -248,6 +248,9 @@ pub enum LintSource { /// Lint level was set by a command-line flag. CommandLine, + + /// Lint level was set by the release channel. + ReleaseChannel } pub type LevelSource = (Level, LintSource); diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 72ce61b133a..39c7f80703d 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -27,6 +27,7 @@ use std::rc::Rc; use syntax::ast; use syntax::ast_map; use syntax::attr; +use syntax::attr::AttrMetaMethods; use syntax::diagnostic::expect; use syntax::parse::token; @@ -375,6 +376,18 @@ pub fn get_stability(cstore: &cstore::CStore, decoder::get_stability(&*cdata, def.node) } +pub fn is_staged_api(cstore: &cstore::CStore, def: ast::DefId) -> bool { + let cdata = cstore.get_crate_data(def.krate); + let attrs = decoder::get_crate_attributes(cdata.data()); + for attr in attrs.iter() { + if attr.name().get() == "staged_api" { + match attr.node.value.node { ast::MetaWord(_) => return true, _ => (/*pass*/) } + } + } + + return false; +} + pub fn get_repr_attrs(cstore: &cstore::CStore, def: ast::DefId) -> Vec<attr::ReprAttr> { let cdata = cstore.get_crate_data(def.krate); diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 9e71c867efa..750f8a29856 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -33,8 +33,7 @@ use middle::ty::{self, Ty}; use middle::astencode::vtable_decoder_helpers; use std::collections::HashMap; -use std::hash::Hash; -use std::hash; +use std::hash::{self, Hash, SipHasher}; use std::io::extensions::u64_from_be_bytes; use std::io; use std::num::FromPrimitive; @@ -94,7 +93,7 @@ pub fn maybe_find_item<'a>(item_id: ast::NodeId, } lookup_hash(items, |a| eq_item(a, item_id), - hash::hash(&(item_id as i64))) + hash::hash::<i64, SipHasher>(&(item_id as i64))) } fn find_item<'a>(item_id: ast::NodeId, items: rbml::Doc<'a>) -> rbml::Doc<'a> { diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 83038df338b..3d54d286258 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -29,8 +29,7 @@ use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use serialize::Encodable; use std::cell::RefCell; -use std::hash::Hash; -use std::hash; +use std::hash::{Hash, Hasher, SipHasher}; use syntax::abi; use syntax::ast::{self, DefId, NodeId}; use syntax::ast_map::{PathElem, PathElems}; @@ -1598,11 +1597,13 @@ fn encode_info_for_items(ecx: &EncodeContext, fn encode_index<T, F>(rbml_w: &mut Encoder, index: Vec<entry<T>>, mut write_fn: F) where F: FnMut(&mut SeekableMemWriter, &T), - T: Hash, + T: Hash<SipHasher>, { let mut buckets: Vec<Vec<entry<T>>> = range(0, 256u16).map(|_| Vec::new()).collect(); for elt in index.into_iter() { - let h = hash::hash(&elt.val) as uint; + let mut s = SipHasher::new(); + elt.val.hash(&mut s); + let h = s.finish() as uint; (&mut buckets[h % 256]).push(elt); } diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 29625d0a6af..e8160487e16 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -272,12 +272,12 @@ fn find_libdir(sysroot: &Path) -> String { } } - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] fn primary_libdir_name() -> String { "lib64".to_string() } - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] fn primary_libdir_name() -> String { "lib32".to_string() } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 359ad8d3941..e712f510d9d 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -189,3 +189,19 @@ pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> { } }) } + +pub fn is_staged_api(tcx: &ty::ctxt, id: DefId) -> bool { + match ty::trait_item_of_item(tcx, id) { + Some(ty::MethodTraitItemId(trait_method_id)) + if trait_method_id != id => { + is_staged_api(tcx, trait_method_id) + } + _ if is_local(id) => { + // Unused case + unreachable!() + } + _ => { + csearch::is_staged_api(&tcx.sess.cstore, id) + } + } +} diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 3e16e2965a6..e9eb3f4f4b0 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -452,7 +452,9 @@ fn assemble_candidates_from_predicates<'cx,'tcx>( for predicate in elaborate_predicates(selcx.tcx(), env_predicates) { match predicate { ty::Predicate::Projection(ref data) => { - let is_match = infcx.probe(|_| { + let same_name = data.item_name() == obligation.predicate.item_name; + + let is_match = same_name && infcx.probe(|_| { let origin = infer::Misc(obligation.cause.span); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); @@ -465,6 +467,9 @@ fn assemble_candidates_from_predicates<'cx,'tcx>( }); if is_match { + debug!("assemble_candidates_from_predicates: candidate {}", + data.repr(selcx.tcx())); + candidate_set.vec.push( ProjectionTyCandidate::ParamEnv(data.clone())); } @@ -527,6 +532,9 @@ fn assemble_candidates_from_impls<'cx,'tcx>( match vtable { super::VtableImpl(data) => { + debug!("assemble_candidates_from_impls: impl candidate {}", + data.repr(selcx.tcx())); + candidate_set.vec.push( ProjectionTyCandidate::Impl(data)); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9b9a58178cc..14349c8e440 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -72,7 +72,7 @@ use std::borrow::BorrowFrom; use std::cell::{Cell, RefCell}; use std::cmp::{self, Ordering}; use std::fmt::{self, Show}; -use std::hash::{Hash, sip, Writer}; +use std::hash::{Hash, Writer, SipHasher, Hasher}; use std::mem; use std::ops; use std::rc::Rc; @@ -946,11 +946,18 @@ impl<'tcx> PartialEq for TyS<'tcx> { } impl<'tcx> Eq for TyS<'tcx> {} +#[cfg(stage0)] impl<'tcx, S: Writer> Hash<S> for TyS<'tcx> { fn hash(&self, s: &mut S) { (self as *const _).hash(s) } } +#[cfg(not(stage0))] +impl<'tcx, S: Writer + Hasher> Hash<S> for TyS<'tcx> { + fn hash(&self, s: &mut S) { + (self as *const _).hash(s) + } +} pub type Ty<'tcx> = &'tcx TyS<'tcx>; @@ -968,7 +975,7 @@ impl<'tcx> PartialEq for InternedTy<'tcx> { impl<'tcx> Eq for InternedTy<'tcx> {} -impl<'tcx, S: Writer> Hash<S> for InternedTy<'tcx> { +impl<'tcx, S: Writer + Hasher> Hash<S> for InternedTy<'tcx> { fn hash(&self, s: &mut S) { self.ty.sty.hash(s) } @@ -1892,6 +1899,10 @@ pub struct ProjectionPredicate<'tcx> { pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>; impl<'tcx> PolyProjectionPredicate<'tcx> { + pub fn item_name(&self) -> ast::Name { + self.0.projection_ty.item_name // safe to skip the binder to access a name + } + pub fn sort_key(&self) -> (ast::DefId, ast::Name) { self.0.projection_ty.sort_key() } @@ -6164,15 +6175,16 @@ pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId) /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -> u64 { - let mut state = sip::SipState::new(); + let mut state = SipHasher::new(); helper(tcx, ty, svh, &mut state); - return state.result(); + return state.finish(); - fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, state: &mut sip::SipState) { + fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, + state: &mut SipHasher) { macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } macro_rules! hash { ($e:expr) => { $e.hash(state) } } - let region = |&: state: &mut sip::SipState, r: Region| { + let region = |&: state: &mut SipHasher, r: Region| { match r { ReStatic => {} ReLateBound(db, BrAnon(i)) => { @@ -6189,7 +6201,7 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - } } }; - let did = |&: state: &mut sip::SipState, did: DefId| { + let did = |&: state: &mut SipHasher, did: DefId| { let h = if ast_util::is_local(did) { svh.clone() } else { @@ -6198,10 +6210,10 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - h.as_str().hash(state); did.node.hash(state); }; - let mt = |&: state: &mut sip::SipState, mt: mt| { + let mt = |&: state: &mut SipHasher, mt: mt| { mt.mutbl.hash(state); }; - let fn_sig = |&: state: &mut sip::SipState, sig: &Binder<FnSig<'tcx>>| { + let fn_sig = |&: state: &mut SipHasher, sig: &Binder<FnSig<'tcx>>| { let sig = anonymize_late_bound_regions(tcx, sig).0; for a in sig.inputs.iter() { helper(tcx, *a, svh, state); } if let ty::FnConverging(output) = sig.output { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 4968066f7b6..b239b0dac47 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -111,7 +111,24 @@ pub struct Options { /// An optional name to use as the crate for std during std injection, /// written `extern crate std = "name"`. Default to "std". Used by /// out-of-tree drivers. - pub alt_std_name: Option<String> + pub alt_std_name: Option<String>, + /// Indicates how the compiler should treat unstable features + pub unstable_features: UnstableFeatures +} + +#[deriving(Clone, Copy)] +pub enum UnstableFeatures { + /// Hard errors for unstable features are active, as on + /// beta/stable channels. + Disallow, + /// Use the default lint levels + Default, + /// Errors are bypassed for bootstrapping. This is required any time + /// during the build that feature-related lints are set to warn or above + /// because the build turns on warnings-as-errors and uses lots of unstable + /// features. As a result, this this is always required for building Rust + /// itself. + Cheat } #[derive(Clone, PartialEq, Eq)] @@ -217,6 +234,7 @@ pub fn basic_options() -> Options { crate_name: None, alt_std_name: None, libs: Vec::new(), + unstable_features: UnstableFeatures::Disallow } } @@ -594,7 +612,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { let end = sess.target.target.target_endian.index(&FullRange); let arch = sess.target.target.arch.index(&FullRange); - let wordsz = sess.target.target.target_word_size.index(&FullRange); + let wordsz = sess.target.target.target_pointer_width.index(&FullRange); let os = sess.target.target.target_os.index(&FullRange); let fam = match sess.target.target.options.is_like_windows { @@ -609,7 +627,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { mk(InternedString::new("target_family"), fam), mk(InternedString::new("target_arch"), intern(arch)), mk(InternedString::new("target_endian"), intern(end)), - mk(InternedString::new("target_word_size"), + mk(InternedString::new("target_pointer_width"), intern(wordsz)) ); } @@ -643,7 +661,7 @@ pub fn build_target_config(opts: &Options, sp: &SpanHandler) -> Config { } }; - let (int_type, uint_type) = match target.target_word_size.index(&FullRange) { + let (int_type, uint_type) = match target.target_pointer_width.index(&FullRange) { "32" => (ast::TyI32, ast::TyU32), "64" => (ast::TyI64, ast::TyU64), w => sp.handler().fatal((format!("target specification was invalid: unrecognized \ @@ -1149,6 +1167,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { crate_name: crate_name, alt_std_name: None, libs: libs, + unstable_features: UnstableFeatures::Disallow } } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 26f98e28a8d..c505e9e3112 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -16,6 +16,7 @@ use std::fmt::Show; use std::hash::{Hash, Hasher}; use std::iter::repeat; use std::time::Duration; +use std::collections::hash_state::HashState; use syntax::ast; use syntax::visit; @@ -140,11 +141,11 @@ pub fn block_query<P>(b: &ast::Block, p: P) -> bool where P: FnMut(&ast::Expr) - /// Efficiency note: This is implemented in an inefficient way because it is typically invoked on /// very small graphs. If the graphs become larger, a more efficient graph representation and /// algorithm would probably be advised. -pub fn can_reach<S,H:Hasher<S>,T:Eq+Clone+Hash<S>>( - edges_map: &HashMap<T,Vec<T>,H>, - source: T, - destination: T) - -> bool +pub fn can_reach<T, S>(edges_map: &HashMap<T, Vec<T>, S>, source: T, + destination: T) -> bool + where S: HashState, + <S as HashState>::Hasher: Hasher<Output=u64>, + T: Hash< <S as HashState>::Hasher> + Eq + Clone, { if source == destination { return true; @@ -202,11 +203,12 @@ pub fn can_reach<S,H:Hasher<S>,T:Eq+Clone+Hash<S>>( /// } /// ``` #[inline(always)] -pub fn memoized<T, U, S, H, F>(cache: &RefCell<HashMap<T, U, H>>, arg: T, f: F) -> U where - T: Clone + Hash<S> + Eq, - U: Clone, - H: Hasher<S>, - F: FnOnce(T) -> U, +pub fn memoized<T, U, S, F>(cache: &RefCell<HashMap<T, U, S>>, arg: T, f: F) -> U + where T: Clone + Hash<<S as HashState>::Hasher> + Eq, + U: Clone, + S: HashState, + <S as HashState>::Hasher: Hasher<Output=u64>, + F: FnOnce(T) -> U, { let key = arg.clone(); let result = cache.borrow().get(&key).map(|result| result.clone()); diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs index ee224d1ec80..044534ae852 100644 --- a/src/librustc/util/nodemap.rs +++ b/src/librustc/util/nodemap.rs @@ -12,12 +12,14 @@ #![allow(non_snake_case)] +use std::collections::hash_state::{DefaultState}; use std::collections::{HashMap, HashSet}; -use std::hash::{Hasher, Hash, Writer}; +use std::default::Default; +use std::hash::{Hasher, Writer}; use syntax::ast; -pub type FnvHashMap<K, V> = HashMap<K, V, FnvHasher>; -pub type FnvHashSet<V> = HashSet<V, FnvHasher>; +pub type FnvHashMap<K, V> = HashMap<K, V, DefaultState<FnvHasher>>; +pub type FnvHashSet<V> = HashSet<V, DefaultState<FnvHasher>>; pub type NodeMap<T> = FnvHashMap<ast::NodeId, T>; pub type DefIdMap<T> = FnvHashMap<ast::DefId, T>; @@ -28,16 +30,16 @@ pub type DefIdSet = FnvHashSet<ast::DefId>; // Hacks to get good names pub mod FnvHashMap { use std::hash::Hash; - use std::collections::HashMap; - pub fn new<K: Hash<super::FnvState> + Eq, V>() -> super::FnvHashMap<K, V> { - HashMap::with_hasher(super::FnvHasher) + use std::default::Default; + pub fn new<K: Hash<super::FnvHasher> + Eq, V>() -> super::FnvHashMap<K, V> { + Default::default() } } pub mod FnvHashSet { use std::hash::Hash; - use std::collections::HashSet; - pub fn new<V: Hash<super::FnvState> + Eq>() -> super::FnvHashSet<V> { - HashSet::with_hasher(super::FnvHasher) + use std::default::Default; + pub fn new<V: Hash<super::FnvHasher> + Eq>() -> super::FnvHashSet<V> { + Default::default() } } pub mod NodeMap { @@ -68,28 +70,26 @@ pub mod DefIdSet { /// /// This uses FNV hashing, as described here: /// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function -#[derive(Clone, Copy, Default)] -pub struct FnvHasher; - #[allow(missing_copy_implementations)] -pub struct FnvState(u64); +pub struct FnvHasher(u64); -impl Hasher<FnvState> for FnvHasher { - fn hash<T: ?Sized + Hash<FnvState>>(&self, t: &T) -> u64 { - let mut state = FnvState(0xcbf29ce484222325); - t.hash(&mut state); - let FnvState(ret) = state; - return ret; - } +impl Default for FnvHasher { + fn default() -> FnvHasher { FnvHasher(0xcbf29ce484222325) } +} + +impl Hasher for FnvHasher { + type Output = u64; + fn reset(&mut self) { *self = Default::default(); } + fn finish(&self) -> u64 { self.0 } } -impl Writer for FnvState { +impl Writer for FnvHasher { fn write(&mut self, bytes: &[u8]) { - let FnvState(mut hash) = *self; + let FnvHasher(mut hash) = *self; for byte in bytes.iter() { hash = hash ^ (*byte as u64); hash = hash * 0x100000001b3; } - *self = FnvState(hash); + *self = FnvHasher(hash); } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 2d433369366..edd1bc873be 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -26,6 +26,7 @@ use middle::ty; use middle::ty_fold::TypeFoldable; use std::collections::HashMap; +use std::collections::hash_state::HashState; use std::hash::{Hash, Hasher}; use std::rc::Rc; use syntax::abi; @@ -1350,11 +1351,11 @@ impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for ty::Binder<T> { } } -#[old_impl_check] -impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap<K,V,H> - where K : Hash<S> + Eq + Repr<'tcx>, - V : Repr<'tcx>, - H : Hasher<S> +impl<'tcx, S, K, V> Repr<'tcx> for HashMap<K, V, S> + where K: Hash<<S as HashState>::Hasher> + Eq + Repr<'tcx>, + V: Repr<'tcx>, + S: HashState, + <S as HashState>::Hasher: Hasher<Output=u64>, { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("HashMap({})", diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index ca39477fbdc..5d863def32e 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -23,6 +23,7 @@ #![crate_name = "rustc_back"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 4812a2948d1..236855b7065 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -47,8 +47,7 @@ //! Original issue: https://github.com/rust-lang/rust/issues/10207 use std::fmt; -use std::hash::Hash; -use std::hash::sip::SipState; +use std::hash::{Hash, SipHasher, Hasher}; use std::iter::range_step; use syntax::ast; use syntax::visit; @@ -78,7 +77,7 @@ impl Svh { // FIXME: this should use SHA1, not SipHash. SipHash is not built to // avoid collisions. - let mut state = SipState::new(); + let mut state = SipHasher::new(); for data in metadata.iter() { data.hash(&mut state); @@ -102,7 +101,7 @@ impl Svh { attr.node.value.hash(&mut state); } - let hash = state.result(); + let hash = state.finish(); return Svh { hash: range_step(0u, 64u, 4u).map(|i| hex(hash >> i)).collect() }; @@ -147,14 +146,13 @@ mod svh_visitor { use syntax::visit; use syntax::visit::{Visitor, FnKind}; - use std::hash::Hash; - use std::hash::sip::SipState; + use std::hash::{Hash, SipHasher}; pub struct StrictVersionHashVisitor<'a> { - pub st: &'a mut SipState, + pub st: &'a mut SipHasher, } - pub fn make<'a>(st: &'a mut SipState) -> StrictVersionHashVisitor<'a> { + pub fn make<'a>(st: &'a mut SipHasher) -> StrictVersionHashVisitor<'a> { StrictVersionHashVisitor { st: st } } @@ -398,7 +396,7 @@ mod svh_visitor { } // All of the remaining methods just record (in the hash - // SipState) that the visitor saw that particular variant + // SipHasher) that the visitor saw that particular variant // (with its payload), and continue walking as the default // visitor would. // diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index 296552a6abd..a3ef6372f06 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { n32:64-S128".to_string(), llvm_target: "aarch64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_word_size: "64".to_string(), + target_pointer_width: "64".to_string(), arch: "aarch64".to_string(), target_os: "linux".to_string(), options: base, diff --git a/src/librustc_back/target/arm_apple_ios.rs b/src/librustc_back/target/arm_apple_ios.rs index 8bb64eae625..e0afef6e390 100644 --- a/src/librustc_back/target/arm_apple_ios.rs +++ b/src/librustc_back/target/arm_apple_ios.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { -a:0:64-n32".to_string(), llvm_target: "arm-apple-ios".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "arm".to_string(), target_os: "ios".to_string(), options: TargetOptions { diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index ecfb1667f60..6fc77a715a5 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -27,7 +27,7 @@ pub fn target() -> Target { -a:0:64-n32".to_string(), llvm_target: "arm-linux-androideabi".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "arm".to_string(), target_os: "android".to_string(), options: base, diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs index 985af35e145..32eccaf54b0 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs @@ -20,7 +20,7 @@ pub fn target() -> Target { -a:0:64-n32".to_string(), llvm_target: "arm-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "arm".to_string(), target_os: "linux".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs index 3cf0c312820..eff3601250f 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs @@ -20,7 +20,7 @@ pub fn target() -> Target { -a:0:64-n32".to_string(), llvm_target: "arm-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "arm".to_string(), target_os: "linux".to_string(), diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index 45669bc9585..a1fcc9ac53f 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { -n8:16:32".to_string(), llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "x86".to_string(), target_os: "ios".to_string(), diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs index feef5b98dcb..1b079323bf9 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_back/target/i686_apple_darwin.rs @@ -22,7 +22,7 @@ pub fn target() -> Target { -n8:16:32".to_string(), llvm_target: "i686-apple-darwin".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "x86".to_string(), target_os: "macos".to_string(), options: base, diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index 4d75590e664..c2ab68ee052 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -26,7 +26,7 @@ pub fn target() -> Target { data_layout: "e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32".to_string(), llvm_target: "i686-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "x86".to_string(), target_os: "windows".to_string(), options: options, diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs index a12657ff4dc..7910eba7ea1 100644 --- a/src/librustc_back/target/i686_unknown_dragonfly.rs +++ b/src/librustc_back/target/i686_unknown_dragonfly.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(), llvm_target: "i686-unknown-dragonfly".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "x86".to_string(), target_os: "dragonfly".to_string(), options: base, diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs index 1a4560d5cd5..c93a564fef5 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(), llvm_target: "i686-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "x86".to_string(), target_os: "linux".to_string(), options: base, diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index c8c5ddcbd0d..8acc248e234 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { -a:0:64-n32".to_string(), llvm_target: "mips-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "mips".to_string(), target_os: "linux".to_string(), options: super::linux_base::opts() diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index 3571f7b26c0..604c62eb69f 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { -a:0:64-n32".to_string(), llvm_target: "mipsel-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_word_size: "32".to_string(), + target_pointer_width: "32".to_string(), arch: "mips".to_string(), target_os: "linux".to_string(), diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 23c8fc7de51..87897c28857 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -85,8 +85,8 @@ pub struct Target { pub llvm_target: String, /// String to use as the `target_endian` `cfg` variable. pub target_endian: String, - /// String to use as the `target_word_size` `cfg` variable. - pub target_word_size: String, + /// String to use as the `target_pointer_width` `cfg` variable. + pub target_pointer_width: String, /// OS name to use for conditional compilation. pub target_os: String, /// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm", @@ -233,7 +233,7 @@ impl Target { data_layout: get_req_field("data-layout"), llvm_target: get_req_field("llvm-target"), target_endian: get_req_field("target-endian"), - target_word_size: get_req_field("target-word-size"), + target_pointer_width: get_req_field("target-word-size"), arch: get_req_field("arch"), target_os: get_req_field("os"), options: Default::default(), diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs index 07e6cdfed2c..0ebd3bd3215 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_back/target/x86_64_apple_darwin.rs @@ -21,7 +21,7 @@ pub fn target() -> Target { s0:64:64-f80:128:128-n8:16:32:64".to_string(), llvm_target: "x86_64-apple-darwin".to_string(), target_endian: "little".to_string(), - target_word_size: "64".to_string(), + target_pointer_width: "64".to_string(), arch: "x86_64".to_string(), target_os: "macos".to_string(), options: base, diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs index 6ca74eb7fc0..9e1294a8962 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -23,7 +23,7 @@ pub fn target() -> Target { s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), llvm_target: "x86_64-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_word_size: "64".to_string(), + target_pointer_width: "64".to_string(), arch: "x86_64".to_string(), target_os: "windows".to_string(), options: base, diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs index bff3eaf6bc8..6635306b0e1 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs @@ -20,7 +20,7 @@ pub fn target() -> Target { s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), llvm_target: "x86_64-unknown-dragonfly".to_string(), target_endian: "little".to_string(), - target_word_size: "64".to_string(), + target_pointer_width: "64".to_string(), arch: "x86_64".to_string(), target_os: "dragonfly".to_string(), options: base, diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs index 8d5603a3878..2aba2b8defb 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs @@ -20,7 +20,7 @@ pub fn target() -> Target { s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), llvm_target: "x86_64-unknown-freebsd".to_string(), target_endian: "little".to_string(), - target_word_size: "64".to_string(), + target_pointer_width: "64".to_string(), arch: "x86_64".to_string(), target_os: "freebsd".to_string(), options: base, diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs index e0a67cd6250..d7a6df3a8b0 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs @@ -20,7 +20,7 @@ pub fn target() -> Target { s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), llvm_target: "x86_64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_word_size: "64".to_string(), + target_pointer_width: "64".to_string(), arch: "x86_64".to_string(), target_os: "linux".to_string(), options: base, diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 26bcd5f4c10..452eaaaa52d 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -10,6 +10,7 @@ #![crate_name = "rustc_borrowck"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 5af114abeea..1c2d956e279 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -16,6 +16,7 @@ #![crate_name = "rustc_driver"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", @@ -46,7 +47,7 @@ pub use syntax::diagnostic; use rustc_trans::back::link; use rustc::session::{config, Session, build_session}; -use rustc::session::config::{Input, PrintRequest}; +use rustc::session::config::{Input, PrintRequest, UnstableFeatures}; use rustc::lint::Lint; use rustc::lint; use rustc::metadata; @@ -132,7 +133,11 @@ fn run_compiler(args: &[String]) { _ => early_error("multiple input filenames provided") }; + let mut sopts = sopts; + sopts.unstable_features = get_unstable_features_setting(); + let mut sess = build_session(sopts, input_file_path, descriptions); + let cfg = config::build_configuration(&sess); if print_crate_info(&sess, Some(&input), &odir, &ofile) { return @@ -181,6 +186,21 @@ fn run_compiler(args: &[String]) { driver::compile_input(sess, cfg, &input, &odir, &ofile, None); } +pub fn get_unstable_features_setting() -> UnstableFeatures { + // Whether this is a feature-staged build, i.e. on the beta or stable channel + let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + // The secret key needed to get through the rustc build itself by + // subverting the unstable features lints + let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY"); + // The matching key to the above, only known by the build system + let bootstrap_provided_key = os::getenv("RUSTC_BOOTSTRAP_KEY"); + match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) { + (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat, + (true, _, _) => UnstableFeatures::Disallow, + (false, _, _) => UnstableFeatures::Default + } +} + /// Returns a version string such as "0.12.0-dev". pub fn release_str() -> Option<&'static str> { option_env!("CFG_RELEASE") diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 0bed754aa3c..961d3a6cfa1 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -15,6 +15,7 @@ #![crate_name = "rustc_llvm"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 93ad69e03b1..f21297c60d6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -10,6 +10,7 @@ #![crate_name = "rustc_resolve"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", @@ -2943,8 +2944,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { HasTypeParameters( generics, FnSpace, foreign_item.id, ItemRibKind), - |this| visit::walk_foreign_item(this, - &**foreign_item)); + |this| { + this.resolve_type_parameters(&generics.ty_params); + this.resolve_where_clause(&generics.where_clause); + visit::walk_foreign_item(this, &**foreign_item) + }); } ForeignItemStatic(..) => { visit::walk_foreign_item(this, diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index b6f90a4c2f5..3497ff2221c 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -16,6 +16,7 @@ #![crate_name = "rustc_trans"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 057d0f378e6..39632f2b084 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1128,7 +1128,7 @@ pub fn call_lifetime_end(cx: Block, ptr: ValueRef) { pub fn call_memcpy(cx: Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) { let _icx = push_ctxt("call_memcpy"); let ccx = cx.ccx(); - let key = match ccx.sess().target.target.target_word_size.index(&FullRange) { + let key = match ccx.sess().target.target.target_pointer_width.index(&FullRange) { "32" => "llvm.memcpy.p0i8.p0i8.i32", "64" => "llvm.memcpy.p0i8.p0i8.i64", tws => panic!("Unsupported target word size for memcpy: {}", tws), @@ -1175,7 +1175,7 @@ fn memzero<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>) { let llty = type_of::type_of(ccx, ty); - let intrinsic_key = match ccx.sess().target.target.target_word_size.index(&FullRange) { + let intrinsic_key = match ccx.sess().target.target.target_pointer_width.index(&FullRange) { "32" => "llvm.memset.p0i8.i32", "64" => "llvm.memset.p0i8.i64", tws => panic!("Unsupported target word size for memset: {}", tws), diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 35fb34eafb4..d450ce24de7 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -721,7 +721,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable /// address space on 64-bit ARMv8 and x86_64. pub fn obj_size_bound(&self) -> u64 { - match self.sess().target.target.target_word_size.index(&FullRange) { + match self.sess().target.target.target_pointer_width.index(&FullRange) { "32" => 1 << 31, "64" => 1 << 47, _ => unreachable!() // error handled by config::build_target_config diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index ed75445b993..b22c7f763f0 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -313,7 +313,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "size_of") => { let tp_ty = *substs.types.get(FnSpace, 0); let lltp_ty = type_of::type_of(ccx, tp_ty); - C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty)) + C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) } (_, "min_align_of") => { let tp_ty = *substs.types.get(FnSpace, 0); diff --git a/src/librustc_trans/trans/machine.rs b/src/librustc_trans/trans/machine.rs index 41738f1e58f..95d67cd54c1 100644 --- a/src/librustc_trans/trans/machine.rs +++ b/src/librustc_trans/trans/machine.rs @@ -43,8 +43,10 @@ pub fn llsize_of_alloc(cx: &CrateContext, ty: Type) -> llsize { // Returns, as near as we can figure, the "real" size of a type. As in, the // bits in this number of bytes actually carry data related to the datum -// with the type. Not junk, padding, accidentally-damaged words, or -// whatever. Rounds up to the nearest byte though, so if you have a 1-bit +// with the type. Not junk, accidentally-damaged words, or whatever. +// Note that padding of the type will be included for structs, but not for the +// other types (i.e. SIMD types). +// Rounds up to the nearest byte though, so if you have a 1-bit // value, we return 1 here, not 0. Most of rustc works in bytes. Be warned // that LLVM *does* distinguish between e.g. a 1-bit value and an 8-bit value // at the codegen level! In general you should prefer `llbitsize_of_real` diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index e2594765f4f..cc98ee9592b 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -32,7 +32,7 @@ use syntax::ast_map; use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::attr; use syntax::codemap::DUMMY_SP; -use std::hash::{sip, Hash}; +use std::hash::{Hasher, Hash, SipHasher}; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: ast::DefId, @@ -125,11 +125,11 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let hash; let s = { - let mut state = sip::SipState::new(); + let mut state = SipHasher::new(); hash_id.hash(&mut state); mono_ty.hash(&mut state); - hash = format!("h{}", state.result()); + hash = format!("h{}", state.finish()); ccx.tcx().map.with_path(fn_id.node, |path| { exported_name(path, hash.index(&FullRange)) }) diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index 66e27ed1188..2e236154d48 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -103,7 +103,7 @@ impl Type { } pub fn int(ccx: &CrateContext) -> Type { - match ccx.tcx().sess.target.target.target_word_size.index(&FullRange) { + match ccx.tcx().sess.target.target.target_pointer_width.index(&FullRange) { "32" => Type::i32(ccx), "64" => Type::i64(ccx), tws => panic!("Unsupported target word size for int: {}", tws), diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 898a5f9fe0c..8b65895dad7 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -77,6 +77,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { enum_variants(fcx, enum_def) }); } + ast::ItemTrait(..) => { + let trait_def = + ty::lookup_trait_def(ccx.tcx, local_def(item.id)); + reject_non_type_param_bounds( + ccx.tcx, + item.span, + &trait_def.generics); + } _ => {} } } @@ -237,21 +245,32 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, generics: &ty::Generics<'tcx>) { + for predicate in generics.predicates.iter() { match predicate { &ty::Predicate::Trait(ty::Binder(ref tr)) => { - let self_ty = tr.self_ty(); - if !self_ty.walk().any(|t| is_ty_param(t)) { - tcx.sess.span_err( - span, - format!("cannot bound type `{}`, where clause \ - bounds may only be attached to types involving \ - type parameters", - self_ty.repr(tcx)).as_slice()) - } + let found_param = tr.input_types().iter() + .flat_map(|ty| ty.walk()) + .any(is_ty_param); + if !found_param { report_bound_error(tcx, span, tr.self_ty() )} + } + &ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(ty, _))) => { + let found_param = ty.walk().any(|t| is_ty_param(t)); + if !found_param { report_bound_error(tcx, span, ty) } } _ => {} - } + }; + } + + fn report_bound_error<'t>(tcx: &ty::ctxt<'t>, + span: Span, + bounded_ty: ty::Ty<'t>) { + tcx.sess.span_err( + span, + format!("cannot bound type `{}`, where clause \ + bounds may only be attached to types involving \ + type parameters", + bounded_ty.repr(tcx)).as_slice()) } fn is_ty_param(ty: ty::Ty) -> bool { @@ -267,6 +286,24 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.check_item_well_formed(i); visit::walk_item(self, i); } + + fn visit_trait_item(&mut self, t: &'v ast::TraitItem) { + match t { + &ast::TraitItem::ProvidedMethod(_) | + &ast::TraitItem::TypeTraitItem(_) => {}, + &ast::TraitItem::RequiredMethod(ref method) => { + match ty::impl_or_trait_item(self.ccx.tcx, local_def(method.id)) { + ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { + reject_non_type_param_bounds( + self.ccx.tcx, + method.span, + &ty_method.generics) + } + _ => {} + } + } + } + } } pub struct BoundsChecker<'cx,'tcx:'cx> { @@ -455,7 +492,6 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let arg_tys = ty::assert_no_late_bound_regions( fcx.tcx(), &ty::ty_fn_args(ctor_ty)); - AdtVariant { fields: args.iter().enumerate().map(|(index, arg)| { let arg_ty = arg_tys[index]; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index ae8731dfa47..85221c2e913 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -65,6 +65,7 @@ This API is completely unstable and subject to change. #![crate_name = "rustc_typeck"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 46c212a9f2d..4885bd373eb 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -11,6 +11,7 @@ pub use self::MaybeTyped::*; use rustc_driver::driver; use rustc::session::{self, config}; +use rustc::session::config::UnstableFeatures; use rustc::session::search_paths::SearchPaths; use rustc::middle::{privacy, ty}; use rustc::lint; @@ -95,10 +96,11 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs, externs: externs, target_triple: triple.unwrap_or(config::host_triple().to_string()), cfg: config::parse_cfgspecs(cfgs), + // Ensure that rustdoc works even if rustc is feature-staged + unstable_features: UnstableFeatures::Default, ..config::basic_options().clone() }; - let codemap = codemap::CodeMap::new(); let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None); let span_diagnostic_handler = diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index a5a48254141..5951ac2bae7 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -157,7 +157,6 @@ nav.sub { left: 0; top: 0; min-height: 100%; - z-index: -1; } .content, nav { max-width: 960px; } @@ -221,6 +220,7 @@ nav.sub { .content pre.line-numbers { float: left; border: none; + position: relative; -webkit-user-select: none; -moz-user-select: none; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ee65ef06623..daa930fddcb 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -10,6 +10,7 @@ #![crate_name = "rustdoc"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index bbe35eb0e9c..8e0f4b2d443 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -22,6 +22,7 @@ use std::collections::{HashSet, HashMap}; use testing; use rustc::session::{self, config}; use rustc::session::search_paths::{SearchPaths, PathKind}; +use rustc_driver::get_unstable_features_setting; use rustc_driver::driver; use syntax::ast; use syntax::codemap::{CodeMap, dummy_spanned}; @@ -52,6 +53,7 @@ pub fn run(input: &str, search_paths: libs.clone(), crate_types: vec!(config::CrateTypeDylib), externs: externs.clone(), + unstable_features: get_unstable_features_setting(), ..config::basic_options().clone() }; @@ -128,6 +130,7 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, .. config::basic_codegen_options() }, test: as_test_harness, + unstable_features: get_unstable_features_setting(), ..config::basic_options().clone() }; diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index d89a4754d2e..42498328ff6 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -13,6 +13,7 @@ use std::uint; use std::default::Default; use std::hash::{Hash, Hasher}; +use std::collections::hash_state::HashState; use {Decodable, Encodable, Decoder, Encoder}; use std::collections::{DList, RingBuf, BTreeMap, BTreeSet, HashMap, HashSet, VecMap}; @@ -156,13 +157,12 @@ impl< } } -#[old_impl_check] -impl< - K: Encodable + Hash<X> + Eq, - V: Encodable, - X, - H: Hasher<X> -> Encodable for HashMap<K, V, H> { +impl<K, V, S> Encodable for HashMap<K, V, S> + where K: Encodable + Hash< <S as HashState>::Hasher> + Eq, + V: Encodable, + S: HashState, + <S as HashState>::Hasher: Hasher<Output=u64> +{ fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { let mut i = 0; @@ -176,17 +176,16 @@ impl< } } -#[old_impl_check] -impl< - K: Decodable + Hash<S> + Eq, - V: Decodable, - S, - H: Hasher<S> + Default -> Decodable for HashMap<K, V, H> { - fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, H>, D::Error> { +impl<K, V, S> Decodable for HashMap<K, V, S> + where K: Decodable + Hash< <S as HashState>::Hasher> + Eq, + V: Decodable, + S: HashState + Default, + <S as HashState>::Hasher: Hasher<Output=u64> +{ + fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> { d.read_map(|d, len| { - let hasher = Default::default(); - let mut map = HashMap::with_capacity_and_hasher(len, hasher); + let state = Default::default(); + let mut map = HashMap::with_capacity_and_hash_state(len, state); for i in range(0u, len) { let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); @@ -197,12 +196,11 @@ impl< } } -#[old_impl_check] -impl< - T: Encodable + Hash<X> + Eq, - X, - H: Hasher<X> -> Encodable for HashSet<T, H> { +impl<T, S> Encodable for HashSet<T, S> + where T: Encodable + Hash< <S as HashState>::Hasher> + Eq, + S: HashState, + <S as HashState>::Hasher: Hasher<Output=u64> +{ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; @@ -215,15 +213,15 @@ impl< } } -#[old_impl_check] -impl< - T: Decodable + Hash<S> + Eq, - S, - H: Hasher<S> + Default -> Decodable for HashSet<T, H> { - fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T, H>, D::Error> { +impl<T, S> Decodable for HashSet<T, S> + where T: Decodable + Hash< <S as HashState>::Hasher> + Eq, + S: HashState + Default, + <S as HashState>::Hasher: Hasher<Output=u64> +{ + fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T, S>, D::Error> { d.read_seq(|d, len| { - let mut set = HashSet::with_capacity_and_hasher(len, Default::default()); + let state = Default::default(); + let mut set = HashSet::with_capacity_and_hash_state(len, state); for i in range(0u, len) { set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index fd0b5c55903..4b631d7ef9e 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -3473,7 +3473,7 @@ mod tests { } } #[test] - #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064) fn test_streaming_parser() { assert_stream_equal( r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#, @@ -3512,7 +3512,7 @@ mod tests { } #[test] - #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064) fn test_read_object_streaming() { assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3))); assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2))); @@ -3596,7 +3596,7 @@ mod tests { ); } #[test] - #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + #[cfg_attr(target_pointer_width = "32", ignore)] // FIXME(#14064) fn test_read_array_streaming() { assert_stream_equal( "[]", diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index f0a51fcea18..d51f070632f 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -16,6 +16,7 @@ Core encoding and decoding interfaces. #![crate_name = "serialize"] #![unstable = "deprecated in favor of rustc-serialize on crates.io"] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", @@ -23,8 +24,9 @@ Core encoding and decoding interfaces. html_root_url = "http://doc.rust-lang.org/nightly/", html_playground_url = "http://play.rust-lang.org/")] #![allow(unknown_features)] -#![feature(slicing_syntax)] +#![cfg_attr(stage0, allow(unused_attributes))] #![feature(old_impl_check)] +#![feature(slicing_syntax)] // test harness access #[cfg(test)] extern crate test; diff --git a/src/libstd/bitflags.rs b/src/libstd/bitflags.rs index 5764962b51b..8dc41368e7f 100644 --- a/src/libstd/bitflags.rs +++ b/src/libstd/bitflags.rs @@ -273,7 +273,7 @@ macro_rules! bitflags { #[cfg(test)] #[allow(non_upper_case_globals)] mod tests { - use hash; + use hash::{self, SipHasher}; use option::Option::{Some, None}; bitflags! { @@ -467,9 +467,9 @@ mod tests { fn test_hash() { let mut x = Flags::empty(); let mut y = Flags::empty(); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<Flags, SipHasher>(&x) == hash::hash::<Flags, SipHasher>(&y)); x = Flags::all(); y = FlagABC; - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<Flags, SipHasher>(&x) == hash::hash::<Flags, SipHasher>(&y)); } } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index c3381d5cd64..c3bdfbb12d8 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -19,16 +19,15 @@ use clone::Clone; use cmp::{max, Eq, PartialEq}; use default::Default; use fmt::{self, Show}; -use hash::{Hash, Hasher, RandomSipHasher}; +use hash::{self, Hash, SipHasher}; use iter::{self, Iterator, IteratorExt, FromIterator, Extend, Map}; use marker::Sized; use mem::{self, replace}; use num::{Int, UnsignedInt}; use ops::{Deref, FnMut, Index, IndexMut}; -use option::Option; -use option::Option::{Some, None}; -use result::Result; -use result::Result::{Ok, Err}; +use option::Option::{self, Some, None}; +use rand::{self, Rng}; +use result::Result::{self, Ok, Err}; use super::table::{ self, @@ -44,6 +43,7 @@ use super::table::BucketState::{ Empty, Full, }; +use super::state::HashState; const INITIAL_LOG2_CAP: uint = 5; pub const INITIAL_CAPACITY: uint = 1 << INITIAL_LOG2_CAP; // 2^5 @@ -297,9 +297,9 @@ fn test_resize_policy() { /// ``` #[derive(Clone)] #[stable] -pub struct HashMap<K, V, H = RandomSipHasher> { +pub struct HashMap<K, V, S = RandomState> { // All hashes are keyed on these values, to prevent hash collision attacks. - hasher: H, + hash_state: S, table: RawTable<K, V>, @@ -439,17 +439,20 @@ impl<K, V, M> SearchResult<K, V, M> { } } -#[old_impl_check] -impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { - fn make_hash<X: ?Sized + Hash<S>>(&self, x: &X) -> SafeHash { - table::make_hash(&self.hasher, x) +impl<K, V, S, H> HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn make_hash<X: ?Sized>(&self, x: &X) -> SafeHash where X: Hash<H> { + table::make_hash(&self.hash_state, x) } /// Search for a key, yielding the index if it's found in the hashtable. /// If you already have the hash for the key lying around, use /// search_hashed. fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> Option<FullBucketImm<'a, K, V>> - where Q: BorrowFrom<K> + Eq + Hash<S> + where Q: BorrowFrom<K> + Eq + Hash<H> { let hash = self.make_hash(q); search_hashed(&self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) @@ -457,7 +460,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { } fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> Option<FullBucketMut<'a, K, V>> - where Q: BorrowFrom<K> + Eq + Hash<S> + where Q: BorrowFrom<K> + Eq + Hash<H> { let hash = self.make_hash(q); search_hashed(&mut self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k))) @@ -486,7 +489,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { } } -impl<K: Hash + Eq, V> HashMap<K, V, RandomSipHasher> { +impl<K: Hash<Hasher> + Eq, V> HashMap<K, V, RandomState> { /// Create an empty HashMap. /// /// # Example @@ -497,9 +500,8 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomSipHasher> { /// ``` #[inline] #[stable] - pub fn new() -> HashMap<K, V, RandomSipHasher> { - let hasher = RandomSipHasher::new(); - HashMap::with_hasher(hasher) + pub fn new() -> HashMap<K, V, RandomState> { + Default::default() } /// Creates an empty hash map with the given initial capacity. @@ -512,14 +514,16 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomSipHasher> { /// ``` #[inline] #[stable] - pub fn with_capacity(capacity: uint) -> HashMap<K, V, RandomSipHasher> { - let hasher = RandomSipHasher::new(); - HashMap::with_capacity_and_hasher(capacity, hasher) + pub fn with_capacity(capacity: uint) -> HashMap<K, V, RandomState> { + HashMap::with_capacity_and_hash_state(capacity, Default::default()) } } -#[old_impl_check] -impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { +impl<K, V, S, H> HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ /// Creates an empty hashmap which will use the given hasher to hash keys. /// /// The creates map has the default initial capacity. @@ -528,17 +532,17 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { /// /// ``` /// use std::collections::HashMap; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_map::RandomState; /// - /// let h = SipHasher::new(); - /// let mut map = HashMap::with_hasher(h); + /// let s = RandomState::new(); + /// let mut map = HashMap::with_hash_state(s); /// map.insert(1i, 2u); /// ``` #[inline] #[unstable = "hasher stuff is unclear"] - pub fn with_hasher(hasher: H) -> HashMap<K, V, H> { + pub fn with_hash_state(hash_state: S) -> HashMap<K, V, S> { HashMap { - hasher: hasher, + hash_state: hash_state, resize_policy: DefaultResizePolicy::new(), table: RawTable::new(0), } @@ -556,21 +560,22 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { /// /// ``` /// use std::collections::HashMap; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_map::RandomState; /// - /// let h = SipHasher::new(); - /// let mut map = HashMap::with_capacity_and_hasher(10, h); + /// let s = RandomState::new(); + /// let mut map = HashMap::with_capacity_and_hash_state(10, s); /// map.insert(1i, 2u); /// ``` #[inline] #[unstable = "hasher stuff is unclear"] - pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashMap<K, V, H> { + pub fn with_capacity_and_hash_state(capacity: uint, hash_state: S) + -> HashMap<K, V, S> { let resize_policy = DefaultResizePolicy::new(); let min_cap = max(INITIAL_CAPACITY, resize_policy.min_capacity(capacity)); let internal_cap = min_cap.checked_next_power_of_two().expect("capacity overflow"); assert!(internal_cap >= capacity, "capacity overflow"); HashMap { - hasher: hasher, + hash_state: hash_state, resize_policy: resize_policy, table: RawTable::new(internal_cap), } @@ -1031,7 +1036,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { /// ``` #[stable] pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> - where Q: Hash<S> + Eq + BorrowFrom<K> + where Q: Hash<H> + Eq + BorrowFrom<K> { self.search(k).map(|bucket| bucket.into_refs().1) } @@ -1054,7 +1059,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { /// ``` #[stable] pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool - where Q: Hash<S> + Eq + BorrowFrom<K> + where Q: Hash<H> + Eq + BorrowFrom<K> { self.search(k).is_some() } @@ -1080,7 +1085,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { /// ``` #[stable] pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> - where Q: Hash<S> + Eq + BorrowFrom<K> + where Q: Hash<H> + Eq + BorrowFrom<K> { self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } @@ -1132,7 +1137,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> { /// ``` #[stable] pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> - where Q: Hash<S> + Eq + BorrowFrom<K> + where Q: Hash<H> + Eq + BorrowFrom<K> { if self.table.size() == 0 { return None @@ -1189,10 +1194,12 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHas } } -#[stable] -#[old_impl_check] -impl<K: Eq + Hash<S>, V: PartialEq, S, H: Hasher<S>> PartialEq for HashMap<K, V, H> { - fn eq(&self, other: &HashMap<K, V, H>) -> bool { +impl<K, V, S, H> PartialEq for HashMap<K, V, S> + where K: Eq + Hash<H>, V: PartialEq, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn eq(&self, other: &HashMap<K, V, S>) -> bool { if self.len() != other.len() { return false; } self.iter().all(|(key, value)| @@ -1202,12 +1209,18 @@ impl<K: Eq + Hash<S>, V: PartialEq, S, H: Hasher<S>> PartialEq for HashMap<K, V, } #[stable] -#[old_impl_check] -impl<K: Eq + Hash<S>, V: Eq, S, H: Hasher<S>> Eq for HashMap<K, V, H> {} +impl<K, V, S, H> Eq for HashMap<K, V, S> + where K: Eq + Hash<H>, V: Eq, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{} #[stable] -#[old_impl_check] -impl<K: Eq + Hash<S> + Show, V: Show, S, H: Hasher<S>> Show for HashMap<K, V, H> { +impl<K, V, S, H> Show for HashMap<K, V, S> + where K: Eq + Hash<H> + Show, V: Show, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "HashMap {{")); @@ -1221,18 +1234,22 @@ impl<K: Eq + Hash<S> + Show, V: Show, S, H: Hasher<S>> Show for HashMap<K, V, H> } #[stable] -#[old_impl_check] -impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> Default for HashMap<K, V, H> { - #[stable] - fn default() -> HashMap<K, V, H> { - HashMap::with_hasher(Default::default()) +impl<K, V, S, H> Default for HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + fn default() -> HashMap<K, V, S> { + HashMap::with_hash_state(Default::default()) } } #[stable] -#[old_impl_check] -impl<K: Hash<S> + Eq, Q: ?Sized, V, S, H: Hasher<S>> Index<Q> for HashMap<K, V, H> - where Q: BorrowFrom<K> + Hash<S> + Eq +impl<K, Q: ?Sized, V, S, H> Index<Q> for HashMap<K, V, S> + where K: Eq + Hash<H>, + Q: Eq + Hash<H> + BorrowFrom<K>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> { type Output = V; @@ -1243,9 +1260,11 @@ impl<K: Hash<S> + Eq, Q: ?Sized, V, S, H: Hasher<S>> Index<Q> for HashMap<K, V, } #[stable] -#[old_impl_check] -impl<K: Hash<S> + Eq, Q: ?Sized, V, S, H: Hasher<S>> IndexMut<Q> for HashMap<K, V, H> - where Q: BorrowFrom<K> + Hash<S> + Eq +impl<K, V, S, H, Q: ?Sized> IndexMut<Q> for HashMap<K, V, S> + where K: Eq + Hash<H>, + Q: Eq + Hash<H> + BorrowFrom<K>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> { type Output = V; @@ -1473,19 +1492,26 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { } #[stable] -#[old_impl_check] -impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> FromIterator<(K, V)> for HashMap<K, V, H> { - fn from_iter<T: Iterator<Item=(K, V)>>(iter: T) -> HashMap<K, V, H> { +impl<K, V, S, H> FromIterator<(K, V)> for HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + fn from_iter<T: Iterator<Item=(K, V)>>(iter: T) -> HashMap<K, V, S> { let lower = iter.size_hint().0; - let mut map = HashMap::with_capacity_and_hasher(lower, Default::default()); + let mut map = HashMap::with_capacity_and_hash_state(lower, + Default::default()); map.extend(iter); map } } #[stable] -#[old_impl_check] -impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> Extend<(K, V)> for HashMap<K, V, H> { +impl<K, V, S, H> Extend<(K, V)> for HashMap<K, V, S> + where K: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ fn extend<T: Iterator<Item=(K, V)>>(&mut self, mut iter: T) { for (k, v) in iter { self.insert(k, v); @@ -1493,6 +1519,64 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> Extend<(K, V)> for HashMap<K, V, H> { } } + +/// `RandomState` is the default state for `HashMap` types. +/// +/// A particular instance `RandomState` will create the same instances of +/// `Hasher`, but the hashers created by two different `RandomState` +/// instances are unlikely to produce the same result for the same values. +#[derive(Clone)] +#[allow(missing_copy_implementations)] +#[unstable = "hashing an hash maps may be altered"] +pub struct RandomState { + k0: u64, + k1: u64, +} + +#[unstable = "hashing an hash maps may be altered"] +impl RandomState { + /// Construct a new `RandomState` that is initialized with random keys. + #[inline] + pub fn new() -> RandomState { + let mut r = rand::thread_rng(); + RandomState { k0: r.gen(), k1: r.gen() } + } +} + +#[unstable = "hashing an hash maps may be altered"] +impl HashState for RandomState { + type Hasher = Hasher; + fn hasher(&self) -> Hasher { + Hasher { inner: SipHasher::new_with_keys(self.k0, self.k1) } + } +} + +#[unstable = "hashing an hash maps may be altered"] +impl Default for RandomState { + #[inline] + fn default() -> RandomState { + RandomState::new() + } +} + +/// A hasher implementation which is generated from `RandomState` instances. +/// +/// This is the default hasher used in a `HashMap` to hash keys. Types do not +/// typically declare an ability to explicitly hash into this particular type, +/// but rather in a `H: hash::Writer` type parameter. +#[allow(missing_copy_implementations)] +pub struct Hasher { inner: SipHasher } + +impl hash::Writer for Hasher { + fn write(&mut self, data: &[u8]) { self.inner.write(data) } +} + +impl hash::Hasher for Hasher { + type Output = u64; + fn reset(&mut self) { self.inner.reset() } + fn finish(&self) -> u64 { self.inner.finish() } +} + #[cfg(test)] mod test_map { use prelude::v1::*; diff --git a/src/libstd/collections/hash/mod.rs b/src/libstd/collections/hash/mod.rs index ee3fc1e6ac3..47e300af269 100644 --- a/src/libstd/collections/hash/mod.rs +++ b/src/libstd/collections/hash/mod.rs @@ -11,6 +11,7 @@ //! Unordered containers, implemented as hash-tables mod bench; +mod table; pub mod map; pub mod set; -mod table; +pub mod state; diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index f66e5384942..4003d3addf1 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -17,12 +17,13 @@ use core::marker::Sized; use default::Default; use fmt::Show; use fmt; -use hash::{Hash, Hasher, RandomSipHasher}; +use hash::{self, Hash}; use iter::{Iterator, IteratorExt, FromIterator, Map, Chain, Extend}; use ops::{BitOr, BitAnd, BitXor, Sub}; use option::Option::{Some, None, self}; -use super::map::{self, HashMap, Keys, INITIAL_CAPACITY}; +use super::map::{self, HashMap, Keys, INITIAL_CAPACITY, RandomState, Hasher}; +use super::state::HashState; // Future Optimization (FIXME!) // ============================= @@ -90,11 +91,11 @@ use super::map::{self, HashMap, Keys, INITIAL_CAPACITY}; /// ``` #[derive(Clone)] #[stable] -pub struct HashSet<T, H = RandomSipHasher> { - map: HashMap<T, (), H> +pub struct HashSet<T, S = RandomState> { + map: HashMap<T, (), S> } -impl<T: Hash + Eq> HashSet<T, RandomSipHasher> { +impl<T: Hash<Hasher> + Eq> HashSet<T, RandomState> { /// Create an empty HashSet. /// /// # Example @@ -105,7 +106,7 @@ impl<T: Hash + Eq> HashSet<T, RandomSipHasher> { /// ``` #[inline] #[stable] - pub fn new() -> HashSet<T, RandomSipHasher> { + pub fn new() -> HashSet<T, RandomState> { HashSet::with_capacity(INITIAL_CAPACITY) } @@ -120,13 +121,16 @@ impl<T: Hash + Eq> HashSet<T, RandomSipHasher> { /// ``` #[inline] #[stable] - pub fn with_capacity(capacity: uint) -> HashSet<T, RandomSipHasher> { + pub fn with_capacity(capacity: uint) -> HashSet<T, RandomState> { HashSet { map: HashMap::with_capacity(capacity) } } } -#[old_impl_check] -impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { +impl<T, S, H> HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ /// Creates a new empty hash set which will use the given hasher to hash /// keys. /// @@ -136,16 +140,16 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// /// ``` /// use std::collections::HashSet; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_map::RandomState; /// - /// let h = SipHasher::new(); - /// let mut set = HashSet::with_hasher(h); + /// let s = RandomState::new(); + /// let mut set = HashSet::with_hash_state(s); /// set.insert(2u); /// ``` #[inline] #[unstable = "hasher stuff is unclear"] - pub fn with_hasher(hasher: H) -> HashSet<T, H> { - HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher) + pub fn with_hash_state(hash_state: S) -> HashSet<T, S> { + HashSet::with_capacity_and_hash_state(INITIAL_CAPACITY, hash_state) } /// Create an empty HashSet with space for at least `capacity` @@ -160,16 +164,19 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// /// ``` /// use std::collections::HashSet; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_map::RandomState; /// - /// let h = SipHasher::new(); - /// let mut set = HashSet::with_capacity_and_hasher(10u, h); + /// let s = RandomState::new(); + /// let mut set = HashSet::with_capacity_and_hash_state(10u, s); /// set.insert(1i); /// ``` #[inline] #[unstable = "hasher stuff is unclear"] - pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet<T, H> { - HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } + pub fn with_capacity_and_hash_state(capacity: uint, hash_state: S) + -> HashSet<T, S> { + HashSet { + map: HashMap::with_capacity_and_hash_state(capacity, hash_state), + } } /// Returns the number of elements the set can hold without reallocating. @@ -300,7 +307,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// assert_eq!(diff, [4i].iter().map(|&x| x).collect()); /// ``` #[stable] - pub fn difference<'a>(&'a self, other: &'a HashSet<T, H>) -> Difference<'a, T, H> { + pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> { Difference { iter: self.iter(), other: other, @@ -328,8 +335,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// assert_eq!(diff1, [1i, 4].iter().map(|&x| x).collect()); /// ``` #[stable] - pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, H>) - -> SymmetricDifference<'a, T, H> { + pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, S>) + -> SymmetricDifference<'a, T, S> { SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } } @@ -351,7 +358,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect()); /// ``` #[stable] - pub fn intersection<'a>(&'a self, other: &'a HashSet<T, H>) -> Intersection<'a, T, H> { + pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> { Intersection { iter: self.iter(), other: other, @@ -376,7 +383,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect()); /// ``` #[stable] - pub fn union<'a>(&'a self, other: &'a HashSet<T, H>) -> Union<'a, T, H> { + pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> { Union { iter: self.iter().chain(other.difference(self)) } } @@ -452,7 +459,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// ``` #[stable] pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool - where Q: BorrowFrom<T> + Hash<S> + Eq + where Q: BorrowFrom<T> + Hash<H> + Eq { self.map.contains_key(value) } @@ -475,7 +482,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// assert_eq!(a.is_disjoint(&b), false); /// ``` #[stable] - pub fn is_disjoint(&self, other: &HashSet<T, H>) -> bool { + pub fn is_disjoint(&self, other: &HashSet<T, S>) -> bool { self.iter().all(|v| !other.contains(v)) } @@ -496,7 +503,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// assert_eq!(set.is_subset(&sup), false); /// ``` #[stable] - pub fn is_subset(&self, other: &HashSet<T, H>) -> bool { + pub fn is_subset(&self, other: &HashSet<T, S>) -> bool { self.iter().all(|v| other.contains(v)) } @@ -521,7 +528,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// ``` #[inline] #[stable] - pub fn is_superset(&self, other: &HashSet<T, H>) -> bool { + pub fn is_superset(&self, other: &HashSet<T, S>) -> bool { other.is_subset(self) } @@ -562,16 +569,19 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// ``` #[stable] pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool - where Q: BorrowFrom<T> + Hash<S> + Eq + where Q: BorrowFrom<T> + Hash<H> + Eq { self.map.remove(value).is_some() } } #[stable] -#[old_impl_check] -impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> { - fn eq(&self, other: &HashSet<T, H>) -> bool { +impl<T, S, H> PartialEq for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ + fn eq(&self, other: &HashSet<T, S>) -> bool { if self.len() != other.len() { return false; } self.iter().all(|key| other.contains(key)) @@ -579,12 +589,18 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> { } #[stable] -#[old_impl_check] -impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {} +impl<T, S, H> Eq for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{} #[stable] -#[old_impl_check] -impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> { +impl<T, S, H> fmt::Show for HashSet<T, S> + where T: Eq + Hash<H> + fmt::Show, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "HashSet {{")); @@ -598,19 +614,25 @@ impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> { } #[stable] -#[old_impl_check] -impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> FromIterator<T> for HashSet<T, H> { - fn from_iter<I: Iterator<Item=T>>(iter: I) -> HashSet<T, H> { +impl<T, S, H> FromIterator<T> for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + fn from_iter<I: Iterator<Item=T>>(iter: I) -> HashSet<T, S> { let lower = iter.size_hint().0; - let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); + let mut set = HashSet::with_capacity_and_hash_state(lower, Default::default()); set.extend(iter); set } } #[stable] -#[old_impl_check] -impl<T: Eq + Hash<S>, S, H: Hasher<S>> Extend<T> for HashSet<T, H> { +impl<T, S, H> Extend<T> for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> +{ fn extend<I: Iterator<Item=T>>(&mut self, mut iter: I) { for k in iter { self.insert(k); @@ -619,21 +641,26 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> Extend<T> for HashSet<T, H> { } #[stable] -#[old_impl_check] -impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> { +impl<T, S, H> Default for HashSet<T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ #[stable] - fn default() -> HashSet<T, H> { - HashSet::with_hasher(Default::default()) + fn default() -> HashSet<T, S> { + HashSet::with_hash_state(Default::default()) } } #[stable] -#[old_impl_check] -impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default> -BitOr<&'b HashSet<T, H>> for &'a HashSet<T, H> { - type Output = HashSet<T, H>; +impl<'a, 'b, T, S, H> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash<H> + Clone, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + type Output = HashSet<T, S>; - /// Returns the union of `self` and `rhs` as a new `HashSet<T, H>`. + /// Returns the union of `self` and `rhs` as a new `HashSet<T, S>`. /// /// # Examples /// @@ -653,18 +680,20 @@ BitOr<&'b HashSet<T, H>> for &'a HashSet<T, H> { /// } /// assert_eq!(i, expected.len()); /// ``` - fn bitor(self, rhs: &HashSet<T, H>) -> HashSet<T, H> { + fn bitor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> { self.union(rhs).cloned().collect() } } #[stable] -#[old_impl_check] -impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default> -BitAnd<&'b HashSet<T, H>> for &'a HashSet<T, H> { - type Output = HashSet<T, H>; +impl<'a, 'b, T, S, H> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash<H> + Clone, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + type Output = HashSet<T, S>; - /// Returns the intersection of `self` and `rhs` as a new `HashSet<T, H>`. + /// Returns the intersection of `self` and `rhs` as a new `HashSet<T, S>`. /// /// # Examples /// @@ -684,18 +713,20 @@ BitAnd<&'b HashSet<T, H>> for &'a HashSet<T, H> { /// } /// assert_eq!(i, expected.len()); /// ``` - fn bitand(self, rhs: &HashSet<T, H>) -> HashSet<T, H> { + fn bitand(self, rhs: &HashSet<T, S>) -> HashSet<T, S> { self.intersection(rhs).cloned().collect() } } #[stable] -#[old_impl_check] -impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default> -BitXor<&'b HashSet<T, H>> for &'a HashSet<T, H> { - type Output = HashSet<T, H>; +impl<'a, 'b, T, S, H> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash<H> + Clone, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + type Output = HashSet<T, S>; - /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet<T, H>`. + /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet<T, S>`. /// /// # Examples /// @@ -715,18 +746,20 @@ BitXor<&'b HashSet<T, H>> for &'a HashSet<T, H> { /// } /// assert_eq!(i, expected.len()); /// ``` - fn bitxor(self, rhs: &HashSet<T, H>) -> HashSet<T, H> { + fn bitxor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> { self.symmetric_difference(rhs).cloned().collect() } } #[stable] -#[old_impl_check] -impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default> -Sub<&'b HashSet<T, H>> for &'a HashSet<T, H> { - type Output = HashSet<T, H>; +impl<'a, 'b, T, S, H> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S> + where T: Eq + Hash<H> + Clone, + S: HashState<Hasher=H> + Default, + H: hash::Hasher<Output=u64> +{ + type Output = HashSet<T, S>; - /// Returns the difference of `self` and `rhs` as a new `HashSet<T, H>`. + /// Returns the difference of `self` and `rhs` as a new `HashSet<T, S>`. /// /// # Examples /// @@ -746,7 +779,7 @@ Sub<&'b HashSet<T, H>> for &'a HashSet<T, H> { /// } /// assert_eq!(i, expected.len()); /// ``` - fn sub(self, rhs: &HashSet<T, H>) -> HashSet<T, H> { + fn sub(self, rhs: &HashSet<T, S>) -> HashSet<T, S> { self.difference(rhs).cloned().collect() } } @@ -771,32 +804,32 @@ pub struct Drain<'a, K: 'a> { /// Intersection iterator #[stable] -pub struct Intersection<'a, T: 'a, H: 'a> { +pub struct Intersection<'a, T: 'a, S: 'a> { // iterator of the first set iter: Iter<'a, T>, // the second set - other: &'a HashSet<T, H>, + other: &'a HashSet<T, S>, } /// Difference iterator #[stable] -pub struct Difference<'a, T: 'a, H: 'a> { +pub struct Difference<'a, T: 'a, S: 'a> { // iterator of the first set iter: Iter<'a, T>, // the second set - other: &'a HashSet<T, H>, + other: &'a HashSet<T, S>, } /// Symmetric difference iterator. #[stable] -pub struct SymmetricDifference<'a, T: 'a, H: 'a> { - iter: Chain<Difference<'a, T, H>, Difference<'a, T, H>> +pub struct SymmetricDifference<'a, T: 'a, S: 'a> { + iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>> } /// Set union iterator. #[stable] -pub struct Union<'a, T: 'a, H: 'a> { - iter: Chain<Iter<'a, T>, Difference<'a, T, H>> +pub struct Union<'a, T: 'a, S: 'a> { + iter: Chain<Iter<'a, T>, Difference<'a, T, S>> } #[stable] @@ -824,9 +857,10 @@ impl<'a, K: 'a> Iterator for Drain<'a, K> { } #[stable] -#[old_impl_check] -impl<'a, T, S, H> Iterator for Intersection<'a, T, H> - where T: Eq + Hash<S>, H: Hasher<S> +impl<'a, T, S, H> Iterator for Intersection<'a, T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> { type Item = &'a T; @@ -848,9 +882,10 @@ impl<'a, T, S, H> Iterator for Intersection<'a, T, H> } #[stable] -#[old_impl_check] -impl<'a, T, S, H> Iterator for Difference<'a, T, H> - where T: Eq + Hash<S>, H: Hasher<S> +impl<'a, T, S, H> Iterator for Difference<'a, T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> { type Item = &'a T; @@ -872,9 +907,10 @@ impl<'a, T, S, H> Iterator for Difference<'a, T, H> } #[stable] -#[old_impl_check] -impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, H> - where T: Eq + Hash<S>, H: Hasher<S> +impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> { type Item = &'a T; @@ -883,9 +919,10 @@ impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, H> } #[stable] -#[old_impl_check] -impl<'a, T, S, H> Iterator for Union<'a, T, H> - where T: Eq + Hash<S>, H: Hasher<S> +impl<'a, T, S, H> Iterator for Union<'a, T, S> + where T: Eq + Hash<H>, + S: HashState<Hasher=H>, + H: hash::Hasher<Output=u64> { type Item = &'a T; diff --git a/src/libstd/collections/hash/state.rs b/src/libstd/collections/hash/state.rs new file mode 100644 index 00000000000..ffbc958f179 --- /dev/null +++ b/src/libstd/collections/hash/state.rs @@ -0,0 +1,51 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use clone::Clone; +use default::Default; +use hash; + +/// A trait representing stateful hashes which can be used to hash keys in a +/// `HashMap`. +/// +/// A HashState is used as a factory for instances of `Hasher` which a `HashMap` +/// can then use to hash keys independently. A `HashMap` by default uses a state +/// which will create instances of a `SipHasher`, but a custom state factory can +/// be provided to the `with_hash_state` function. +/// +/// If a hashing algorithm has no initial state, then the `Hasher` type for that +/// algorithm can implement the `Default` trait and create hash maps with the +/// `DefaultState` structure. This state is 0-sized and will simply delegate +/// to `Default` when asked to create a hasher. +pub trait HashState { + type Hasher: hash::Hasher; + + /// Creates a new hasher based on the given state of this object. + fn hasher(&self) -> Self::Hasher; +} + +/// A structure which is a factory for instances of `Hasher` which implement the +/// default trait. +/// +/// This struct has is 0-sized and does not need construction. +pub struct DefaultState<H>; + +impl<H: Default + hash::Hasher> HashState for DefaultState<H> { + type Hasher = H; + fn hasher(&self) -> H { Default::default() } +} + +impl<H> Clone for DefaultState<H> { + fn clone(&self) -> DefaultState<H> { DefaultState } +} + +impl<H> Default for DefaultState<H> { + fn default() -> DefaultState<H> { DefaultState } +} diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 6eb98da4da4..e43cc053ba0 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -26,6 +26,7 @@ use option::Option::{Some, None}; use ptr::{Unique, PtrExt, copy_nonoverlapping_memory, zero_memory}; use ptr; use rt::heap::{allocate, deallocate}; +use collections::hash_state::HashState; const EMPTY_BUCKET: u64 = 0u64; @@ -138,12 +139,18 @@ impl SafeHash { /// We need to remove hashes of 0. That's reserved for empty buckets. /// This function wraps up `hash_keyed` to be the only way outside this /// module to generate a SafeHash. -pub fn make_hash<T: ?Sized + Hash<S>, S, H: Hasher<S>>(hasher: &H, t: &T) -> SafeHash { +pub fn make_hash<T: ?Sized, S, H>(hash_state: &S, t: &T) -> SafeHash + where T: Hash<H>, + S: HashState<Hasher=H>, + H: Hasher<Output=u64> +{ + let mut state = hash_state.hasher(); + t.hash(&mut state); // We need to avoid 0u64 in order to prevent collisions with // EMPTY_HASH. We can maintain our precious uniform distribution // of initial indexes by unconditionally setting the MSB, // effectively reducing 64-bits hashes to 63 bits. - SafeHash { hash: 0x8000_0000_0000_0000 | hasher.hash(t) } + SafeHash { hash: 0x8000_0000_0000_0000 | state.finish() } } // `replace` casts a `*u64` to a `*SafeHash`. Since we statically diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 9b2a4926bcb..71ab89027ff 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -333,3 +333,10 @@ pub mod hash_set { //! A hashset pub use super::hash::set::*; } + +/// Experimental support for providing custom hash algorithms to a HashMap and +/// HashSet. +#[unstable = "module was recently added"] +pub mod hash_state { + pub use super::hash::state::*; +} diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs deleted file mode 100644 index 69e7e429d07..00000000000 --- a/src/libstd/hash.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Generic hashing support. -//! -//! This module provides a generic way to compute the hash of a value. The -//! simplest way to make a type hashable is to use `#[derive(Hash)]`: -//! -//! # Example -//! -//! ```rust -//! use std::hash; -//! use std::hash::Hash; -//! -//! #[derive(Hash)] -//! struct Person { -//! id: uint, -//! name: String, -//! phone: u64, -//! } -//! -//! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; -//! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; -//! -//! assert!(hash::hash(&person1) != hash::hash(&person2)); -//! ``` -//! -//! If you need more control over how a value is hashed, you need to implement -//! the trait `Hash`: -//! -//! ```rust -//! use std::hash; -//! use std::hash::Hash; -//! use std::hash::sip::SipState; -//! -//! struct Person { -//! id: uint, -//! name: String, -//! phone: u64, -//! } -//! -//! impl Hash for Person { -//! fn hash(&self, state: &mut SipState) { -//! self.id.hash(state); -//! self.phone.hash(state); -//! } -//! } -//! -//! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; -//! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; -//! -//! assert!(hash::hash(&person1) == hash::hash(&person2)); -//! ``` - -#![experimental] - -pub use core::hash::{Hash, Hasher, Writer, hash, sip}; - -use core::marker::Sized; -use default::Default; -use rand::Rng; -use rand; - -/// `RandomSipHasher` computes the SipHash algorithm from a stream of bytes -/// initialized with random keys. -#[derive(Clone)] -pub struct RandomSipHasher { - hasher: sip::SipHasher, -} - -impl RandomSipHasher { - /// Construct a new `RandomSipHasher` that is initialized with random keys. - #[inline] - pub fn new() -> RandomSipHasher { - let mut r = rand::thread_rng(); - let r0 = r.gen(); - let r1 = r.gen(); - RandomSipHasher { - hasher: sip::SipHasher::new_with_keys(r0, r1), - } - } -} - -impl Hasher<sip::SipState> for RandomSipHasher { - #[inline] - fn hash<T: ?Sized + Hash<sip::SipState>>(&self, value: &T) -> u64 { - self.hasher.hash(value) - } -} - -#[stable] -impl Default for RandomSipHasher { - #[stable] - #[inline] - fn default() -> RandomSipHasher { - RandomSipHasher::new() - } -} diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 879f1192a4a..f824d821601 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -34,7 +34,7 @@ use sys::process::Process as ProcessImp; use sys; use thread::Thread; -#[cfg(windows)] use std::hash::sip::SipState; +#[cfg(windows)] use hash; #[cfg(windows)] use str; /// Signal a process to exit, without forcibly killing it. Corresponds to @@ -98,7 +98,7 @@ pub struct Process { /// A representation of environment variable name /// It compares case-insensitive on Windows and case-sensitive everywhere else. #[cfg(not(windows))] -#[derive(PartialEq, Eq, Hash, Clone, Show)] +#[derive(Hash, PartialEq, Eq, Clone, Show)] struct EnvKey(CString); #[doc(hidden)] @@ -107,8 +107,8 @@ struct EnvKey(CString); struct EnvKey(CString); #[cfg(windows)] -impl Hash for EnvKey { - fn hash(&self, state: &mut SipState) { +impl<H: hash::Writer + hash::Hasher> hash::Hash<H> for EnvKey { + fn hash(&self, state: &mut H) { let &EnvKey(ref x) = self; match str::from_utf8(x.as_bytes()) { Ok(s) => for ch in s.chars() { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fa8cc6f4a18..c2daa08d4d3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -96,6 +96,7 @@ #![crate_name = "std"] #![stable] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", @@ -149,6 +150,7 @@ pub use core::clone; #[cfg(not(test))] pub use core::cmp; pub use core::default; pub use core::finally; +pub use core::hash; pub use core::intrinsics; pub use core::iter; #[cfg(not(test))] pub use core::marker; @@ -242,7 +244,6 @@ pub mod time; /* Common data structures */ pub mod collections; -pub mod hash; /* Threads and communication */ @@ -274,6 +275,7 @@ mod std { pub use clone; pub use cmp; pub use hash; + pub use default; pub use sync; // used for select!() pub use error; // used for try!() diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index f433cd1e664..9c6911cf4d1 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -424,12 +424,14 @@ mod tests { assert_eq!(int::MIN.to_u32(), None); assert_eq!(int::MIN.to_u64(), None); - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), + all(not(stage0), target_pointer_width = "32")))] fn check_word_size() { assert_eq!(int::MIN.to_i32(), Some(int::MIN as i32)); } - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), + all(not(stage0), target_pointer_width = "64")))] fn check_word_size() { assert_eq!(int::MIN.to_i32(), None); } @@ -492,12 +494,14 @@ mod tests { assert_eq!(i64::MIN.to_u32(), None); assert_eq!(i64::MIN.to_u64(), None); - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), + all(not(stage0), target_pointer_width = "32")))] fn check_word_size() { assert_eq!(i64::MIN.to_int(), None); } - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), + all(not(stage0), target_pointer_width = "64")))] fn check_word_size() { assert_eq!(i64::MIN.to_int(), Some(i64::MIN as int)); } @@ -517,13 +521,15 @@ mod tests { // int::MAX.to_u32() is word-size specific assert_eq!(int::MAX.to_u64(), Some(int::MAX as u64)); - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), + all(not(stage0), target_pointer_width = "32")))] fn check_word_size() { assert_eq!(int::MAX.to_i32(), Some(int::MAX as i32)); assert_eq!(int::MAX.to_u32(), Some(int::MAX as u32)); } - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), + all(not(stage0), target_pointer_width = "64")))] fn check_word_size() { assert_eq!(int::MAX.to_i32(), None); assert_eq!(int::MAX.to_u32(), None); @@ -587,13 +593,15 @@ mod tests { assert_eq!(i64::MAX.to_u32(), None); assert_eq!(i64::MAX.to_u64(), Some(i64::MAX as u64)); - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), + all(not(stage0), target_pointer_width = "32")))] fn check_word_size() { assert_eq!(i64::MAX.to_int(), None); assert_eq!(i64::MAX.to_uint(), None); } - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), + all(not(stage0), target_pointer_width = "64")))] fn check_word_size() { assert_eq!(i64::MAX.to_int(), Some(i64::MAX as int)); assert_eq!(i64::MAX.to_uint(), Some(i64::MAX as uint)); @@ -684,13 +692,15 @@ mod tests { // uint::MAX.to_u32() is word-size specific assert_eq!(uint::MAX.to_u64(), Some(uint::MAX as u64)); - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), + all(not(stage0), target_pointer_width = "32")))] fn check_word_size() { assert_eq!(uint::MAX.to_u32(), Some(uint::MAX as u32)); assert_eq!(uint::MAX.to_i64(), Some(uint::MAX as i64)); } - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), + all(not(stage0), target_pointer_width = "64")))] fn check_word_size() { assert_eq!(uint::MAX.to_u32(), None); assert_eq!(uint::MAX.to_i64(), None); @@ -740,12 +750,14 @@ mod tests { assert_eq!(u32::MAX.to_u32(), Some(u32::MAX as u32)); assert_eq!(u32::MAX.to_u64(), Some(u32::MAX as u64)); - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), + all(not(stage0), target_pointer_width = "32")))] fn check_word_size() { assert_eq!(u32::MAX.to_int(), None); } - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), + all(not(stage0), target_pointer_width = "64")))] fn check_word_size() { assert_eq!(u32::MAX.to_int(), Some(u32::MAX as int)); } @@ -766,12 +778,14 @@ mod tests { assert_eq!(u64::MAX.to_u32(), None); assert_eq!(u64::MAX.to_u64(), Some(u64::MAX as u64)); - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), + all(not(stage0), target_pointer_width = "32")))] fn check_word_size() { assert_eq!(u64::MAX.to_uint(), None); } - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), + all(not(stage0), target_pointer_width = "64")))] fn check_word_size() { assert_eq!(u64::MAX.to_uint(), Some(u64::MAX as uint)); } diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index 0b7dc19fcab..b13278205b4 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -91,7 +91,7 @@ impl FromStr for Path { } } -impl<S: hash::Writer> hash::Hash<S> for Path { +impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path { #[inline] fn hash(&self, state: &mut S) { self.repr.hash(state) diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 5c4e7aa9ac2..0a43c7b5140 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -118,7 +118,7 @@ impl FromStr for Path { } } -impl<S: hash::Writer> hash::Hash<S> for Path { +impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path { #[cfg(not(test))] #[inline] fn hash(&self, state: &mut S) { diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index d3e6cd166ec..91e3b4a0687 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -230,9 +230,9 @@ use rc::Rc; use result::Result::{Ok, Err}; use vec::Vec; -#[cfg(not(target_word_size="64"))] +#[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] use core_rand::IsaacRng as IsaacWordRng; -#[cfg(target_word_size="64")] +#[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] use core_rand::Isaac64Rng as IsaacWordRng; pub use core_rand::{Rand, Rng, SeedableRng, Open01, Closed01}; diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs index be44aa99f49..f6161ec193d 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys/common/backtrace.rs @@ -12,8 +12,11 @@ use prelude::v1::*; use io::IoResult; -#[cfg(target_word_size = "64")] pub const HEX_WIDTH: uint = 18; -#[cfg(target_word_size = "32")] pub const HEX_WIDTH: uint = 10; +#[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] +pub const HEX_WIDTH: uint = 18; + +#[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] +pub const HEX_WIDTH: uint = 10; // All rust symbols are in theory lists of "::"-separated identifiers. Some // assemblers, however, can't handle these characters in symbol names. To get diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index cc661877bc0..1d523ed6edd 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -169,13 +169,13 @@ mod signal { unsafe impl ::marker::Sync for sigaction { } #[repr(C)] - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] pub struct sigset_t { __val: [libc::c_ulong; 32], } #[repr(C)] - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] pub struct sigset_t { __val: [libc::c_ulong; 16], } diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 1357bbdd5a3..36bf696dba5 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -11,7 +11,8 @@ use prelude::v1::*; use self::Req::*; -use collections; +use collections::HashMap; +use collections::hash_map::Hasher; use ffi::CString; use hash::Hash; use io::process::{ProcessExit, ExitStatus, ExitSignal}; @@ -60,7 +61,7 @@ impl Process { out_fd: Option<P>, err_fd: Option<P>) -> IoResult<Process> where C: ProcessConfig<K, V>, P: AsInner<FileDesc>, - K: BytesContainer + Eq + Hash, V: BytesContainer + K: BytesContainer + Eq + Hash<Hasher>, V: BytesContainer { use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; use libc::funcs::bsd44::getdtablesize; @@ -553,11 +554,11 @@ fn with_argv<T,F>(prog: &CString, args: &[CString], cb(ptrs.as_ptr()) } -fn with_envp<K,V,T,F>(env: Option<&collections::HashMap<K, V>>, +fn with_envp<K,V,T,F>(env: Option<&HashMap<K, V>>, cb: F) -> T where F : FnOnce(*const c_void) -> T, - K : BytesContainer + Eq + Hash, + K : BytesContainer + Eq + Hash<Hasher>, V : BytesContainer { // On posixy systems we can pass a char** for envp, which is a diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 1fd619a28db..48a51813ba4 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -182,12 +182,14 @@ mod imp { sa_restorer: *mut libc::c_void, } - #[cfg(target_word_size = "32")] + #[cfg(any(all(stage0, target_word_size = "32"), + all(not(stage0), target_pointer_width = "32")))] #[repr(C)] pub struct sigset_t { __val: [libc::c_ulong; 32], } - #[cfg(target_word_size = "64")] + #[cfg(any(all(stage0, target_word_size = "64"), + all(not(stage0), target_pointer_width = "64")))] #[repr(C)] pub struct sigset_t { __val: [libc::c_ulong; 16], diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 8e1f169b5cd..1b837385d1e 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -13,6 +13,7 @@ use prelude::v1::*; use collections; use ffi::CString; use hash::Hash; +use collections::hash_map::Hasher; use io::fs::PathExtensions; use io::process::{ProcessExit, ExitStatus, ExitSignal}; use io::{IoResult, IoError}; @@ -109,7 +110,7 @@ impl Process { out_fd: Option<P>, err_fd: Option<P>) -> IoResult<Process> where C: ProcessConfig<K, V>, P: AsInner<FileDesc>, - K: BytesContainer + Eq + Hash, V: BytesContainer + K: BytesContainer + Eq + Hash<Hasher>, V: BytesContainer { use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; use libc::consts::os::extra::{ @@ -424,8 +425,10 @@ fn make_command_line(prog: &CString, args: &[CString]) -> String { } } -fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T where - K: BytesContainer + Eq + Hash, V: BytesContainer, F: FnOnce(*mut c_void) -> T, +fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T + where K: BytesContainer + Eq + Hash<Hasher>, + V: BytesContainer, + F: FnOnce(*mut c_void) -> T, { // On Windows we pass an "environment block" which is not a char**, but // rather a concatenation of null-terminated k=v\0 sequences, with a final diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 31fe23847d9..e4460ca865b 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -590,7 +590,12 @@ impl CodeMap { Some(ref info) => { // save the parent expn_id for next loop iteration expnid = info.call_site.expn_id; - if info.callee.span.is_none() { + if info.callee.name == "format_args" { + // This is a hack because the format_args builtin calls unstable APIs. + // I spent like 6 hours trying to solve this more generally but am stupid. + is_internal = true; + false + } else if info.callee.span.is_none() { // it's a compiler built-in, we *really* don't want to mess with it // so we skip it, unless it was called by a regular macro, in which case // we will handle the caller macro next turn diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index 844bd80d161..db99c142443 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -30,7 +30,8 @@ pub fn expand_deriving_hash<F>(cx: &mut ExtCtxt, let generics = LifetimeBounds { lifetimes: Vec::new(), bounds: vec!(("__S", - vec!(Path::new(vec!("std", "hash", "Writer"))))), + vec!(Path::new(vec!("std", "hash", "Writer")), + Path::new(vec!("std", "hash", "Hasher"))))), }; let args = Path::new_local("__S"); let inline = cx.meta_word(span, InternedString::new("inline")); diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9e14f9dd1ea..7c8ccf3a1a1 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -16,6 +16,7 @@ #![crate_name = "syntax"] #![experimental] +#![staged_api] #![crate_type = "dylib"] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 8abb46011e6..13a14d069d7 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -37,9 +37,11 @@ //! Moreover, a switch to, e.g. `P<'a, T>` would be easy and mostly automated. use std::fmt::{self, Show}; -use std::hash::Hash; +use std::hash::{Hash, Hasher}; +#[cfg(stage0)] use std::hash::Writer; use std::ops::Deref; use std::ptr; + use serialize::{Encodable, Decodable, Encoder, Decoder}; /// An owned smart pointer. @@ -105,7 +107,14 @@ impl<T: Show> Show for P<T> { } } -impl<S, T: Hash<S>> Hash<S> for P<T> { +#[cfg(stage0)] +impl<S: Writer, T: Hash<S>> Hash<S> for P<T> { + fn hash(&self, state: &mut S) { + (**self).hash(state); + } +} +#[cfg(not(stage0))] +impl<S: Hasher, T: Hash<S>> Hash<S> for P<T> { fn hash(&self, state: &mut S) { (**self).hash(state); } diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index daa51203287..8e1a5860259 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -48,7 +48,7 @@ fn no_prelude(attrs: &[ast::Attribute]) -> bool { } struct StandardLibraryInjector<'a> { - alt_std_name: Option<String>, + alt_std_name: Option<String> } impl<'a> fold::Folder for StandardLibraryInjector<'a> { @@ -84,14 +84,13 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> { fn inject_crates_ref(krate: ast::Crate, alt_std_name: Option<String>) -> ast::Crate { let mut fold = StandardLibraryInjector { - alt_std_name: alt_std_name, + alt_std_name: alt_std_name }; fold.fold_crate(krate) } struct PreludeInjector<'a>; - impl<'a> fold::Folder for PreludeInjector<'a> { fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { // Add #![no_std] here, so we don't re-inject when compiling pretty-printed source. @@ -104,20 +103,10 @@ impl<'a> fold::Folder for PreludeInjector<'a> { attr::mark_used(&no_std_attr); krate.attrs.push(no_std_attr); + // only add `use std::prelude::*;` if there wasn't a + // `#![no_implicit_prelude]` at the crate level. + // fold_mod() will insert glob path. if !no_prelude(krate.attrs.index(&FullRange)) { - // only add `use std::prelude::*;` if there wasn't a - // `#![no_implicit_prelude]` at the crate level. - // fold_mod() will insert glob path. - let globs_attr = attr::mk_attr_inner(attr::mk_attr_id(), - attr::mk_list_item( - InternedString::new("feature"), - vec!( - attr::mk_word_item(InternedString::new("globs")), - ))); - // std_inject runs after feature checking so manually mark this attr - attr::mark_used(&globs_attr); - krate.attrs.push(globs_attr); - krate.module = self.fold_mod(krate.module); } krate diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 93de342d487..7058fa64811 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -20,6 +20,7 @@ use std::cmp::Ordering; use std::collections::HashMap; use std::fmt; use std::hash::Hash; +use std::collections::hash_map::Hasher; use std::ops::Deref; use std::rc::Rc; @@ -28,8 +29,8 @@ pub struct Interner<T> { vect: RefCell<Vec<T> >, } -// when traits can extend traits, we should extend index<Name,T> to get .index(&FullRange) -impl<T: Eq + Hash + Clone + 'static> Interner<T> { +// when traits can extend traits, we should extend index<Name,T> to get [] +impl<T: Eq + Hash<Hasher> + Clone + 'static> Interner<T> { pub fn new() -> Interner<T> { Interner { map: RefCell::new(HashMap::new()), @@ -78,7 +79,7 @@ impl<T: Eq + Hash + Clone + 'static> Interner<T> { } pub fn find<Q: ?Sized>(&self, val: &Q) -> Option<Name> - where Q: BorrowFrom<T> + Eq + Hash { + where Q: BorrowFrom<T> + Eq + Hash<Hasher> { let map = self.map.borrow(); match (*map).get(val) { Some(v) => Some(*v), @@ -203,7 +204,7 @@ impl StrInterner { } pub fn find<Q: ?Sized>(&self, val: &Q) -> Option<Name> - where Q: BorrowFrom<RcStr> + Eq + Hash { + where Q: BorrowFrom<RcStr> + Eq + Hash<Hasher> { match (*self.map.borrow()).get(val) { Some(v) => Some(*v), None => None, diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index c953f591d80..44ae00d997c 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -40,6 +40,7 @@ #![crate_name = "term"] #![experimental = "use the crates.io `term` library instead"] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 68d06cc4dab..d21a73de6df 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -25,6 +25,7 @@ #![crate_name = "test"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 1abb52459e4..6061c4fd1d3 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::collections::hash_map; +use std::collections::hash_map::{self, Hasher}; use std::fmt; use std::hash::Hash; use std::io; @@ -440,7 +440,7 @@ pub fn write_boxplot<W: Writer, T: Float + fmt::String + fmt::Show + FromPrimiti /// Returns a HashMap with the number of occurrences of every element in the /// sequence that the iterator exposes. pub fn freq_count<T, U>(mut iter: T) -> hash_map::HashMap<U, uint> - where T: Iterator<Item=U>, U: Eq + Clone + Hash + where T: Iterator<Item=U>, U: Eq + Clone + Hash<Hasher> { let mut map: hash_map::HashMap<U,uint> = hash_map::HashMap::new(); for elem in iter { diff --git a/src/libunicode/lib.rs b/src/libunicode/lib.rs index db98b429e40..33b5bc4b5a4 100644 --- a/src/libunicode/lib.rs +++ b/src/libunicode/lib.rs @@ -22,6 +22,7 @@ #![crate_name = "unicode"] #![experimental] +#![staged_api] #![crate_type = "rlib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 1dcac9fe074..edeb07c960e 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -18,6 +18,7 @@ extern crate rand; use std::collections::BTreeSet; use std::collections::BitvSet; use std::collections::HashSet; +use std::collections::hash_map::Hasher; use std::hash::Hash; use std::os; use std::time::Duration; @@ -43,7 +44,7 @@ trait MutableSet<T> { fn contains(&self, k: &T) -> bool; } -impl<T: Hash + Eq> MutableSet<T> for HashSet<T> { +impl<T: Hash<Hasher> + Eq> MutableSet<T> for HashSet<T> { fn insert(&mut self, k: T) { self.insert(k); } fn remove(&mut self, k: &T) -> bool { self.remove(k) } fn contains(&self, k: &T) -> bool { self.contains(k) } diff --git a/src/test/compile-fail/associated-types-multiple-types-one-trait.rs b/src/test/compile-fail/associated-types-multiple-types-one-trait.rs new file mode 100644 index 00000000000..9436f825de8 --- /dev/null +++ b/src/test/compile-fail/associated-types-multiple-types-one-trait.rs @@ -0,0 +1,56 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + type X; + type Y; +} + +fn have_x_want_x<T:Foo<X=u32>>(t: &T) +{ + want_x(t); +} + +fn have_x_want_y<T:Foo<X=u32>>(t: &T) +{ + want_y(t); //~ ERROR type mismatch +} + +fn have_y_want_x<T:Foo<Y=i32>>(t: &T) +{ + want_x(t); //~ ERROR type mismatch +} + +fn have_y_want_y<T:Foo<Y=i32>>(t: &T) +{ + want_y(t); +} + +fn have_xy_want_x<T:Foo<X=u32,Y=i32>>(t: &T) +{ + want_x(t); +} + +fn have_xy_want_y<T:Foo<X=u32,Y=i32>>(t: &T) +{ + want_y(t); +} + +fn have_xy_want_xy<T:Foo<X=u32,Y=i32>>(t: &T) +{ + want_x(t); + want_y(t); +} + +fn want_x<T:Foo<X=u32>>(t: &T) { } + +fn want_y<T:Foo<Y=i32>>(t: &T) { } + +fn main() { } diff --git a/src/test/compile-fail/extern-with-type-bounds.rs b/src/test/compile-fail/extern-with-type-bounds.rs new file mode 100644 index 00000000000..8c7d00a9a11 --- /dev/null +++ b/src/test/compile-fail/extern-with-type-bounds.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(intrinsics)] + +use std::intrinsics::TypeId; + +extern "rust-intrinsic" { + // Real example from libcore + fn type_id<T: ?Sized + 'static>() -> TypeId; + + // Silent bounds made explicit to make sure they are actually + // resolved. + fn transmute<T: Sized, U: Sized>(val: T) -> U; + + // Bounds aren't checked right now, so this should work + // even though it's incorrect. + fn size_of<T: Clone>() -> uint; + + // Unresolved bounds should still error. + fn align_of<T: NoSuchTrait>() -> uint; + //~^ ERROR attempt to bound type parameter with a nonexistent trait `NoSuchTrait` +} + +fn main() {} + diff --git a/src/test/compile-fail/feature-gate-feature-gate.rs b/src/test/compile-fail/feature-gate-feature-gate.rs new file mode 100644 index 00000000000..b903b29658b --- /dev/null +++ b/src/test/compile-fail/feature-gate-feature-gate.rs @@ -0,0 +1,14 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![forbid(unstable_features)] +#![feature(intrinsics)] //~ ERROR unstable feature + +fn main() { } diff --git a/src/test/compile-fail/feature-gated-feature-in-macro-arg.rs b/src/test/compile-fail/feature-gated-feature-in-macro-arg.rs index cd49c7c016e..1e15e67876e 100644 --- a/src/test/compile-fail/feature-gated-feature-in-macro-arg.rs +++ b/src/test/compile-fail/feature-gated-feature-in-macro-arg.rs @@ -8,6 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME #20661: format_args! emits calls to the unstable std::fmt::rt +// module, so the compiler has some hacks to make that possible +// (in span_is_internal). Unnfortunately those hacks defeat this +// particular scenario of checking feature gates in arguments to +// println!(). + +// ignore-test + // tests that input to a macro is checked for use of gated features. If this // test succeeds due to the acceptance of a feature, pick a new feature to // test. Not ideal, but oh well :( diff --git a/src/test/compile-fail/huge-enum.rs b/src/test/compile-fail/huge-enum.rs index 7c7a75abf3f..aef1fa85e0d 100644 --- a/src/test/compile-fail/huge-enum.rs +++ b/src/test/compile-fail/huge-enum.rs @@ -12,12 +12,12 @@ // FIXME: work properly with higher limits -#[cfg(target_word_size = "32")] +#[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] fn main() { let big: Option<[u32; (1<<29)-1]> = None; } -#[cfg(target_word_size = "64")] +#[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] fn main() { let big: Option<[u32; (1<<45)-1]> = None; } diff --git a/src/test/compile-fail/issue-17913.rs b/src/test/compile-fail/issue-17913.rs index 3224edb381c..7ae8dfef9bc 100644 --- a/src/test/compile-fail/issue-17913.rs +++ b/src/test/compile-fail/issue-17913.rs @@ -10,14 +10,14 @@ // error-pattern: too big for the current architecture -#[cfg(target_word_size = "64")] +#[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] fn main() { let n = 0u; let a = box [&n; 0xF000000000000000u]; println!("{}", a[0xFFFFFFu]); } -#[cfg(target_word_size = "32")] +#[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] fn main() { let n = 0u; let a = box [&n; 0xFFFFFFFFu]; diff --git a/src/test/compile-fail/where-clauses-not-parameter.rs b/src/test/compile-fail/where-clauses-not-parameter.rs index 148473f8987..d8af859c081 100644 --- a/src/test/compile-fail/where-clauses-not-parameter.rs +++ b/src/test/compile-fail/where-clauses-not-parameter.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn equal<T>(_: &T, _: &T) -> bool where int : Eq { +fn equal<T>(_: &T, _: &T) -> bool where isize : Eq { true //~^ ERROR cannot bound type `isize`, where clause bounds may only be attached } @@ -16,24 +16,26 @@ fn equal<T>(_: &T, _: &T) -> bool where int : Eq { fn test<T: Eq>() -> bool where Option<T> : Eq {} // This should be rejected as well. -fn test2() -> bool where Option<int> : Eq {} -//~^ ERROR cannot bound type `core::option::Option<isize>`, where clause bounds +fn test2() -> bool where Option<isize> : Eq {} +//~^ ERROR cannot bound type `core::option::Option<isize>`, where clause bounds may #[derive(PartialEq)] //~^ ERROR cannot bound type `isize`, where clause bounds -enum Foo<T> where int : Eq { MkFoo } +enum Foo<T> where isize : Eq { MkFoo } //~^ ERROR cannot bound type `isize`, where clause bounds fn test3<T: Eq>() -> bool where Option<Foo<T>> : Eq {} -fn test4() -> bool where Option<Foo<int>> : Eq {} +fn test4() -> bool where Option<Foo<isize>> : Eq {} //~^ ERROR cannot bound type `core::option::Option<Foo<isize>>`, where clause bounds -trait Baz<T> where int : Eq { - fn baz() where String : Eq; +trait Baz<T> where isize : Eq { + //~^ ERROR cannot bound type `isize`, where clause bounds may only + fn baz() where String : Eq; //~ ERROR cannot bound type `collections::string::String` + //~^ ERROR cannot bound type `isize`, where clause } -impl Baz<int> for int where int : Eq { +impl Baz<int> for int where isize : Eq { //~^ ERROR cannot bound type `isize`, where clause bounds fn baz() where String : Eq {} } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index f20087ef677..dac6e628d10 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -1,5 +1,4 @@ #![no_std] -#![feature(globs)] #[macro_use] extern crate "std" as std; #[prelude_import] diff --git a/src/test/run-pass/deriving-hash.rs b/src/test/run-pass/deriving-hash.rs index ddad703d7df..02ab7e5db5b 100644 --- a/src/test/run-pass/deriving-hash.rs +++ b/src/test/run-pass/deriving-hash.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -use std::hash; -use std::hash::Hash; +use std::hash::{Hash, SipHasher}; #[derive(Hash)] struct Person { @@ -19,6 +17,10 @@ struct Person { phone: uint, } +fn hash<T: Hash<SipHasher>>(t: &T) -> u64 { + std::hash::hash::<T, SipHasher>(t) +} + fn main() { let person1 = Person { id: 5, @@ -30,6 +32,6 @@ fn main() { name: "Bob".to_string(), phone: 555_666_7777 }; - assert!(hash::hash(&person1) == hash::hash(&person1)); - assert!(hash::hash(&person1) != hash::hash(&person2)); + assert!(hash(&person1) == hash(&person1)); + assert!(hash(&person1) != hash(&person2)); } diff --git a/src/test/run-pass/deriving-meta-multiple.rs b/src/test/run-pass/deriving-meta-multiple.rs index c435a1f344d..f45dce9da63 100644 --- a/src/test/run-pass/deriving-meta-multiple.rs +++ b/src/test/run-pass/deriving-meta-multiple.rs @@ -9,7 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::hash::hash; +use std::hash::{Hash, SipHasher}; // testing multiple separate deriving attributes #[derive(PartialEq)] @@ -20,6 +20,8 @@ struct Foo { baz: int } +fn hash<T: Hash<SipHasher>>(_t: &T) {} + pub fn main() { let a = Foo {bar: 4, baz: -3}; diff --git a/src/test/run-pass/deriving-meta.rs b/src/test/run-pass/deriving-meta.rs index 54dc2b97b77..d6a2fad08ed 100644 --- a/src/test/run-pass/deriving-meta.rs +++ b/src/test/run-pass/deriving-meta.rs @@ -9,7 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::hash::hash; +use std::hash::{Hash, SipHasher}; #[derive(PartialEq, Clone, Hash)] struct Foo { @@ -17,6 +17,8 @@ struct Foo { baz: int } +fn hash<T: Hash<SipHasher>>(_t: &T) {} + pub fn main() { let a = Foo {bar: 4, baz: -3}; diff --git a/src/test/run-pass/drop-trait-enum.rs b/src/test/run-pass/drop-trait-enum.rs index f1cc4fb1724..6addfc59a3d 100644 --- a/src/test/run-pass/drop-trait-enum.rs +++ b/src/test/run-pass/drop-trait-enum.rs @@ -66,7 +66,7 @@ pub fn main() { assert_eq!(receiver.recv().ok(), None); let (sender, receiver) = channel(); - let _t = Thread::spawn(move|| { + let _t = Thread::scoped(move|| { let v = Foo::FailingVariant { on_drop: SendOnDrop { sender: sender } }; }); assert_eq!(receiver.recv().unwrap(), Message::Dropped); @@ -74,7 +74,7 @@ pub fn main() { let (sender, receiver) = channel(); let _t = { - Thread::spawn(move|| { + Thread::scoped(move|| { let mut v = Foo::NestedVariant(box 42u, SendOnDrop { sender: sender.clone() }, sender.clone()); diff --git a/src/test/run-pass/extern-stress.rs b/src/test/run-pass/extern-stress.rs index bb9e9407382..c3e04177cce 100644 --- a/src/test/run-pass/extern-stress.rs +++ b/src/test/run-pass/extern-stress.rs @@ -42,7 +42,7 @@ fn count(n: libc::uintptr_t) -> libc::uintptr_t { pub fn main() { range(0u, 100).map(|_| { - Thread::spawn(move|| { + Thread::scoped(move|| { assert_eq!(count(5), 16); }) }).collect::<Vec<_>>(); diff --git a/src/test/run-pass/extern-yield.rs b/src/test/run-pass/extern-yield.rs index 46829e9ba6e..f5e91b9de67 100644 --- a/src/test/run-pass/extern-yield.rs +++ b/src/test/run-pass/extern-yield.rs @@ -39,7 +39,7 @@ fn count(n: libc::uintptr_t) -> libc::uintptr_t { pub fn main() { range(0, 10u).map(|i| { - Thread::spawn(move|| { + Thread::scoped(move|| { let result = count(5); println!("result = {}", result); assert_eq!(result, 16); diff --git a/src/test/run-pass/huge-largest-array.rs b/src/test/run-pass/huge-largest-array.rs index e24731546ed..e1b0c115365 100644 --- a/src/test/run-pass/huge-largest-array.rs +++ b/src/test/run-pass/huge-largest-array.rs @@ -10,12 +10,12 @@ use std::mem::size_of; -#[cfg(target_word_size = "32")] +#[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] pub fn main() { assert_eq!(size_of::<[u8; (1 << 31) - 1]>(), (1 << 31) - 1); } -#[cfg(target_word_size = "64")] +#[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] pub fn main() { assert_eq!(size_of::<[u8; (1 << 47) - 1]>(), (1 << 47) - 1); } diff --git a/src/test/run-pass/issue-9396.rs b/src/test/run-pass/issue-9396.rs index 34bb50c5cf6..73355d15a27 100644 --- a/src/test/run-pass/issue-9396.rs +++ b/src/test/run-pass/issue-9396.rs @@ -15,7 +15,7 @@ use std::time::Duration; pub fn main() { let (tx, rx) = channel(); - let _t = Thread::spawn(move||{ + let _t = Thread::scoped(move||{ let mut timer = Timer::new().unwrap(); timer.sleep(Duration::milliseconds(10)); tx.send(()).unwrap(); diff --git a/src/test/run-pass/simd-size-align.rs b/src/test/run-pass/simd-size-align.rs new file mode 100644 index 00000000000..582810f0def --- /dev/null +++ b/src/test/run-pass/simd-size-align.rs @@ -0,0 +1,70 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(simd)] +#![allow(non_camel_case_types)] + +use std::mem; + +/// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec<T>` properly +/// Please consult the issue #20460 +fn check<T>() { + assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0) +} + +fn main() { + check::<u8x2>(); + check::<u8x3>(); + check::<u8x4>(); + check::<u8x5>(); + check::<u8x6>(); + check::<u8x7>(); + check::<u8x8>(); + + check::<i16x2>(); + check::<i16x3>(); + check::<i16x4>(); + check::<i16x5>(); + check::<i16x6>(); + check::<i16x7>(); + check::<i16x8>(); + + check::<f32x2>(); + check::<f32x3>(); + check::<f32x4>(); + check::<f32x5>(); + check::<f32x6>(); + check::<f32x7>(); + check::<f32x8>(); +} + +#[simd] struct u8x2(u8, u8); +#[simd] struct u8x3(u8, u8, u8); +#[simd] struct u8x4(u8, u8, u8, u8); +#[simd] struct u8x5(u8, u8, u8, u8, u8); +#[simd] struct u8x6(u8, u8, u8, u8, u8, u8); +#[simd] struct u8x7(u8, u8, u8, u8, u8, u8, u8); +#[simd] struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8); + +#[simd] struct i16x2(i16, i16); +#[simd] struct i16x3(i16, i16, i16); +#[simd] struct i16x4(i16, i16, i16, i16); +#[simd] struct i16x5(i16, i16, i16, i16, i16); +#[simd] struct i16x6(i16, i16, i16, i16, i16, i16); +#[simd] struct i16x7(i16, i16, i16, i16, i16, i16, i16); +#[simd] struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); + +#[simd] struct f32x2(f32, f32); +#[simd] struct f32x3(f32, f32, f32); +#[simd] struct f32x4(f32, f32, f32, f32); +#[simd] struct f32x5(f32, f32, f32, f32, f32); +#[simd] struct f32x6(f32, f32, f32, f32, f32, f32); +#[simd] struct f32x7(f32, f32, f32, f32, f32, f32, f32); +#[simd] struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); diff --git a/src/test/run-pass/tcp-accept-stress.rs b/src/test/run-pass/tcp-accept-stress.rs index cd3cb872fd3..cad71732034 100644 --- a/src/test/run-pass/tcp-accept-stress.rs +++ b/src/test/run-pass/tcp-accept-stress.rs @@ -34,11 +34,11 @@ fn test() { let (srv_tx, srv_rx) = channel(); let (cli_tx, cli_rx) = channel(); - for _ in range(0, N) { + let _t = range(0, N).map(|_| { let a = a.clone(); let cnt = cnt.clone(); let srv_tx = srv_tx.clone(); - Thread::spawn(move|| { + Thread::scoped(move|| { let mut a = a; loop { match a.accept() { @@ -52,18 +52,18 @@ fn test() { } } srv_tx.send(()); - }); - } + }) + }).collect::<Vec<_>>(); - for _ in range(0, N) { + let _t = range(0, N).map(|_| { let cli_tx = cli_tx.clone(); - Thread::spawn(move|| { + Thread::scoped(move|| { for _ in range(0, M) { let _s = TcpStream::connect(addr).unwrap(); } cli_tx.send(()); - }); - } + }) + }).collect::<Vec<_>>(); drop((cli_tx, srv_tx)); // wait for senders diff --git a/src/test/run-pass/threads.rs b/src/test/run-pass/threads.rs index c47ca0db2a1..abc2938df00 100644 --- a/src/test/run-pass/threads.rs +++ b/src/test/run-pass/threads.rs @@ -13,7 +13,7 @@ use std::thread::Thread; pub fn main() { let mut i = 10; while i > 0 { - Thread::spawn({let i = i; move|| child(i)}); + Thread::scoped({let i = i; move|| child(i)}); i = i - 1; } println!("main thread exiting"); diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs index bba043ea8f8..e346c4ff349 100644 --- a/src/test/run-pass/typeid-intrinsic.rs +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -14,7 +14,7 @@ extern crate "typeid-intrinsic" as other1; extern crate "typeid-intrinsic2" as other2; -use std::hash; +use std::hash::{self, SipHasher}; use std::intrinsics; use std::intrinsics::TypeId; @@ -70,5 +70,6 @@ pub fn main() { // check it has a hash let (a, b) = (TypeId::of::<uint>(), TypeId::of::<uint>()); - assert_eq!(hash::hash(&a), hash::hash(&b)); + assert_eq!(hash::hash::<TypeId, SipHasher>(&a), + hash::hash::<TypeId, SipHasher>(&b)); } diff --git a/src/test/run-pass/unique-send-2.rs b/src/test/run-pass/unique-send-2.rs index bb3019ede4b..ba75c7629b5 100644 --- a/src/test/run-pass/unique-send-2.rs +++ b/src/test/run-pass/unique-send-2.rs @@ -19,13 +19,13 @@ pub fn main() { let (tx, rx) = channel(); let n = 100u; let mut expected = 0u; - for i in range(0u, n) { + let _t = range(0u, n).map(|i| { + expected += i; let tx = tx.clone(); - Thread::spawn(move|| { + Thread::scoped(move|| { child(&tx, i) - }); - expected += i; - } + }) + }).collect::<Vec<_>>(); let mut actual = 0u; for _ in range(0u, n) { diff --git a/src/test/run-pass/unwind-resource.rs b/src/test/run-pass/unwind-resource.rs index 3f59b2c6c76..159bac10183 100644 --- a/src/test/run-pass/unwind-resource.rs +++ b/src/test/run-pass/unwind-resource.rs @@ -37,7 +37,7 @@ fn f(tx: Sender<bool>) { pub fn main() { let (tx, rx) = channel(); - let _t = Thread::spawn(move|| f(tx.clone())); + let _t = Thread::scoped(move|| f(tx.clone())); println!("hiiiiiiiii"); assert!(rx.recv().unwrap()); } diff --git a/src/test/run-pass/vec-fixed-length.rs b/src/test/run-pass/vec-fixed-length.rs index 20e1becd008..101999bbe08 100644 --- a/src/test/run-pass/vec-fixed-length.rs +++ b/src/test/run-pass/vec-fixed-length.rs @@ -21,7 +21,7 @@ pub fn main() { // FIXME #10183 // FIXME #18069 - //if cfg!(target_word_size = "64") { + //if cfg!(target_pointer_width = "64") { // assert_eq!(size_of::<[u8; (1 << 32)]>(), (1u << 32)); //} } |
