From 7d296c4843785f64a4246213375b21c1ab1e7462 Mon Sep 17 00:00:00 2001
From: Vitali Lovich <vlovich@google.com>
Date: Fri, 2 Feb 2018 11:17:48 -0800
Subject: [PATCH 01/46] Add Condvar APIs not susceptible to spurious wake

Provide wait_until and wait_timeout_until helper wrappers that aren't
susceptible to spurious wake.
---
 src/libstd/sync/condvar.rs | 207 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 205 insertions(+), 2 deletions(-)

diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 564021758176b..1e5beaaa34275 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -14,7 +14,7 @@ use sync::{mutex, MutexGuard, PoisonError};
 use sys_common::condvar as sys;
 use sys_common::mutex as sys_mutex;
 use sys_common::poison::{self, LockResult};
-use time::Duration;
+use time::{Duration, Instant};
 
 /// A type indicating whether a timed wait on a condition variable returned
 /// due to a time out or not.
@@ -219,6 +219,61 @@ impl Condvar {
         }
     }
 
+    /// Blocks the current thread until this condition variable receives a
+    /// notification and the required condition is met. There are no spurious
+    /// wakeups when calling this.
+    ///
+    /// This function will atomically unlock the mutex specified (represented by
+    /// `guard`) and block the current thread. This means that any calls
+    /// to [`notify_one`] or [`notify_all`] which happen logically after the
+    /// mutex is unlocked are candidates to wake this thread up. When this
+    /// function call returns, the lock specified will have been re-acquired.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the mutex being waited on is
+    /// poisoned when this thread re-acquires the lock. For more information,
+    /// see information about [poisoning] on the [`Mutex`] type.
+    ///
+    /// [`notify_one`]: #method.notify_one
+    /// [`notify_all`]: #method.notify_all
+    /// [poisoning]: ../sync/struct.Mutex.html#poisoning
+    /// [`Mutex`]: ../sync/struct.Mutex.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = pair.clone();
+    ///
+    /// thread::spawn(move|| {
+    ///     let &(ref lock, ref cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // Wait for the thread to start up.
+    /// let &(ref lock, ref cvar) = &*pair;
+    /// // As long as the value inside the `Mutex` is false, we wait.
+    /// cvar.wait_until(lock.lock().unwrap(), |ref started| { started });
+    /// ```
+    #[stable(feature = "wait_until", since = "1.24")]
+    pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
+                                mut condition: F)
+                                -> LockResult<MutexGuard<'a, T>>
+                                where F: FnMut(&T) -> bool {
+        while !condition(&*guard) {
+            guard = self.wait(guard)?;
+        }
+        Ok(guard)
+    }
+
+
     /// Waits on this condition variable for a notification, timing out after a
     /// specified duration.
     ///
@@ -293,7 +348,15 @@ impl Condvar {
     ///
     /// Note that the best effort is made to ensure that the time waited is
     /// measured with a monotonic clock, and not affected by the changes made to
-    /// the system time.
+    /// the system time.  This function is susceptible to spurious wakeups.
+    /// Condition variables normally have a boolean predicate associated with
+    /// them, and the predicate must always be checked each time this function
+    /// returns to protect against spurious wakeups.  Additionally, it is
+    /// typically desirable for the time-out to not exceed some duration in
+    /// spite of spurious wakes, thus the sleep-duration is decremented by the
+    /// amount slept.  Alternatively, use the `wait_timeout_until` method
+    /// to wait until a condition is met with a total time-out regardless
+    /// of spurious wakes.
     ///
     /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
     /// known to have elapsed.
@@ -302,6 +365,7 @@ impl Condvar {
     /// returns, regardless of whether the timeout elapsed or not.
     ///
     /// [`wait`]: #method.wait
+    /// [`wait_timeout_until`]: #method.wait_timeout_until
     /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
     ///
     /// # Examples
@@ -353,6 +417,76 @@ impl Condvar {
         }
     }
 
+    /// Waits on this condition variable for a notification, timing out after a
+    /// specified duration.
+    ///
+    /// The semantics of this function are equivalent to [`wait_until`] except
+    /// that the thread will be blocked for roughly no longer than `dur`. This
+    /// method should not be used for precise timing due to anomalies such as
+    /// preemption or platform differences that may not cause the maximum
+    /// amount of time waited to be precisely `dur`.
+    ///
+    /// Note that the best effort is made to ensure that the time waited is
+    /// measured with a monotonic clock, and not affected by the changes made to
+    /// the system time.
+    ///
+    /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
+    /// known to have elapsed without the condition being met.
+    ///
+    /// Like [`wait_until`], the lock specified will be re-acquired when this
+    /// function returns, regardless of whether the timeout elapsed or not.
+    ///
+    /// [`wait_until`]: #method.wait_until
+    /// [`wait_timeout`]: #method.wait_timeout
+    /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex, Condvar};
+    /// use std::thread;
+    /// use std::time::Duration;
+    ///
+    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+    /// let pair2 = pair.clone();
+    ///
+    /// thread::spawn(move|| {
+    ///     let &(ref lock, ref cvar) = &*pair2;
+    ///     let mut started = lock.lock().unwrap();
+    ///     *started = true;
+    ///     // We notify the condvar that the value has changed.
+    ///     cvar.notify_one();
+    /// });
+    ///
+    /// // wait for the thread to start up
+    /// let &(ref lock, ref cvar) = &*pair;
+    /// let result = cvar.wait_timeout_until(lock, Duration::from_millis(100), |started| {
+    ///     started
+    /// }).unwrap();
+    /// if result.1.timed_out() {
+    ///     // timed-out without the condition ever evaluating to true.
+    /// }
+    /// // access the locked mutex via result.0
+    /// ```
+    #[stable(feature = "wait_timeout_until", since = "1.24")]
+    pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
+                                        mut dur: Duration, mut condition: F)
+                                        -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
+                                        where F: FnMut(&T) -> bool {
+        let timed_out = Duration::new(0, 0);
+        loop {
+            if !condition(&*guard) {
+                return Ok((guard, WaitTimeoutResult(false)));
+            } else if dur == timed_out {
+                return Ok((guard, WaitTimeoutResult(false)));
+            }
+            let wait_timer = Instant::now();
+            let wait_result = self.wait_timeout(guard, dur)?;
+            dur = dur.checked_sub(wait_timer.elapsed()).unwrap_or(timed_out);
+            guard = wait_result.0;
+        }
+    }
+
     /// Wakes up one blocked thread on this condvar.
     ///
     /// If there is a blocked thread on this condition variable, then it will
@@ -546,6 +680,29 @@ mod tests {
         }
     }
 
+    #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
+    fn wait_until() {
+        let pair = Arc::new((Mutex::new(false), Condvar::new()));
+        let pair2 = pair.clone();
+
+        // Inside of our lock, spawn a new thread, and then wait for it to start.
+        thread::spawn(move|| {
+            let &(ref lock, ref cvar) = &*pair2;
+            let mut started = lock.lock().unwrap();
+            *started = true;
+            // We notify the condvar that the value has changed.
+            cvar.notify_one();
+        });
+
+        // Wait for the thread to start up.
+        let &(ref lock, ref cvar) = &*pair;
+        let guard = cvar.wait_until(lock.lock().unwrap(), |started| {
+            started
+        });
+        assert!(*guard);
+    }
+
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
     fn wait_timeout_wait() {
@@ -565,6 +722,52 @@ mod tests {
         }
     }
 
