about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Cargo.lock1
-rw-r--r--src/liballoc/slice.rs16
-rw-r--r--src/liballoc/str.rs126
-rw-r--r--src/liballoc/tests/slice.rs9
-rw-r--r--src/liballoc/tests/str.rs13
-rw-r--r--src/libcore/alloc.rs8
-rw-r--r--src/libcore/marker.rs2
-rw-r--r--src/libcore/num/mod.rs16
-rw-r--r--src/libcore/tests/num/mod.rs21
-rw-r--r--src/libcore/tests/result.rs6
-rw-r--r--src/libproc_macro/lib.rs2
-rw-r--r--src/librustc/session/mod.rs3
-rw-r--r--src/librustc/ty/context.rs16
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_codegen_utils/lib.rs2
-rw-r--r--src/librustc_data_structures/Cargo.toml1
-rw-r--r--src/librustc_data_structures/lib.rs1
-rw-r--r--src/librustc_data_structures/sync.rs33
-rw-r--r--src/librustc_metadata/lib.rs2
-rw-r--r--src/librustc_privacy/lib.rs2
-rw-r--r--src/librustc_save_analysis/lib.rs2
-rw-r--r--src/librustc_traits/lib.rs2
-rw-r--r--src/librustc_typeck/check/method/suggest.rs62
-rw-r--r--src/libstd/alloc.rs22
-rw-r--r--src/libstd/collections/hash/table.rs120
-rw-r--r--src/libstd/fs.rs2
-rw-r--r--src/libstd/sys/unix/fs.rs17
-rw-r--r--src/test/ui/hygiene/no_implicit_prelude.stderr2
-rw-r--r--src/test/ui/hygiene/trait_items.stderr2
-rw-r--r--src/test/ui/span/issue-7575.stderr16
30 files changed, 327 insertions, 202 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 3a27107f825..d5a1d18a676 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -2044,6 +2044,7 @@ dependencies = [
  "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_cratesio_shim 0.0.0",
  "serialize 0.0.0",
  "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs
index 161493f3892..90bc2f9769c 100644
--- a/src/liballoc/slice.rs
+++ b/src/liballoc/slice.rs
@@ -566,15 +566,17 @@ impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T> for [V] {
     }
 
     fn join(&self, sep: &T) -> Vec<T> {
+        let mut iter = self.iter();
+        let first = match iter.next() {
+            Some(first) => first,
+            None => return vec![],
+        };
         let size = self.iter().fold(0, |acc, v| acc + v.borrow().len());
         let mut result = Vec::with_capacity(size + self.len());
-        let mut first = true;
-        for v in self {
-            if first {
-                first = false
-            } else {
-                result.push(sep.clone())
-            }
+        result.extend_from_slice(first.borrow());
+
+        for v in iter {
+            result.push(sep.clone());
             result.extend_from_slice(v.borrow())
         }
         result
diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs
index 823e56b64e3..32ca8d1fa5e 100644
--- a/src/liballoc/str.rs
+++ b/src/liballoc/str.rs
@@ -86,52 +86,108 @@ impl<S: Borrow<str>> SliceConcatExt<str> for [S] {
     type Output = String;
 
     fn concat(&self) -> String {
-        if self.is_empty() {
-            return String::new();
-        }
-
-        // `len` calculation may overflow but push_str will check boundaries
-        let len = self.iter().map(|s| s.borrow().len()).sum();
-        let mut result = String::with_capacity(len);
-
-        for s in self {
-            result.push_str(s.borrow())
-        }
-
-        result
+        self.join("")
     }
 
     fn join(&self, sep: &str) -> String {
-        if self.is_empty() {
-            return String::new();
-        }
-
-        // concat is faster
-        if sep.is_empty() {
-            return self.concat();
+        unsafe {
+            String::from_utf8_unchecked( join_generic_copy(self, sep.as_bytes()) )
         }
+    }
 
-        // this is wrong without the guarantee that `self` is non-empty
-        // `len` calculation may overflow but push_str but will check boundaries
-        let len = sep.len() * (self.len() - 1) +
-                  self.iter().map(|s| s.borrow().len()).sum::<usize>();
-        let mut result = String::with_capacity(len);
-        let mut first = true;
+    fn connect(&self, sep: &str) -> String {
+        self.join(sep)
+    }
+}
 
-        for s in self {
-            if first {
-                first = false;
-            } else {
-                result.push_str(sep);
+macro_rules! spezialize_for_lengths {
+    ($separator:expr, $target:expr, $iter:expr; $($num:expr),*) => {
+        let mut target = $target;
+        let iter = $iter;
+        let sep_bytes = $separator;
+        match $separator.len() {
+            $(
+                // loops with hardcoded sizes run much faster
+                // specialize the cases with small separator lengths
+                $num => {
+                    for s in iter {
+                        copy_slice_and_advance!(target, sep_bytes);
+                        copy_slice_and_advance!(target, s.borrow().as_ref());
+                    }
+                },
+            )*
+            _ => {
+                // arbitrary non-zero size fallback
+                for s in iter {
+                    copy_slice_and_advance!(target, sep_bytes);
+                    copy_slice_and_advance!(target, s.borrow().as_ref());
+                }
             }
-            result.push_str(s.borrow());
         }
-        result
+    };
+}
+
+macro_rules! copy_slice_and_advance {
+    ($target:expr, $bytes:expr) => {
+        let len = $bytes.len();
+        let (head, tail) = {$target}.split_at_mut(len);
+        head.copy_from_slice($bytes);
+        $target = tail;
     }
+}
 
-    fn connect(&self, sep: &str) -> String {
-        self.join(sep)
+// Optimized join implementation that works for both Vec<T> (T: Copy) and String's inner vec
+// Currently (2018-05-13) there is a bug with type inference and specialization (see issue #36262)
+// For this reason SliceConcatExt<T> is not specialized for T: Copy and SliceConcatExt<str> is the
+// only user of this function. It is left in place for the time when that is fixed.
+//
+// the bounds for String-join are S: Borrow<str> and for Vec-join Borrow<[T]>
+// [T] and str both impl AsRef<[T]> for some T
+// => s.borrow().as_ref() and we always have slices
+fn join_generic_copy<B, T, S>(slice: &[S], sep: &[T]) -> Vec<T>
+where
+    T: Copy,
+    B: AsRef<[T]> + ?Sized,
+    S: Borrow<B>,
+{
+    let sep_len = sep.len();
+    let mut iter = slice.iter();
+
+    // the first slice is the only one without a separator preceding it
+    let first = match iter.next() {
+        Some(first) => first,
+        None => return vec![],
+    };
+
+    // compute the exact total length of the joined Vec
+    // if the `len` calculation overflows, we'll panic
+    // we would have run out of memory anyway and the rest of the function requires
+    // the entire Vec pre-allocated for safety
+    let len =  sep_len.checked_mul(iter.len()).and_then(|n| {
+            slice.iter()
+                .map(|s| s.borrow().as_ref().len())
+                .try_fold(n, usize::checked_add)
+        }).expect("attempt to join into collection with len > usize::MAX");
+
+    // crucial for safety
+    let mut result = Vec::with_capacity(len);
+    assert!(result.capacity() >= len);
+
+    result.extend_from_slice(first.borrow().as_ref());
+
+    unsafe {
+        {
+            let pos = result.len();
+            let target = result.get_unchecked_mut(pos..len);
+
+            // copy separator and slices over without bounds checks
+            // generate loops with hardcoded offsets for small separators
+            // massive improvements possible (~ x2)
+            spezialize_for_lengths!(sep, target, iter; 0, 1, 2, 3, 4);
+        }
+        result.set_len(len);
     }
+    result
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs
index 6fd0b33f02a..3b7eec38609 100644
--- a/src/liballoc/tests/slice.rs
+++ b/src/liballoc/tests/slice.rs
@@ -610,6 +610,15 @@ fn test_join() {
 }
 
 #[test]
+fn test_join_nocopy() {
+    let v: [String; 0] = [];
+    assert_eq!(v.join(","), "");
+    assert_eq!(["a".to_string(), "ab".into()].join(","), "a,ab");
+    assert_eq!(["a".to_string(), "ab".into(), "abc".into()].join(","), "a,ab,abc");
+    assert_eq!(["a".to_string(), "ab".into(), "".into()].join(","), "a,ab,");
+}
+
+#[test]
 fn test_insert() {
     let mut a = vec![1, 2, 4];
     a.insert(2, 3);
diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs
index d11bf5dc3e9..03d295d16e6 100644
--- a/src/liballoc/tests/str.rs
+++ b/src/liballoc/tests/str.rs
@@ -162,6 +162,19 @@ fn test_join_for_different_lengths() {
     test_join!("-a-bc", ["", "a", "bc"], "-");
 }
 
+// join has fast paths for small separators up to 4 bytes
+// this tests the slow paths.
+#[test]
+fn test_join_for_different_lengths_with_long_separator() {
+    assert_eq!("~~~~~".len(), 15);
+
+    let empty: &[&str] = &[];
+    test_join!("", empty, "~~~~~");
+    test_join!("a", ["a"], "~~~~~");
+    test_join!("a~~~~~b", ["a", "b"], "~~~~~");
+    test_join!("~~~~~a~~~~~bc", ["", "a", "bc"], "~~~~~");
+}
+
 #[test]
 fn test_unsafe_slice() {
     assert_eq!("ab", unsafe {"abc".slice_unchecked(0, 2)});
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index 674c4fb57c7..6172a98bca6 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -392,6 +392,14 @@ impl From<AllocErr> for CollectionAllocErr {
     }
 }
 
+#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
+impl From<LayoutErr> for CollectionAllocErr {
+    #[inline]
+    fn from(_: LayoutErr) -> Self {
+        CollectionAllocErr::CapacityOverflow
+    }
+}
+
 /// A memory allocator that can be registered to be the one backing `std::alloc::Global`
 /// though the `#[global_allocator]` attributes.
 pub unsafe trait GlobalAlloc {
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 77db165bcbd..3d3f63ecf37 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -294,7 +294,7 @@ pub trait Copy : Clone {
 /// This trait is automatically implemented when the compiler determines
 /// it's appropriate.
 ///
-/// The precise definition is: a type `T` is `Sync` if `&T` is
+/// The precise definition is: a type `T` is `Sync` if and only if `&T` is
 /// [`Send`][send]. In other words, if there is no possibility of
 /// [undefined behavior][ub] (including data races) when passing
 /// `&T` references between threads.
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 013d0334d41..ea652ad811e 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -2313,7 +2313,7 @@ Basic usage:
 ```
 ", $Feature, "assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(1), ",
 "Some(", stringify!($SelfT), "::max_value() - 1));
-assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3),None);", $EndFeature, "
+assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
             #[inline]
@@ -4454,6 +4454,20 @@ macro_rules! impl_from {
     }
 }
 
+// Bool -> Any
+impl_from! { bool, u8, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, u16, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, u32, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, u64, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, u128, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, usize, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, i8, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, i16, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, i32, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, i64, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, i128, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from! { bool, isize, #[stable(feature = "from_bool", since = "1.28.0")] }
+
 // Unsigned -> Unsigned
 impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
 impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs
index f3439890fce..b5e6a019a22 100644
--- a/src/libcore/tests/num/mod.rs
+++ b/src/libcore/tests/num/mod.rs
@@ -134,6 +134,15 @@ fn test_infallible_try_from_int_error() {
 }
 
 macro_rules! test_impl_from {
+    ($fn_name:ident, bool, $target: ty) => {
+        #[test]
+        fn $fn_name() {
+            let one: $target = 1;
+            let zero: $target = 0;
+            assert_eq!(one, <$target>::from(true));
+            assert_eq!(zero, <$target>::from(false));
+        }
+    };
     ($fn_name: ident, $Small: ty, $Large: ty) => {
         #[test]
         fn $fn_name() {
@@ -173,6 +182,18 @@ test_impl_from! { test_u16i32, u16, i32 }
 test_impl_from! { test_u16i64, u16, i64 }
 test_impl_from! { test_u32i64, u32, i64 }
 
+// Bool -> Integer
+test_impl_from! { test_boolu8, bool, u8 }
+test_impl_from! { test_boolu16, bool, u16 }
+test_impl_from! { test_boolu32, bool, u32 }
+test_impl_from! { test_boolu64, bool, u64 }
+test_impl_from! { test_boolu128, bool, u128 }
+test_impl_from! { test_booli8, bool, i8 }
+test_impl_from! { test_booli16, bool, i16 }
+test_impl_from! { test_booli32, bool, i32 }
+test_impl_from! { test_booli64, bool, i64 }
+test_impl_from! { test_booli128, bool, i128 }
+
 // Signed -> Float
 test_impl_from! { test_i8f32, i8, f32 }
 test_impl_from! { test_i8f64, i8, f64 }
diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs
index ce41bde8342..d9927ce4487 100644
--- a/src/libcore/tests/result.rs
+++ b/src/libcore/tests/result.rs
@@ -220,13 +220,15 @@ fn test_try() {
     assert_eq!(try_result_none(), None);
 
     fn try_result_ok() -> Result<u8, u8> {
-        let val = Ok(1)?;
+        let result: Result<u8, u8> = Ok(1);
+        let val = result?;
         Ok(val)
     }
     assert_eq!(try_result_ok(), Ok(1));
 
     fn try_result_err() -> Result<u8, u8> {
-        let val = Err(1)?;
+        let result: Result<u8, u8> = Err(1);
+        let val = result?;
         Ok(val)
     }
     assert_eq!(try_result_err(), Err(1));
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 9d037cefcee..befc1ba064a 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -36,6 +36,8 @@
 #![feature(lang_items)]
 #![feature(optin_builtin_traits)]
 
+#![recursion_limit="256"]
+
 extern crate syntax;
 extern crate syntax_pos;
 extern crate rustc_errors;
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 8df66d8d688..076d56fb808 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -845,10 +845,10 @@ impl Session {
     /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
     /// This expends fuel if applicable, and records fuel if applicable.
     pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
-        assert!(self.query_threads() == 1);
         let mut ret = true;
         match self.optimization_fuel_crate {
             Some(ref c) if c == crate_name => {
+                assert!(self.query_threads() == 1);
                 let fuel = self.optimization_fuel_limit.get();
                 ret = fuel != 0;
                 if fuel == 0 && !self.out_of_fuel.get() {
@@ -862,6 +862,7 @@ impl Session {
         }
         match self.print_fuel_crate {
             Some(ref c) if c == crate_name => {
+                assert!(self.query_threads() == 1);
                 self.print_fuel.set(self.print_fuel.get() + 1);
             }
             _ => {}
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 68f55b49933..35b2ce50da7 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -58,7 +58,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
                                            StableVec};
 use arena::{TypedArena, SyncDroplessArena};
 use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_data_structures::sync::{Lrc, Lock};
+use rustc_data_structures::sync::{self, Lrc, Lock, WorkerLocal};
 use std::any::Any;
 use std::borrow::Borrow;
 use std::cmp::Ordering;
@@ -80,14 +80,14 @@ use syntax_pos::Span;
 use hir;
 
 pub struct AllArenas<'tcx> {
-    pub global: GlobalArenas<'tcx>,
+    pub global: WorkerLocal<GlobalArenas<'tcx>>,
     pub interner: SyncDroplessArena,
 }
 
 impl<'tcx> AllArenas<'tcx> {
     pub fn new() -> Self {
         AllArenas {
-            global: GlobalArenas::new(),
+            global: WorkerLocal::new(|_| GlobalArenas::new()),
             interner: SyncDroplessArena::new(),
         }
     }
@@ -854,7 +854,7 @@ impl<'a, 'gcx, 'tcx> Deref for TyCtxt<'a, 'gcx, 'tcx> {
 }
 
 pub struct GlobalCtxt<'tcx> {
-    global_arenas: &'tcx GlobalArenas<'tcx>,
+    global_arenas: &'tcx WorkerLocal<GlobalArenas<'tcx>>,
     global_interners: CtxtInterners<'tcx>,
 
     cstore: &'tcx CrateStoreDyn,
@@ -1179,6 +1179,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             output_filenames: Arc::new(output_filenames.clone()),
         };
 
+        sync::assert_send_val(&gcx);
+
         tls::enter_global(gcx, f)
     }
 
@@ -1704,7 +1706,7 @@ pub mod tls {
     use ty::maps;
     use errors::{Diagnostic, TRACK_DIAGNOSTICS};
     use rustc_data_structures::OnDrop;
-    use rustc_data_structures::sync::Lrc;
+    use rustc_data_structures::sync::{self, Lrc};
     use dep_graph::OpenTask;
 
     /// This is the implicit state of rustc. It contains the current
@@ -1832,6 +1834,10 @@ pub mod tls {
         if context == 0 {
             f(None)
         } else {
+            // We could get a ImplicitCtxt pointer from another thread.
+            // Ensure that ImplicitCtxt is Sync
+            sync::assert_sync::<ImplicitCtxt>();
+
             unsafe { f(Some(&*(context as *const ImplicitCtxt))) }
         }
     }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 419bffcae06..0bb0208e2a1 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -617,6 +617,8 @@ pub struct Slice<T> {
     opaque: OpaqueSliceContents,
 }
 
+unsafe impl<T: Sync> Sync for Slice<T> {}
+
 impl<T: Copy> Slice<T> {
     #[inline]
     fn from_arena<'tcx>(arena: &'tcx SyncDroplessArena, slice: &[T]) -> &'tcx Slice<T> {
diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs
index 0c18571f4ff..d09e8f4845e 100644
--- a/src/librustc_codegen_utils/lib.rs
+++ b/src/librustc_codegen_utils/lib.rs
@@ -23,6 +23,8 @@
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 
+#![recursion_limit="256"]
+
 extern crate ar;
 extern crate flate2;
 #[macro_use]
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index 15956829ff9..17ee771e529 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -17,6 +17,7 @@ cfg-if = "0.1.2"
 stable_deref_trait = "1.0.0"
 parking_lot_core = "0.2.8"
 rustc-rayon = "0.1.0"
+rustc-rayon-core = "0.1.0"
 rustc-hash = "1.0.1"
 
 [dependencies.parking_lot]
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 23a920739b9..7046a2a2a49 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -44,6 +44,7 @@ extern crate parking_lot;
 extern crate cfg_if;
 extern crate stable_deref_trait;
 extern crate rustc_rayon as rayon;
+extern crate rustc_rayon_core as rayon_core;
 extern crate rustc_hash;
 
 // See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs
index 36617631330..6f7d9e1b54b 100644
--- a/src/librustc_data_structures/sync.rs
+++ b/src/librustc_data_structures/sync.rs
@@ -36,7 +36,6 @@ use std::marker::PhantomData;
 use std::fmt::Debug;
 use std::fmt::Formatter;
 use std::fmt;
-use std;
 use std::ops::{Deref, DerefMut};
 use owning_ref::{Erased, OwningRef};
 
@@ -101,6 +100,33 @@ cfg_if! {
         use std::cell::Cell;
 
         #[derive(Debug)]
+        pub struct WorkerLocal<T>(OneThread<T>);
+
+        impl<T> WorkerLocal<T> {
+            /// Creates a new worker local where the `initial` closure computes the
+            /// value this worker local should take for each thread in the thread pool.
+            #[inline]
+            pub fn new<F: FnMut(usize) -> T>(mut f: F) -> WorkerLocal<T> {
+                WorkerLocal(OneThread::new(f(0)))
+            }
+
+            /// Returns the worker-local value for each thread
+            #[inline]
+            pub fn into_inner(self) -> Vec<T> {
+                vec![OneThread::into_inner(self.0)]
+            }
+        }
+
+        impl<T> Deref for WorkerLocal<T> {
+            type Target = T;
+
+            #[inline(always)]
+            fn deref(&self) -> &T {
+                &*self.0
+            }
+        }
+
+        #[derive(Debug)]
         pub struct MTLock<T>(T);
 
         impl<T> MTLock<T> {
@@ -200,9 +226,12 @@ cfg_if! {
         use parking_lot::Mutex as InnerLock;
         use parking_lot::RwLock as InnerRwLock;
 
+        use std;
         use std::thread;
         pub use rayon::{join, scope};
 
+        pub use rayon_core::WorkerLocal;
+
         pub use rayon::iter::ParallelIterator;
         use rayon::iter::IntoParallelIterator;
 
@@ -638,7 +667,9 @@ pub struct OneThread<T> {
     inner: T,
 }
 
+#[cfg(parallel_queries)]
 unsafe impl<T> std::marker::Sync for OneThread<T> {}
+#[cfg(parallel_queries)]
 unsafe impl<T> std::marker::Send for OneThread<T> {}
 
 impl<T> OneThread<T> {
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 7ecf2eba43d..d76ca5bdf27 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -23,6 +23,8 @@
 #![feature(specialization)]
 #![feature(rustc_private)]
 
+#![recursion_limit="256"]
+
 extern crate libc;
 #[macro_use]
 extern crate log;
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index bfb8c282d37..f32f6eda8ff 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -14,6 +14,8 @@
 
 #![feature(rustc_diagnostic_macros)]
 
+#![recursion_limit="256"]
+
 #[macro_use] extern crate rustc;
 #[macro_use] extern crate syntax;
 extern crate rustc_typeck;
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index e57a793ff42..64dcd3e5175 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -15,6 +15,8 @@
 #![cfg_attr(stage0, feature(macro_lifetime_matcher))]
 #![allow(unused_attributes)]
 
+#![recursion_limit="256"]
+
 #[macro_use]
 extern crate rustc;
 
diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs
index 733d8e1708e..7fa69cb9833 100644
--- a/src/librustc_traits/lib.rs
+++ b/src/librustc_traits/lib.rs
@@ -17,6 +17,8 @@
 #![feature(iterator_find_map)]
 #![feature(in_band_lifetimes)]
 
+#![recursion_limit="256"]
+
 extern crate chalk_engine;
 #[macro_use]
 extern crate log;
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 8a575c14787..6031984350b 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -119,11 +119,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             }
                         };
 
-                        let note_str = format!("candidate #{} is defined in an impl{} \
-                                                for the type `{}`",
-                                               idx + 1,
-                                               insertion,
-                                               impl_ty);
+                        let note_str = if sources.len() > 1 {
+                            format!("candidate #{} is defined in an impl{} for the type `{}`",
+                                    idx + 1,
+                                    insertion,
+                                    impl_ty)
+                        } else {
+                            format!("the candidate is defined in an impl{} for the type `{}`",
+                                    insertion,
+                                    impl_ty)
+                        };
                         if let Some(note_span) = note_span {
                             // We have a span pointing to the method. Show note with snippet.
                             err.span_note(self.tcx.sess.codemap().def_span(note_span), &note_str);
@@ -137,11 +142,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             .unwrap();
                         let item_span = self.tcx.sess.codemap()
                             .def_span(self.tcx.def_span(item.def_id));
-                        span_note!(err,
-                                   item_span,
-                                   "candidate #{} is defined in the trait `{}`",
-                                   idx + 1,
-                                   self.tcx.item_path_str(trait_did));
+                        if sources.len() > 1 {
+                            span_note!(err,
+                                       item_span,
+                                       "candidate #{} is defined in the trait `{}`",
+                                       idx + 1,
+                                       self.tcx.item_path_str(trait_did));
+                        } else {
+                            span_note!(err,
+                                       item_span,
+                                       "the candidate is defined in the trait `{}`",
+                                       self.tcx.item_path_str(trait_did));
+                        }
                         err.help(&format!("to disambiguate the method call, write `{}::{}({}{})` \
                                           instead",
                                           self.tcx.item_path_str(trait_did),
@@ -285,7 +297,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     tcx.sess.diagnostic().struct_dummy()
                 };
 
-                if let Some(def) =  actual.ty_adt_def() {
+                if let Some(def) = actual.ty_adt_def() {
                     if let Some(full_sp) = tcx.hir.span_if_local(def.did) {
                         let def_sp = tcx.sess.codemap().def_span(full_sp);
                         err.span_label(def_sp, format!("{} `{}` not found {}",
@@ -368,7 +380,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if !static_sources.is_empty() {
                     err.note("found the following associated functions; to be used as methods, \
                               functions must have a `self` parameter");
-                    err.help(&format!("try with `{}::{}`", self.ty_to_string(actual), item_name));
+                    err.span_label(span, "this is an associated function, not a method");
+                }
+                if static_sources.len() == 1 {
+                    if let Some(expr) = rcvr_expr {
+                        err.span_suggestion(expr.span.to(span),
+                                            "use associated function syntax instead",
+                                            format!("{}::{}",
+                                                    self.ty_to_string(actual),
+                                                    item_name));
+                    } else {
+                        err.help(&format!("try with `{}::{}`",
+                                          self.ty_to_string(actual), item_name));
+                    }
+
+                    report_candidates(&mut err, static_sources);
+                } else if static_sources.len() > 1 {
 
                     report_candidates(&mut err, static_sources);
                 }
@@ -468,9 +495,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         } else {
             let limit = if candidates.len() == 5 { 5 } else { 4 };
             for (i, trait_did) in candidates.iter().take(limit).enumerate() {
-                msg.push_str(&format!("\ncandidate #{}: `use {};`",
-                                        i + 1,
-                                        self.tcx.item_path_str(*trait_did)));
+                if candidates.len() > 1 {
+                    msg.push_str(&format!("\ncandidate #{}: `use {};`",
+                                            i + 1,
+                                            self.tcx.item_path_str(*trait_did)));
+                } else {
+                    msg.push_str(&format!("\n`use {};`",
+                                            self.tcx.item_path_str(*trait_did)));
+                }
             }
             if candidates.len() > limit {
                 msg.push_str(&format!("\nand {} others", candidates.len() - limit));
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
index 4f9dffc7c95..3b1a3a439e7 100644
--- a/src/libstd/alloc.rs
+++ b/src/libstd/alloc.rs
@@ -19,21 +19,22 @@
 
 use core::sync::atomic::{AtomicPtr, Ordering};
 use core::{mem, ptr};
+use sys_common::util::dumb_print;
 
 static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
 
 /// Registers a custom OOM hook, replacing any that was previously registered.
 ///
-/// The OOM hook is invoked when an infallible memory allocation fails.
-/// The default hook prints a message to standard error and aborts the
-/// execution, but this behavior can be customized with the [`set_oom_hook`]
-/// and [`take_oom_hook`] functions.
+/// The OOM hook is invoked when an infallible memory allocation fails, before
+/// the runtime aborts. The default hook prints a message to standard error,
+/// but this behavior can be customized with the [`set_oom_hook`] and
+/// [`take_oom_hook`] functions.
 ///
 /// The hook is provided with a `Layout` struct which contains information
 /// about the allocation that failed.
 ///
 /// The OOM hook is a global resource.
-pub fn set_oom_hook(hook: fn(Layout) -> !) {
+pub fn set_oom_hook(hook: fn(Layout)) {
     HOOK.store(hook as *mut (), Ordering::SeqCst);
 }
 
@@ -42,7 +43,7 @@ pub fn set_oom_hook(hook: fn(Layout) -> !) {
 /// *See also the function [`set_oom_hook`].*
 ///
 /// If no custom hook is registered, the default hook will be returned.
-pub fn take_oom_hook() -> fn(Layout) -> ! {
+pub fn take_oom_hook() -> fn(Layout) {
     let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
     if hook.is_null() {
         default_oom_hook
@@ -51,8 +52,8 @@ pub fn take_oom_hook() -> fn(Layout) -> ! {
     }
 }
 
-fn default_oom_hook(layout: Layout) -> ! {
-    rtabort!("memory allocation of {} bytes failed", layout.size())
+fn default_oom_hook(layout: Layout) {
+    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
 }
 
 #[cfg(not(test))]
@@ -60,12 +61,13 @@ fn default_oom_hook(layout: Layout) -> ! {
 #[lang = "oom"]
 pub extern fn rust_oom(layout: Layout) -> ! {
     let hook = HOOK.load(Ordering::SeqCst);
-    let hook: fn(Layout) -> ! = if hook.is_null() {
+    let hook: fn(Layout) = if hook.is_null() {
         default_oom_hook
     } else {
         unsafe { mem::transmute(hook) }
     };
-    hook(layout)
+    hook(layout);
+    unsafe { ::sys::abort_internal(); }
 }
 
 #[cfg(not(test))]
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index eed2debcaa2..c62a409ac02 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -8,11 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use alloc::{Global, Alloc, Layout, CollectionAllocErr, oom};
-use cmp;
+use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, oom};
 use hash::{BuildHasher, Hash, Hasher};
 use marker;
-use mem::{align_of, size_of, needs_drop};
+use mem::{size_of, needs_drop};
 use mem;
 use ops::{Deref, DerefMut};
 use ptr::{self, Unique, NonNull};
@@ -651,64 +650,12 @@ impl<K, V, M> GapThenFull<K, V, M>
     }
 }
 
-
-/// Rounds up to a multiple of a power of two. Returns the closest multiple
-/// of `target_alignment` that is higher or equal to `unrounded`.
-///
-/// # Panics
-///
-/// Panics if `target_alignment` is not a power of two.
-#[inline]
-fn round_up_to_next(unrounded: usize, target_alignment: usize) -> usize {
-    assert!(target_alignment.is_power_of_two());
-    (unrounded + target_alignment - 1) & !(target_alignment - 1)
-}
-
-#[test]
-fn test_rounding() {
-    assert_eq!(round_up_to_next(0, 4), 0);
-    assert_eq!(round_up_to_next(1, 4), 4);
-    assert_eq!(round_up_to_next(2, 4), 4);
-    assert_eq!(round_up_to_next(3, 4), 4);
-    assert_eq!(round_up_to_next(4, 4), 4);
-    assert_eq!(round_up_to_next(5, 4), 8);
-}
-
-// Returns a tuple of (pairs_offset, end_of_pairs_offset),
-// from the start of a mallocated array.
-#[inline]
-fn calculate_offsets(hashes_size: usize,
-                     pairs_size: usize,
-                     pairs_align: usize)
-                     -> (usize, usize, bool) {
-    let pairs_offset = round_up_to_next(hashes_size, pairs_align);
-    let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size);
-
-    (pairs_offset, end_of_pairs, oflo)
-}
-
-// Returns a tuple of (minimum required malloc alignment,
-// array_size), from the start of a mallocated array.
-fn calculate_allocation(hash_size: usize,
-                        hash_align: usize,
-                        pairs_size: usize,
-                        pairs_align: usize)
-                        -> (usize, usize, bool) {
-    let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align);
-
-    let align = cmp::max(hash_align, pairs_align);
-
-    (align, end_of_pairs, oflo)
-}
-
-#[test]
-fn test_offset_calculation() {
-    assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false));
-    assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false));
-    assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false));
-    assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false));
-    assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false));
-    assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false));
+// Returns a Layout which describes the allocation required for a hash table,
+// and the offset of the array of (key, value) pairs in the allocation.
+fn calculate_layout<K, V>(capacity: usize) -> Result<(Layout, usize), LayoutErr> {
+    let hashes = Layout::array::<HashUint>(capacity)?;
+    let pairs = Layout::array::<(K, V)>(capacity)?;
+    hashes.extend(pairs)
 }
 
 pub(crate) enum Fallibility {
@@ -735,37 +682,11 @@ impl<K, V> RawTable<K, V> {
             });
         }
 
-        // No need for `checked_mul` before a more restrictive check performed
-        // later in this method.
-        let hashes_size = capacity.wrapping_mul(size_of::<HashUint>());
-        let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>());
-
         // Allocating hashmaps is a little tricky. We need to allocate two
         // arrays, but since we know their sizes and alignments up front,
         // we just allocate a single array, and then have the subarrays
         // point into it.
-        //
-        // This is great in theory, but in practice getting the alignment
-        // right is a little subtle. Therefore, calculating offsets has been
-        // factored out into a different function.
-        let (alignment, size, oflo) = calculate_allocation(hashes_size,
-                                                           align_of::<HashUint>(),
-                                                           pairs_size,
-                                                           align_of::<(K, V)>());
-        if oflo {
-            return Err(CollectionAllocErr::CapacityOverflow);
-        }
-
-        // One check for overflow that covers calculation and rounding of size.
-        let size_of_bucket = size_of::<HashUint>().checked_add(size_of::<(K, V)>())
-            .ok_or(CollectionAllocErr::CapacityOverflow)?;
-        let capacity_mul_size_of_bucket = capacity.checked_mul(size_of_bucket);
-        if capacity_mul_size_of_bucket.is_none() || size < capacity_mul_size_of_bucket.unwrap() {
-            return Err(CollectionAllocErr::CapacityOverflow);
-        }
-
-        let layout = Layout::from_size_align(size, alignment)
-            .map_err(|_| CollectionAllocErr::CapacityOverflow)?;
+        let (layout, _) = calculate_layout::<K, V>(capacity)?;
         let buffer = Global.alloc(layout).map_err(|e| match fallibility {
             Infallible => oom(layout),
             Fallible => e,
@@ -790,18 +711,12 @@ impl<K, V> RawTable<K, V> {
     }
 
     fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> {
-        let hashes_size = self.capacity() * size_of::<HashUint>();
-        let pairs_size = self.capacity() * size_of::<(K, V)>();
-
-        let (pairs_offset, _, oflo) =
-            calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>());
-        debug_assert!(!oflo, "capacity overflow");
-
+        let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity()).unwrap();
         let buffer = self.hashes.ptr() as *mut u8;
         unsafe {
             RawBucket {
                 hash_start: buffer as *mut HashUint,
-                pair_start: buffer.offset(pairs_offset as isize) as *const (K, V),
+                pair_start: buffer.add(pairs_offset) as *const (K, V),
                 idx: index,
                 _marker: marker::PhantomData,
             }
@@ -1194,18 +1109,9 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
             }
         }
 
-        let hashes_size = self.capacity() * size_of::<HashUint>();
-        let pairs_size = self.capacity() * size_of::<(K, V)>();
-        let (align, size, oflo) = calculate_allocation(hashes_size,
-                                                       align_of::<HashUint>(),
-                                                       pairs_size,
-                                                       align_of::<(K, V)>());
-
-        debug_assert!(!oflo, "should be impossible");
-
+        let (layout, _) = calculate_layout::<K, V>(self.capacity()).unwrap();
         unsafe {
-            Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(),
-                           Layout::from_size_align(size, align).unwrap());
+            Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout);
             // Remember how everything was allocated out of one buffer
             // during initialization? We only need one call to free here.
         }
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 442a0873ae0..987687ea8e8 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -295,8 +295,6 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
 /// # Examples
 ///
 /// ```no_run
-/// #![feature(fs_read_write)]
-///
 /// use std::fs;
 /// use std::net::SocketAddr;
 ///
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index c4092dcd388..774340388e1 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -890,8 +890,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
                     )
             };
             if let Err(ref copy_err) = copy_result {
-                if let Some(libc::ENOSYS) = copy_err.raw_os_error() {
-                    HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed);
+                match copy_err.raw_os_error() {
+                    Some(libc::ENOSYS) | Some(libc::EPERM) => {
+                        HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed);
+                    }
+                    _ => {}
                 }
             }
             copy_result
@@ -902,9 +905,13 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
             Ok(ret) => written += ret as u64,
             Err(err) => {
                 match err.raw_os_error() {
-                    Some(os_err) if os_err == libc::ENOSYS || os_err == libc::EXDEV => {
-                        // Either kernel is too old or the files are not mounted on the same fs.
-                        // Try again with fallback method
+                    Some(os_err) if os_err == libc::ENOSYS
+                                 || os_err == libc::EXDEV
+                                 || os_err == libc::EPERM => {
+                        // Try fallback io::copy if either:
+                        // - Kernel version is < 4.5 (ENOSYS)
+                        // - Files are mounted on different fs (EXDEV)
+                        // - copy_file_range is disallowed, for example by seccomp (EPERM)
                         assert_eq!(written, 0);
                         let ret = io::copy(&mut reader, &mut writer)?;
                         writer.set_permissions(perm)?;
diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr
index 5753d1a32f7..b3d82e9094b 100644
--- a/src/test/ui/hygiene/no_implicit_prelude.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude.stderr
@@ -22,7 +22,7 @@ LL |         ().clone() //~ ERROR no method named `clone` found
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
-           candidate #1: `use std::clone::Clone;`
+           `use std::clone::Clone;`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/hygiene/trait_items.stderr b/src/test/ui/hygiene/trait_items.stderr
index 56d9c585d6f..1b2975bcf1c 100644
--- a/src/test/ui/hygiene/trait_items.stderr
+++ b/src/test/ui/hygiene/trait_items.stderr
@@ -9,7 +9,7 @@ LL |     pub macro m() { ().f() } //~ ERROR no method named `f` found for type `
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
-           candidate #1: `use foo::T;`
+           `use foo::T;`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr
index dc2cd4c2ddc..e31134f843b 100644
--- a/src/test/ui/span/issue-7575.stderr
+++ b/src/test/ui/span/issue-7575.stderr
@@ -2,10 +2,9 @@ error[E0599]: no method named `f9` found for type `usize` in the current scope
   --> $DIR/issue-7575.rs:74:18
    |
 LL |     u.f8(42) + u.f9(342) + m.fff(42)
-   |                  ^^
+   |                  ^^ this is an associated function, not a method
    |
    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
-   = help: try with `usize::f9`
 note: candidate #1 is defined in the trait `CtxtFn`
   --> $DIR/issue-7575.rs:16:5
    |
@@ -37,11 +36,13 @@ LL | struct Myisize(isize);
    | ---------------------- method `fff` not found for this
 ...
 LL |     u.f8(42) + u.f9(342) + m.fff(42)
-   |                              ^^^
+   |                            --^^^
+   |                            | |
+   |                            | this is an associated function, not a method
+   |                            help: use associated function syntax instead: `Myisize::fff`
    |
    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
-   = help: try with `Myisize::fff`
-note: candidate #1 is defined in an impl for the type `Myisize`
+note: the candidate is defined in an impl for the type `Myisize`
   --> $DIR/issue-7575.rs:51:5
    |
 LL |     fn fff(i: isize) -> isize {
@@ -51,11 +52,10 @@ error[E0599]: no method named `is_str` found for type `T` in the current scope
   --> $DIR/issue-7575.rs:82:7
    |
 LL |     t.is_str()
-   |       ^^^^^^
+   |       ^^^^^^ this is an associated function, not a method
    |
    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
-   = help: try with `T::is_str`
-note: candidate #1 is defined in the trait `ManyImplTrait`
+note: the candidate is defined in the trait `ManyImplTrait`
   --> $DIR/issue-7575.rs:57:5
    |
 LL |     fn is_str() -> bool {