+    #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
+    fn wait_timeout_until_wait() {
+        let m = Arc::new(Mutex::new(()));
+        let c = Arc::new(Condvar::new());
+
+        let g = m.lock().unwrap();
+        let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), || { false }).unwrap();
+        // no spurious wakeups. ensure it timed-out
+        assert!(wait.timed_out());
+    }
+
+    #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
+    fn wait_timeout_until_instant_satisfy() {
+        let m = Arc::new(Mutex::new(()));
+        let c = Arc::new(Condvar::new());
+
+        let g = m.lock().unwrap();
+        let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), || { true }).unwrap();
+        // ensure it didn't time-out even if we were not given any time.
+        assert!(!wait.timed_out());
+    }
+
+    #[test]
+    #[cfg_attr(target_os = "emscripten", ignore)]
+    fn wait_timeout_until_wake() {
+        let pair = Arc::new((Mutex::new(false), Condvar::new()));
+        let pair_copy = pair.clone();
+
+        let g = m.lock().unwrap();
+        let t = thread::spawn(move || {
+            let &(ref lock, ref cvar) = &*pair2;
+            let mut started = lock.lock().unwrap();
+            thread::sleep(Duration::from_millis(1));
+            started = true;
+            cvar.notify_one();
+        });
+        let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&notified| {
+            notified
+        }).unwrap();
+        // ensure it didn't time-out even if we were not given any time.
+        assert!(!wait.timed_out());
+        assert!(*g2);
+    }
+
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
     fn wait_timeout_wake() {

From 404e1a67007a254ab35e4fe8a8650e9335590a76 Mon Sep 17 00:00:00 2001
From: Vitali Lovich <vlovich@google.com>
Date: Fri, 2 Feb 2018 11:52:16 -0800
Subject: [PATCH 02/46] Fix typo

---
 src/libstd/sync/condvar.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 1e5beaaa34275..c58f8fd299010 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -478,7 +478,7 @@ impl Condvar {
             if !condition(&*guard) {
                 return Ok((guard, WaitTimeoutResult(false)));
             } else if dur == timed_out {
-                return Ok((guard, WaitTimeoutResult(false)));
+                return Ok((guard, WaitTimeoutResult(true)));
             }
             let wait_timer = Instant::now();
             let wait_result = self.wait_timeout(guard, dur)?;

From e72bd6df5398dd7ee02c6057b861537c49649b4e Mon Sep 17 00:00:00 2001
From: Vitali Lovich <vlovich@google.com>
Date: Fri, 2 Feb 2018 12:07:16 -0800
Subject: [PATCH 03/46] Review response

Make condition closure accept mut T&.
Clarify spurious wakeup documentation.
Cleanup doc example code.
---
 src/libstd/sync/condvar.rs | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index c58f8fd299010..76b68fc4f4fe9 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -220,8 +220,9 @@ impl Condvar {
     }
 
     /// Blocks the current thread until this condition variable receives a
-    /// notification and the required condition is met. There are no spurious
-    /// wakeups when calling this.
+    /// notification and the required condition is met. Spurious wakeups are
+    /// ignored and this function will only return once the condition has been
+    /// met.
     ///
     /// This function will atomically unlock the mutex specified (represented by
     /// `guard`) and block the current thread. This means that any calls
@@ -260,14 +261,14 @@ impl Condvar {
     /// // Wait for the thread to start up.
     /// let &(ref lock, ref cvar) = &*pair;
     /// // As long as the value inside the `Mutex` is false, we wait.
-    /// cvar.wait_until(lock.lock().unwrap(), |ref started| { started });
+    /// cvar.wait_until(lock.lock().unwrap(), |started| { started });
     /// ```
     #[stable(feature = "wait_until", since = "1.24")]
     pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
                                 mut condition: F)
                                 -> LockResult<MutexGuard<'a, T>>
-                                where F: FnMut(&T) -> bool {
-        while !condition(&*guard) {
+                                where F: FnMut(&mut T) -> bool {
+        while !condition(&mut *guard) {
             guard = self.wait(guard)?;
         }
         Ok(guard)
@@ -418,7 +419,8 @@ impl Condvar {
     }
 
     /// Waits on this condition variable for a notification, timing out after a
-    /// specified duration.
+    /// specified duration.  Spurious wakes will not cause this function to
+    /// return.
     ///
     /// The semantics of this function are equivalent to [`wait_until`] except
     /// that the thread will be blocked for roughly no longer than `dur`. This
@@ -472,10 +474,10 @@ impl Condvar {
     pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
                                         mut dur: Duration, mut condition: F)
                                         -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
-                                        where F: FnMut(&T) -> bool {
+                                        where F: FnMut(&mut T) -> bool {
         let timed_out = Duration::new(0, 0);
         loop {
-            if !condition(&*guard) {
+            if !condition(&mut *guard) {
                 return Ok((guard, WaitTimeoutResult(false)));
             } else if dur == timed_out {
                 return Ok((guard, WaitTimeoutResult(true)));

From 95e4dc2ad143c91d0930ea28634e6f5c54ac0812 Mon Sep 17 00:00:00 2001
From: Vitali Lovich <vlovich@google.com>
Date: Mon, 5 Feb 2018 15:11:00 -0800
Subject: [PATCH 04/46] Simplify wait_timeout_until & fix condition typo

---
 src/libstd/sync/condvar.rs | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 76b68fc4f4fe9..e6a3388aa2587 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -475,17 +475,16 @@ impl Condvar {
                                         mut dur: Duration, mut condition: F)
                                         -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
                                         where F: FnMut(&mut T) -> bool {
-        let timed_out = Duration::new(0, 0);
+        let start = Instant::now();
         loop {
-            if !condition(&mut *guard) {
+            if condition(&mut *guard) {
                 return Ok((guard, WaitTimeoutResult(false)));
-            } else if dur == timed_out {
-                return Ok((guard, WaitTimeoutResult(true)));
             }
-            let wait_timer = Instant::now();
-            let wait_result = self.wait_timeout(guard, dur)?;
-            dur = dur.checked_sub(wait_timer.elapsed()).unwrap_or(timed_out);
-            guard = wait_result.0;
+            let timeout = match dur.checked_sub(start.elapsed()) {
+                Some(timeout) => timeout,
+                None => return Ok((guard, WaitTimeoutResult(true))),
+            }
+            guard = self.wait_timeout(guard, dur)?.0;
         }
     }
 

From 770fdeddb4ca7cedca41a391d4b283069e1d9a8c Mon Sep 17 00:00:00 2001
From: hedgehog1024 <hedgehog1024@scryptmail.com>
Date: Mon, 12 Feb 2018 22:19:37 +0300
Subject: [PATCH 05/46] Stabilize 'entry_and_modify' feature for BTreeMap

---
 src/liballoc/btree/map.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs
index b320bed54320a..b98489c516a05 100644
--- a/src/liballoc/btree/map.rs
+++ b/src/liballoc/btree/map.rs
@@ -2114,7 +2114,6 @@ impl<'a, K: Ord, V> Entry<'a, K, V> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(entry_and_modify)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
@@ -2129,7 +2128,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> {
     ///    .or_insert(42);
     /// assert_eq!(map["poneyland"], 43);
     /// ```
-    #[unstable(feature = "entry_and_modify", issue = "44733")]
+    #[stable(feature = "entry_and_modify", since = "1.25.0")]
     pub fn and_modify<F>(self, mut f: F) -> Self
         where F: FnMut(&mut V)
     {

From 862132be72d4de87330e31d53489b8c718a6663e Mon Sep 17 00:00:00 2001
From: hedgehog1024 <hedgehog1024@scryptmail.com>
Date: Mon, 12 Feb 2018 22:25:03 +0300
Subject: [PATCH 06/46] Stabilize 'entry_and_modify' feature for HashMap

---
 src/libstd/collections/hash/map.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 82a687ae5e493..80e52123a0177 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -2066,7 +2066,6 @@ impl<'a, K, V> Entry<'a, K, V> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(entry_and_modify)]
     /// use std::collections::HashMap;
     ///
     /// let mut map: HashMap<&str, u32> = HashMap::new();
@@ -2081,7 +2080,7 @@ impl<'a, K, V> Entry<'a, K, V> {
     ///    .or_insert(42);
     /// assert_eq!(map["poneyland"], 43);
     /// ```
-    #[unstable(feature = "entry_and_modify", issue = "44733")]
+    #[stable(feature = "entry_and_modify", since = "1.25.0")]
     pub fn and_modify<F>(self, mut f: F) -> Self
         where F: FnMut(&mut V)
     {

From 4360dfa126ba5d26a520e8a0d2dd9680081dad0d Mon Sep 17 00:00:00 2001
From: hedgehog1024 <hedgehog1024@scryptmail.com>
Date: Mon, 12 Feb 2018 22:27:33 +0300
Subject: [PATCH 07/46] Delete information about 'entry_and_modify' from
 Unstable book

---
 .../src/library-features/entry-and-modify.md  | 77 -------------------
 1 file changed, 77 deletions(-)
 delete mode 100644 src/doc/unstable-book/src/library-features/entry-and-modify.md

diff --git a/src/doc/unstable-book/src/library-features/entry-and-modify.md b/src/doc/unstable-book/src/library-features/entry-and-modify.md
deleted file mode 100644
index 1280c71e83c92..0000000000000
--- a/src/doc/unstable-book/src/library-features/entry-and-modify.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# `entry_and_modify`
-
-The tracking issue for this feature is: [#44733]
-
-[#44733]: https://github.com/rust-lang/rust/issues/44733
-
-------------------------
-
-This introduces a new method for the Entry API of maps
-(`std::collections::HashMap` and `std::collections::BTreeMap`), so that
-occupied entries can be modified before any potential inserts into the
-map.
-
-For example:
-
-```rust
-#![feature(entry_and_modify)]
-# fn main() {
-use std::collections::HashMap;
-
-struct Foo {
-    new: bool,
-}
-
-let mut map: HashMap<&str, Foo> = HashMap::new();
-
-map.entry("quux")
-   .and_modify(|e| e.new = false)
-   .or_insert(Foo { new: true });
-# }
-```
-
-This is not possible with the stable API alone since inserting a default
-_before_ modifying the `new` field would mean we would lose the default state:
-
-```rust
-# fn main() {
-use std::collections::HashMap;
-
-struct Foo {
-    new: bool,
-}
-
-let mut map: HashMap<&str, Foo> = HashMap::new();
-
-map.entry("quux").or_insert(Foo { new: true }).new = false;
-# }
-```
-
-In the above code the `new` field will never be `true`, even though we only
-intended to update that field to `false` for previously extant entries.
-
-To achieve the same effect as `and_modify` we would have to manually match
-against the `Occupied` and `Vacant` variants of the `Entry` enum, which is
-a little less user-friendly, and much more verbose:
-
-```rust
-# fn main() {
-use std::collections::HashMap;
-use std::collections::hash_map::Entry;
-
-struct Foo {
-    new: bool,
-}
-
-let mut map: HashMap<&str, Foo> = HashMap::new();
-
-match map.entry("quux") {
-    Entry::Occupied(entry) => {
-        entry.into_mut().new = false;
-    },
-    Entry::Vacant(entry) => {
-        entry.insert(Foo { new: true });
-    },
-};
-# }
-```

From 97df227d19791b0e9d199be28851fb924c3c1e21 Mon Sep 17 00:00:00 2001
From: Vitali Lovich <vlovich@google.com>
Date: Mon, 12 Feb 2018 21:08:14 -0800
Subject: [PATCH 08/46] Fix wait_timeout value

---
 src/libstd/sync/condvar.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index e6a3388aa2587..65235aa62a19b 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -484,7 +484,7 @@ impl Condvar {
                 Some(timeout) => timeout,
                 None => return Ok((guard, WaitTimeoutResult(true))),
             }
-            guard = self.wait_timeout(guard, dur)?.0;
+            guard = self.wait_timeout(guard, timeout)?.0;
         }
     }
 

From f45a474bd6c7ccfe35e7be5f341e3d04aa5d178e Mon Sep 17 00:00:00 2001
From: James Cowgill <jcowgill@debian.org>
Date: Tue, 6 Feb 2018 17:11:27 +0000
Subject: [PATCH 09/46] rustc_trans: add abi::CastTarget::ChunkedPrefix

---
 src/librustc_trans/abi.rs | 40 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 12698964d2e65..60f3105170b7d 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -407,7 +407,8 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum CastTarget {
     Uniform(Uniform),
-    Pair(Reg, Reg)
+    Pair(Reg, Reg),
+    ChunkedPrefix { prefix: [RegKind; 8], chunk: Size, total: Size }
 }
 
 impl From<Reg> for CastTarget {
@@ -429,7 +430,8 @@ impl CastTarget {
             CastTarget::Pair(a, b) => {
                 (a.size.abi_align(a.align(cx)) + b.size)
                     .abi_align(self.align(cx))
-            }
+            },
+            CastTarget::ChunkedPrefix { total, .. } => total
         }
     }
 
@@ -440,6 +442,12 @@ impl CastTarget {
                 cx.data_layout().aggregate_align
                     .max(a.align(cx))
                     .max(b.align(cx))
+            },
+            CastTarget::ChunkedPrefix { chunk, .. } => {
+                cx.data_layout().aggregate_align
+                    .max(Reg { kind: RegKind::Integer, size: chunk }.align(cx))
+                    .max(Reg { kind: RegKind::Float, size: chunk }.align(cx))
+                    .max(Reg { kind: RegKind::Vector, size: chunk }.align(cx))
             }
         }
     }
@@ -452,6 +460,34 @@ impl CastTarget {
                     a.llvm_type(cx),
                     b.llvm_type(cx)
                 ], false)
+            },
+            CastTarget::ChunkedPrefix { prefix, chunk, total } => {
+                let total_chunks = total.bytes() / chunk.bytes();
+                let rem_bytes = total.bytes() % chunk.bytes();
+                let prefix_chunks = total_chunks.min(prefix.len() as u64);
+
+                let int_ll_type = Reg { kind: RegKind::Integer, size: chunk }.llvm_type(cx);
+
+                // Simple cases simplify to an array
+                if rem_bytes == 0 && prefix.into_iter().all(|&kind| kind == RegKind::Integer) {
+                    return Type::array(&int_ll_type, total_chunks);
+                }
+
+                // The final structure is made up of:
+                //  Up to 8 chunks of the type specified in the prefix
+                //  Any other complete chunks as integers
+                //  One final integer needed to make up the total structure size
+                let mut args: Vec<_> =
+                    prefix.into_iter().take(prefix_chunks as usize)
+                        .map(|&kind| Reg { kind: kind, size: chunk }.llvm_type(cx))
+                    .chain((0..total_chunks - prefix_chunks).map(|_| int_ll_type))
+                    .collect();
+
+                if rem_bytes > 0 {
+                    args.push(Type::ix(cx, rem_bytes * 8));
+                }
+
+                Type::struct_(cx, &args, false)
             }
         }
     }

From 6fe2d1d765810c05ce2aa2184baa9f4aabf1a151 Mon Sep 17 00:00:00 2001
From: Vitali Lovich <vlovich@google.com>
Date: Tue, 13 Feb 2018 11:32:04 -0800
Subject: [PATCH 10/46] Misc fixes

Switch feature guards to unstable
Add missing semicolon
Remove mut that's no longer necessary
---
 src/libstd/sync/condvar.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 65235aa62a19b..98fadbd35439a 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -263,7 +263,7 @@ impl Condvar {
     /// // As long as the value inside the `Mutex` is false, we wait.
     /// cvar.wait_until(lock.lock().unwrap(), |started| { started });
     /// ```
-    #[stable(feature = "wait_until", since = "1.24")]
+    #[unstable(feature = "wait_until", issue = "47960")]
     pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
                                 mut condition: F)
                                 -> LockResult<MutexGuard<'a, T>>
@@ -470,9 +470,9 @@ impl Condvar {
     /// }
     /// // access the locked mutex via result.0
     /// ```
-    #[stable(feature = "wait_timeout_until", since = "1.24")]
+    #[unstable(feature = "wait_timeout_until", issue = "47960")]
     pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
-                                        mut dur: Duration, mut condition: F)
+                                        dur: Duration, mut condition: F)
                                         -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
                                         where F: FnMut(&mut T) -> bool {
         let start = Instant::now();
@@ -483,7 +483,7 @@ impl Condvar {
             let timeout = match dur.checked_sub(start.elapsed()) {
                 Some(timeout) => timeout,
                 None => return Ok((guard, WaitTimeoutResult(true))),
-            }
+            };
             guard = self.wait_timeout(guard, timeout)?.0;
         }
     }

From 16350526d8d8b514327c62b904d26f74937a1b23 Mon Sep 17 00:00:00 2001
From: Jimmy Brush <code@jimmah.com>
Date: Thu, 8 Feb 2018 07:48:16 -0500
Subject: [PATCH 11/46] pass correct pie args to gcc linker

When linking with gcc, run gcc -v to see if --enable-default-pie is
compiled in. If it is, pass -no-pie when necessary to disable pie.
Otherwise, pass -pie when necessary to enable it.

Fixes #48032 and fixes #35061
---
 src/librustc_trans/back/link.rs   | 66 ++++++++++++++++++++++++++-----
 src/librustc_trans/back/linker.rs | 10 +++++
 2 files changed, 66 insertions(+), 10 deletions(-)

diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index f050edcd513b9..a84ac5cb8bc2f 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -897,16 +897,33 @@ fn link_args(cmd: &mut Linker,
 
     let used_link_args = &trans.crate_info.link_args;
 
-    if crate_type == config::CrateTypeExecutable &&
-       t.options.position_independent_executables {
-        let empty_vec = Vec::new();
-        let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
-        let more_args = &sess.opts.cg.link_arg;
-        let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
-
-        if get_reloc_model(sess) == llvm::RelocMode::PIC
-            && !sess.crt_static() && !args.any(|x| *x == "-static") {
-            cmd.position_independent_executable();
+    if crate_type == config::CrateTypeExecutable {
+        let mut position_independent_executable = false;
+
+        if t.options.position_independent_executables {
+            let empty_vec = Vec::new();
+            let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
+            let more_args = &sess.opts.cg.link_arg;
+            let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter());
+
+            if get_reloc_model(sess) == llvm::RelocMode::PIC
+                && !sess.crt_static() && !args.any(|x| *x == "-static") {
+                position_independent_executable = true;
+            }
+        }
+
+        // Check to see if gcc defaults to generating a position independent
+        // executable. If so, tell it when to disable pie. Otherwise, tell it
+        // when to enable it. We can't do both because older versions of gcc
+        // don't understand -no-pie and will blow up.
+        if is_pie_default(sess) {
+            if !position_independent_executable {
+                cmd.no_position_independent_executable();
+            }
+        } else {
+            if position_independent_executable {
+                cmd.position_independent_executable();
+            }
         }
     }
 
@@ -1421,3 +1438,32 @@ fn is_full_lto_enabled(sess: &Session) -> bool {
         Lto::ThinLocal => false,
     }
 }
+
+fn is_pie_default(sess: &Session) -> bool {
+    match sess.linker_flavor() {
+        LinkerFlavor::Gcc => {
+            let (_, mut cmd, envs) = get_linker(sess);
+            // This will set PATH on windows
+            cmd.envs(envs);
+            cmd.arg("-v");
+
+            info!("{:?}", &cmd);
+
+            let output = cmd.command()
+                .stdout(Stdio::piped()).stderr(Stdio::piped())
+                .spawn()
+                .unwrap()
+                .wait_with_output()
+                .unwrap();
+
+            let ret = String::from_utf8_lossy(&output.stderr)
+                .contains("--enable-default-pie");
+
+            info!("gcc {} compiled with --enable-default-pie",
+                  if ret { "IS" } else { "is NOT" });
+
+            ret
+        },
+        _ => false,
+    }
+}
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index aa29c3cc12058..7e7811c56c74e 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -105,6 +105,7 @@ pub trait Linker {
     fn add_object(&mut self, path: &Path);
     fn gc_sections(&mut self, keep_metadata: bool);
     fn position_independent_executable(&mut self);
+    fn no_position_independent_executable(&mut self);
     fn partial_relro(&mut self);
     fn full_relro(&mut self);
     fn optimize(&mut self);
@@ -179,6 +180,7 @@ impl<'a> Linker for GccLinker<'a> {
     fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
     fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
     fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
+    fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); }
     fn partial_relro(&mut self) { self.linker_arg("-z,relro"); }
     fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); }
     fn build_static_executable(&mut self) { self.cmd.arg("-static"); }
@@ -439,6 +441,10 @@ impl<'a> Linker for MsvcLinker<'a> {
         // noop
     }
 
+    fn no_position_independent_executable(&mut self) {
+        // noop
+    }
+
     fn partial_relro(&mut self) {
         // noop
     }
@@ -647,6 +653,10 @@ impl<'a> Linker for EmLinker<'a> {
         // noop
     }
 
+    fn no_position_independent_executable(&mut self) {
+        // noop
+    }
+
     fn partial_relro(&mut self) {
         // noop
     }

From 8a72f589e5f8d628a5dcfcedbdd8eec117fbe2a2 Mon Sep 17 00:00:00 2001
From: Jimmy Brush <code@jimmah.com>
Date: Sat, 10 Feb 2018 13:16:59 -0500
Subject: [PATCH 12/46] pass correct pie args to gcc linker 2

Recent versions of gcc default to creating a position independent
executable and must be explicitly told not to with the -no-pie argument.

Old versions of gcc don't understand -no-pie and will throw an error.
Check for that case and retry without -no-pie. This is safe because
these old versions of gcc should never default to creating a position
independent executable.
---
 src/librustc_trans/back/link.rs | 66 ++++++++++++---------------------
 1 file changed, 23 insertions(+), 43 deletions(-)

diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index a84ac5cb8bc2f..d15450212ae37 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -652,9 +652,6 @@ fn link_natively(sess: &Session,
         prog = time(sess.time_passes(), "running linker", || {
             exec_linker(sess, &mut cmd, tmpdir)
         });
-        if !retry_on_segfault || i > 3 {
-            break
-        }
         let output = match prog {
             Ok(ref output) => output,
             Err(_) => break,
@@ -665,6 +662,26 @@ fn link_natively(sess: &Session,
         let mut out = output.stderr.clone();
         out.extend(&output.stdout);
         let out = String::from_utf8_lossy(&out);
+
+        // Check to see if the link failed with "unrecognized command line option:
+        // '-no-pie'". If so, reperform the link step without the -no-pie option. This
+        // is safe because if the linker doesn't support -no-pie then it should not
+        // default to linking executables as pie. Different versions of gcc seem to
+        // use different quotes in the error message so don't check for them.
+        if out.contains("unrecognized command line option") && out.contains("-no-pie") {
+            info!("linker output: {:?}", out);
+            warn!("Linker does not support -no-pie command line option. Retrying without.");
+            for arg in cmd.take_args() {
+                if arg.to_string_lossy() != "-no-pie" {
+                    cmd.arg(arg);
+                }
+            }
+            info!("{:?}", &cmd);
+            continue;
+        }
+        if !retry_on_segfault || i > 3 {
+            break
+        }
         let msg_segv = "clang: error: unable to execute command: Segmentation fault: 11";
         let msg_bus  = "clang: error: unable to execute command: Bus error: 10";
         if !(out.contains(msg_segv) || out.contains(msg_bus)) {
@@ -912,18 +929,10 @@ fn link_args(cmd: &mut Linker,
             }
         }
 
-        // Check to see if gcc defaults to generating a position independent
-        // executable. If so, tell it when to disable pie. Otherwise, tell it
-        // when to enable it. We can't do both because older versions of gcc
-        // don't understand -no-pie and will blow up.
-        if is_pie_default(sess) {
-            if !position_independent_executable {
-                cmd.no_position_independent_executable();
-            }
+        if position_independent_executable {
+            cmd.position_independent_executable();
         } else {
-            if position_independent_executable {
-                cmd.position_independent_executable();
-            }
+            cmd.no_position_independent_executable();
         }
     }
 
@@ -1438,32 +1447,3 @@ fn is_full_lto_enabled(sess: &Session) -> bool {
         Lto::ThinLocal => false,
     }
 }
-
-fn is_pie_default(sess: &Session) -> bool {
-    match sess.linker_flavor() {
-        LinkerFlavor::Gcc => {
-            let (_, mut cmd, envs) = get_linker(sess);
-            // This will set PATH on windows
-            cmd.envs(envs);
-            cmd.arg("-v");
-
-            info!("{:?}", &cmd);
-
-            let output = cmd.command()
-                .stdout(Stdio::piped()).stderr(Stdio::piped())
-                .spawn()
-                .unwrap()
-                .wait_with_output()
-                .unwrap();
-
-            let ret = String::from_utf8_lossy(&output.stderr)
-                .contains("--enable-default-pie");
-
-            info!("gcc {} compiled with --enable-default-pie",
-                  if ret { "IS" } else { "is NOT" });
-
-            ret
-        },
-        _ => false,
-    }
-}

From f0e9af1c5509ecd57c2398085b639abfb15f4ba1 Mon Sep 17 00:00:00 2001
From: Jimmy Brush <code@jimmah.com>
Date: Sun, 11 Feb 2018 10:50:18 -0500
Subject: [PATCH 13/46] verify passed -no-pie arg before retrying failed link

---
 src/librustc_trans/back/command.rs | 4 ++++
 src/librustc_trans/back/link.rs    | 4 +++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/librustc_trans/back/command.rs b/src/librustc_trans/back/command.rs
index 3b765a493e0e7..0bccef1e62a8e 100644
--- a/src/librustc_trans/back/command.rs
+++ b/src/librustc_trans/back/command.rs
@@ -109,6 +109,10 @@ impl Command {
 
     // extensions
 
+    pub fn get_args(&self) -> &[OsString] {
+        &self.args
+    }
+
     pub fn take_args(&mut self) -> Vec<OsString> {
         mem::replace(&mut self.args, Vec::new())
     }
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index d15450212ae37..6f8b425ad56dc 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -668,7 +668,9 @@ fn link_natively(sess: &Session,
         // is safe because if the linker doesn't support -no-pie then it should not
         // default to linking executables as pie. Different versions of gcc seem to
         // use different quotes in the error message so don't check for them.
-        if out.contains("unrecognized command line option") && out.contains("-no-pie") {
+        if out.contains("unrecognized command line option") &&
+           out.contains("-no-pie") &&
+           cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") {
             info!("linker output: {:?}", out);
             warn!("Linker does not support -no-pie command line option. Retrying without.");
             for arg in cmd.take_args() {

From c8def9222be5079585e15b2902039d371b7527ce Mon Sep 17 00:00:00 2001
From: Jimmy Brush <code@jimmah.com>
Date: Mon, 12 Feb 2018 13:32:55 -0500
Subject: [PATCH 14/46] handle -no-pie error from clang

---
 src/librustc_trans/back/link.rs | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 6f8b425ad56dc..0a3e6265c1b7e 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -664,11 +664,13 @@ fn link_natively(sess: &Session,
         let out = String::from_utf8_lossy(&out);
 
         // Check to see if the link failed with "unrecognized command line option:
-        // '-no-pie'". If so, reperform the link step without the -no-pie option. This
-        // is safe because if the linker doesn't support -no-pie then it should not
-        // default to linking executables as pie. Different versions of gcc seem to
-        // use different quotes in the error message so don't check for them.
-        if out.contains("unrecognized command line option") &&
+        // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so,
+        // reperform the link step without the -no-pie option. This is safe because
+        // if the linker doesn't support -no-pie then it should not default to
+        // linking executables as pie. Different versions of gcc seem to use
+        // different quotes in the error message so don't check for them.
+        if (out.contains("unrecognized command line option") ||
+            out.contains("unknown argument")) &&
            out.contains("-no-pie") &&
            cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") {
             info!("linker output: {:?}", out);

From ab9cae1ba192afcc35e8bd6a5fddcd1445d05da7 Mon Sep 17 00:00:00 2001
From: Jimmy Brush <code@jimmah.com>
Date: Tue, 13 Feb 2018 22:09:02 -0500
Subject: [PATCH 15/46] only pass -no-pie if linker_is_gnu

---
 src/librustc_trans/back/link.rs | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 0a3e6265c1b7e..8be4dc48d5122 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -669,7 +669,8 @@ fn link_natively(sess: &Session,
         // if the linker doesn't support -no-pie then it should not default to
         // linking executables as pie. Different versions of gcc seem to use
         // different quotes in the error message so don't check for them.
-        if (out.contains("unrecognized command line option") ||
+        if sess.target.target.options.linker_is_gnu &&
+           (out.contains("unrecognized command line option") ||
             out.contains("unknown argument")) &&
            out.contains("-no-pie") &&
            cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie") {
@@ -936,7 +937,12 @@ fn link_args(cmd: &mut Linker,
         if position_independent_executable {
             cmd.position_independent_executable();
         } else {
-            cmd.no_position_independent_executable();
+            // recent versions of gcc can be configured to generate position
+            // independent executables by default. We have to pass -no-pie to
+            // explicitly turn that off.
+            if sess.target.target.options.linker_is_gnu {
+                cmd.no_position_independent_executable();
+            }
         }
     }
 

From 68042ba0d35f16d66dadf62334ca6bbf20d97268 Mon Sep 17 00:00:00 2001
From: James Cowgill <jcowgill@debian.org>
Date: Thu, 8 Feb 2018 11:01:34 +0000
Subject: [PATCH 16/46] rustc_trans: rewrite mips64 abi

---
 src/librustc_trans/cabi_mips64.rs | 150 +++++++++++++++++++++++++-----
 1 file changed, 127 insertions(+), 23 deletions(-)

diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs
index e44063faab810..ad35dbeadfc8d 100644
--- a/src/librustc_trans/cabi_mips64.rs
+++ b/src/librustc_trans/cabi_mips64.rs
@@ -8,50 +8,154 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use abi::{ArgType, FnType, LayoutExt, Reg, Uniform};
+use abi::{ArgAttribute, ArgType, CastTarget, FnType, LayoutExt, PassMode, Reg, RegKind, Uniform};
 use context::CodegenCx;
+use rustc::ty::layout::{self, Size};
 
-use rustc::ty::layout::Size;
+fn extend_integer_width_mips(arg: &mut ArgType, bits: u64) {
+    // Always sign extend u32 values on 64-bit mips
+    if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
+        if let layout::Int(i, signed) = scalar.value {
+            if !signed && i.size().bits() == 32 {
+                if let PassMode::Direct(ref mut attrs) = arg.mode {
+                    attrs.set(ArgAttribute::SExt);
+                    return;
+                }
+            }
+        }
+    }
+
+    arg.extend_integer_width_to(bits);
+}
+
+fn bits_to_int_reg(bits: u64) -> Reg {
+    if bits <= 8 {
+        Reg::i8()
+    } else if bits <= 16 {
+        Reg::i16()
+    } else if bits <= 32 {
+        Reg::i32()
+    } else {
+        Reg::i64()
+    }
+}
 
-fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
-                             ret: &mut ArgType<'tcx>,
-                             offset: &mut Size) {
+fn float_reg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &ArgType<'tcx>, i: usize) -> Option<Reg> {
+    match ret.layout.field(cx, i).abi {
+        layout::Abi::Scalar(ref scalar) => match scalar.value {
+            layout::F32 => Some(Reg::f32()),
+            layout::F64 => Some(Reg::f64()),
+            _ => None
+        },
+        _ => None
+    }
+}
+
+fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
     if !ret.layout.is_aggregate() {
-        ret.extend_integer_width_to(64);
+        extend_integer_width_mips(ret, 64);
+        return;
+    }
+
+    let size = ret.layout.size;
+    let bits = size.bits();
+    if bits <= 128 {
+        // Unlike other architectures which return aggregates in registers, MIPS n64 limits the
+        // use of float registers to structures (not unions) containing exactly one or two
+        // float fields.
+
+        if let layout::FieldPlacement::Arbitrary { .. } = ret.layout.fields {
+            if ret.layout.fields.count() == 1 {
+                if let Some(reg) = float_reg(cx, ret, 0) {
+                    ret.cast_to(reg);
+                    return;
+                }
+            } else if ret.layout.fields.count() == 2 {
+                if let Some(reg0) = float_reg(cx, ret, 0) {
+                    if let Some(reg1) = float_reg(cx, ret, 1) {
+                        ret.cast_to(CastTarget::Pair(reg0, reg1));
+                        return;
+                    }
+                }
+            }
+        }
+
+        // Cast to a uniform int structure
+        ret.cast_to(Uniform {
+            unit: bits_to_int_reg(bits),
+            total: size
+        });
     } else {
         ret.make_indirect();
-        *offset += cx.tcx.data_layout.pointer_size;
     }
 }
 
-fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) {
+fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
+    if !arg.layout.is_aggregate() {
+        extend_integer_width_mips(arg, 64);
+        return;
+    }
+
     let dl = &cx.tcx.data_layout;
     let size = arg.layout.size;
-    let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align);
+    let mut prefix = [RegKind::Integer; 8];
+    let mut prefix_index = 0;
 
-    if arg.layout.is_aggregate() {
-        arg.cast_to(Uniform {
-            unit: Reg::i64(),
-            total: size
-        });
-        if !offset.is_abi_aligned(align) {
-            arg.pad_with(Reg::i64());
+    match arg.layout.fields {
+        layout::FieldPlacement::Array { .. } => {
+            // Arrays are passed indirectly
+            arg.make_indirect();
+            return;
         }
-    } else {
-        arg.extend_integer_width_to(64);
-    }
+        layout::FieldPlacement::Union(_) => {
+            // Unions and are always treated as a series of 64-bit integer chunks
+        },
+        layout::FieldPlacement::Arbitrary { .. } => {
+            // Structures are split up into a series of 64-bit integer chunks, but any aligned
+            // doubles not part of another aggregate are passed as floats.
+            let mut last_offset = Size::from_bytes(0);
+
+            for i in 0..arg.layout.fields.count() {
+                let field = arg.layout.field(cx, i);
+                let offset = arg.layout.fields.offset(i);
+
+                // We only care about aligned doubles
+                if let layout::Abi::Scalar(ref scalar) = field.abi {
+                    if let layout::F64 = scalar.value {
+                        if offset.is_abi_aligned(dl.f64_align) {
+                            // Skip over enough integers to cover [last_offset, offset)
+                            assert!(last_offset.is_abi_aligned(dl.f64_align));
+                            prefix_index += ((offset - last_offset).bits() / 64) as usize;
+
+                            if prefix_index >= prefix.len() {
+                                break;
+                            }
+
+                            prefix[prefix_index] = RegKind::Float;
+                            prefix_index += 1;
+                            last_offset = offset + Reg::f64().size;
+                        }
+                    }
+                }
+            }
+        }
+    };
 
-    *offset = offset.abi_align(align) + size.abi_align(align);
+    // Extract first 8 chunks as the prefix
+    arg.cast_to(CastTarget::ChunkedPrefix {
+        prefix: prefix,
+        chunk: Size::from_bytes(8),
+        total: size
+    });
 }
 
 pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) {
-    let mut offset = Size::from_bytes(0);
     if !fty.ret.is_ignore() {
-        classify_ret_ty(cx, &mut fty.ret, &mut offset);
+        classify_ret_ty(cx, &mut fty.ret);
     }
 
     for arg in &mut fty.args {
         if arg.is_ignore() { continue; }
-        classify_arg_ty(cx, arg, &mut offset);
+        classify_arg_ty(cx, arg);
     }
 }

From 05d66dc7a4ff053b5cbfa5ddafa890af291f4fc2 Mon Sep 17 00:00:00 2001
From: James Cowgill <jcowgill@debian.org>
Date: Wed, 14 Feb 2018 12:47:38 +0000
Subject: [PATCH 17/46] rustc_trans: add chunked prefix fields to CastTarget

---
 src/librustc_trans/abi.rs         | 138 +++++++++++-------------------
 src/librustc_trans/cabi_x86_64.rs |   2 +-
 2 files changed, 53 insertions(+), 87 deletions(-)

diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 60f3105170b7d..ee0f2415bd808 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -40,7 +40,7 @@ use rustc::ty::layout::{self, Align, Size, TyLayout};
 use rustc::ty::layout::{HasDataLayout, LayoutOf};
 
 use libc::c_uint;
-use std::{cmp, iter};
+use std::cmp;
 
 pub use syntax::abi::Abi;
 pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
@@ -279,30 +279,6 @@ impl Uniform {
     pub fn align(&self, cx: &CodegenCx) -> Align {
         self.unit.align(cx)
     }
-
-    pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
-        let llunit = self.unit.llvm_type(cx);
-
-        if self.total <= self.unit.size {
-            return llunit;
-        }
-
-        let count = self.total.bytes() / self.unit.size.bytes();
-        let rem_bytes = self.total.bytes() % self.unit.size.bytes();
-
-        if rem_bytes == 0 {
-            return Type::array(&llunit, count);
-        }
-
-        // Only integers can be really split further.
-        assert_eq!(self.unit.kind, RegKind::Integer);
-
-        let args: Vec<_> = (0..count).map(|_| llunit)
-            .chain(iter::once(Type::ix(cx, rem_bytes * 8)))
-            .collect();
-
-        Type::struct_(cx, &args, false)
-    }
 }
 
 pub trait LayoutExt<'tcx> {
@@ -405,91 +381,81 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub enum CastTarget {
-    Uniform(Uniform),
-    Pair(Reg, Reg),
-    ChunkedPrefix { prefix: [RegKind; 8], chunk: Size, total: Size }
+pub struct CastTarget {
+    pub prefix: [Option<RegKind>; 8],
+    pub prefix_chunk: Size,
+    pub rest: Uniform,
 }
 
 impl From<Reg> for CastTarget {
     fn from(unit: Reg) -> CastTarget {
-        CastTarget::Uniform(Uniform::from(unit))
+        CastTarget::from(Uniform::from(unit))
     }
 }
 
 impl From<Uniform> for CastTarget {
     fn from(uniform: Uniform) -> CastTarget {
-        CastTarget::Uniform(uniform)
+        CastTarget {
+            prefix: [None; 8],
+            prefix_chunk: Size::from_bytes(0),
+            rest: uniform
+        }
     }
 }
 
 impl CastTarget {
-    pub fn size(&self, cx: &CodegenCx) -> Size {
-        match *self {
-            CastTarget::Uniform(u) => u.total,
-            CastTarget::Pair(a, b) => {
-                (a.size.abi_align(a.align(cx)) + b.size)
-                    .abi_align(self.align(cx))
-            },
-            CastTarget::ChunkedPrefix { total, .. } => total
+    pub fn pair(a: Reg, b: Reg) -> CastTarget {
+        CastTarget {
+            prefix: [Some(a.kind), None, None, None, None, None, None, None],
+            prefix_chunk: a.size,
+            rest: Uniform::from(b)
         }
     }
 
+    pub fn size(&self, cx: &CodegenCx) -> Size {
+        (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
+            .abi_align(self.rest.align(cx)) + self.rest.total
+    }
+
     pub fn align(&self, cx: &CodegenCx) -> Align {
-        match *self {
-            CastTarget::Uniform(u) => u.align(cx),
-            CastTarget::Pair(a, b) => {
-                cx.data_layout().aggregate_align
-                    .max(a.align(cx))
-                    .max(b.align(cx))
-            },
-            CastTarget::ChunkedPrefix { chunk, .. } => {
-                cx.data_layout().aggregate_align
-                    .max(Reg { kind: RegKind::Integer, size: chunk }.align(cx))
-                    .max(Reg { kind: RegKind::Float, size: chunk }.align(cx))
-                    .max(Reg { kind: RegKind::Vector, size: chunk }.align(cx))
-            }
-        }
+        self.prefix.iter()
+            .filter_map(|x| x.map(|kind| Reg { kind: kind, size: self.prefix_chunk }.align(cx)))
+            .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)),
+                |acc, align| acc.max(align))
     }
 
     pub fn llvm_type(&self, cx: &CodegenCx) -> Type {
-        match *self {
-            CastTarget::Uniform(u) => u.llvm_type(cx),
-            CastTarget::Pair(a, b) => {
-                Type::struct_(cx, &[
-                    a.llvm_type(cx),
-                    b.llvm_type(cx)
-                ], false)
-            },
-            CastTarget::ChunkedPrefix { prefix, chunk, total } => {
-                let total_chunks = total.bytes() / chunk.bytes();
-                let rem_bytes = total.bytes() % chunk.bytes();
-                let prefix_chunks = total_chunks.min(prefix.len() as u64);
-
-                let int_ll_type = Reg { kind: RegKind::Integer, size: chunk }.llvm_type(cx);
+        let rest_ll_unit = self.rest.unit.llvm_type(cx);
+        let rest_count = self.rest.total.bytes() / self.rest.unit.size.bytes();
+        let rem_bytes = self.rest.total.bytes() % self.rest.unit.size.bytes();
+
+        if self.prefix.iter().all(|x| x.is_none()) {
+            // Simplify to a single unit when there is no prefix and size <= unit size
+            if self.rest.total <= self.rest.unit.size {
+                return rest_ll_unit;
+            }
 
-                // Simple cases simplify to an array
-                if rem_bytes == 0 && prefix.into_iter().all(|&kind| kind == RegKind::Integer) {
-                    return Type::array(&int_ll_type, total_chunks);
-                }
+            // Simplify to array when all chunks are the same size and type
+            if rem_bytes == 0 {
+                return Type::array(&rest_ll_unit, rest_count);
+            }
+        }
 
-                // The final structure is made up of:
-                //  Up to 8 chunks of the type specified in the prefix
-                //  Any other complete chunks as integers
-                //  One final integer needed to make up the total structure size
-                let mut args: Vec<_> =
-                    prefix.into_iter().take(prefix_chunks as usize)
-                        .map(|&kind| Reg { kind: kind, size: chunk }.llvm_type(cx))
-                    .chain((0..total_chunks - prefix_chunks).map(|_| int_ll_type))
-                    .collect();
-
-                if rem_bytes > 0 {
-                    args.push(Type::ix(cx, rem_bytes * 8));
-                }
+        // Create list of fields in the main structure
+        let mut args: Vec<_> =
+            self.prefix.iter().flat_map(|option_kind| option_kind.map(
+                    |kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx)))
+            .chain((0..rest_count).map(|_| rest_ll_unit))
+            .collect();
 
-                Type::struct_(cx, &args, false)
-            }
+        // Append final integer
+        if rem_bytes != 0 {
+            // Only integers can be really split further.
+            assert_eq!(self.rest.unit.kind, RegKind::Integer);
+            args.push(Type::ix(cx, rem_bytes * 8));
         }
+
+        Type::struct_(cx, &args, false)
     }
 }
 
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index b8144a3ca7a3e..7eadaa7f493a3 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -171,7 +171,7 @@ fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
     let mut target = CastTarget::from(lo);
     if size > offset {
         if let Some(hi) = reg_component(cls, &mut i, size - offset) {
-            target = CastTarget::Pair(lo, hi);
+            target = CastTarget::pair(lo, hi);
         }
     }
     assert_eq!(reg_component(cls, &mut i, Size::from_bytes(0)), None);

From 47c33f7bd0535fe6e47e38700ac1c8bf33e3f0d5 Mon Sep 17 00:00:00 2001
From: James Cowgill <jcowgill@debian.org>
Date: Wed, 14 Feb 2018 12:48:04 +0000
Subject: [PATCH 18/46] rustc_trans: adjust mips64 abi to use new CastTarget

---
 src/librustc_trans/cabi_mips64.rs | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs
index ad35dbeadfc8d..94bf53cee1edb 100644
--- a/src/librustc_trans/cabi_mips64.rs
+++ b/src/librustc_trans/cabi_mips64.rs
@@ -73,7 +73,7 @@ fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>)
             } else if ret.layout.fields.count() == 2 {
                 if let Some(reg0) = float_reg(cx, ret, 0) {
                     if let Some(reg1) = float_reg(cx, ret, 1) {
-                        ret.cast_to(CastTarget::Pair(reg0, reg1));
+                        ret.cast_to(CastTarget::pair(reg0, reg1));
                         return;
                     }
                 }
@@ -98,7 +98,7 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>)
 
     let dl = &cx.tcx.data_layout;
     let size = arg.layout.size;
-    let mut prefix = [RegKind::Integer; 8];
+    let mut prefix = [None; 8];
     let mut prefix_index = 0;
 
     match arg.layout.fields {
@@ -123,15 +123,20 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>)
                 if let layout::Abi::Scalar(ref scalar) = field.abi {
                     if let layout::F64 = scalar.value {
                         if offset.is_abi_aligned(dl.f64_align) {
-                            // Skip over enough integers to cover [last_offset, offset)
+                            // Insert enough integers to cover [last_offset, offset)
                             assert!(last_offset.is_abi_aligned(dl.f64_align));
-                            prefix_index += ((offset - last_offset).bits() / 64) as usize;
+                            for _ in 0..((offset - last_offset).bits() / 64)
+                                .min((prefix.len() - prefix_index) as u64) {
 
-                            if prefix_index >= prefix.len() {
+                                prefix[prefix_index] = Some(RegKind::Integer);
+                                prefix_index += 1;
+                            }
+
+                            if prefix_index == prefix.len() {
                                 break;
                             }
 
-                            prefix[prefix_index] = RegKind::Float;
+                            prefix[prefix_index] = Some(RegKind::Float);
                             prefix_index += 1;
                             last_offset = offset + Reg::f64().size;
                         }
@@ -142,10 +147,11 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>)
     };
 
     // Extract first 8 chunks as the prefix
-    arg.cast_to(CastTarget::ChunkedPrefix {
+    let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
+    arg.cast_to(CastTarget {
         prefix: prefix,
-        chunk: Size::from_bytes(8),
-        total: size
+        prefix_chunk: Size::from_bytes(8),
+        rest: Uniform { unit: Reg::i64(), total: rest_size }
     });
 }
 

From ebec5e39067fdbc8abcad69e7933f6387a3b9fb7 Mon Sep 17 00:00:00 2001
From: "Jonathan A. Kollasch" <jakllsch@kollasch.net>
Date: Fri, 16 Feb 2018 14:29:24 -0600
Subject: [PATCH 19/46] Add powerpc-unknown-netbsd target

---
 src/bootstrap/native.rs                       |  1 +
 src/librustc_back/target/mod.rs               |  1 +
 .../target/powerpc_unknown_netbsd.rs          | 35 +++++++++++++++++++
 3 files changed, 37 insertions(+)
 create mode 100644 src/librustc_back/target/powerpc_unknown_netbsd.rs

diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 29cd23bdbb197..b44be44234805 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -480,6 +480,7 @@ impl Step for Openssl {
             "mips64el-unknown-linux-gnuabi64" => "linux64-mips64",
             "mipsel-unknown-linux-gnu" => "linux-mips32",
             "powerpc-unknown-linux-gnu" => "linux-ppc",
+            "powerpc-unknown-netbsd" => "BSD-generic32",
             "powerpc64-unknown-linux-gnu" => "linux-ppc64",
             "powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
             "s390x-unknown-linux-gnu" => "linux64-s390x",
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 2872c59157d6b..42ae2fc13ae05 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -186,6 +186,7 @@ supported_targets! {
     ("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
 
     ("i686-unknown-netbsd", i686_unknown_netbsd),
+    ("powerpc-unknown-netbsd", powerpc_unknown_netbsd),
     ("sparc64-unknown-netbsd", sparc64_unknown_netbsd),
     ("x86_64-unknown-netbsd", x86_64_unknown_netbsd),
     ("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd),
diff --git a/src/librustc_back/target/powerpc_unknown_netbsd.rs b/src/librustc_back/target/powerpc_unknown_netbsd.rs
new file mode 100644
index 0000000000000..2c78dbd206171
--- /dev/null
+++ b/src/librustc_back/target/powerpc_unknown_netbsd.rs
@@ -0,0 +1,35 @@
+// Copyright 2012 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 LinkerFlavor;
+use target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::netbsd_base::opts();
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+    base.max_atomic_width = Some(32);
+
+    // see #36994
+    base.exe_allocation_crate = None;
+
+    Ok(Target {
+        llvm_target: "powerpc-unknown-netbsd".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
+        arch: "powerpc".to_string(),
+        target_os: "netbsd".to_string(),
+        target_env: "".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: base,
+    })
+}

From b1f04a3a2e1a01ea1b77153dd8d22e7837542aa0 Mon Sep 17 00:00:00 2001
From: Vitali Lovich <vlovich@google.com>
Date: Thu, 15 Feb 2018 09:28:25 -0800
Subject: [PATCH 20/46] Fix unit test compilation

Also fix some code snippets in documentation.
---
 src/libstd/sync/condvar.rs | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 98fadbd35439a..546e105deb7e6 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -244,6 +244,8 @@ impl Condvar {
     /// # Examples
     ///
     /// ```
+    /// #![feature(wait_until)]
+    ///
     /// use std::sync::{Arc, Mutex, Condvar};
     /// use std::thread;
     ///
@@ -261,7 +263,7 @@ impl Condvar {
     /// // Wait for the thread to start up.
     /// let &(ref lock, ref cvar) = &*pair;
     /// // As long as the value inside the `Mutex` is false, we wait.
-    /// cvar.wait_until(lock.lock().unwrap(), |started| { started });
+    /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap();
     /// ```
     #[unstable(feature = "wait_until", issue = "47960")]
     pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
@@ -445,6 +447,8 @@ impl Condvar {
     /// # Examples
     ///
     /// ```
+    /// #![feature(wait_timeout_until)]
+    ///
     /// use std::sync::{Arc, Mutex, Condvar};
     /// use std::thread;
     /// use std::time::Duration;
@@ -462,8 +466,8 @@ impl Condvar {
     ///
     /// // wait for the thread to start up
     /// let &(ref lock, ref cvar) = &*pair;
-    /// let result = cvar.wait_timeout_until(lock, Duration::from_millis(100), |started| {
-    ///     started
+    /// let result = cvar.wait_timeout_until(lock.lock().unwrap(), Duration::from_millis(100), |started| {
+    ///     *started
     /// }).unwrap();
     /// if result.1.timed_out() {
     ///     // timed-out without the condition ever evaluating to true.
@@ -613,6 +617,7 @@ impl Drop for Condvar {
 
 #[cfg(test)]
 mod tests {
+    /// #![feature(wait_until)]
     use sync::mpsc::channel;
     use sync::{Condvar, Mutex, Arc};
     use sync::atomic::{AtomicBool, Ordering};
@@ -699,9 +704,9 @@ mod tests {
         // Wait for the thread to start up.
         let &(ref lock, ref cvar) = &*pair;
         let guard = cvar.wait_until(lock.lock().unwrap(), |started| {
-            started
+            *started
         });
-        assert!(*guard);
+        assert!(*guard.unwrap());
     }
 
     #[test]
@@ -730,7 +735,7 @@ mod tests {
         let c = Arc::new(Condvar::new());
 
         let g = m.lock().unwrap();
-        let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), || { false }).unwrap();
+        let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), |_| { false }).unwrap();
         // no spurious wakeups. ensure it timed-out
         assert!(wait.timed_out());
     }
@@ -742,7 +747,7 @@ mod tests {
         let c = Arc::new(Condvar::new());
 
         let g = m.lock().unwrap();
-        let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), || { true }).unwrap();
+        let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), |_| { true }).unwrap();
         // ensure it didn't time-out even if we were not given any time.
         assert!(!wait.timed_out());
     }
@@ -753,15 +758,16 @@ mod tests {
         let pair = Arc::new((Mutex::new(false), Condvar::new()));
         let pair_copy = pair.clone();
 
+        let &(ref m, ref c) = &*pair;
         let g = m.lock().unwrap();
-        let t = thread::spawn(move || {
-            let &(ref lock, ref cvar) = &*pair2;
+        let _t = thread::spawn(move || {
+            let &(ref lock, ref cvar) = &*pair_copy;
             let mut started = lock.lock().unwrap();
             thread::sleep(Duration::from_millis(1));
-            started = true;
+            *started = true;
             cvar.notify_one();
         });
-        let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&notified| {
+        let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&mut notified| {
             notified
         }).unwrap();
         // ensure it didn't time-out even if we were not given any time.

From d549db8031a07b79009f9efe8b3233cd8900c82b Mon Sep 17 00:00:00 2001
From: Vitali Lovich <vlovich@google.com>
Date: Sat, 17 Feb 2018 09:17:58 -0800
Subject: [PATCH 21/46] Fix tidy violation

---
 src/libstd/sync/condvar.rs | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 546e105deb7e6..7f9b566762884 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -466,9 +466,11 @@ impl Condvar {
     ///
     /// // wait for the thread to start up
     /// let &(ref lock, ref cvar) = &*pair;
-    /// let result = cvar.wait_timeout_until(lock.lock().unwrap(), Duration::from_millis(100), |started| {
-    ///     *started
-    /// }).unwrap();
+    /// let result = cvar.wait_timeout_until(
+    ///     lock.lock().unwrap(),
+    ///     Duration::from_millis(100),
+    ///     |started| started,
+    /// ).unwrap();
     /// if result.1.timed_out() {
     ///     // timed-out without the condition ever evaluating to true.
     /// }

From 6ad328ca772edc2474844a35133a6f902a80bccd Mon Sep 17 00:00:00 2001
From: Mark Mansi <markm@cs.wisc.edu>
Date: Sat, 17 Feb 2018 11:42:11 -0600
Subject: [PATCH 22/46] Move macro-at-most-once-rep-ambig test to ui test

---
 .../macros}/macro-at-most-once-rep-ambig.rs   |  0
 .../macro-at-most-once-rep-ambig.stderr       | 80 +++++++++++++++++++
 2 files changed, 80 insertions(+)
 rename src/test/{compile-fail => ui/macros}/macro-at-most-once-rep-ambig.rs (100%)
 create mode 100644 src/test/ui/macros/macro-at-most-once-rep-ambig.stderr

diff --git a/src/test/compile-fail/macro-at-most-once-rep-ambig.rs b/src/test/ui/macros/macro-at-most-once-rep-ambig.rs
similarity index 100%
rename from src/test/compile-fail/macro-at-most-once-rep-ambig.rs
rename to src/test/ui/macros/macro-at-most-once-rep-ambig.rs
diff --git a/src/test/ui/macros/macro-at-most-once-rep-ambig.stderr b/src/test/ui/macros/macro-at-most-once-rep-ambig.stderr
new file mode 100644
index 0000000000000..67a77e0a481d8
--- /dev/null
+++ b/src/test/ui/macros/macro-at-most-once-rep-ambig.stderr
@@ -0,0 +1,80 @@
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-ambig.rs:40:11
+   |
+40 |     foo!(a?a?a); //~ ERROR no rules expected the token `?`
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-ambig.rs:41:11
+   |
+41 |     foo!(a?a); //~ ERROR no rules expected the token `?`
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-ambig.rs:42:11
+   |
+42 |     foo!(a?); //~ ERROR no rules expected the token `?`
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-ambig.rs:43:11
+   |
+43 |     baz!(a?a?a); //~ ERROR no rules expected the token `?`
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-ambig.rs:44:11
+   |
+44 |     baz!(a?a); //~ ERROR no rules expected the token `?`
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-ambig.rs:45:11
+   |
+45 |     baz!(a?); //~ ERROR no rules expected the token `?`
+   |           ^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-ambig.rs:46:11
+   |
+46 |     baz!(a,); //~ ERROR unexpected end of macro invocation
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-ambig.rs:47:11
+   |
+47 |     baz!(a?a?a,); //~ ERROR no rules expected the token `?`
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-ambig.rs:48:11
+   |
+48 |     baz!(a?a,); //~ ERROR no rules expected the token `?`
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-ambig.rs:49:11
+   |
+49 |     baz!(a?,); //~ ERROR no rules expected the token `?`
+   |           ^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-ambig.rs:50:5
+   |
+50 |     barplus!(); //~ ERROR unexpected end of macro invocation
+   |     ^^^^^^^^^^^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-ambig.rs:51:15
+   |
+51 |     barplus!(a?); //~ ERROR unexpected end of macro invocation
+   |               ^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-ambig.rs:52:15
+   |
+52 |     barstar!(a?); //~ ERROR unexpected end of macro invocation
+   |               ^
+
+error: aborting due to 13 previous errors
+

From d17d645ad75c797a293ccf1fa3881853617f292c Mon Sep 17 00:00:00 2001
From: Corey Farwell <coreyf@rwell.org>
Date: Sun, 18 Feb 2018 16:08:48 -0500
Subject: [PATCH 23/46] Add tests ensuring zero-Duration timeouts result in
 errors.

Part of https://github.com/rust-lang/rust/issues/48311
---
 src/libstd/net/tcp.rs          | 20 +++++++++++++++++
 src/libstd/net/udp.rs          | 17 ++++++++++++++
 src/libstd/sys/unix/ext/net.rs | 41 +++++++++++++++++++++++++++++++++-
 3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index 78235ea1b4b5f..ee63e185ddb23 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -1545,6 +1545,26 @@ mod tests {
         drop(listener);
     }
 
+    // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+    // when passed zero Durations
+    #[test]
+    fn test_timeout_zero_duration() {
+        let addr = next_test_ip4();
+
+        let listener = t!(TcpListener::bind(&addr));
+        let stream = t!(TcpStream::connect(&addr));
+
+        let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        drop(listener);
+    }
+
     #[test]
     fn nodelay() {
         let addr = next_test_ip4();
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
index fc7f9205d06ff..4163bec000bb5 100644
--- a/src/libstd/net/udp.rs
+++ b/src/libstd/net/udp.rs
@@ -1024,6 +1024,23 @@ mod tests {
         assert!(start.elapsed() > Duration::from_millis(400));
     }
 
+    // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+    // when passed zero Durations
+    #[test]
+    fn test_timeout_zero_duration() {
+        let addr = next_test_ip4();
+
+        let socket = t!(UdpSocket::bind(&addr));
+
+        let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+    }
+
     #[test]
     fn connect_send_recv() {
         let addr = next_test_ip4();
diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs
index 86b0f35be924d..f1bf8f240d3fb 100644
--- a/src/libstd/sys/unix/ext/net.rs
+++ b/src/libstd/sys/unix/ext/net.rs
@@ -1410,7 +1410,7 @@ impl IntoRawFd for UnixDatagram {
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod test {
     use thread;
-    use io;
+    use io::{self, ErrorKind};
     use io::prelude::*;
     use time::Duration;
     use sys_common::io::test::tmpdir;
@@ -1613,6 +1613,27 @@ mod test {
         assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut);
     }
 
+    // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+    // when passed zero Durations
+    #[test]
+    fn test_unix_stream_timeout_zero_duration() {
+        let dir = tmpdir();
+        let socket_path = dir.path().join("sock");
+
+        let listener = or_panic!(UnixListener::bind(&socket_path));
+        let stream = or_panic!(UnixStream::connect(&socket_path));
+
+        let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        drop(listener);
+    }
+
     #[test]
     fn test_unix_datagram() {
         let dir = tmpdir();
@@ -1712,6 +1733,24 @@ mod test {
         thread.join().unwrap();
     }
 
+    // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+    // when passed zero Durations
+    #[test]
+    fn test_unix_datagram_timeout_zero_duration() {
+        let dir = tmpdir();
+        let path = dir.path().join("sock");
+
+        let datagram = or_panic!(UnixDatagram::bind(&path));
+
+        let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+    }
+
     #[test]
     fn abstract_namespace_not_allowed() {
         assert!(UnixStream::connect("\0asdf").is_err());

From c0e87f13a4d2f6fcef92c8c01bdc8dda9e0549a5 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Thu, 15 Feb 2018 15:54:40 +0000
Subject: [PATCH 24/46] Make ".e0" not parse as 0.0

This forces floats to have either a digit before the separating point, or after. Thus ".e0" is invalid like ".", when using `parse()`.
---
 src/libcore/num/dec2flt/parse.rs     | 3 ++-
 src/libcore/tests/num/dec2flt/mod.rs | 6 ++++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/libcore/num/dec2flt/parse.rs b/src/libcore/num/dec2flt/parse.rs
index d20986faa0fc2..69418434ebead 100644
--- a/src/libcore/num/dec2flt/parse.rs
+++ b/src/libcore/num/dec2flt/parse.rs
@@ -73,7 +73,8 @@ pub fn parse_decimal(s: &str) -> ParseResult {
         }
         Some(&b'.') => {
             let (fractional, s) = eat_digits(&s[1..]);
-            if integral.is_empty() && fractional.is_empty() && s.is_empty() {
+            if integral.is_empty() && fractional.is_empty() {
+                // We require at least a single digit before or after the point.
                 return Invalid;
             }
 
diff --git a/src/libcore/tests/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs
index 9934e1dab9662..17b2f59cd4df2 100644
--- a/src/libcore/tests/num/dec2flt/mod.rs
+++ b/src/libcore/tests/num/dec2flt/mod.rs
@@ -101,6 +101,12 @@ fn lonely_dot() {
     assert!(".".parse::<f64>().is_err());
 }
 
+#[test]
+fn exponentiated_dot() {
+    assert!(".e0".parse::<f32>().is_err());
+    assert!(".e0".parse::<f64>().is_err());
+}
+
 #[test]
 fn lonely_sign() {
     assert!("+".parse::<f32>().is_err());

From 80970e6953faaba886215d8abd34e70f1d510103 Mon Sep 17 00:00:00 2001
From: Josh Stone <jistone@redhat.com>
Date: Mon, 19 Feb 2018 14:05:21 -0800
Subject: [PATCH 25/46] rustbuild: Restore Config.libdir_relative

This re-introduces a `Config.libdir_relative` field, now derived from
`libdir` and made relative to `prefix` if necessary.

This fixes a regression from #46592 when `--libdir` is given an absolute
path.  `Builder::sysroot_libdir` should always use a relative path so
its callers don't clobber system locations, and `librustc` also asserts
that `CFG_LIBDIR_RELATIVE` is really relative.
---
 src/bootstrap/builder.rs |  4 ++--
 src/bootstrap/compile.rs |  2 +-
 src/bootstrap/config.rs  | 17 +++++++++++++++++
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 66a1c97246200..05aa6283ee579 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -444,8 +444,8 @@ impl<'a> Builder<'a> {
 
             fn run(self, builder: &Builder) -> Interned<PathBuf> {
                 let compiler = self.compiler;
-                let lib = if compiler.stage >= 1 && builder.build.config.libdir.is_some() {
-                    builder.build.config.libdir.clone().unwrap()
+                let lib = if compiler.stage >= 1 && builder.build.config.libdir_relative.is_some() {
+                    builder.build.config.libdir_relative.clone().unwrap()
                 } else {
                     PathBuf::from("lib")
                 };
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 2dcc0e0e7cd9f..e6389f27785b5 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -517,7 +517,7 @@ fn rustc_cargo_env(build: &Build, cargo: &mut Command) {
          .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default());
 
     let libdir_relative =
-        build.config.libdir.clone().unwrap_or(PathBuf::from("lib"));
+        build.config.libdir_relative.clone().unwrap_or(PathBuf::from("lib"));
     cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
 
     // If we're not building a compiler with debugging information then remove
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 812ca6d64fb6a..6d98153e233ba 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -126,6 +126,7 @@ pub struct Config {
     pub docdir: Option<PathBuf>,
     pub bindir: Option<PathBuf>,
     pub libdir: Option<PathBuf>,
+    pub libdir_relative: Option<PathBuf>,
     pub mandir: Option<PathBuf>,
     pub codegen_tests: bool,
     pub nodejs: Option<PathBuf>,
@@ -417,6 +418,22 @@ impl Config {
             config.mandir = install.mandir.clone().map(PathBuf::from);
         }
 
+        // Try to infer `libdir_relative` from `libdir`.
+        if let Some(ref libdir) = config.libdir {
+            let mut libdir = libdir.as_path();
+            if !libdir.is_relative() {
+                // Try to make it relative to the prefix.
+                if let Some(ref prefix) = config.prefix {
+                    if let Ok(suffix) = libdir.strip_prefix(prefix) {
+                        libdir = suffix;
+                    }
+                }
+            }
+            if libdir.is_relative() {
+                config.libdir_relative = Some(libdir.to_path_buf());
+            }
+        }
+
         // Store off these values as options because if they're not provided
         // we'll infer default values for them later
         let mut thinlto = None;

From 8174c0d65932dd6d7845af9b715090f57417b641 Mon Sep 17 00:00:00 2001
From: Josh Stone <jistone@redhat.com>
Date: Mon, 19 Feb 2018 16:08:36 -0800
Subject: [PATCH 26/46] rustbuild: make libdir_relative a method

---
 src/bootstrap/builder.rs |  7 ++++---
 src/bootstrap/compile.rs |  3 +--
 src/bootstrap/config.rs  | 30 ++++++++++++------------------
 3 files changed, 17 insertions(+), 23 deletions(-)

diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 05aa6283ee579..fcb78c479fa27 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -444,10 +444,11 @@ impl<'a> Builder<'a> {
 
             fn run(self, builder: &Builder) -> Interned<PathBuf> {
                 let compiler = self.compiler;
-                let lib = if compiler.stage >= 1 && builder.build.config.libdir_relative.is_some() {
-                    builder.build.config.libdir_relative.clone().unwrap()
+                let config = &builder.build.config;
+                let lib = if compiler.stage >= 1 && config.libdir_relative().is_some() {
+                    builder.build.config.libdir_relative().unwrap()
                 } else {
-                    PathBuf::from("lib")
+                    Path::new("lib")
                 };
                 let sysroot = builder.sysroot(self.compiler).join(lib)
                     .join("rustlib").join(self.target).join("lib");
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index e6389f27785b5..c85b04ddc0245 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -516,8 +516,7 @@ fn rustc_cargo_env(build: &Build, cargo: &mut Command) {
          .env("CFG_VERSION", build.rust_version())
          .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default());
 
-    let libdir_relative =
-        build.config.libdir_relative.clone().unwrap_or(PathBuf::from("lib"));
+    let libdir_relative = build.config.libdir_relative().unwrap_or(Path::new("lib"));
     cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
 
     // If we're not building a compiler with debugging information then remove
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 6d98153e233ba..3cf8f36df25ee 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -17,7 +17,7 @@ use std::collections::{HashMap, HashSet};
 use std::env;
 use std::fs::File;
 use std::io::prelude::*;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::process;
 use std::cmp;
 
@@ -126,7 +126,6 @@ pub struct Config {
     pub docdir: Option<PathBuf>,
     pub bindir: Option<PathBuf>,
     pub libdir: Option<PathBuf>,
-    pub libdir_relative: Option<PathBuf>,
     pub mandir: Option<PathBuf>,
     pub codegen_tests: bool,
     pub nodejs: Option<PathBuf>,
@@ -418,22 +417,6 @@ impl Config {
             config.mandir = install.mandir.clone().map(PathBuf::from);
         }
 
-        // Try to infer `libdir_relative` from `libdir`.
-        if let Some(ref libdir) = config.libdir {
-            let mut libdir = libdir.as_path();
-            if !libdir.is_relative() {
-                // Try to make it relative to the prefix.
-                if let Some(ref prefix) = config.prefix {
-                    if let Ok(suffix) = libdir.strip_prefix(prefix) {
-                        libdir = suffix;
-                    }
-                }
-            }
-            if libdir.is_relative() {
-                config.libdir_relative = Some(libdir.to_path_buf());
-            }
-        }
-
         // Store off these values as options because if they're not provided
         // we'll infer default values for them later
         let mut thinlto = None;
@@ -581,6 +564,17 @@ impl Config {
         config
     }
 
+    /// Try to find the relative path of `libdir`.
+    pub fn libdir_relative(&self) -> Option<&Path> {
+        let libdir = self.libdir.as_ref()?;
+        if libdir.is_relative() {
+            Some(libdir)
+        } else {
+            // Try to make it relative to the prefix.
+            libdir.strip_prefix(self.prefix.as_ref()?).ok()
+        }
+    }
+
     pub fn verbose(&self) -> bool {
         self.verbose > 0
     }

From 6af23f977c44fc67d8611b2581c334e795999bcd Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 20 Feb 2018 08:26:30 +0100
Subject: [PATCH 27/46] add Iterator::flatten and redefine flat_map(f) in terms
 of map(f).flatten()

---
 src/libcore/iter/iterator.rs | 47 ++++++++++++++++++++-
 src/libcore/iter/mod.rs      | 81 ++++++++++++++++--------------------
 src/libcore/lib.rs           |  1 +
 src/libcore/tests/iter.rs    |  2 +
 4 files changed, 84 insertions(+), 47 deletions(-)

diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index 33adb3f49dd0d..8ed3450dc3ac4 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -12,7 +12,7 @@ use cmp::Ordering;
 use ops::Try;
 
 use super::{AlwaysOk, LoopState};
-use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse};
+use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Flatten, FlatMap, Fuse};
 use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
 use super::{Zip, Sum, Product};
 use super::{ChainState, FromIterator, ZipImpl};
@@ -997,11 +997,15 @@ pub trait Iterator {
     /// an extra layer of indirection. `flat_map()` will remove this extra layer
     /// on its own.
     ///
+    /// You can think of [`flat_map(f)`][flat_map] as the equivalent of
+    /// [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`.
+    ///
     /// Another way of thinking about `flat_map()`: [`map`]'s closure returns
     /// one item for each element, and `flat_map()`'s closure returns an
     /// iterator for each element.
     ///
     /// [`map`]: #method.map
+    /// [`flatten`]: #method.flatten
     ///
     /// # Examples
     ///
@@ -1021,7 +1025,46 @@ pub trait Iterator {
     fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
         where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U,
     {
-        FlatMap{iter: self, f: f, frontiter: None, backiter: None }
+        self.map(f).flatten()
+    }
+
+    /// Creates an iterator that flattens nested structure.
+    ///
+    /// This is useful when you have an iterator of iterators or an iterator of
+    /// things that can be turned into iterators and you want to remove one
+    /// level of indirection.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iterator_flatten)]
+    ///
+    /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]];
+    /// let flattened = data.into_iter().flatten().collect::<Vec<u8>>();
+    /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]);
+    /// ```
+    ///
+    /// Mapping and then flattening:
+    ///
+    /// ```
+    /// #![feature(iterator_flatten)]
+    ///
+    /// let words = ["alpha", "beta", "gamma"];
+    ///
+    /// // chars() returns an iterator
+    /// let merged: String = words.iter()
+    ///                           .map(|s| s.chars())
+    ///                           .flatten()
+    ///                           .collect();
+    /// assert_eq!(merged, "alphabetagamma");
+    /// ```
+    #[inline]
+    #[unstable(feature = "iterator_flatten", issue = "0")]
+    fn flatten(self) -> Flatten<Self, <Self::Item as IntoIterator>::IntoIter>
+    where Self: Sized, Self::Item: IntoIterator {
+        Flatten { iter: self, frontiter: None, backiter: None }
     }
 
     /// Creates an iterator which ends after the first [`None`].
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index 1a2da83429af9..bd801d2ae69c8 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -2403,37 +2403,35 @@ impl<B, I, St, F> Iterator for Scan<I, St, F> where
 /// An iterator that maps each element to an iterator, and yields the elements
 /// of the produced iterators.
 ///
-/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
+/// This `type` is created by the [`flat_map`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
 /// [`flat_map`]: trait.Iterator.html#method.flat_map
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone)]
-pub struct FlatMap<I, U: IntoIterator, F> {
-    iter: I,
-    f: F,
-    frontiter: Option<U::IntoIter>,
-    backiter: Option<U::IntoIter>,
-}
+type FlatMap<I, U, F> = Flatten<Map<I, F>, <U as IntoIterator>::IntoIter>;
 
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<I: fmt::Debug, U: IntoIterator, F> fmt::Debug for FlatMap<I, U, F>
-    where U::IntoIter: fmt::Debug
-{
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_struct("FlatMap")
-            .field("iter", &self.iter)
-            .field("frontiter", &self.frontiter)
-            .field("backiter", &self.backiter)
-            .finish()
-    }
+/// An iterator that flattens one level of nesting in an iterator of things
+/// that can be turned into iterators.
+///
+/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`flatten`]: trait.Iterator.html#method.flatten
+/// [`Iterator`]: trait.Iterator.html
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+#[unstable(feature = "iterator_flatten", issue = "0")]
+#[derive(Clone, Debug)]
+pub struct Flatten<I, U> {
+    iter: I,
+    frontiter: Option<U>,
+    backiter: Option<U>,
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
-    where F: FnMut(I::Item) -> U,
+#[unstable(feature = "iterator_flatten", issue = "0")]
+impl<I: Iterator, U: Iterator> Iterator for Flatten<I, U>
+    where I::Item: IntoIterator<IntoIter = U, Item = U::Item>
 {
     type Item = U::Item;
 
@@ -2441,13 +2439,11 @@ impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
     fn next(&mut self) -> Option<U::Item> {
         loop {
             if let Some(ref mut inner) = self.frontiter {
-                if let Some(x) = inner.by_ref().next() {
-                    return Some(x)
-                }
+                if let elt@Some(_) = inner.next() { return elt }
             }
-            match self.iter.next().map(&mut self.f) {
+            match self.iter.next() {
                 None => return self.backiter.as_mut().and_then(|it| it.next()),
-                next => self.frontiter = next.map(IntoIterator::into_iter),
+                Some(inner) => self.frontiter = Some(inner.into_iter()),
             }
         }
     }
@@ -2473,10 +2469,9 @@ impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
         self.frontiter = None;
 
         {
-            let f = &mut self.f;
             let frontiter = &mut self.frontiter;
             init = self.iter.try_fold(init, |acc, x| {
-                let mut mid = f(x).into_iter();
+                let mut mid = x.into_iter();
                 let r = mid.try_fold(acc, &mut fold);
                 *frontiter = Some(mid);
                 r
@@ -2497,27 +2492,24 @@ impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
         where Fold: FnMut(Acc, Self::Item) -> Acc,
     {
         self.frontiter.into_iter()
-            .chain(self.iter.map(self.f).map(U::into_iter))
+            .chain(self.iter.map(IntoIterator::into_iter))
             .chain(self.backiter)
             .fold(init, |acc, iter| iter.fold(acc, &mut fold))
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> where
-    F: FnMut(I::Item) -> U,
-    U: IntoIterator,
-    U::IntoIter: DoubleEndedIterator
+#[unstable(feature = "iterator_flatten", issue = "0")]
+impl<I, U> DoubleEndedIterator for Flatten<I, U>
+    where I: DoubleEndedIterator, U: DoubleEndedIterator,
+          I::Item: IntoIterator<IntoIter = U, Item = U::Item>
 {
     #[inline]
     fn next_back(&mut self) -> Option<U::Item> {
         loop {
             if let Some(ref mut inner) = self.backiter {
-                if let Some(y) = inner.next_back() {
-                    return Some(y)
-                }
+                if let elt@Some(_) = inner.next_back() { return elt }
             }
-            match self.iter.next_back().map(&mut self.f) {
+            match self.iter.next_back() {
                 None => return self.frontiter.as_mut().and_then(|it| it.next_back()),
                 next => self.backiter = next.map(IntoIterator::into_iter),
             }
@@ -2534,10 +2526,9 @@ impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> wher
         self.backiter = None;
 
         {
-            let f = &mut self.f;
             let backiter = &mut self.backiter;
             init = self.iter.try_rfold(init, |acc, x| {
-                let mut mid = f(x).into_iter();
+                let mut mid = x.into_iter();
                 let r = mid.try_rfold(acc, &mut fold);
                 *backiter = Some(mid);
                 r
@@ -2558,15 +2549,15 @@ impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> wher
         where Fold: FnMut(Acc, Self::Item) -> Acc,
     {
         self.frontiter.into_iter()
-            .chain(self.iter.map(self.f).map(U::into_iter))
+            .chain(self.iter.map(IntoIterator::into_iter))
             .chain(self.backiter)
             .rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
-impl<I, U, F> FusedIterator for FlatMap<I, U, F>
-    where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
+#[unstable(feature = "fused", issue = "0")]
+impl<I: FusedIterator, U: Iterator> FusedIterator for Flatten<I, U>
+    where I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
 
 /// An iterator that yields `None` forever after the underlying iterator
 /// yields `None` once.
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index d2162d307e038..3dd30ee1c69e2 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -93,6 +93,7 @@
 #![feature(doc_spotlight)]
 #![feature(rustc_const_unstable)]
 #![feature(iterator_repeat_with)]
+#![feature(iterator_flatten)]
 
 #[prelude_import]
 #[allow(unused)]
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index f91c919d7447d..f28f5ef181ce9 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -836,6 +836,8 @@ fn test_iterator_scan() {
     assert_eq!(i, ys.len());
 }
 
+// Note: We test flatten() by testing flat_map().
+
 #[test]
 fn test_iterator_flat_map() {
     let xs = [0, 3, 6];

From 36be763d0e5b0e6ceb7cbf55097427a269caec1a Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Sat, 10 Feb 2018 07:22:46 +0100
Subject: [PATCH 28/46] Iterator::flatten: fix tracking issue number on
 FusedIterator for Flatten

---
 src/libcore/iter/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index bd801d2ae69c8..cd823d1028ed6 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -2555,7 +2555,7 @@ impl<I, U> DoubleEndedIterator for Flatten<I, U>
     }
 }
 
-#[unstable(feature = "fused", issue = "0")]
+#[unstable(feature = "fused", issue = "35602")]
 impl<I: FusedIterator, U: Iterator> FusedIterator for Flatten<I, U>
     where I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
 

From 0e394010e6ad3d6fa68c9b8c651d4745348881cd Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Wed, 14 Feb 2018 00:58:14 +0100
Subject: [PATCH 29/46] core::iter::Flatten: update FlatMap & Flatten according
 to discussion

---
 src/libcore/iter/iterator.rs |  26 +++--
 src/libcore/iter/mod.rs      | 178 ++++++++++++++++++++++++++++++++---
 src/libcore/tests/iter.rs    | 108 ++++++++++++++++++++-
 src/libcore/tests/lib.rs     |   2 +
 4 files changed, 294 insertions(+), 20 deletions(-)

diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index 8ed3450dc3ac4..879696ba8e793 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -12,7 +12,8 @@ use cmp::Ordering;
 use ops::Try;
 
 use super::{AlwaysOk, LoopState};
-use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Flatten, FlatMap, Fuse};
+use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Fuse};
+use super::{Flatten, FlatMap, flatten_compat};
 use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev};
 use super::{Zip, Sum, Product};
 use super::{ChainState, FromIterator, ZipImpl};
@@ -997,8 +998,8 @@ pub trait Iterator {
     /// an extra layer of indirection. `flat_map()` will remove this extra layer
     /// on its own.
     ///
-    /// You can think of [`flat_map(f)`][flat_map] as the equivalent of
-    /// [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`.
+    /// You can think of [`flat_map(f)`][flat_map] as the semantic equivalent
+    /// of [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`.
     ///
     /// Another way of thinking about `flat_map()`: [`map`]'s closure returns
     /// one item for each element, and `flat_map()`'s closure returns an
@@ -1025,7 +1026,7 @@ pub trait Iterator {
     fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F>
         where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U,
     {
-        self.map(f).flatten()
+        FlatMap { inner: flatten_compat(self.map(f)) }
     }
 
     /// Creates an iterator that flattens nested structure.
@@ -1060,11 +1061,24 @@ pub trait Iterator {
     ///                           .collect();
     /// assert_eq!(merged, "alphabetagamma");
     /// ```
+    ///
+    /// You can also rewrite this in terms of [`flat_map()`] which is preferable
+    /// in this case since that conveys intent clearer:
+    ///
+    /// ```
+    /// let words = ["alpha", "beta", "gamma"];
+    ///
+    /// // chars() returns an iterator
+    /// let merged: String = words.iter()
+    ///                           .flat_map(|s| s.chars())
+    ///                           .collect();
+    /// assert_eq!(merged, "alphabetagamma");
+    /// ```
     #[inline]
     #[unstable(feature = "iterator_flatten", issue = "0")]
-    fn flatten(self) -> Flatten<Self, <Self::Item as IntoIterator>::IntoIter>
+    fn flatten(self) -> Flatten<Self>
     where Self: Sized, Self::Item: IntoIterator {
-        Flatten { iter: self, frontiter: None, backiter: None }
+        Flatten { inner: flatten_compat(self) }
     }
 
     /// Creates an iterator which ends after the first [`None`].
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index cd823d1028ed6..e498f7d1b93c5 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -2403,14 +2403,87 @@ impl<B, I, St, F> Iterator for Scan<I, St, F> where
 /// An iterator that maps each element to an iterator, and yields the elements
 /// of the produced iterators.
 ///
-/// This `type` is created by the [`flat_map`] method on [`Iterator`]. See its
+/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
 /// [`flat_map`]: trait.Iterator.html#method.flat_map
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
-type FlatMap<I, U, F> = Flatten<Map<I, F>, <U as IntoIterator>::IntoIter>;
+pub struct FlatMap<I, U: IntoIterator, F> {
+    inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Clone, U: Clone + IntoIterator, F: Clone> Clone for FlatMap<I, U, F>
+    where <U as IntoIterator>::IntoIter: Clone
+{
+    fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } }
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<I: fmt::Debug, U: IntoIterator, F> fmt::Debug for FlatMap<I, U, F>
+    where U::IntoIter: fmt::Debug
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("FlatMap").field("inner", &self.inner).finish()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
+    where F: FnMut(I::Item) -> U,
+{
+    type Item = U::Item;
+
+    #[inline]
+    fn next(&mut self) -> Option<U::Item> { self.inner.next() }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+
+    #[inline]
+    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
+        Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+    {
+        self.inner.try_fold(init, fold)
+    }
+
+    #[inline]
+    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+        where Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.inner.fold(init, fold)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
+    where F: FnMut(I::Item) -> U,
+          U: IntoIterator,
+          U::IntoIter: DoubleEndedIterator
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }
+
+    #[inline]
+    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
+        Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+    {
+        self.inner.try_rfold(init, fold)
+    }
+
+    #[inline]
+    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+        where Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.inner.rfold(init, fold)
+    }
+}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, U, F> FusedIterator for FlatMap<I, U, F>
+    where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
 
 /// An iterator that flattens one level of nesting in an iterator of things
 /// that can be turned into iterators.
@@ -2422,16 +2495,102 @@ type FlatMap<I, U, F> = Flatten<Map<I, F>, <U as IntoIterator>::IntoIter>;
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
 #[unstable(feature = "iterator_flatten", issue = "0")]
+pub struct Flatten<I: Iterator>
+where I::Item: IntoIterator {
+    inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
+}
+
+#[unstable(feature = "iterator_flatten", issue = "0")]
+impl<I, U> fmt::Debug for Flatten<I>
+    where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug,
+          I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Flatten").field("inner", &self.inner).finish()
+    }
+}
+
+#[unstable(feature = "iterator_flatten", issue = "0")]
+impl<I, U> Clone for Flatten<I>
+    where I: Iterator + Clone, U: Iterator + Clone,
+          I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
+{
+    fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } }
+}
+
+#[unstable(feature = "iterator_flatten", issue = "0")]
+impl<I, U> Iterator for Flatten<I>
+    where I: Iterator, U: Iterator,
+          I::Item: IntoIterator<IntoIter = U, Item = U::Item>
+{
+    type Item = U::Item;
+
+    #[inline]
+    fn next(&mut self) -> Option<U::Item> { self.inner.next() }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+
+    #[inline]
+    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
+        Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+    {
+        self.inner.try_fold(init, fold)
+    }
+
+    #[inline]
+    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+        where Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.inner.fold(init, fold)
+    }
+}
+
+#[unstable(feature = "iterator_flatten", issue = "0")]
+impl<I, U> DoubleEndedIterator for Flatten<I>
+    where I: DoubleEndedIterator, U: DoubleEndedIterator,
+          I::Item: IntoIterator<IntoIter = U, Item = U::Item>
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<U::Item> { self.inner.next_back() }
+
+    #[inline]
+    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
+        Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+    {
+        self.inner.try_rfold(init, fold)
+    }
+
+    #[inline]
+    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+        where Fold: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.inner.rfold(init, fold)
+    }
+}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, U> FusedIterator for Flatten<I>
+    where I: FusedIterator, U: Iterator,
+          I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
+
+/// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
+fn flatten_compat<I, U>(iter: I) -> FlattenCompat<I, U> {
+    FlattenCompat { iter, frontiter: None, backiter: None }
+}
+
+/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
+/// this type.
 #[derive(Clone, Debug)]
-pub struct Flatten<I, U> {
+struct FlattenCompat<I, U> {
     iter: I,
     frontiter: Option<U>,
     backiter: Option<U>,
 }
 
-#[unstable(feature = "iterator_flatten", issue = "0")]
-impl<I: Iterator, U: Iterator> Iterator for Flatten<I, U>
-    where I::Item: IntoIterator<IntoIter = U, Item = U::Item>
+impl<I, U> Iterator for FlattenCompat<I, U>
+    where I: Iterator, U: Iterator,
+          I::Item: IntoIterator<IntoIter = U, Item = U::Item>
 {
     type Item = U::Item;
 
@@ -2498,8 +2657,7 @@ impl<I: Iterator, U: Iterator> Iterator for Flatten<I, U>
     }
 }
 
-#[unstable(feature = "iterator_flatten", issue = "0")]
-impl<I, U> DoubleEndedIterator for Flatten<I, U>
+impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
     where I: DoubleEndedIterator, U: DoubleEndedIterator,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item>
 {
@@ -2555,10 +2713,6 @@ impl<I, U> DoubleEndedIterator for Flatten<I, U>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
-impl<I: FusedIterator, U: Iterator> FusedIterator for Flatten<I, U>
-    where I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
-
 /// An iterator that yields `None` forever after the underlying iterator
 /// yields `None` once.
 ///
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index f28f5ef181ce9..edd75f7795ed7 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -836,8 +836,6 @@ fn test_iterator_scan() {
     assert_eq!(i, ys.len());
 }
 
-// Note: We test flatten() by testing flat_map().
-
 #[test]
 fn test_iterator_flat_map() {
     let xs = [0, 3, 6];
@@ -876,6 +874,44 @@ fn test_iterator_flat_map_fold() {
     assert_eq!(i, 0);
 }
 
+#[test]
+fn test_iterator_flatten() {
+    let xs = [0, 3, 6];
+    let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+    let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten();
+    let mut i = 0;
+    for x in it {
+        assert_eq!(x, ys[i]);
+        i += 1;
+    }
+    assert_eq!(i, ys.len());
+}
+
+/// Test `Flatten::fold` with items already picked off the front and back,
+/// to make sure all parts of the `Flatten` are folded correctly.
+#[test]
+fn test_iterator_flatten_fold() {
+    let xs = [0, 3, 6];
+    let ys = [1, 2, 3, 4, 5, 6, 7];
+    let mut it = xs.iter().map(|&x| x..x+3).flatten();
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.next_back(), Some(8));
+    let i = it.fold(0, |i, x| {
+        assert_eq!(x, ys[i]);
+        i + 1
+    });
+    assert_eq!(i, ys.len());
+
+    let mut it = xs.iter().map(|&x| x..x+3).flatten();
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.next_back(), Some(8));
+    let i = it.rfold(ys.len(), |i, x| {
+        assert_eq!(x, ys[i - 1]);
+        i - 1
+    });
+    assert_eq!(i, 0);
+}
+
 #[test]
 fn test_inspect() {
     let xs = [1, 2, 3, 4];
@@ -1289,6 +1325,23 @@ fn test_double_ended_flat_map() {
     assert_eq!(it.next_back(), None);
 }
 
+#[test]
+fn test_double_ended_flatten() {
+    let u = [0,1];
+    let v = [5,6,7,8];
+    let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten();
+    assert_eq!(it.next_back().unwrap(), &8);
+    assert_eq!(it.next().unwrap(),      &5);
+    assert_eq!(it.next_back().unwrap(), &7);
+    assert_eq!(it.next_back().unwrap(), &6);
+    assert_eq!(it.next_back().unwrap(), &8);
+    assert_eq!(it.next().unwrap(),      &6);
+    assert_eq!(it.next_back().unwrap(), &7);
+    assert_eq!(it.next_back(), None);
+    assert_eq!(it.next(),      None);
+    assert_eq!(it.next_back(), None);
+}
+
 #[test]
 fn test_double_ended_range() {
     assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
@@ -1980,3 +2033,54 @@ fn test_flat_map_try_folds() {
     assert_eq!(iter.try_rfold(0, i8::checked_add), None);
     assert_eq!(iter.next_back(), Some(35));
 }
+
+#[test]
+fn test_flatten_try_folds() {
+    let f = &|acc, x| i32::checked_add(acc*2/3, x);
+    let mr = &|x| (5*x)..(5*x + 5);
+    assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f));
+    assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f));
+    let mut iter = (0..10).map(mr).flatten();
+    iter.next(); iter.next_back(); // have front and back iters in progress
+    assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f));
+
+    let mut iter = (0..10).map(|x| (4*x)..(4*x + 4)).flatten();
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(17));
+    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+    assert_eq!(iter.next_back(), Some(35));
+}
+
+#[test]
+fn test_functor_laws() {
+    // identity:
+    fn identity<T>(x: T) -> T { x }
+    assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum());
+
+    // composition:
+    fn f(x: usize) -> usize { x + 3 }
+    fn g(x: usize) -> usize { x * 2 }
+    fn h(x: usize) -> usize { g(f(x)) }
+    assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum());
+}
+
+#[test]
+fn test_monad_laws_left_identity() {
+    fn f(x: usize) -> impl Iterator<Item = usize> {
+        (0..10).map(move |y| x * y)
+    }
+    assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum());
+}
+
+#[test]
+fn test_monad_laws_right_identity() {
+    assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum());
+}
+
+#[test]
+fn test_monad_laws_associativity() {
+    fn f(x: usize) -> impl Iterator<Item = usize> { 0..x }
+    fn g(x: usize) -> impl Iterator<Item = usize> { (0..x).rev() }
+    assert_eq!((0..10).flat_map(f).flat_map(g).sum::<usize>(),
+                (0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>());
+}
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 3e901a9d442ce..7954d52f6b1e3 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -25,6 +25,8 @@
 #![feature(inclusive_range)]
 #![feature(inclusive_range_syntax)]
 #![feature(iterator_try_fold)]
+#![feature(iterator_flatten)]
+#![feature(conservative_impl_trait)]
 #![feature(iter_rfind)]
 #![feature(iter_rfold)]
 #![feature(iterator_repeat_with)]

From 3d74c74fa0761542353ee1a2f4a832e9ba9b5ac4 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Wed, 14 Feb 2018 17:31:23 +0100
Subject: [PATCH 30/46] core::iter::Iterator::flatten: tracking issue is #48213

---
 src/libcore/iter/iterator.rs |  2 +-
 src/libcore/iter/mod.rs      | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index 879696ba8e793..75a0e6aa2e6cc 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -1075,7 +1075,7 @@ pub trait Iterator {
     /// assert_eq!(merged, "alphabetagamma");
     /// ```
     #[inline]
-    #[unstable(feature = "iterator_flatten", issue = "0")]
+    #[unstable(feature = "iterator_flatten", issue = "48213")]
     fn flatten(self) -> Flatten<Self>
     where Self: Sized, Self::Item: IntoIterator {
         Flatten { inner: flatten_compat(self) }
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index e498f7d1b93c5..623cad754dd72 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -2494,13 +2494,13 @@ impl<I, U, F> FusedIterator for FlatMap<I, U, F>
 /// [`flatten`]: trait.Iterator.html#method.flatten
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
-#[unstable(feature = "iterator_flatten", issue = "0")]
+#[unstable(feature = "iterator_flatten", issue = "48213")]
 pub struct Flatten<I: Iterator>
 where I::Item: IntoIterator {
     inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
 }
 
-#[unstable(feature = "iterator_flatten", issue = "0")]
+#[unstable(feature = "iterator_flatten", issue = "48213")]
 impl<I, U> fmt::Debug for Flatten<I>
     where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
@@ -2510,7 +2510,7 @@ impl<I, U> fmt::Debug for Flatten<I>
     }
 }
 
-#[unstable(feature = "iterator_flatten", issue = "0")]
+#[unstable(feature = "iterator_flatten", issue = "48213")]
 impl<I, U> Clone for Flatten<I>
     where I: Iterator + Clone, U: Iterator + Clone,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item>,
@@ -2518,7 +2518,7 @@ impl<I, U> Clone for Flatten<I>
     fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } }
 }
 
-#[unstable(feature = "iterator_flatten", issue = "0")]
+#[unstable(feature = "iterator_flatten", issue = "48213")]
 impl<I, U> Iterator for Flatten<I>
     where I: Iterator, U: Iterator,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item>
@@ -2546,7 +2546,7 @@ impl<I, U> Iterator for Flatten<I>
     }
 }
 
-#[unstable(feature = "iterator_flatten", issue = "0")]
+#[unstable(feature = "iterator_flatten", issue = "48213")]
 impl<I, U> DoubleEndedIterator for Flatten<I>
     where I: DoubleEndedIterator, U: DoubleEndedIterator,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item>

From 819d57abc94d162e0d6f58fcbed757849f8305b4 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Fri, 16 Feb 2018 01:05:03 +0100
Subject: [PATCH 31/46] core::iter::Iterator::flatten: improve docs wrt. deep
 vs. shallow flatten per @clarcharr's review

---
 src/libcore/iter/iterator.rs | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index 75a0e6aa2e6cc..e68e059385299 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -1074,6 +1074,26 @@ pub trait Iterator {
     ///                           .collect();
     /// assert_eq!(merged, "alphabetagamma");
     /// ```
+    ///
+    /// Flattening once only removes one level of nesting:
+    ///
+    /// ```
+    /// #![feature(iterator_flatten)]
+    ///
+    /// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
+    ///
+    /// let d2 = d3.iter().flatten().collect::<Vec<_>>();
+    /// assert_eq!(d2, [&[1, 2], &[3, 4], &[5, 6], &[7, 8]]);
+    ///
+    /// let d1 = d3.iter().flatten().flatten().collect::<Vec<_>>();
+    /// assert_eq!(d1, [&1, &2, &3, &4, &5, &6, &7, &8]);
+    /// ```
+    ///
+    /// Here we see that `flatten()` does not perform a "deep" flatten.
+    /// Instead, only one level of nesting is removed. That is, if you
+    /// `flatten()` a three-dimensional array the result will be
+    /// two-dimensional and not one-dimensional. To get a one-dimensional
+    /// structure, you have to `flatten()` again.
     #[inline]
     #[unstable(feature = "iterator_flatten", issue = "48213")]
     fn flatten(self) -> Flatten<Self>

From 98d8fc192dc03945b5a09288fb6e12d688489928 Mon Sep 17 00:00:00 2001
From: newpavlov <newpavlov@gmail.com>
Date: Tue, 20 Feb 2018 16:05:25 +0300
Subject: [PATCH 32/46] added rdrand feature and removed rdrnd feature

---
 src/librustc_trans/llvm_util.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs
index b25562252e72e..4969f72412838 100644
--- a/src/librustc_trans/llvm_util.rs
+++ b/src/librustc_trans/llvm_util.rs
@@ -75,9 +75,9 @@ unsafe fn configure_llvm(sess: &Session) {
                                  llvm_args.as_ptr());
 }
 
-// WARNING: the features must be known to LLVM or the feature
-// detection code will walk past the end of the feature array,
-// leading to crashes.
+// WARNING: the features after aplpying `to_llvm_feature` must be known
+// to LLVM or the feature detection code will walk past the end of the feature
+// array, leading to crashes.
 
 const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];
 
@@ -86,7 +86,7 @@ const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"];
 const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse",
                                                  "sse2", "sse3", "sse4.1", "sse4.2",
                                                  "ssse3", "tbm", "lzcnt", "popcnt",
-                                                 "sse4a", "rdrnd", "rdseed", "fma",
+                                                 "sse4a","fma", "rdrand", "rdseed",
                                                  "xsave", "xsaveopt", "xsavec",
                                                  "xsaves", "aes", "pclmulqdq",
                                                  "avx512bw", "avx512cd",
@@ -108,6 +108,7 @@ const MIPS_WHITELIST: &'static [&'static str] = &["msa"];
 pub fn to_llvm_feature(s: &str) -> &str {
     match s {
         "pclmulqdq" => "pclmul",
+        "rdrand" => "rdrnd",
         s => s,
     }
 }

From 4c6b9bcaa9eeca8e764b53a080dd6fa94c86e592 Mon Sep 17 00:00:00 2001
From: newpavlov <newpavlov@gmail.com>
Date: Tue, 20 Feb 2018 16:08:22 +0300
Subject: [PATCH 33/46] features in alphabetic order

---
 src/librustc_trans/llvm_util.rs | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs
index 4969f72412838..be3d92020ab7d 100644
--- a/src/librustc_trans/llvm_util.rs
+++ b/src/librustc_trans/llvm_util.rs
@@ -83,18 +83,17 @@ const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "
 
 const AARCH64_WHITELIST: &'static [&'static str] = &["neon", "v7"];
 
-const X86_WHITELIST: &'static [&'static str] = &["avx", "avx2", "bmi", "bmi2", "sse",
-                                                 "sse2", "sse3", "sse4.1", "sse4.2",
-                                                 "ssse3", "tbm", "lzcnt", "popcnt",
-                                                 "sse4a","fma", "rdrand", "rdseed",
-                                                 "xsave", "xsaveopt", "xsavec",
-                                                 "xsaves", "aes", "pclmulqdq",
-                                                 "avx512bw", "avx512cd",
-                                                 "avx512dq", "avx512er",
-                                                 "avx512f", "avx512ifma",
-                                                 "avx512pf", "avx512vbmi",
-                                                 "avx512vl", "avx512vpopcntdq",
-                                                 "mmx", "fxsr"];
+const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
+                                                 "avx512cd", "avx512dq", "avx512er",
+                                                 "avx512f", "avx512ifma", "avx512pf",
+                                                 "avx512vbmi", "avx512vl", "avx512vpopcntdq",
+                                                 "bmi", "bmi2", "fma", "fxsr",
+                                                 "lzcnt", "mmx", "pclmulqdq",
+                                                 "popcnt", "rdrand", "rdseed",
+                                                 "sse", "sse2", "sse3", "sse4.1",
+                                                 "sse4.2", "sse4a", "ssse3",
+                                                 "tbm", "xsave", "xsavec",
+                                                 "xsaveopt", "xsaves"];
 
 const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];
 

From 14b403c91ab9a1e4b776e00adcd9d88153e3b736 Mon Sep 17 00:00:00 2001
From: Vitali Lovich <vlovich@google.com>
Date: Tue, 20 Feb 2018 13:07:21 -0800
Subject: [PATCH 34/46] Fix doc compile error

---
 src/libstd/sync/condvar.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs
index 7f9b566762884..3e40cbb37e3d8 100644
--- a/src/libstd/sync/condvar.rs
+++ b/src/libstd/sync/condvar.rs
@@ -469,7 +469,7 @@ impl Condvar {
     /// let result = cvar.wait_timeout_until(
     ///     lock.lock().unwrap(),
     ///     Duration::from_millis(100),
-    ///     |started| started,
+    ///     |&mut started| started,
     /// ).unwrap();
     /// if result.1.timed_out() {
     ///     // timed-out without the condition ever evaluating to true.

From a33c1da861bed9dddd69f971131c4797eb6ebfeb Mon Sep 17 00:00:00 2001
From: Artyom Pavlov <newpavlov@gmail.com>
Date: Wed, 21 Feb 2018 09:59:28 +0300
Subject: [PATCH 35/46] typo fix

---
 src/librustc_trans/llvm_util.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs
index be3d92020ab7d..6271dcdfb2433 100644
--- a/src/librustc_trans/llvm_util.rs
+++ b/src/librustc_trans/llvm_util.rs
@@ -75,7 +75,7 @@ unsafe fn configure_llvm(sess: &Session) {
                                  llvm_args.as_ptr());
 }
 
-// WARNING: the features after aplpying `to_llvm_feature` must be known
+// WARNING: the features after applying `to_llvm_feature` must be known
 // to LLVM or the feature detection code will walk past the end of the feature
 // array, leading to crashes.
 

From a895d438c251886666c979b1c68ed63fd357d03a Mon Sep 17 00:00:00 2001
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Date: Sat, 17 Feb 2018 15:29:11 +0100
Subject: [PATCH 36/46] bootstrap: Add missing cputype matching for sparc

---
 src/bootstrap/bootstrap.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 603a97ddfd412..5966bb65df9c8 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -294,7 +294,7 @@ def default_build_triple():
             raise ValueError('unknown byteorder: {}'.format(sys.byteorder))
         # only the n64 ABI is supported, indicate it
         ostype += 'abi64'
-    elif cputype == 'sparcv9' or cputype == 'sparc64':
+    elif cputype == 'sparc' or cputype == 'sparcv9' or cputype == 'sparc64':
         pass
     else:
         err = "unknown cpu type: {}".format(cputype)

From 871e82e7a48f7ea0c08a30276c9be6f1cfcec087 Mon Sep 17 00:00:00 2001
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Date: Sat, 17 Feb 2018 15:31:43 +0100
Subject: [PATCH 37/46] bootstrap: Add openssl configuration for
 sparc-unknown-linux-gnu

---
 src/bootstrap/native.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 29cd23bdbb197..b1528059e72cc 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -483,6 +483,7 @@ impl Step for Openssl {
             "powerpc64-unknown-linux-gnu" => "linux-ppc64",
             "powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
             "s390x-unknown-linux-gnu" => "linux64-s390x",
+            "sparc-unknown-linux-gnu" => "linux-sparcv9",
             "sparc64-unknown-linux-gnu" => "linux64-sparcv9",
             "sparc64-unknown-netbsd" => "BSD-sparc64",
             "x86_64-apple-darwin" => "darwin64-x86_64-cc",

From 100469f4e941037178c64c365b62efa856c0188a Mon Sep 17 00:00:00 2001
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Date: Sat, 17 Feb 2018 15:48:05 +0100
Subject: [PATCH 38/46] librustc_back: Add support for sparc-linux-gnu

---
 src/librustc_back/target/mod.rs               |  1 +
 .../target/sparc_unknown_linux_gnu.rs         | 34 +++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 src/librustc_back/target/sparc_unknown_linux_gnu.rs

diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 2872c59157d6b..1ea23c1ea9ca6 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -146,6 +146,7 @@ supported_targets! {
     ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu),
     ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
     ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
+    ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
     ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
     ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
     ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
diff --git a/src/librustc_back/target/sparc_unknown_linux_gnu.rs b/src/librustc_back/target/sparc_unknown_linux_gnu.rs
new file mode 100644
index 0000000000000..a03e6937b2ca7
--- /dev/null
+++ b/src/librustc_back/target/sparc_unknown_linux_gnu.rs
@@ -0,0 +1,34 @@
+// Copyright 2018 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 LinkerFlavor;
+use target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::linux_base::opts();
+    base.cpu = "v9".to_string();
+    base.max_atomic_width = Some(64);
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string());
+    base.exe_allocation_crate = None;
+
+    Ok(Target {
+        llvm_target: "sparc-unknown-linux-gnu".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".to_string(),
+        arch: "sparc".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: base,
+    })
+}

From 84aae4ed12fcafb48216cd7b3f6ea448902f8c58 Mon Sep 17 00:00:00 2001
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Date: Fri, 23 Feb 2018 11:22:19 +0100
Subject: [PATCH 39/46] Add sparc-unknown-linux-gnu target

---
 src/tools/build-manifest/src/main.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 4113f8fd124c7..0845179532224 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -86,6 +86,7 @@ static TARGETS: &'static [&'static str] = &[
     "powerpc64-unknown-linux-gnu",
     "powerpc64le-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
+    "sparc-unknown-linux-gnu",
     "sparc64-unknown-linux-gnu",
     "sparcv9-sun-solaris",
     "wasm32-unknown-emscripten",

From 0b6583ed97aa323cfa3e40d1cb1a1759fb0e1fc1 Mon Sep 17 00:00:00 2001
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Date: Sat, 24 Feb 2018 01:08:02 +0100
Subject: [PATCH 40/46] bootstrap: Add openssl configuration for
 x86_64-unknown-linux-gnux32

---
 src/bootstrap/native.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 29cd23bdbb197..248c2d9bd0caf 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -490,6 +490,7 @@ impl Step for Openssl {
             "x86_64-unknown-freebsd" => "BSD-x86_64",
             "x86_64-unknown-dragonfly" => "BSD-x86_64",
             "x86_64-unknown-linux-gnu" => "linux-x86_64",
+            "x86_64-unknown-linux-gnux32" => "linux-x32",
             "x86_64-unknown-linux-musl" => "linux-x86_64",
             "x86_64-unknown-netbsd" => "BSD-x86_64",
             _ => panic!("don't know how to configure OpenSSL for {}", target),

From e3781c65852f7624fd58b723b66be7470cb41ea0 Mon Sep 17 00:00:00 2001
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Date: Sat, 24 Feb 2018 01:15:48 +0100
Subject: [PATCH 41/46] test: Fix s390x-unknown-linux-gnu atomic-lock-free test
 not run for systemz

---
 src/test/run-make/atomic-lock-free/Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/test/run-make/atomic-lock-free/Makefile b/src/test/run-make/atomic-lock-free/Makefile
index 4849b0307423d..63b8608afc763 100644
--- a/src/test/run-make/atomic-lock-free/Makefile
+++ b/src/test/run-make/atomic-lock-free/Makefile
@@ -36,6 +36,8 @@ ifeq ($(filter powerpc,$(LLVM_COMPONENTS)),powerpc)
 	nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
 	$(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs
 	nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
+endif
+ifeq ($(filter systemz,$(LLVM_COMPONENTS)),systemz)
 	$(RUSTC) --target=s390x-unknown-linux-gnu atomic_lock_free.rs
 	nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add
 endif

From 34b45c192f604b3dcb6f99c9d161a074fac45daf Mon Sep 17 00:00:00 2001
From: Bryan Drewery <bryan@shatow.net>
Date: Fri, 23 Feb 2018 19:33:03 -0800
Subject: [PATCH 42/46] Workaround abort(2) on compilation error on FreeBSD.

Same problem as OpenBSD, tracking bug #43575.
---
 src/librustc_back/target/freebsd_base.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_back/target/freebsd_base.rs
index 21dca99aa5005..a0f84a6ab0495 100644
--- a/src/librustc_back/target/freebsd_base.rs
+++ b/src/librustc_back/target/freebsd_base.rs
@@ -33,6 +33,7 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         pre_link_args: args,
         position_independent_executables: true,
+        eliminate_frame_pointer: false, // FIXME 43575
         relro_level: RelroLevel::Full,
         exe_allocation_crate: super::maybe_jemalloc(),
         .. Default::default()

From 264a92182e037c46cdcf37890e3142eaf634444d Mon Sep 17 00:00:00 2001
From: penpalperson <16357077+penpalperson@users.noreply.github.com>
Date: Sat, 24 Feb 2018 15:56:33 -0700
Subject: [PATCH 43/46] Added error-format flag to x.py.

---
 src/bootstrap/bin/rustc.rs | 5 +++++
 src/bootstrap/builder.rs   | 3 +++
 src/bootstrap/config.rs    | 2 ++
 src/bootstrap/flags.rs     | 3 +++
 4 files changed, 13 insertions(+)

diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 55d104b182698..ca35a896e08c8 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -61,6 +61,11 @@ fn main() {
         args.remove(n);
     }
 
+    if let Some(s) = env::var_os("RUSTC_ERROR_FORMAT") {
+        args.push("--error-format".into());
+        args.push(s);
+    }
+
     // Detect whether or not we're a build script depending on whether --target
     // is passed (a bit janky...)
     let target = args.windows(2)
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 66a1c97246200..343d30922fded 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -598,6 +598,9 @@ impl<'a> Builder<'a> {
         if let Some(target_linker) = self.build.linker(target) {
             cargo.env("RUSTC_TARGET_LINKER", target_linker);
         }
+        if let Some(ref error_format) = self.config.rustc_error_format {
+            cargo.env("RUSTC_ERROR_FORMAT", error_format);
+        }
         if cmd != "build" && cmd != "check" {
             cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.build.build)));
         }
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 812ca6d64fb6a..70a873043ad32 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -57,6 +57,7 @@ pub struct Config {
     pub profiler: bool,
     pub ignore_git: bool,
     pub exclude: Vec<PathBuf>,
+    pub rustc_error_format: Option<String>,
 
     pub run_host_only: bool,
 
@@ -330,6 +331,7 @@ impl Config {
         config.test_miri = false;
         config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
 
+        config.rustc_error_format = flags.rustc_error_format;
         config.on_fail = flags.on_fail;
         config.stage = flags.stage;
         config.src = flags.src;
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index eb5c3b8ce147f..8ca5910a11c0d 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -43,6 +43,7 @@ pub struct Flags {
     pub cmd: Subcommand,
     pub incremental: bool,
     pub exclude: Vec<PathBuf>,
+    pub rustc_error_format: Option<String>,
 }
 
 pub enum Subcommand {
@@ -118,6 +119,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
         opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
         opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
         opts.optflag("h", "help", "print this help message");
+        opts.optflag("", "error-format", "rustc error format");
 
         // fn usage()
         let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
@@ -370,6 +372,7 @@ Arguments:
             verbose: matches.opt_count("verbose"),
             stage,
             on_fail: matches.opt_str("on-fail"),
+            rustc_error_format: matches.opt_str("error-format"),
             keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
             build: matches.opt_str("build").map(|s| INTERNER.intern_string(s)),
             host: split(matches.opt_strs("host"))

From 64236092e5aa8fca2b9175df5a1192fd3d46e29b Mon Sep 17 00:00:00 2001
From: Nathan Ringo <remexre@gmail.com>
Date: Sat, 24 Feb 2018 23:48:51 -0600
Subject: [PATCH 44/46] Fixes docs for ASCII functions to no longer claim
 U+0021 is '@'.

---
 src/libcore/num/mod.rs     | 2 +-
 src/libstd/ascii.rs        | 2 +-
 src/libstd_unicode/char.rs | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 43330b63f9b9c..7d5aa25016bdd 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -2892,7 +2892,7 @@ impl u8 {
     }
 
     /// Checks if the value is an ASCII graphic character:
-    /// U+0021 '@' ... U+007E '~'.
+    /// U+0021 '!' ... U+007E '~'.
     ///
     /// # Examples
     ///
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs
index 82e1a3447dc5d..430c9df396a5e 100644
--- a/src/libstd/ascii.rs
+++ b/src/libstd/ascii.rs
@@ -245,7 +245,7 @@ pub trait AsciiExt {
     fn is_ascii_punctuation(&self) -> bool { unimplemented!(); }
 
     /// Checks if the value is an ASCII graphic character:
-    /// U+0021 '@' ... U+007E '~'.
+    /// U+0021 '!' ... U+007E '~'.
     /// For strings, true if all characters in the string are
     /// ASCII graphic characters.
     ///
diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs
index b4be4a9691183..844ff7a3c1252 100644
--- a/src/libstd_unicode/char.rs
+++ b/src/libstd_unicode/char.rs
@@ -1332,7 +1332,7 @@ impl char {
     }
 
     /// Checks if the value is an ASCII graphic character:
-    /// U+0021 '@' ... U+007E '~'.
+    /// U+0021 '!' ... U+007E '~'.
     ///
     /// # Examples
     ///

From 0aa753ba30254631ce05f37cd2ff0dd428d931c5 Mon Sep 17 00:00:00 2001
From: Manish Goregaokar <manishsmail@gmail.com>
Date: Sat, 24 Feb 2018 21:06:29 -0800
Subject: [PATCH 45/46] 1.25.0 -> 1.26.-

---
 src/liballoc/btree/map.rs          | 2 +-
 src/libstd/collections/hash/map.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs
index b98489c516a05..618ef81fdd981 100644
--- a/src/liballoc/btree/map.rs
+++ b/src/liballoc/btree/map.rs
@@ -2128,7 +2128,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> {
     ///    .or_insert(42);
     /// assert_eq!(map["poneyland"], 43);
     /// ```
-    #[stable(feature = "entry_and_modify", since = "1.25.0")]
+    #[stable(feature = "entry_and_modify", since = "1.26.0")]
     pub fn and_modify<F>(self, mut f: F) -> Self
         where F: FnMut(&mut V)
     {
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 80e52123a0177..b63a45ecade43 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -2080,7 +2080,7 @@ impl<'a, K, V> Entry<'a, K, V> {
     ///    .or_insert(42);
     /// assert_eq!(map["poneyland"], 43);
     /// ```
-    #[stable(feature = "entry_and_modify", since = "1.25.0")]
+    #[stable(feature = "entry_and_modify", since = "1.26.0")]
     pub fn and_modify<F>(self, mut f: F) -> Self
         where F: FnMut(&mut V)
     {

From a554a2f5645f12cf42d311ac11bcaad594c91347 Mon Sep 17 00:00:00 2001
From: Corey Farwell <coreyf@rwell.org>
Date: Mon, 19 Feb 2018 08:45:45 -0500
Subject: [PATCH 46/46] Return error if timeout is zero-Duration on Redox.

---
 src/libstd/sys/redox/net/tcp.rs | 10 +++++++++-
 src/libstd/sys/redox/net/udp.rs | 10 +++++++++-
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs
index 319965ab3965e..b5664908479cf 100644
--- a/src/libstd/sys/redox/net/tcp.rs
+++ b/src/libstd/sys/redox/net/tcp.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use cmp;
-use io::{Error, ErrorKind, Result};
+use io::{self, Error, ErrorKind, Result};
 use mem;
 use net::{SocketAddr, Shutdown};
 use path::Path;
@@ -130,6 +130,10 @@ impl TcpStream {
     pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
         let file = self.0.dup(b"read_timeout")?;
         if let Some(duration) = duration_option {
+            if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+                return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                          "cannot set a 0 duration timeout"));
+            }
             file.write(&TimeSpec {
                 tv_sec: duration.as_secs() as i64,
                 tv_nsec: duration.subsec_nanos() as i32
@@ -143,6 +147,10 @@ impl TcpStream {
     pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
         let file = self.0.dup(b"write_timeout")?;
         if let Some(duration) = duration_option {
+            if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+                return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                          "cannot set a 0 duration timeout"));
+            }
             file.write(&TimeSpec {
                 tv_sec: duration.as_secs() as i64,
                 tv_nsec: duration.subsec_nanos() as i32
diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs
index 7e7666e7ef364..2ed67bd2836f2 100644
--- a/src/libstd/sys/redox/net/udp.rs
+++ b/src/libstd/sys/redox/net/udp.rs
@@ -10,7 +10,7 @@
 
 use cell::UnsafeCell;
 use cmp;
-use io::{Error, ErrorKind, Result};
+use io::{self, Error, ErrorKind, Result};
 use mem;
 use net::{SocketAddr, Ipv4Addr, Ipv6Addr};
 use path::Path;
@@ -179,6 +179,10 @@ impl UdpSocket {
     pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
         let file = self.0.dup(b"read_timeout")?;
         if let Some(duration) = duration_option {
+            if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+                return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                          "cannot set a 0 duration timeout"));
+            }
             file.write(&TimeSpec {
                 tv_sec: duration.as_secs() as i64,
                 tv_nsec: duration.subsec_nanos() as i32
@@ -192,6 +196,10 @@ impl UdpSocket {
     pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
         let file = self.0.dup(b"write_timeout")?;
         if let Some(duration) = duration_option {
+            if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+                return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                          "cannot set a 0 duration timeout"));
+            }
             file.write(&TimeSpec {
                 tv_sec: duration.as_secs() as i64,
                 tv_nsec: duration.subsec_nanos() as i32