From 3f20a5dff7926da1b7bfe511cc26887ddf70c0b5 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 18 Feb 2019 10:54:16 +0100
Subject: [PATCH 01/37] Optimize copying large ranges of undefmask blocks

---
 src/librustc/mir/interpret/allocation.rs | 45 ++++++++++++++++++++----
 src/librustc_mir/interpret/memory.rs     | 22 ++++++++++--
 2 files changed, 58 insertions(+), 9 deletions(-)

diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index e96392edd64bf..06d5f27ccd744 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -613,7 +613,6 @@ impl<Tag> DerefMut for Relocations<Tag> {
 ////////////////////////////////////////////////////////////////////////////////
 
 type Block = u64;
-const BLOCK_SIZE: u64 = 64;
 
 #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
 pub struct UndefMask {
@@ -624,6 +623,8 @@ pub struct UndefMask {
 impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
 
 impl UndefMask {
+    pub const BLOCK_SIZE: u64 = 64;
+
     pub fn new(size: Size) -> Self {
         let mut m = UndefMask {
             blocks: vec![],
@@ -643,6 +644,7 @@ impl UndefMask {
             return Err(self.len);
         }
 
+        // FIXME(oli-obk): optimize this for allocations larger than a block.
         let idx = (start.bytes()..end.bytes())
             .map(|i| Size::from_bytes(i))
             .find(|&i| !self.get(i));
@@ -662,8 +664,31 @@ impl UndefMask {
     }
 
     pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) {
-        for i in start.bytes()..end.bytes() {
-            self.set(Size::from_bytes(i), new_state);
+        let (blocka, bita) = bit_index(start);
+        let (blockb, bitb) = bit_index(end);
+        if blocka == blockb {
+            // within a single block
+            for i in bita .. bitb {
+                self.set_bit(blocka, i, new_state);
+            }
+            return;
+        }
+        // across block boundaries
+        for i in bita .. Self::BLOCK_SIZE as usize {
+            self.set_bit(blocka, i, new_state);
+        }
+        for i in 0 .. bitb {
+            self.set_bit(blockb, i, new_state);
+        }
+        // fill in all the other blocks (much faster than one bit at a time)
+        if new_state {
+            for block in (blocka + 1) .. blockb {
+                self.blocks[block] = 0xFFFF_FFFF_FFFF_FFFF;
+            }
+        } else {
+            for block in (blocka + 1) .. blockb {
+                self.blocks[block] = 0;
+            }
         }
     }
 
@@ -676,6 +701,11 @@ impl UndefMask {
     #[inline]
     pub fn set(&mut self, i: Size, new_state: bool) {
         let (block, bit) = bit_index(i);
+        self.set_bit(block, bit, new_state);
+    }
+
+    #[inline]
+    fn set_bit(&mut self, block: usize, bit: usize, new_state: bool) {
         if new_state {
             self.blocks[block] |= 1 << bit;
         } else {
@@ -684,11 +714,12 @@ impl UndefMask {
     }
 
     pub fn grow(&mut self, amount: Size, new_state: bool) {
-        let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len.bytes();
+        let unused_trailing_bits = self.blocks.len() as u64 * Self::BLOCK_SIZE - self.len.bytes();
         if amount.bytes() > unused_trailing_bits {
-            let additional_blocks = amount.bytes() / BLOCK_SIZE + 1;
+            let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1;
             assert_eq!(additional_blocks as usize as u64, additional_blocks);
             self.blocks.extend(
+                // FIXME(oli-obk): optimize this by repeating `new_state as Block`
                 iter::repeat(0).take(additional_blocks as usize),
             );
         }
@@ -701,8 +732,8 @@ impl UndefMask {
 #[inline]
 fn bit_index(bits: Size) -> (usize, usize) {
     let bits = bits.bytes();
-    let a = bits / BLOCK_SIZE;
-    let b = bits % BLOCK_SIZE;
+    let a = bits / UndefMask::BLOCK_SIZE;
+    let b = bits % UndefMask::BLOCK_SIZE;
     assert_eq!(a as usize as u64, a);
     assert_eq!(b as usize as u64, b);
     (a as usize, b as usize)
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 88b936afaa4c1..78668c5ad875e 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -20,7 +20,7 @@ use syntax::ast::Mutability;
 use super::{
     Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
     EvalResult, Scalar, EvalErrorKind, AllocKind, PointerArithmetic,
-    Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck,
+    Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck, UndefMask,
 };
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
@@ -785,10 +785,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         assert_eq!(size.bytes() as usize as u64, size.bytes());
 
         let undef_mask = self.get(src.alloc_id)?.undef_mask.clone();
+        let get = |i| undef_mask.get(src.offset + Size::from_bytes(i));
         let dest_allocation = self.get_mut(dest.alloc_id)?;
 
+        // an optimization where we can just overwrite an entire range of definedness bits if
+        // they are going to be uniformly `1` or `0`.
+        if size.bytes() * repeat > UndefMask::BLOCK_SIZE {
+            let first = undef_mask.get(src.offset);
+            // check that all bits are the same as the first bit
+            // FIXME(oli-obk): consider making this a function on `UndefMask` and optimize it, too
+            if (1..size.bytes()).all(|i| get(i) == first) {
+                dest_allocation.undef_mask.set_range(
+                    dest.offset,
+                    dest.offset + size * repeat,
+                    first,
+                );
+                return Ok(())
+            }
+        }
+
+        // the default path
         for i in 0..size.bytes() {
-            let defined = undef_mask.get(src.offset + Size::from_bytes(i));
+            let defined = get(i);
 
             for j in 0..repeat {
                 dest_allocation.undef_mask.set(

From 1e3d1b65c500a33993462c84ecb80136d184acb2 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 18 Feb 2019 13:55:55 +0100
Subject: [PATCH 02/37] No magic numbers

---
 src/librustc/mir/interpret/allocation.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index 06d5f27ccd744..18880c551ed55 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -683,7 +683,7 @@ impl UndefMask {
         // fill in all the other blocks (much faster than one bit at a time)
         if new_state {
             for block in (blocka + 1) .. blockb {
-                self.blocks[block] = 0xFFFF_FFFF_FFFF_FFFF;
+                self.blocks[block] = u64::max_value();
             }
         } else {
             for block in (blocka + 1) .. blockb {

From aa8c48a2746e85b1a2e2ff53a34f30b81920fa5f Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 19 Feb 2019 09:35:06 +0100
Subject: [PATCH 03/37] Don't try to copy relocations if there are none

---
 src/librustc_mir/interpret/memory.rs | 39 ++++++++++++++++------------
 1 file changed, 22 insertions(+), 17 deletions(-)

diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 78668c5ad875e..8cbc404e28b31 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -700,24 +700,29 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         // relocations overlapping the edges; those would not be handled correctly).
         let relocations = {
             let relocations = self.get(src.alloc_id)?.relocations(self, src, size);
-            let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize));
-            for i in 0..length {
-                new_relocations.extend(
-                    relocations
-                    .iter()
-                    .map(|&(offset, reloc)| {
-                        // compute offset for current repetition
-                        let dest_offset = dest.offset + (i * size);
-                        (
-                            // shift offsets from source allocation to destination allocation
-                            offset + dest_offset - src.offset,
-                            reloc,
-                        )
-                    })
-                );
-            }
+            if relocations.is_empty() {
+                // nothing to copy, ignore even the `length` loop
+                Vec::new()
+            } else {
+                let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize));
+                for i in 0..length {
+                    new_relocations.extend(
+                        relocations
+                        .iter()
+                        .map(|&(offset, reloc)| {
+                            // compute offset for current repetition
+                            let dest_offset = dest.offset + (i * size);
+                            (
+                                // shift offsets from source allocation to destination allocation
+                                offset + dest_offset - src.offset,
+                                reloc,
+                            )
+                        })
+                    );
+                }
 
-            new_relocations
+                new_relocations
+            }
         };
 
         let tcx = self.tcx.tcx;

From d32b7e5b13ee833675c8fb3c905a4286690ceb15 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 19 Feb 2019 09:43:39 +0100
Subject: [PATCH 04/37] Test the `UndefMask` type

---
 src/test/run-pass-fulldeps/undef_mask.rs | 26 ++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 src/test/run-pass-fulldeps/undef_mask.rs

diff --git a/src/test/run-pass-fulldeps/undef_mask.rs b/src/test/run-pass-fulldeps/undef_mask.rs
new file mode 100644
index 0000000000000..37c44e2df6c5e
--- /dev/null
+++ b/src/test/run-pass-fulldeps/undef_mask.rs
@@ -0,0 +1,26 @@
+// ignore-cross-compile
+// ignore-stage1
+
+#![feature(rustc_private)]
+
+extern crate rustc;
+
+use rustc::mir::interpret::UndefMask;
+use rustc::ty::layout::Size;
+
+fn main() {
+    let mut mask = UndefMask::new(Size::from_bytes(500));
+    assert!(!mask.get(Size::from_bytes(499)));
+    mask.set(Size::from_bytes(499), true);
+    assert!(mask.get(Size::from_bytes(499)));
+    mask.set_range_inbounds(Size::from_bytes(100), Size::from_bytes(256), true);
+    for i in 0..100 {
+        assert!(!mask.get(Size::from_bytes(i)));
+    }
+    for i in 100..256 {
+        assert!(mask.get(Size::from_bytes(i)));
+    }
+    for i in 256..499 {
+        assert!(!mask.get(Size::from_bytes(i)));
+    }
+}

From 4ded592f60c3f1a16db56fadcd7924121ed92ce8 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 19 Feb 2019 12:40:56 +0100
Subject: [PATCH 05/37] Use a more general approach for setting large
 definedness ranges

---
 src/librustc_mir/interpret/memory.rs | 70 ++++++++++++++++++----------
 1 file changed, 45 insertions(+), 25 deletions(-)

diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 8cbc404e28b31..6cbb611c1a3ec 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -20,7 +20,7 @@ use syntax::ast::Mutability;
 use super::{
     Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
     EvalResult, Scalar, EvalErrorKind, AllocKind, PointerArithmetic,
-    Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck, UndefMask,
+    Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck,
 };
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
@@ -789,38 +789,58 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         // The bits have to be saved locally before writing to dest in case src and dest overlap.
         assert_eq!(size.bytes() as usize as u64, size.bytes());
 
-        let undef_mask = self.get(src.alloc_id)?.undef_mask.clone();
-        let get = |i| undef_mask.get(src.offset + Size::from_bytes(i));
-        let dest_allocation = self.get_mut(dest.alloc_id)?;
+        let undef_mask = &self.get(src.alloc_id)?.undef_mask;
+
+        // a precomputed cache for ranges of defined/undefined bits
+        // 0000010010001110 will become
+        // [5, 1, 2, 1, 3, 3, 1]
+        // where each element toggles the state
+        let mut ranges = smallvec::SmallVec::<[u64; 1]>::new();
+        let first = undef_mask.get(src.offset);
+        let mut cur_len = 1;
+        let mut cur = first;
+        for i in 1..size.bytes() {
+            // FIXME: optimize to bitshift the current undef block's bits and read the top bit
+            if undef_mask.get(src.offset + Size::from_bytes(i)) == cur {
+                cur_len += 1;
+            } else {
+                ranges.push(cur_len);
+                cur_len = 1;
+                cur = !cur;
+            }
+        }
 
+        // now fill in all the data
+        let dest_allocation = self.get_mut(dest.alloc_id)?;
         // an optimization where we can just overwrite an entire range of definedness bits if
         // they are going to be uniformly `1` or `0`.
-        if size.bytes() * repeat > UndefMask::BLOCK_SIZE {
-            let first = undef_mask.get(src.offset);
-            // check that all bits are the same as the first bit
-            // FIXME(oli-obk): consider making this a function on `UndefMask` and optimize it, too
-            if (1..size.bytes()).all(|i| get(i) == first) {
-                dest_allocation.undef_mask.set_range(
-                    dest.offset,
-                    dest.offset + size * repeat,
-                    first,
-                );
-                return Ok(())
-            }
+        if ranges.is_empty() {
+            dest_allocation.undef_mask.set_range(
+                dest.offset,
+                dest.offset + size * repeat,
+                first,
+            );
+            return Ok(())
         }
 
-        // the default path
-        for i in 0..size.bytes() {
-            let defined = get(i);
-
-            for j in 0..repeat {
-                dest_allocation.undef_mask.set(
-                    dest.offset + Size::from_bytes(i + (size.bytes() * j)),
-                    defined
+        // remember to fill in the trailing bits
+        ranges.push(cur_len);
+
+        for mut j in 0..repeat {
+            j *= size.bytes();
+            j += dest.offset.bytes();
+            let mut cur = first;
+            for range in &ranges {
+                let old_j = j;
+                j += range;
+                dest_allocation.undef_mask.set_range_inbounds(
+                    Size::from_bytes(old_j),
+                    Size::from_bytes(j),
+                    cur,
                 );
+                cur = !cur;
             }
         }
-
         Ok(())
     }
 }

From 60fde17a293ab94c56e415f5d5dd036527b4f201 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Wed, 20 Feb 2019 15:07:25 +0100
Subject: [PATCH 06/37] Use bit operations for setting large ranges of bits in
 a u64

---
 src/librustc/mir/interpret/allocation.rs | 49 ++++++++++++++++--------
 src/librustc_mir/interpret/memory.rs     |  2 +-
 src/test/run-pass-fulldeps/undef_mask.rs |  2 +-
 3 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index 18880c551ed55..004804f7c211e 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -100,8 +100,7 @@ impl AllocationExtra<(), ()> for () {
 impl<Tag, Extra> Allocation<Tag, Extra> {
     /// Creates a read-only allocation initialized by the given bytes
     pub fn from_bytes(slice: &[u8], align: Align, extra: Extra) -> Self {
-        let mut undef_mask = UndefMask::new(Size::ZERO);
-        undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
+        let undef_mask = UndefMask::new(Size::from_bytes(slice.len() as u64), true);
         Self {
             bytes: slice.to_owned(),
             relocations: Relocations::new(),
@@ -121,7 +120,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
         Allocation {
             bytes: vec![0; size.bytes() as usize],
             relocations: Relocations::new(),
-            undef_mask: UndefMask::new(size),
+            undef_mask: UndefMask::new(size, false),
             align,
             mutability: Mutability::Mutable,
             extra,
@@ -625,12 +624,12 @@ impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
 impl UndefMask {
     pub const BLOCK_SIZE: u64 = 64;
 
-    pub fn new(size: Size) -> Self {
+    pub fn new(size: Size, state: bool) -> Self {
         let mut m = UndefMask {
             blocks: vec![],
             len: Size::ZERO,
         };
-        m.grow(size, false);
+        m.grow(size, state);
         m
     }
 
@@ -667,25 +666,40 @@ impl UndefMask {
         let (blocka, bita) = bit_index(start);
         let (blockb, bitb) = bit_index(end);
         if blocka == blockb {
-            // within a single block
-            for i in bita .. bitb {
-                self.set_bit(blocka, i, new_state);
+            // first set all bits but the first `bita`
+            // then unset the last `64 - bitb` bits
+            let range = if bitb == 0 {
+                u64::max_value() << bita
+            } else {
+                (u64::max_value() << bita) & (u64::max_value() >> (64 - bitb))
+            };
+            if new_state {
+                self.blocks[blocka] |= range;
+            } else {
+                self.blocks[blocka] &= !range;
             }
             return;
         }
         // across block boundaries
-        for i in bita .. Self::BLOCK_SIZE as usize {
-            self.set_bit(blocka, i, new_state);
-        }
-        for i in 0 .. bitb {
-            self.set_bit(blockb, i, new_state);
-        }
-        // fill in all the other blocks (much faster than one bit at a time)
         if new_state {
+            // set bita..64 to 1
+            self.blocks[blocka] |= u64::max_value() << bita;
+            // set 0..bitb to 1
+            if bitb != 0 {
+                self.blocks[blockb] |= u64::max_value() >> (64 - bitb);
+            }
+            // fill in all the other blocks (much faster than one bit at a time)
             for block in (blocka + 1) .. blockb {
                 self.blocks[block] = u64::max_value();
             }
         } else {
+            // set bita..64 to 0
+            self.blocks[blocka] &= !(u64::max_value() << bita);
+            // set 0..bitb to 0
+            if bitb != 0 {
+                self.blocks[blockb] &= !(u64::max_value() >> (64 - bitb));
+            }
+            // fill in all the other blocks (much faster than one bit at a time)
             for block in (blocka + 1) .. blockb {
                 self.blocks[block] = 0;
             }
@@ -695,7 +709,7 @@ impl UndefMask {
     #[inline]
     pub fn get(&self, i: Size) -> bool {
         let (block, bit) = bit_index(i);
-        (self.blocks[block] & 1 << bit) != 0
+        (self.blocks[block] & (1 << bit)) != 0
     }
 
     #[inline]
@@ -714,6 +728,9 @@ impl UndefMask {
     }
 
     pub fn grow(&mut self, amount: Size, new_state: bool) {
+        if amount.bytes() == 0 {
+            return;
+        }
         let unused_trailing_bits = self.blocks.len() as u64 * Self::BLOCK_SIZE - self.len.bytes();
         if amount.bytes() > unused_trailing_bits {
             let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1;
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 6cbb611c1a3ec..fba0a9af21392 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -815,7 +815,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         // an optimization where we can just overwrite an entire range of definedness bits if
         // they are going to be uniformly `1` or `0`.
         if ranges.is_empty() {
-            dest_allocation.undef_mask.set_range(
+            dest_allocation.undef_mask.set_range_inbounds(
                 dest.offset,
                 dest.offset + size * repeat,
                 first,
diff --git a/src/test/run-pass-fulldeps/undef_mask.rs b/src/test/run-pass-fulldeps/undef_mask.rs
index 37c44e2df6c5e..cf6e6f7231638 100644
--- a/src/test/run-pass-fulldeps/undef_mask.rs
+++ b/src/test/run-pass-fulldeps/undef_mask.rs
@@ -9,7 +9,7 @@ use rustc::mir::interpret::UndefMask;
 use rustc::ty::layout::Size;
 
 fn main() {
-    let mut mask = UndefMask::new(Size::from_bytes(500));
+    let mut mask = UndefMask::new(Size::from_bytes(500), false);
     assert!(!mask.get(Size::from_bytes(499)));
     mask.set(Size::from_bytes(499), true);
     assert!(mask.get(Size::from_bytes(499)));

From 876258b0fa31fc1d1a79ddc0e5a0c9c5f0e8f85b Mon Sep 17 00:00:00 2001
From: Philipp Oppermann <dev@phil-opp.com>
Date: Wed, 6 Mar 2019 19:46:33 +0100
Subject: [PATCH 07/37] Default to integrated `rust-lld` linker for UEFI
 targets

---
 src/librustc_target/spec/uefi_base.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_target/spec/uefi_base.rs b/src/librustc_target/spec/uefi_base.rs
index 631966c09a498..956767a22a0e1 100644
--- a/src/librustc_target/spec/uefi_base.rs
+++ b/src/librustc_target/spec/uefi_base.rs
@@ -59,7 +59,7 @@ pub fn opts() -> TargetOptions {
         singlethread: true,
         emit_debug_gdb_scripts: false,
 
-        linker: Some("lld-link".to_string()),
+        linker: Some("rust-lld".to_string()),
         lld_flavor: LldFlavor::Link,
         pre_link_args,
 

From 94a6936a692ed5e6f6c6a64d622d21ea4083e051 Mon Sep 17 00:00:00 2001
From: kennytm <kennytm@gmail.com>
Date: Sat, 9 Mar 2019 14:28:25 +0800
Subject: [PATCH 08/37] Track embedded-book in the toolstate

---
 src/ci/docker/x86_64-gnu-tools/checktools.sh | 1 +
 src/tools/publish_toolstate.py               | 8 +++++---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh
index 3343716419ff4..97e6ee25ec7a0 100755
--- a/src/ci/docker/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh
@@ -78,6 +78,7 @@ status_check() {
     check_dispatch $1 beta clippy-driver src/tools/clippy
     # these tools are not required for beta to successfully branch
     check_dispatch $1 nightly miri src/tools/miri
+    check_dispatch $1 nightly embedded-book src/doc/embedded-book
 }
 
 # If this PR is intended to update one of these tools, do not let the build pass
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index fb6132a5358ef..430db48954826 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -12,7 +12,7 @@
 except ImportError:
     import urllib.request as urllib2
 
-# List of people to ping when the status of a tool changed.
+# List of people to ping when the status of a tool or a book changed.
 MAINTAINERS = {
     'miri': '@oli-obk @RalfJung @eddyb',
     'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch',
@@ -22,6 +22,7 @@
     'nomicon': '@frewsxcv @Gankro',
     'reference': '@steveklabnik @Havvy @matthewjasper @alercah',
     'rust-by-example': '@steveklabnik @marioidival @projektir',
+    'embedded-book': '',
 }
 
 REPOS = {
@@ -33,6 +34,7 @@
     'nomicon': 'https://github.com/rust-lang-nursery/nomicon',
     'reference': 'https://github.com/rust-lang-nursery/reference',
     'rust-by-example': 'https://github.com/rust-lang/rust-by-example',
+    'embedded-book': 'https://github.com/rust-embedded/book',
 }
 
 
@@ -70,7 +72,7 @@ def issue(
 
             cc @{}, the PR reviewer, and @rust-lang/compiler -- nominating for prioritization.
 
-            ''').format(relevant_pr_number, tool, REPOS[tool], relevant_pr_user, pr_reviewer),
+            ''').format(relevant_pr_number, tool, REPOS.get(tool), relevant_pr_user, pr_reviewer),
             'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number),
             'assignees': assignees,
             'labels': ['T-compiler', 'I-nominated'],
@@ -137,7 +139,7 @@ def update_latest(
             if build_failed:
                 try:
                     issue(
-                        tool, MAINTAINERS.get(tool),
+                        tool, MAINTAINERS.get(tool, ''),
                         relevant_pr_number, relevant_pr_user, pr_reviewer,
                     )
                 except IOError as e:

From bd2e12609f190e7bf206dac2de2d68dbb4b1b5e6 Mon Sep 17 00:00:00 2001
From: Dirk Leifeld <leifeld@posteo.de>
Date: Sat, 9 Mar 2019 19:16:54 +0100
Subject: [PATCH 09/37] Revert "Revert "Add clamp functions""

---
 src/libcore/cmp.rs | 26 ++++++++++++++++++++++++++
 src/libstd/f32.rs  | 20 ++++++++++++++++++++
 src/libstd/f64.rs  | 20 ++++++++++++++++++++
 3 files changed, 66 insertions(+)

diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index 81fcdeee12d29..259135b9ca0ab 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -567,6 +567,32 @@ pub trait Ord: Eq + PartialOrd<Self> {
     where Self: Sized {
         if self <= other { self } else { other }
     }
+
+    /// Returns max if self is greater than max, and min if self is less than min.
+    /// Otherwise this will return self.  Panics if min > max.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(clamp)]
+    ///
+    /// assert!((-3).clamp(-2, 1) == -2);
+    /// assert!(0.clamp(-2, 1) == 0);
+    /// assert!(2.clamp(-2, 1) == 1);
+    /// ```
+    #[unstable(feature = "clamp", issue = "44095")]
+    fn clamp(self, min: Self, max: Self) -> Self
+    where Self: Sized {
+        assert!(min <= max);
+        if self < min {
+            min
+        }
+        else if self > max {
+            max
+        } else {
+            self
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index cb1f93581775c..df4dc2c779125 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -956,6 +956,26 @@ impl f32 {
     pub fn atanh(self) -> f32 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
+    /// Returns max if self is greater than max, and min if self is less than min.
+    /// Otherwise this returns self.  Panics if min > max, min equals NaN, or max equals NaN.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert!((-3.0f32).clamp(-2.0f32, 1.0f32) == -2.0f32);
+    /// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32);
+    /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32);
+    /// ```
+    #[unstable(feature = "clamp", issue = "44095")]
+    #[inline]
+    pub fn clamp(self, min: f32, max: f32) -> f32 {
+        assert!(min <= max);
+        let mut x = self;
+        if x < min { x = min; }
+        if x > max { x = max; }
+        x
+    }
+
 }
 
 #[cfg(test)]
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index 7fa7b80751938..00e7f27912817 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -878,6 +878,26 @@ impl f64 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
 
+    /// Returns max if self is greater than max, and min if self is less than min.
+    /// Otherwise this returns self.  Panics if min > max, min equals NaN, or max equals NaN.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// assert!((-3.0f64).clamp(-2.0f64, 1.0f64) == -2.0f64);
+    /// assert!((0.0f64).clamp(-2.0f64, 1.0f64) == 0.0f64);
+    /// assert!((2.0f64).clamp(-2.0f64, 1.0f64) == 1.0f64);
+    /// ```
+    #[unstable(feature = "clamp", issue = "44095")]
+    #[inline]
+    pub fn clamp(self, min: f64, max: f64) -> f64 {
+        assert!(min <= max);
+        let mut x = self;
+        if x < min { x = min; }
+        if x > max { x = max; }
+        x
+    }
+
     // Solaris/Illumos requires a wrapper around log, log2, and log10 functions
     // because of their non-standard behavior (e.g., log(-n) returns -Inf instead
     // of expected NaN).

From 6041ec3b788a519ab740925c6b1c2f0ac19ad17d Mon Sep 17 00:00:00 2001
From: Dirk Leifeld <leifeld@posteo.de>
Date: Sat, 9 Mar 2019 20:10:48 +0100
Subject: [PATCH 10/37] add feature clamp

---
 src/libstd/f32.rs | 1 +
 src/libstd/f64.rs | 1 +
 src/libstd/lib.rs | 1 +
 3 files changed, 3 insertions(+)

diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index df4dc2c779125..d158a6a5bccc8 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -962,6 +962,7 @@ impl f32 {
     /// # Examples
     ///
     /// ```
+    /// #![feature(clamp)]
     /// assert!((-3.0f32).clamp(-2.0f32, 1.0f32) == -2.0f32);
     /// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32);
     /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32);
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index 00e7f27912817..5be0cfa9b8f0a 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -884,6 +884,7 @@ impl f64 {
     /// # Examples
     ///
     /// ```
+    /// #![feature(clamp)]
     /// assert!((-3.0f64).clamp(-2.0f64, 1.0f64) == -2.0f64);
     /// assert!((0.0f64).clamp(-2.0f64, 1.0f64) == 0.0f64);
     /// assert!((2.0f64).clamp(-2.0f64, 1.0f64) == 1.0f64);
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 6dd3a6cc0fdbd..1c4918de42882 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -240,6 +240,7 @@
 #![feature(cfg_target_thread_local)]
 #![feature(char_error_internals)]
 #![feature(checked_duration_since)]
+#![feature(clamp)]
 #![feature(compiler_builtins_lib)]
 #![feature(concat_idents)]
 #![feature(const_cstr_unchecked)]

From 135b686db41f67c4241144e25277a90092b014f4 Mon Sep 17 00:00:00 2001
From: James Munns <james@onevariable.com>
Date: Sun, 10 Mar 2019 17:38:16 +0800
Subject: [PATCH 11/37] Update src/tools/publish_toolstate.py

Co-Authored-By: kennytm <kennytm@gmail.com>
---
 src/tools/publish_toolstate.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 430db48954826..6e06034db599a 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -22,7 +22,7 @@
     'nomicon': '@frewsxcv @Gankro',
     'reference': '@steveklabnik @Havvy @matthewjasper @alercah',
     'rust-by-example': '@steveklabnik @marioidival @projektir',
-    'embedded-book': '',
+    'embedded-book': '@adamgreig @andre-richter @jamesmunns @korken89 @ryankurte @thejpster @therealprof',
 }
 
 REPOS = {

From d6f51006cd47ca3f1ccacc4e0faa345877653b81 Mon Sep 17 00:00:00 2001
From: kennytm <kennytm@gmail.com>
Date: Sun, 10 Mar 2019 18:02:40 +0800
Subject: [PATCH 12/37] Fix tidy

---
 src/tools/publish_toolstate.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 6e06034db599a..f2a585e627307 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -22,7 +22,10 @@
     'nomicon': '@frewsxcv @Gankro',
     'reference': '@steveklabnik @Havvy @matthewjasper @alercah',
     'rust-by-example': '@steveklabnik @marioidival @projektir',
-    'embedded-book': '@adamgreig @andre-richter @jamesmunns @korken89 @ryankurte @thejpster @therealprof',
+    'embedded-book': (
+        '@adamgreig @andre-richter @jamesmunns @korken89 '
+        '@ryankurte @thejpster @therealprof'
+    ),
 }
 
 REPOS = {

From 8371377d16d12bff9d8a219ae85849c686917125 Mon Sep 17 00:00:00 2001
From: Eric Huss <eric@huss.org>
Date: Sat, 9 Mar 2019 15:48:58 -0800
Subject: [PATCH 13/37] CI: Set job names.

This should make it easier to identify what each job is doing when looking at the Travis or Appveyor UI.

- Set `name` for each job in Travis.
- Move `CI_JOB_NAME` to the front in Appveyor so that it appears first in the UI.
---
 .travis.yml  | 54 ++++++++++++++++++++++++++++++++++++++++++++------
 appveyor.yml | 56 ++++++++++++++++++++++++++--------------------------
 2 files changed, 76 insertions(+), 34 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 7985b6c0e191f..7a8772d7abd63 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,20 +12,27 @@ git:
   depth: 2
   submodules: false
 
+env:
+  global:
+    - CI_JOB_NAME=$TRAVIS_JOB_NAME
+
 matrix:
   fast_finish: true
   include:
     # Images used in testing PR and try-build should be run first.
     - env: IMAGE=x86_64-gnu-llvm-6.0 RUST_BACKTRACE=1
+      name: x86_64-gnu-llvm-6.0
       if: type = pull_request OR branch = auto
 
     - env: IMAGE=dist-x86_64-linux DEPLOY=1
+      name: dist-x86_64-linux
       if: branch = try OR branch = auto
 
     # "alternate" deployments, these are "nightlies" but have LLVM assertions
     # turned on, they're deployed to a different location primarily for
     # additional testing.
-    - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1 CI_JOB_NAME=dist-x86_64-linux-alt
+    - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1
+      name: dist-x86_64-linux-alt
       if: branch = try OR branch = auto
 
     - env: >
@@ -37,9 +44,9 @@ matrix:
         MACOSX_DEPLOYMENT_TARGET=10.7
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
-        CI_JOB_NAME=dist-x86_64-apple-alt
       os: osx
       osx_image: xcode9.3-moar
+      name: dist-x86_64-apple-alt
       if: branch = auto
 
     # macOS builders. These are placed near the beginning because they are very
@@ -60,9 +67,9 @@ matrix:
         MACOSX_STD_DEPLOYMENT_TARGET=10.7
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
-        CI_JOB_NAME=x86_64-apple
       os: osx
       osx_image: xcode9.3-moar
+      name: x86_64-apple
       if: branch = auto
 
     - env: >
@@ -74,9 +81,9 @@ matrix:
         MACOSX_STD_DEPLOYMENT_TARGET=10.7
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
-        CI_JOB_NAME=i686-apple
       os: osx
       osx_image: xcode9.3-moar
+      name: i686-apple
       if: branch = auto
 
     # OSX builders producing releases. These do not run the full test suite and
@@ -95,9 +102,9 @@ matrix:
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
         DIST_REQUIRE_ALL_TOOLS=1
-        CI_JOB_NAME=dist-i686-apple
       os: osx
       osx_image: xcode9.3-moar
+      name: dist-i686-apple
       if: branch = auto
 
     - env: >
@@ -110,81 +117,116 @@ matrix:
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
         DIST_REQUIRE_ALL_TOOLS=1
-        CI_JOB_NAME=dist-x86_64-apple
       os: osx
       osx_image: xcode9.3-moar
+      name: dist-x86_64-apple
       if: branch = auto
 
     # Linux builders, remaining docker images
     - env: IMAGE=arm-android
+      name: arm-android
       if: branch = auto
     - env: IMAGE=armhf-gnu
+      name: armhf-gnu
       if: branch = auto
     - env: IMAGE=dist-various-1 DEPLOY=1
+      name: dist-various-1
       if: branch = auto
     - env: IMAGE=dist-various-2 DEPLOY=1
+      name: dist-various-2
       if: branch = auto
     - env: IMAGE=dist-aarch64-linux DEPLOY=1
+      name: dist-aarch64-linux
       if: branch = auto
     - env: IMAGE=dist-android DEPLOY=1
+      name: dist-android
       if: branch = auto
     - env: IMAGE=dist-arm-linux DEPLOY=1
+      name: dist-arm-linux
       if: branch = auto
     - env: IMAGE=dist-armhf-linux DEPLOY=1
+      name: dist-armhf-linux
       if: branch = auto
     - env: IMAGE=dist-armv7-linux DEPLOY=1
+      name: dist-armv7-linux
       if: branch = auto
     - env: IMAGE=dist-i586-gnu-i586-i686-musl DEPLOY=1
+      name: dist-i586-gnu-i586-i686-musl
       if: branch = auto
     - env: IMAGE=dist-i686-freebsd DEPLOY=1
+      name: dist-i686-freebsd
       if: branch = auto
     - env: IMAGE=dist-i686-linux DEPLOY=1
+      name: dist-i686-linux
       if: branch = auto
     - env: IMAGE=dist-mips-linux DEPLOY=1
+      name: dist-mips-linux
       if: branch = auto
     - env: IMAGE=dist-mips64-linux DEPLOY=1
+      name: dist-mips64-linux
       if: branch = auto
     - env: IMAGE=dist-mips64el-linux DEPLOY=1
+      name: dist-mips64el-linux
       if: branch = auto
     - env: IMAGE=dist-mipsel-linux DEPLOY=1
+      name: dist-mipsel-linux
       if: branch = auto
     - env: IMAGE=dist-powerpc-linux DEPLOY=1
+      name: dist-powerpc-linux
       if: branch = auto
     - env: IMAGE=dist-powerpc64-linux DEPLOY=1
+      name: dist-powerpc64-linux
       if: branch = auto
     - env: IMAGE=dist-powerpc64le-linux DEPLOY=1
+      name: dist-powerpc64le-linux
       if: branch = auto
     - env: IMAGE=dist-s390x-linux DEPLOY=1
+      name: dist-s390x-linux
       if: branch = auto
     - env: IMAGE=dist-x86_64-freebsd DEPLOY=1
+      name: dist-x86_64-freebsd
       if: branch = auto
     - env: IMAGE=dist-x86_64-musl DEPLOY=1
+      name: dist-x86_64-musl
       if: branch = auto
     - env: IMAGE=dist-x86_64-netbsd DEPLOY=1
+      name: dist-x86_64-netbsd
       if: branch = auto
     - env: IMAGE=asmjs
+      name: asmjs
       if: branch = auto
     - env: IMAGE=i686-gnu
+      name: i686-gnu
       if: branch = auto
     - env: IMAGE=i686-gnu-nopt
+      name: i686-gnu-nopt
       if: branch = auto
     - env: IMAGE=test-various
+      name: test-various
       if: branch = auto
     - env: IMAGE=x86_64-gnu
+      name: x86_64-gnu
       if: branch = auto
     - env: IMAGE=x86_64-gnu-full-bootstrap
+      name: x86_64-gnu-full-bootstrap
       if: branch = auto
     - env: IMAGE=x86_64-gnu-aux
+      name: x86_64-gnu-aux
       if: branch = auto
     - env: IMAGE=x86_64-gnu-tools
+      name: x86_64-gnu-tools
       if: branch = auto OR (type = pull_request AND commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri|cargo)\b)/)
     - env: IMAGE=x86_64-gnu-debug
+      name: x86_64-gnu-debug
       if: branch = auto
     - env: IMAGE=x86_64-gnu-nopt
+      name: x86_64-gnu-nopt
       if: branch = auto
     - env: IMAGE=x86_64-gnu-distcheck
+      name: x86_64-gnu-distcheck
       if: branch = auto
     - env: IMAGE=mingw-check
+      name: mingw-check
       if: type = pull_request OR branch = auto
 
     - stage: publish toolstate
diff --git a/appveyor.yml b/appveyor.yml
index d70ad54b1c812..040e21cba9682 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -7,34 +7,34 @@ environment:
 
   matrix:
   # 32/64 bit MSVC tests
-  - MSYS_BITS: 64
+  - CI_JOB_NAME: x86_64-msvc
+    MSYS_BITS: 64
     RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
     SCRIPT: python x.py test
-    CI_JOB_NAME: x86_64-msvc
-  - MSYS_BITS: 32
+  - CI_JOB_NAME: i686-msvc-1
+    MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
     SCRIPT: make appveyor-subset-1
-    CI_JOB_NAME: i686-msvc-1
-  - MSYS_BITS: 32
+  - CI_JOB_NAME: i686-msvc-2
+    MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
     SCRIPT: make appveyor-subset-2
-    CI_JOB_NAME: i686-msvc-2
 
   # MSVC aux tests
-  - MSYS_BITS: 64
+  - CI_JOB_NAME: x86_64-msvc-aux
+    MSYS_BITS: 64
     RUST_CHECK_TARGET: check-aux EXCLUDE_CARGO=1
     RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
-    CI_JOB_NAME: x86_64-msvc-aux
-  - MSYS_BITS: 64
+  - CI_JOB_NAME: x86_64-msvc-cargo
+    MSYS_BITS: 64
     SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
     RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
-    CI_JOB_NAME: x86_64-msvc-cargo
 
   # MSVC tools tests
-  - MSYS_BITS: 64
+  - CI_JOB_NAME: x86_64-msvc-tools
+    MSYS_BITS: 64
     SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows
     RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri
-    CI_JOB_NAME: x86_64-msvc-tools
 
   # 32/64-bit MinGW builds.
   #
@@ -49,30 +49,31 @@ environment:
   # bucket, but they cleraly didn't originate there! The downloads originally
   # came from the mingw-w64 SourceForge download site. Unfortunately
   # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
-  - MSYS_BITS: 32
+  - CI_JOB_NAME: i686-mingw-1
+    MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
     SCRIPT: make appveyor-subset-1
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
     MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
     MINGW_DIR: mingw32
-    CI_JOB_NAME: i686-mingw-1
-  - MSYS_BITS: 32
+  - CI_JOB_NAME: i686-mingw-2
+    MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
     SCRIPT: make appveyor-subset-2
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
     MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
     MINGW_DIR: mingw32
-    CI_JOB_NAME: i686-mingw-2
-  - MSYS_BITS: 64
+  - CI_JOB_NAME: x86_64-mingw
+    MSYS_BITS: 64
     SCRIPT: python x.py test
     RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
     MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
     MINGW_DIR: mingw64
-    CI_JOB_NAME: x86_64-mingw
 
   # 32/64 bit MSVC and GNU deployment
-  - RUST_CONFIGURE_ARGS: >
+  - CI_JOB_NAME: dist-x86_64-msvc
+    RUST_CONFIGURE_ARGS: >
       --build=x86_64-pc-windows-msvc
       --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
       --enable-full-tools
@@ -80,9 +81,9 @@ environment:
     SCRIPT: python x.py dist
     DIST_REQUIRE_ALL_TOOLS: 1
     DEPLOY: 1
-    CI_JOB_NAME: dist-x86_64-msvc
     APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 Preview
-  - RUST_CONFIGURE_ARGS: >
+  - CI_JOB_NAME: dist-i686-msvc
+    RUST_CONFIGURE_ARGS: >
       --build=i686-pc-windows-msvc
       --target=i586-pc-windows-msvc
       --enable-full-tools
@@ -90,8 +91,8 @@ environment:
     SCRIPT: python x.py dist
     DIST_REQUIRE_ALL_TOOLS: 1
     DEPLOY: 1
-    CI_JOB_NAME: dist-i686-msvc
-  - MSYS_BITS: 32
+  - CI_JOB_NAME: dist-i686-mingw
+    MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools
     SCRIPT: python x.py dist
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
@@ -99,8 +100,8 @@ environment:
     MINGW_DIR: mingw32
     DIST_REQUIRE_ALL_TOOLS: 1
     DEPLOY: 1
-    CI_JOB_NAME: dist-i686-mingw
-  - MSYS_BITS: 64
+  - CI_JOB_NAME: dist-x86_64-mingw
+    MSYS_BITS: 64
     SCRIPT: python x.py dist
     RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
@@ -108,14 +109,13 @@ environment:
     MINGW_DIR: mingw64
     DIST_REQUIRE_ALL_TOOLS: 1
     DEPLOY: 1
-    CI_JOB_NAME: dist-x86_64-mingw
 
   # "alternate" deployment, see .travis.yml for more info
-  - MSYS_BITS: 64
+  - CI_JOB_NAME: dist-x86_64-msvc-alt
+    MSYS_BITS: 64
     RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
     SCRIPT: python x.py dist
     DEPLOY_ALT: 1
-    CI_JOB_NAME: dist-x86_64-msvc-alt
 
 matrix:
   fast_finish: true

From 4888b1fb99f1bf6a58bebaededdfbf4477383634 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 10 Mar 2019 17:45:45 +0100
Subject: [PATCH 14/37] we can now skip should_panic tests with the libtest
 harness

---
 src/liballoc/tests/binary_heap.rs |  2 +-
 src/liballoc/tests/btree/map.rs   |  5 -----
 src/liballoc/tests/slice.rs       | 18 ------------------
 src/liballoc/tests/str.rs         | 11 -----------
 src/liballoc/tests/string.rs      |  9 ---------
 src/liballoc/tests/vec.rs         | 12 ------------
 src/liballoc/tests/vec_deque.rs   |  1 -
 src/libcore/tests/cell.rs         |  3 ---
 src/libcore/tests/iter.rs         |  2 --
 src/libcore/tests/num/bignum.rs   | 14 --------------
 src/libcore/tests/option.rs       |  3 ---
 src/libcore/tests/result.rs       |  3 ---
 src/libcore/tests/slice.rs        |  7 -------
 src/libcore/tests/time.rs         |  2 --
 14 files changed, 1 insertion(+), 91 deletions(-)

diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs
index 1d4a3edc1ac42..a97a790f5a2d8 100644
--- a/src/liballoc/tests/binary_heap.rs
+++ b/src/liballoc/tests/binary_heap.rs
@@ -282,7 +282,7 @@ fn assert_covariance() {
 //
 // Destructors must be called exactly once per element.
 #[test]
-#[cfg(not(miri))] // Miri does not support panics
+#[cfg(not(miri))] // Miri does not support entropy
 fn panic_safe() {
     static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
 
diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs
index f14750089c956..844afe870766b 100644
--- a/src/liballoc/tests/btree/map.rs
+++ b/src/liballoc/tests/btree/map.rs
@@ -226,7 +226,6 @@ fn test_range_equal_empty_cases() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_range_equal_excluded() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
     map.range((Excluded(2), Excluded(2)));
@@ -234,7 +233,6 @@ fn test_range_equal_excluded() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_range_backwards_1() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
     map.range((Included(3), Included(2)));
@@ -242,7 +240,6 @@ fn test_range_backwards_1() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_range_backwards_2() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
     map.range((Included(3), Excluded(2)));
@@ -250,7 +247,6 @@ fn test_range_backwards_2() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_range_backwards_3() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
     map.range((Excluded(3), Included(2)));
@@ -258,7 +254,6 @@ fn test_range_backwards_3() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_range_backwards_4() {
     let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
     map.range((Excluded(3), Excluded(2)));
diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs
index feba46b0fad78..fb99c95fc6842 100644
--- a/src/liballoc/tests/slice.rs
+++ b/src/liballoc/tests/slice.rs
@@ -258,7 +258,6 @@ fn test_swap_remove() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_swap_remove_fail() {
     let mut v = vec![1];
     let _ = v.swap_remove(0);
@@ -632,7 +631,6 @@ fn test_insert() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_insert_oob() {
     let mut a = vec![1, 2, 3];
     a.insert(4, 5);
@@ -657,7 +655,6 @@ fn test_remove() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_remove_fail() {
     let mut a = vec![1];
     let _ = a.remove(0);
@@ -939,7 +936,6 @@ fn test_windowsator() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_windowsator_0() {
     let v = &[1, 2, 3, 4];
     let _it = v.windows(0);
@@ -964,7 +960,6 @@ fn test_chunksator() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_chunksator_0() {
     let v = &[1, 2, 3, 4];
     let _it = v.chunks(0);
@@ -989,7 +984,6 @@ fn test_chunks_exactator() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_chunks_exactator_0() {
     let v = &[1, 2, 3, 4];
     let _it = v.chunks_exact(0);
@@ -1014,7 +1008,6 @@ fn test_rchunksator() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_rchunksator_0() {
     let v = &[1, 2, 3, 4];
     let _it = v.rchunks(0);
@@ -1039,7 +1032,6 @@ fn test_rchunks_exactator() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_rchunks_exactator_0() {
     let v = &[1, 2, 3, 4];
     let _it = v.rchunks_exact(0);
@@ -1092,7 +1084,6 @@ fn test_vec_default() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_overflow_does_not_cause_segfault() {
     let mut v = vec![];
     v.reserve_exact(!0);
@@ -1102,7 +1093,6 @@ fn test_overflow_does_not_cause_segfault() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_overflow_does_not_cause_segfault_managed() {
     let mut v = vec![Rc::new(1)];
     v.reserve_exact(!0);
@@ -1278,7 +1268,6 @@ fn test_mut_chunks_rev() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mut_chunks_0() {
     let mut v = [1, 2, 3, 4];
     let _it = v.chunks_mut(0);
@@ -1311,7 +1300,6 @@ fn test_mut_chunks_exact_rev() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mut_chunks_exact_0() {
     let mut v = [1, 2, 3, 4];
     let _it = v.chunks_exact_mut(0);
@@ -1344,7 +1332,6 @@ fn test_mut_rchunks_rev() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mut_rchunks_0() {
     let mut v = [1, 2, 3, 4];
     let _it = v.rchunks_mut(0);
@@ -1377,7 +1364,6 @@ fn test_mut_rchunks_exact_rev() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mut_rchunks_exact_0() {
     let mut v = [1, 2, 3, 4];
     let _it = v.rchunks_exact_mut(0);
@@ -1411,7 +1397,6 @@ fn test_box_slice_clone() {
 #[test]
 #[allow(unused_must_use)] // here, we care about the side effects of `.clone()`
 #[cfg_attr(target_os = "emscripten", ignore)]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_box_slice_clone_panics() {
     use std::sync::Arc;
     use std::sync::atomic::{AtomicUsize, Ordering};
@@ -1476,7 +1461,6 @@ fn test_copy_from_slice() {
 
 #[test]
 #[should_panic(expected = "destination and source slices have different lengths")]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_copy_from_slice_dst_longer() {
     let src = [0, 1, 2, 3];
     let mut dst = [0; 5];
@@ -1485,7 +1469,6 @@ fn test_copy_from_slice_dst_longer() {
 
 #[test]
 #[should_panic(expected = "destination and source slices have different lengths")]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_copy_from_slice_dst_shorter() {
     let src = [0, 1, 2, 3];
     let mut dst = [0; 3];
@@ -1605,7 +1588,6 @@ thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
 
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)] // no threads
-#[cfg(not(miri))] // Miri does not support panics
 fn panic_safe() {
     let prev = panic::take_hook();
     panic::set_hook(Box::new(move |info| {
diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs
index b33a564218888..f2dc19a42296a 100644
--- a/src/liballoc/tests/str.rs
+++ b/src/liballoc/tests/str.rs
@@ -351,7 +351,6 @@ mod slice_index {
     //  to be used in `should_panic`)
     #[test]
     #[should_panic(expected = "out of bounds")]
-    #[cfg(not(miri))] // Miri does not support panics
     fn assert_range_eq_can_fail_by_panic() {
         assert_range_eq!("abc", 0..5, "abc");
     }
@@ -361,7 +360,6 @@ mod slice_index {
     //  to be used in `should_panic`)
     #[test]
     #[should_panic(expected = "==")]
-    #[cfg(not(miri))] // Miri does not support panics
     fn assert_range_eq_can_fail_by_inequality() {
         assert_range_eq!("abc", 0..2, "abc");
     }
@@ -409,7 +407,6 @@ mod slice_index {
 
                 #[test]
                 #[should_panic(expected = $expect_msg)]
-                #[cfg(not(miri))] // Miri does not support panics
                 fn index_fail() {
                     let v: String = $data.into();
                     let v: &str = &v;
@@ -418,7 +415,6 @@ mod slice_index {
 
                 #[test]
                 #[should_panic(expected = $expect_msg)]
-                #[cfg(not(miri))] // Miri does not support panics
                 fn index_mut_fail() {
                     let mut v: String = $data.into();
                     let v: &mut str = &mut v;
@@ -514,7 +510,6 @@ mod slice_index {
 
     #[test]
     #[should_panic]
-    #[cfg(not(miri))] // Miri does not support panics
     fn test_slice_fail() {
         &"中华Việt Nam"[0..2];
     }
@@ -666,14 +661,12 @@ mod slice_index {
     // check the panic includes the prefix of the sliced string
     #[test]
     #[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
-    #[cfg(not(miri))] // Miri does not support panics
     fn test_slice_fail_truncated_1() {
         &LOREM_PARAGRAPH[..1024];
     }
     // check the truncation in the panic message
     #[test]
     #[should_panic(expected="luctus, im`[...]")]
-    #[cfg(not(miri))] // Miri does not support panics
     fn test_slice_fail_truncated_2() {
         &LOREM_PARAGRAPH[..1024];
     }
@@ -688,7 +681,6 @@ fn test_str_slice_rangetoinclusive_ok() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_str_slice_rangetoinclusive_notok() {
     let s = "abcαβγ";
     &s[..=3];
@@ -704,7 +696,6 @@ fn test_str_slicemut_rangetoinclusive_ok() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_str_slicemut_rangetoinclusive_notok() {
     let mut s = "abcαβγ".to_owned();
     let s: &mut str = &mut s;
@@ -894,7 +885,6 @@ fn test_as_bytes() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_as_bytes_fail() {
     // Don't double free. (I'm not sure if this exercises the
     // original problem code path anymore.)
@@ -984,7 +974,6 @@ fn test_split_at_mut() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_split_at_boundscheck() {
     let s = "ศไทย中华Việt Nam";
     s.split_at(1);
diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs
index 7e93d84fe3b97..7e75b8c4f28c8 100644
--- a/src/liballoc/tests/string.rs
+++ b/src/liballoc/tests/string.rs
@@ -231,7 +231,6 @@ fn test_split_off_empty() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_split_off_past_end() {
     let orig = "Hello, world!";
     let mut split = String::from(orig);
@@ -240,7 +239,6 @@ fn test_split_off_past_end() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_split_off_mid_char() {
     let mut orig = String::from("山");
     orig.split_off(1);
@@ -289,7 +287,6 @@ fn test_str_truncate_invalid_len() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_str_truncate_split_codepoint() {
     let mut s = String::from("\u{FC}"); // ü
     s.truncate(1);
@@ -324,7 +321,6 @@ fn remove() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn remove_bad() {
     "ศ".to_string().remove(1);
 }
@@ -360,13 +356,11 @@ fn insert() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn insert_bad1() {
     "".to_string().insert(1, 't');
 }
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn insert_bad2() {
     "ệ".to_string().insert(1, 't');
 }
@@ -447,7 +441,6 @@ fn test_replace_range() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_replace_range_char_boundary() {
     let mut s = "Hello, 世界!".to_owned();
     s.replace_range(..8, "");
@@ -464,7 +457,6 @@ fn test_replace_range_inclusive_range() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_replace_range_out_of_bounds() {
     let mut s = String::from("12345");
     s.replace_range(5..6, "789");
@@ -472,7 +464,6 @@ fn test_replace_range_out_of_bounds() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_replace_range_inclusive_out_of_bounds() {
     let mut s = String::from("12345");
     s.replace_range(5..=5, "789");
diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs
index 6e4ca1d90e642..545332bcd6a2f 100644
--- a/src/liballoc/tests/vec.rs
+++ b/src/liballoc/tests/vec.rs
@@ -368,7 +368,6 @@ fn test_vec_truncate_drop() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_vec_truncate_fail() {
     struct BadElem(i32);
     impl Drop for BadElem {
@@ -392,7 +391,6 @@ fn test_index() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_index_out_of_bounds() {
     let vec = vec![1, 2, 3];
     let _ = vec[3];
@@ -400,7 +398,6 @@ fn test_index_out_of_bounds() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_slice_out_of_bounds_1() {
     let x = vec![1, 2, 3, 4, 5];
     &x[!0..];
@@ -408,7 +405,6 @@ fn test_slice_out_of_bounds_1() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_slice_out_of_bounds_2() {
     let x = vec![1, 2, 3, 4, 5];
     &x[..6];
@@ -416,7 +412,6 @@ fn test_slice_out_of_bounds_2() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_slice_out_of_bounds_3() {
     let x = vec![1, 2, 3, 4, 5];
     &x[!0..4];
@@ -424,7 +419,6 @@ fn test_slice_out_of_bounds_3() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_slice_out_of_bounds_4() {
     let x = vec![1, 2, 3, 4, 5];
     &x[1..6];
@@ -432,7 +426,6 @@ fn test_slice_out_of_bounds_4() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_slice_out_of_bounds_5() {
     let x = vec![1, 2, 3, 4, 5];
     &x[3..2];
@@ -440,7 +433,6 @@ fn test_slice_out_of_bounds_5() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_swap_remove_empty() {
     let mut vec = Vec::<i32>::new();
     vec.swap_remove(0);
@@ -511,7 +503,6 @@ fn test_drain_items_zero_sized() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_drain_out_of_bounds() {
     let mut v = vec![1, 2, 3, 4, 5];
     v.drain(5..6);
@@ -585,7 +576,6 @@ fn test_drain_max_vec_size() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_drain_inclusive_out_of_bounds() {
     let mut v = vec![1, 2, 3, 4, 5];
     v.drain(5..=5);
@@ -615,7 +605,6 @@ fn test_splice_inclusive_range() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_splice_out_of_bounds() {
     let mut v = vec![1, 2, 3, 4, 5];
     let a = [10, 11, 12];
@@ -624,7 +613,6 @@ fn test_splice_out_of_bounds() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_splice_inclusive_out_of_bounds() {
     let mut v = vec![1, 2, 3, 4, 5];
     let a = [10, 11, 12];
diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs
index 16ddc1444fcf9..e0fe10a55f55c 100644
--- a/src/liballoc/tests/vec_deque.rs
+++ b/src/liballoc/tests/vec_deque.rs
@@ -108,7 +108,6 @@ fn test_index() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_index_out_of_bounds() {
     let mut deq = VecDeque::new();
     for i in 1..4 {
diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs
index b16416022c04e..56f295dff8e43 100644
--- a/src/libcore/tests/cell.rs
+++ b/src/libcore/tests/cell.rs
@@ -109,7 +109,6 @@ fn double_borrow_single_release_no_borrow_mut() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn discard_doesnt_unborrow() {
     let x = RefCell::new(0);
     let _b = x.borrow();
@@ -350,7 +349,6 @@ fn refcell_ref_coercion() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn refcell_swap_borrows() {
     let x = RefCell::new(0);
     let _b = x.borrow();
@@ -360,7 +358,6 @@ fn refcell_swap_borrows() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn refcell_replace_borrows() {
     let x = RefCell::new(0);
     let _b = x.borrow();
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index d880abb181c20..4652fc329dc02 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -253,7 +253,6 @@ fn test_iterator_step_by_nth_overflow() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_iterator_step_by_zero() {
     let mut it = (0..).step_by(0);
     it.next();
@@ -1414,7 +1413,6 @@ fn test_rposition() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_rposition_panic() {
     let v: [(Box<_>, Box<_>); 4] =
         [(box 0, box 0), (box 0, box 0),
diff --git a/src/libcore/tests/num/bignum.rs b/src/libcore/tests/num/bignum.rs
index 956c22c998219..b873f1dd0652f 100644
--- a/src/libcore/tests/num/bignum.rs
+++ b/src/libcore/tests/num/bignum.rs
@@ -3,7 +3,6 @@ use core::num::bignum::tests::Big8x3 as Big;
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_from_u64_overflow() {
     Big::from_u64(0x1000000);
 }
@@ -20,14 +19,12 @@ fn test_add() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_add_overflow_1() {
     Big::from_small(1).add(&Big::from_u64(0xffffff));
 }
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_add_overflow_2() {
     Big::from_u64(0xffffff).add(&Big::from_small(1));
 }
@@ -45,7 +42,6 @@ fn test_add_small() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_add_small_overflow() {
     Big::from_u64(0xffffff).add_small(1);
 }
@@ -61,14 +57,12 @@ fn test_sub() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_sub_underflow_1() {
     Big::from_u64(0x10665).sub(&Big::from_u64(0x10666));
 }
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_sub_underflow_2() {
     Big::from_small(0).sub(&Big::from_u64(0x123456));
 }
@@ -82,7 +76,6 @@ fn test_mul_small() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mul_small_overflow() {
     Big::from_u64(0x800000).mul_small(2);
 }
@@ -101,14 +94,12 @@ fn test_mul_pow2() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mul_pow2_overflow_1() {
     Big::from_u64(0x1).mul_pow2(24);
 }
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mul_pow2_overflow_2() {
     Big::from_u64(0x123).mul_pow2(16);
 }
@@ -127,14 +118,12 @@ fn test_mul_pow5() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mul_pow5_overflow_1() {
     Big::from_small(1).mul_pow5(12);
 }
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mul_pow5_overflow_2() {
     Big::from_small(230).mul_pow5(8);
 }
@@ -152,14 +141,12 @@ fn test_mul_digits() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mul_digits_overflow_1() {
     Big::from_u64(0x800000).mul_digits(&[2]);
 }
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_mul_digits_overflow_2() {
     Big::from_u64(0x1000).mul_digits(&[0, 0x10]);
 }
@@ -219,7 +206,6 @@ fn test_get_bit() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_get_bit_out_of_range() {
     Big::from_small(42).get_bit(24);
 }
diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs
index 87ce2720c5918..b059b134868d9 100644
--- a/src/libcore/tests/option.rs
+++ b/src/libcore/tests/option.rs
@@ -69,7 +69,6 @@ fn test_option_dance() {
 }
 
 #[test] #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_option_too_much_dance() {
     struct A;
     let mut y = Some(A);
@@ -130,7 +129,6 @@ fn test_unwrap() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_unwrap_panic1() {
     let x: Option<isize> = None;
     x.unwrap();
@@ -138,7 +136,6 @@ fn test_unwrap_panic1() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_unwrap_panic2() {
     let x: Option<String> = None;
     x.unwrap();
diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs
index bbc8568517667..1fab07526a07f 100644
--- a/src/libcore/tests/result.rs
+++ b/src/libcore/tests/result.rs
@@ -117,7 +117,6 @@ fn test_unwrap_or_else() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 pub fn test_unwrap_or_else_panic() {
     fn handler(msg: &'static str) -> isize {
         if msg == "I got this." {
@@ -139,7 +138,6 @@ pub fn test_expect_ok() {
 }
 #[test]
 #[should_panic(expected="Got expected error: \"All good\"")]
-#[cfg(not(miri))] // Miri does not support panics
 pub fn test_expect_err() {
     let err: Result<isize, &'static str> = Err("All good");
     err.expect("Got expected error");
@@ -153,7 +151,6 @@ pub fn test_expect_err_err() {
 }
 #[test]
 #[should_panic(expected="Got expected ok: \"All good\"")]
-#[cfg(not(miri))] // Miri does not support panics
 pub fn test_expect_err_ok() {
     let err: Result<&'static str, isize> = Ok("All good");
     err.expect_err("Got expected ok");
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 31d16e0e32057..ac9c17a0f7c35 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -782,7 +782,6 @@ mod slice_index {
     //  to be used in `should_panic`)
     #[test]
     #[should_panic(expected = "out of range")]
-    #[cfg(not(miri))] // Miri does not support panics
     fn assert_range_eq_can_fail_by_panic() {
         assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]);
     }
@@ -792,7 +791,6 @@ mod slice_index {
     //  to be used in `should_panic`)
     #[test]
     #[should_panic(expected = "==")]
-    #[cfg(not(miri))] // Miri does not support panics
     fn assert_range_eq_can_fail_by_inequality() {
         assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]);
     }
@@ -842,7 +840,6 @@ mod slice_index {
 
                 #[test]
                 #[should_panic(expected = $expect_msg)]
-                #[cfg(not(miri))] // Miri does not support panics
                 fn index_fail() {
                     let v = $data;
                     let v: &[_] = &v;
@@ -851,7 +848,6 @@ mod slice_index {
 
                 #[test]
                 #[should_panic(expected = $expect_msg)]
-                #[cfg(not(miri))] // Miri does not support panics
                 fn index_mut_fail() {
                     let mut v = $data;
                     let v: &mut [_] = &mut v;
@@ -1304,7 +1300,6 @@ fn test_copy_within() {
 
 #[test]
 #[should_panic(expected = "src is out of bounds")]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_copy_within_panics_src_too_long() {
     let mut bytes = *b"Hello, World!";
     // The length is only 13, so 14 is out of bounds.
@@ -1313,7 +1308,6 @@ fn test_copy_within_panics_src_too_long() {
 
 #[test]
 #[should_panic(expected = "dest is out of bounds")]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_copy_within_panics_dest_too_long() {
     let mut bytes = *b"Hello, World!";
     // The length is only 13, so a slice of length 4 starting at index 10 is out of bounds.
@@ -1321,7 +1315,6 @@ fn test_copy_within_panics_dest_too_long() {
 }
 #[test]
 #[should_panic(expected = "src end is before src start")]
-#[cfg(not(miri))] // Miri does not support panics
 fn test_copy_within_panics_src_inverted() {
     let mut bytes = *b"Hello, World!";
     // 2 is greater than 1, so this range is invalid.
diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs
index 09aae4583482f..6efd22572dc18 100644
--- a/src/libcore/tests/time.rs
+++ b/src/libcore/tests/time.rs
@@ -107,14 +107,12 @@ fn checked_sub() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn sub_bad1() {
     let _ = Duration::new(0, 0) - Duration::new(0, 1);
 }
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn sub_bad2() {
     let _ = Duration::new(0, 0) - Duration::new(1, 0);
 }

From 52d9fa827d3cf5ef5fc0e2042ca1fc7f6dc391ed Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 10 Mar 2019 17:52:45 +0100
Subject: [PATCH 15/37] enabled too many tests

---
 src/liballoc/tests/binary_heap.rs | 2 +-
 src/liballoc/tests/slice.rs       | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs
index a97a790f5a2d8..0930f8dacd494 100644
--- a/src/liballoc/tests/binary_heap.rs
+++ b/src/liballoc/tests/binary_heap.rs
@@ -282,7 +282,7 @@ fn assert_covariance() {
 //
 // Destructors must be called exactly once per element.
 #[test]
-#[cfg(not(miri))] // Miri does not support entropy
+#[cfg(not(miri))] // Miri does not support panics nor entropy
 fn panic_safe() {
     static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
 
diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs
index fb99c95fc6842..b54c128a0249a 100644
--- a/src/liballoc/tests/slice.rs
+++ b/src/liballoc/tests/slice.rs
@@ -1397,6 +1397,7 @@ fn test_box_slice_clone() {
 #[test]
 #[allow(unused_must_use)] // here, we care about the side effects of `.clone()`
 #[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg(not(miri))] // Miri does not support threads nor entropy
 fn test_box_slice_clone_panics() {
     use std::sync::Arc;
     use std::sync::atomic::{AtomicUsize, Ordering};
@@ -1588,6 +1589,7 @@ thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
 
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)] // no threads
+#[cfg(not(miri))] // Miri does not support threads nor entropy
 fn panic_safe() {
     let prev = panic::take_hook();
     panic::set_hook(Box::new(move |info| {

From 537d4dd98a647905434ddd449b490133c65e0ab2 Mon Sep 17 00:00:00 2001
From: Andy Russell <arussell123@gmail.com>
Date: Thu, 28 Feb 2019 13:54:19 -0500
Subject: [PATCH 16/37] overhaul intra-doc-link ambiguity warning

- Makes the warning part of the `intra_doc_link_resolution_failure`
lint.
- Tightens the span to just the ambiguous link.
- Reports ambiguities across all three namespaces.
- Uses structured suggestions for disambiguation.
- Adds a test for the warnings.
---
 .../passes/collect_intra_doc_links.rs         | 240 +++++++++++-------
 src/test/rustdoc-ui/intra-links-ambiguity.rs  |  36 +++
 .../rustdoc-ui/intra-links-ambiguity.stderr   |  82 ++++++
 src/test/rustdoc/intra-links.rs               |   3 +-
 4 files changed, 266 insertions(+), 95 deletions(-)
 create mode 100644 src/test/rustdoc-ui/intra-links-ambiguity.rs
 create mode 100644 src/test/rustdoc-ui/intra-links-ambiguity.stderr

diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index fefff1f3a7593..36bfe2fb2c3da 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1,7 +1,8 @@
-use rustc::lint as lint;
-use rustc::hir;
+use errors::Applicability;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
+use rustc::hir;
+use rustc::lint as lint;
 use rustc::ty;
 use syntax;
 use syntax::ast::{self, Ident};
@@ -53,6 +54,13 @@ struct LinkCollector<'a, 'tcx> {
     is_nightly_build: bool,
 }
 
+#[derive(Debug, Copy, Clone)]
+enum Namespace {
+    Type,
+    Value,
+    Macro,
+}
+
 impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     fn new(cx: &'a DocContext<'tcx>) -> Self {
         LinkCollector {
@@ -345,57 +353,52 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                     }
                     PathKind::Unknown => {
                         // Try everything!
+                        let mut candidates = vec![];
+
                         if let Some(macro_def) = macro_resolve(cx, path_str) {
-                            if let Ok(type_def) =
-                                self.resolve(path_str, false, &current_item, parent_node)
-                            {
-                                let (type_kind, article, type_disambig)
-                                    = type_ns_kind(type_def.0, path_str);
-                                ambiguity_error(cx, &item.attrs, path_str,
-                                                article, type_kind, &type_disambig,
-                                                "a", "macro", &format!("macro@{}", path_str));
-                                continue;
-                            } else if let Ok(value_def) =
-                                self.resolve(path_str, true, &current_item, parent_node)
-                            {
-                                let (value_kind, value_disambig)
-                                    = value_ns_kind(value_def.0, path_str)
-                                        .expect("struct and mod cases should have been \
-                                                 caught in previous branch");
-                                ambiguity_error(cx, &item.attrs, path_str,
-                                                "a", value_kind, &value_disambig,
-                                                "a", "macro", &format!("macro@{}", path_str));
-                            }
-                            (macro_def, None)
-                        } else if let Ok(type_def) =
+                            candidates.push(((macro_def, None), Namespace::Macro));
+                        }
+
+                        if let Ok(type_def) =
                             self.resolve(path_str, false, &current_item, parent_node)
                         {
-                            // It is imperative we search for not-a-value first
-                            // Otherwise we will find struct ctors for when we are looking
-                            // for structs, and the link won't work if there is something in
-                            // both namespaces.
-                            if let Ok(value_def) =
-                                self.resolve(path_str, true, &current_item, parent_node)
-                            {
-                                let kind = value_ns_kind(value_def.0, path_str);
-                                if let Some((value_kind, value_disambig)) = kind {
-                                    let (type_kind, article, type_disambig)
-                                        = type_ns_kind(type_def.0, path_str);
-                                    ambiguity_error(cx, &item.attrs, path_str,
-                                                    article, type_kind, &type_disambig,
-                                                    "a", value_kind, &value_disambig);
-                                    continue;
-                                }
-                            }
-                            type_def
-                        } else if let Ok(value_def) =
+                            candidates.push((type_def, Namespace::Type));
+                        }
+
+                        if let Ok(value_def) =
                             self.resolve(path_str, true, &current_item, parent_node)
                         {
-                            value_def
-                        } else {
+                            // Structs, variants, and mods exist in both namespaces, skip them.
+                            match value_def.0 {
+                                Def::StructCtor(..)
+                                | Def::Mod(..)
+                                | Def::Variant(..)
+                                | Def::VariantCtor(..)
+                                | Def::SelfCtor(..) => (),
+                                _ => candidates.push((value_def, Namespace::Value)),
+                            }
+                        }
+
+                        if candidates.len() == 1 {
+                            candidates.remove(0).0
+                        } else if candidates.is_empty() {
                             resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
                             // this could just be a normal link
                             continue;
+                        } else {
+                            let candidates = candidates.into_iter().map(|((def, _), ns)| {
+                                (def, ns)
+                            }).collect::<Vec<_>>();
+
+                            ambiguity_error(
+                                cx,
+                                &item.attrs,
+                                path_str,
+                                &dox,
+                                link_range,
+                                &candidates,
+                            );
+                            continue;
                         }
                     }
                     PathKind::Macro => {
@@ -505,59 +508,108 @@ fn resolution_failure(
     diag.emit();
 }
 
-fn ambiguity_error(cx: &DocContext<'_>, attrs: &Attributes,
-                   path_str: &str,
-                   article1: &str, kind1: &str, disambig1: &str,
-                   article2: &str, kind2: &str, disambig2: &str) {
+fn ambiguity_error(
+    cx: &DocContext<'_>,
+    attrs: &Attributes,
+    path_str: &str,
+    dox: &str,
+    link_range: Option<Range<usize>>,
+    candidates: &[(Def, Namespace)],
+) {
     let sp = span_of_attrs(attrs);
-    cx.sess()
-      .struct_span_warn(sp,
-                        &format!("`{}` is both {} {} and {} {}",
-                                 path_str, article1, kind1,
-                                 article2, kind2))
-      .help(&format!("try `{}` if you want to select the {}, \
-                      or `{}` if you want to \
-                      select the {}",
-                      disambig1, kind1, disambig2,
-                      kind2))
-      .emit();
-}
 
-/// Given a def, returns its name and disambiguator
-/// for a value namespace.
-///
-/// Returns `None` for things which cannot be ambiguous since
-/// they exist in both namespaces (structs and modules).
-fn value_ns_kind(def: Def, path_str: &str) -> Option<(&'static str, String)> {
-    match def {
-        // Structs, variants, and mods exist in both namespaces; skip them.
-        Def::StructCtor(..) | Def::Mod(..) | Def::Variant(..) |
-        Def::VariantCtor(..) | Def::SelfCtor(..)
-            => None,
-        Def::Fn(..)
-            => Some(("function", format!("{}()", path_str))),
-        Def::Method(..)
-            => Some(("method", format!("{}()", path_str))),
-        Def::Const(..)
-            => Some(("const", format!("const@{}", path_str))),
-        Def::Static(..)
-            => Some(("static", format!("static@{}", path_str))),
-        _ => Some(("value", format!("value@{}", path_str))),
+    let mut msg = format!("`{}` is ", path_str);
+
+    match candidates {
+        [(first_def, _), (second_def, _)] => {
+            msg += &format!(
+                "both {} {} and {} {}",
+                first_def.article(),
+                first_def.kind_name(),
+                second_def.article(),
+                second_def.kind_name(),
+            );
+        }
+        _ => {
+            let mut candidates = candidates.iter().peekable();
+            while let Some((def, _)) = candidates.next() {
+                if candidates.peek().is_some() {
+                    msg += &format!("{} {}, ", def.article(), def.kind_name());
+                } else {
+                    msg += &format!("and {} {}", def.article(), def.kind_name());
+                }
+            }
+        }
     }
-}
 
-/// Given a def, returns its name, the article to be used, and a disambiguator
-/// for the type namespace.
-fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String) {
-    let (kind, article) = match def {
-        // We can still have non-tuple structs.
-        Def::Struct(..) => ("struct", "a"),
-        Def::Enum(..) => ("enum", "an"),
-        Def::Trait(..) => ("trait", "a"),
-        Def::Union(..) => ("union", "a"),
-        _ => ("type", "a"),
-    };
-    (kind, article, format!("{}@{}", kind, path_str))
+    let mut diag = cx.tcx.struct_span_lint_hir(
+        lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
+        hir::CRATE_HIR_ID,
+        sp,
+        &msg,
+    );
+
+    if let Some(link_range) = link_range {
+        if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) {
+            diag.set_span(sp);
+            diag.span_label(sp, "ambiguous link");
+
+            for (def, ns) in candidates {
+                let (action, mut suggestion) = match def {
+                    Def::Method(..) | Def::Fn(..) => {
+                        ("add parentheses", format!("{}()", path_str))
+                    }
+                    _ => {
+                        let type_ = match (def, ns) {
+                            (Def::Const(..), _) => "const",
+                            (Def::Static(..), _) => "static",
+                            (Def::Struct(..), _) => "struct",
+                            (Def::Enum(..), _) => "enum",
+                            (Def::Union(..), _) => "union",
+                            (Def::Trait(..), _) => "trait",
+                            (Def::Mod(..), _) => "module",
+                            (_, Namespace::Type) => "type",
+                            (_, Namespace::Value) => "value",
+                            (_, Namespace::Macro) => "macro",
+                        };
+
+                        // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
+                        ("prefix with the item type", format!("{}@{}", type_, path_str))
+                    }
+                };
+
+                if dox.bytes().nth(link_range.start) == Some(b'`') {
+                    suggestion = format!("`{}`", suggestion);
+                }
+
+                diag.span_suggestion(
+                    sp,
+                    &format!("to link to the {}, {}", def.kind_name(), action),
+                    suggestion,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        } else {
+            // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
+            //                       ^     ~~~~
+            //                       |     link_range
+            //                       last_new_line_offset
+            let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
+            let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
+
+            // Print the line containing the `link_range` and manually mark it with '^'s.
+            diag.note(&format!(
+                "the link appears in this line:\n\n{line}\n\
+                 {indicator: <before$}{indicator:^<found$}",
+                line=line,
+                indicator="",
+                before=link_range.start - last_new_line_offset,
+                found=link_range.len(),
+            ));
+        }
+    }
+
+    diag.emit();
 }
 
 /// Given an enum variant's def, return the def of its enum and the associated fragment.
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.rs b/src/test/rustdoc-ui/intra-links-ambiguity.rs
new file mode 100644
index 0000000000000..7316fcdad6772
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.rs
@@ -0,0 +1,36 @@
+#![deny(intra_doc_link_resolution_failure)]
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+
+pub fn ambiguous() {}
+
+pub struct ambiguous {}
+
+#[macro_export]
+macro_rules! multi_conflict { () => {} }
+
+#[allow(non_camel_case_types)]
+pub struct multi_conflict {}
+
+pub fn multi_conflict() {}
+
+pub mod type_and_value {}
+
+pub const type_and_value: i32 = 0;
+
+pub mod foo {
+    pub enum bar {}
+
+    pub fn bar() {}
+}
+
+/// [`ambiguous`] is ambiguous. //~ERROR `ambiguous`
+///
+/// [ambiguous] is ambiguous. //~ERROR ambiguous
+///
+/// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
+///
+/// Ambiguous [type_and_value]. //~ERROR type_and_value
+///
+/// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar`
+pub struct Docs {}
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
new file mode 100644
index 0000000000000..5b8978e3053b6
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
@@ -0,0 +1,82 @@
+error: `ambiguous` is both a struct and a function
+  --> $DIR/intra-links-ambiguity.rs:27:6
+   |
+LL | /// [`ambiguous`] is ambiguous. //~ERROR `ambiguous`
+   |      ^^^^^^^^^^^ ambiguous link
+   |
+note: lint level defined here
+  --> $DIR/intra-links-ambiguity.rs:1:9
+   |
+LL | #![deny(intra_doc_link_resolution_failure)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the struct, prefix with the item type
+   |
+LL | /// [`struct@ambiguous`] is ambiguous. //~ERROR `ambiguous`
+   |      ^^^^^^^^^^^^^^^^^^
+help: to link to the function, add parentheses
+   |
+LL | /// [`ambiguous()`] is ambiguous. //~ERROR `ambiguous`
+   |      ^^^^^^^^^^^^^
+
+error: `ambiguous` is both a struct and a function
+  --> $DIR/intra-links-ambiguity.rs:29:6
+   |
+LL | /// [ambiguous] is ambiguous. //~ERROR ambiguous
+   |      ^^^^^^^^^ ambiguous link
+help: to link to the struct, prefix with the item type
+   |
+LL | /// [struct@ambiguous] is ambiguous. //~ERROR ambiguous
+   |      ^^^^^^^^^^^^^^^^
+help: to link to the function, add parentheses
+   |
+LL | /// [ambiguous()] is ambiguous. //~ERROR ambiguous
+   |      ^^^^^^^^^^^
+
+error: `multi_conflict` is a macro, a struct, and a function
+  --> $DIR/intra-links-ambiguity.rs:31:6
+   |
+LL | /// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
+   |      ^^^^^^^^^^^^^^^^ ambiguous link
+help: to link to the macro, prefix with the item type
+   |
+LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
+   |      ^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the struct, prefix with the item type
+   |
+LL | /// [`struct@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the function, add parentheses
+   |
+LL | /// [`multi_conflict()`] is a three-way conflict. //~ERROR `multi_conflict`
+   |      ^^^^^^^^^^^^^^^^^^
+
+error: `type_and_value` is both a module and a constant
+  --> $DIR/intra-links-ambiguity.rs:33:16
+   |
+LL | /// Ambiguous [type_and_value]. //~ERROR type_and_value
+   |                ^^^^^^^^^^^^^^ ambiguous link
+help: to link to the module, prefix with the item type
+   |
+LL | /// Ambiguous [module@type_and_value]. //~ERROR type_and_value
+   |                ^^^^^^^^^^^^^^^^^^^^^
+help: to link to the constant, prefix with the item type
+   |
+LL | /// Ambiguous [const@type_and_value]. //~ERROR type_and_value
+   |                ^^^^^^^^^^^^^^^^^^^^
+
+error: `foo::bar` is both an enum and a function
+  --> $DIR/intra-links-ambiguity.rs:35:42
+   |
+LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar`
+   |                                          ^^^^^^^^^^ ambiguous link
+help: to link to the enum, prefix with the item type
+   |
+LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`]. //~ERROR `foo::bar`
+   |                                          ^^^^^^^^^^^^^^^
+help: to link to the function, add parentheses
+   |
+LL | /// Ambiguous non-implied shortcut link [`foo::bar()`]. //~ERROR `foo::bar`
+   |                                          ^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/rustdoc/intra-links.rs b/src/test/rustdoc/intra-links.rs
index 9139fc51b092e..c356ab3a8ac52 100644
--- a/src/test/rustdoc/intra-links.rs
+++ b/src/test/rustdoc/intra-links.rs
@@ -22,6 +22,7 @@
 //! * [`ThisType::this_method`](ThisType::this_method)
 //! * [`ThisEnum`](ThisEnum)
 //! * [`ThisEnum::ThisVariant`](ThisEnum::ThisVariant)
+//! * [`ThisEnum::ThisVariantCtor`](ThisEnum::ThisVariantCtor)
 //! * [`ThisTrait`](ThisTrait)
 //! * [`ThisTrait::this_associated_method`](ThisTrait::this_associated_method)
 //! * [`ThisTrait::ThisAssociatedType`](ThisTrait::ThisAssociatedType)
@@ -50,7 +51,7 @@ pub struct ThisType;
 impl ThisType {
     pub fn this_method() {}
 }
-pub enum ThisEnum { ThisVariant, }
+pub enum ThisEnum { ThisVariant, ThisVariantCtor(u32), }
 pub trait ThisTrait {
     type ThisAssociatedType;
     const THIS_ASSOCIATED_CONST: u8;

From d70d79ffb4bc60fb98e45aaf9442ea8e6cb15d01 Mon Sep 17 00:00:00 2001
From: Andy Russell <arussell123@gmail.com>
Date: Sat, 9 Mar 2019 16:25:12 -0500
Subject: [PATCH 17/37] replace ad-hoc namespace enums

---
 .../passes/collect_intra_doc_links.rs         | 165 +++++++-----------
 .../rustdoc-ui/intra-links-ambiguity.stderr   |  10 +-
 2 files changed, 72 insertions(+), 103 deletions(-)

diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 36bfe2fb2c3da..b105e0a0b6fcc 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1,5 +1,5 @@
 use errors::Applicability;
-use rustc::hir::def::Def;
+use rustc::hir::def::{Def, Namespace::{self, *}, PerNS};
 use rustc::hir::def_id::DefId;
 use rustc::hir;
 use rustc::lint as lint;
@@ -36,29 +36,9 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
     }
 }
 
-#[derive(Debug)]
-enum PathKind {
-    /// Either a value or type, but not a macro
-    Unknown,
-    /// Macro
-    Macro,
-    /// Values, functions, consts, statics (everything in the value namespace)
-    Value,
-    /// Types, traits (everything in the type namespace)
-    Type,
-}
-
 struct LinkCollector<'a, 'tcx> {
     cx: &'a DocContext<'tcx>,
     mod_ids: Vec<ast::NodeId>,
-    is_nightly_build: bool,
-}
-
-#[derive(Debug, Copy, Clone)]
-enum Namespace {
-    Type,
-    Value,
-    Macro,
 }
 
 impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
@@ -66,16 +46,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         LinkCollector {
             cx,
             mod_ids: Vec::new(),
-            is_nightly_build: UnstableFeatures::from_environment().is_nightly_build(),
         }
     }
 
-    /// Resolves a given string as a path, along with whether or not it is
-    /// in the value namespace. Also returns an optional URL fragment in the case
-    /// of variants and methods.
+    /// Resolves a string as a path within a particular namespace. Also returns an optional
+    /// URL fragment in the case of variants and methods.
     fn resolve(&self,
                path_str: &str,
-               is_val: bool,
+               ns: Namespace,
                current_item: &Option<String>,
                parent_id: Option<ast::NodeId>)
         -> Result<(Def, Option<String>), ()>
@@ -86,11 +64,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         // path.
         if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) {
             // FIXME: `with_scope` requires the `NodeId` of a module.
-            let result = cx.enter_resolver(|resolver| resolver.with_scope(id,
-                |resolver| {
-                    resolver.resolve_str_path_error(DUMMY_SP,
-                                                    &path_str, is_val)
-            }));
+            let result = cx.enter_resolver(|resolver| {
+                resolver.with_scope(id, |resolver| {
+                    resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS)
+                })
+            });
 
             if let Ok(result) = result {
                 // In case this is a trait item, skip the
@@ -103,16 +81,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     _ => return Ok((result.def, None))
                 };
 
-                if value != is_val {
+                if value != (ns == ValueNS) {
                     return Err(())
                 }
-            } else if let Some(prim) = is_primitive(path_str, is_val) {
+            } else if let Some(prim) = is_primitive(path_str, ns) {
                 return Ok((prim, Some(path_str.to_owned())))
             } else {
                 // If resolution failed, it may still be a method
                 // because methods are not handled by the resolver
                 // If so, bail when we're not looking for a value.
-                if !is_val {
+                if ns != ValueNS {
                     return Err(())
                 }
             }
@@ -136,7 +114,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     path = name.clone();
                 }
             }
-            if let Some(prim) = is_primitive(&path, false) {
+            if let Some(prim) = is_primitive(&path, TypeNS) {
                 let did = primitive_impl(cx, &path).ok_or(())?;
                 return cx.tcx.associated_items(did)
                     .find(|item| item.ident.name == item_name)
@@ -160,8 +138,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                                      .find(|item| item.ident.name == item_name);
                     if let Some(item) = item {
                         let out = match item.kind {
-                            ty::AssociatedKind::Method if is_val => "method",
-                            ty::AssociatedKind::Const if is_val => "associatedconstant",
+                            ty::AssociatedKind::Method if ns == ValueNS => "method",
+                            ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant",
                             _ => return Err(())
                         };
                         Ok((ty.def, Some(format!("{}.{}", out, item_name))))
@@ -198,9 +176,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                                  .find(|item| item.ident.name == item_name);
                     if let Some(item) = item {
                         let kind = match item.kind {
-                            ty::AssociatedKind::Const if is_val => "associatedconstant",
-                            ty::AssociatedKind::Type if !is_val => "associatedtype",
-                            ty::AssociatedKind::Method if is_val => {
+                            ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant",
+                            ty::AssociatedKind::Type if ns == TypeNS => "associatedtype",
+                            ty::AssociatedKind::Method if ns == ValueNS => {
                                 if item.defaultness.has_value() {
                                     "method"
                                 } else {
@@ -287,10 +265,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 
         look_for_tests(&cx, &dox, &item, true);
 
-        if !self.is_nightly_build {
-            return None;
-        }
-
         for (ori_link, link_range) in markdown_links(&dox) {
             // Bail early for real links.
             if ori_link.contains('/') {
@@ -298,28 +272,28 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             }
             let link = ori_link.replace("`", "");
             let (def, fragment) = {
-                let mut kind = PathKind::Unknown;
+                let mut kind = None;
                 let path_str = if let Some(prefix) =
                     ["struct@", "enum@", "type@",
                      "trait@", "union@"].iter()
                                       .find(|p| link.starts_with(**p)) {
-                    kind = PathKind::Type;
+                    kind = Some(TypeNS);
                     link.trim_start_matches(prefix)
                 } else if let Some(prefix) =
                     ["const@", "static@",
                      "value@", "function@", "mod@",
                      "fn@", "module@", "method@"]
                         .iter().find(|p| link.starts_with(**p)) {
-                    kind = PathKind::Value;
+                    kind = Some(ValueNS);
                     link.trim_start_matches(prefix)
                 } else if link.ends_with("()") {
-                    kind = PathKind::Value;
+                    kind = Some(ValueNS);
                     link.trim_end_matches("()")
                 } else if link.starts_with("macro@") {
-                    kind = PathKind::Macro;
+                    kind = Some(MacroNS);
                     link.trim_start_matches("macro@")
                 } else if link.ends_with('!') {
-                    kind = PathKind::Macro;
+                    kind = Some(MacroNS);
                     link.trim_end_matches('!')
                 } else {
                     &link[..]
@@ -331,8 +305,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                 }
 
                 match kind {
-                    PathKind::Value => {
-                        if let Ok(def) = self.resolve(path_str, true, &current_item, parent_node) {
+                    Some(ns @ ValueNS) => {
+                        if let Ok(def) = self.resolve(path_str, ns, &current_item, parent_node) {
                             def
                         } else {
                             resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
@@ -342,8 +316,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                             continue;
                         }
                     }
-                    PathKind::Type => {
-                        if let Ok(def) = self.resolve(path_str, false, &current_item, parent_node) {
+                    Some(ns @ TypeNS) => {
+                        if let Ok(def) = self.resolve(path_str, ns, &current_item, parent_node) {
                             def
                         } else {
                             resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
@@ -351,57 +325,49 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                             continue;
                         }
                     }
-                    PathKind::Unknown => {
+                    None => {
                         // Try everything!
-                        let mut candidates = vec![];
-
-                        if let Some(macro_def) = macro_resolve(cx, path_str) {
-                            candidates.push(((macro_def, None), Namespace::Macro));
-                        }
-
-                        if let Ok(type_def) =
-                            self.resolve(path_str, false, &current_item, parent_node)
-                        {
-                            candidates.push((type_def, Namespace::Type));
-                        }
-
-                        if let Ok(value_def) =
-                            self.resolve(path_str, true, &current_item, parent_node)
-                        {
-                            // Structs, variants, and mods exist in both namespaces, skip them.
-                            match value_def.0 {
-                                Def::StructCtor(..)
-                                | Def::Mod(..)
-                                | Def::Variant(..)
-                                | Def::VariantCtor(..)
-                                | Def::SelfCtor(..) => (),
-                                _ => candidates.push((value_def, Namespace::Value)),
-                            }
-                        }
+                        let candidates = PerNS {
+                            macro_ns: macro_resolve(cx, path_str).map(|def| (def, None)),
+                            type_ns: self
+                                .resolve(path_str, TypeNS, &current_item, parent_node)
+                                .ok(),
+                            value_ns: self
+                                .resolve(path_str, ValueNS, &current_item, parent_node)
+                                .ok()
+                                .and_then(|(def, fragment)| {
+                                    // Constructors are picked up in the type namespace.
+                                    match def {
+                                        Def::StructCtor(..)
+                                        | Def::VariantCtor(..)
+                                        | Def::SelfCtor(..) => None,
+                                        _ => Some((def, fragment))
+                                    }
+                                }),
+                        };
 
-                        if candidates.len() == 1 {
-                            candidates.remove(0).0
-                        } else if candidates.is_empty() {
+                        if candidates.is_empty() {
                             resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
                             // this could just be a normal link
                             continue;
-                        } else {
-                            let candidates = candidates.into_iter().map(|((def, _), ns)| {
-                                (def, ns)
-                            }).collect::<Vec<_>>();
+                        }
 
+                        let is_unambiguous = candidates.clone().present_items().count() == 1;
+                        if is_unambiguous {
+                            candidates.present_items().next().unwrap()
+                        } else {
                             ambiguity_error(
                                 cx,
                                 &item.attrs,
                                 path_str,
                                 &dox,
                                 link_range,
-                                &candidates,
+                                candidates.map(|candidate| candidate.map(|(def, _)| def)),
                             );
                             continue;
                         }
                     }
-                    PathKind::Macro => {
+                    Some(MacroNS) => {
                         if let Some(def) = macro_resolve(cx, path_str) {
                             (def, None)
                         } else {
@@ -514,13 +480,16 @@ fn ambiguity_error(
     path_str: &str,
     dox: &str,
     link_range: Option<Range<usize>>,
-    candidates: &[(Def, Namespace)],
+    candidates: PerNS<Option<Def>>,
 ) {
     let sp = span_of_attrs(attrs);
 
     let mut msg = format!("`{}` is ", path_str);
 
-    match candidates {
+    let candidates = [TypeNS, ValueNS, MacroNS].iter().filter_map(|&ns| {
+        candidates[ns].map(|def| (def, ns))
+    }).collect::<Vec<_>>();
+    match candidates.as_slice() {
         [(first_def, _), (second_def, _)] => {
             msg += &format!(
                 "both {} {} and {} {}",
@@ -568,9 +537,9 @@ fn ambiguity_error(
                             (Def::Union(..), _) => "union",
                             (Def::Trait(..), _) => "trait",
                             (Def::Mod(..), _) => "module",
-                            (_, Namespace::Type) => "type",
-                            (_, Namespace::Value) => "value",
-                            (_, Namespace::Macro) => "macro",
+                            (_, TypeNS) => "type",
+                            (_, ValueNS) => "value",
+                            (_, MacroNS) => "macro",
                         };
 
                         // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
@@ -646,11 +615,11 @@ const PRIMITIVES: &[(&str, Def)] = &[
     ("char",  Def::PrimTy(hir::PrimTy::Char)),
 ];
 
-fn is_primitive(path_str: &str, is_val: bool) -> Option<Def> {
-    if is_val {
-        None
-    } else {
+fn is_primitive(path_str: &str, ns: Namespace) -> Option<Def> {
+    if ns == TypeNS {
         PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1)
+    } else {
+        None
     }
 }
 
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
index 5b8978e3053b6..b85161dc1469e 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
@@ -32,15 +32,11 @@ help: to link to the function, add parentheses
 LL | /// [ambiguous()] is ambiguous. //~ERROR ambiguous
    |      ^^^^^^^^^^^
 
-error: `multi_conflict` is a macro, a struct, and a function
+error: `multi_conflict` is a struct, a function, and a macro
   --> $DIR/intra-links-ambiguity.rs:31:6
    |
 LL | /// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
    |      ^^^^^^^^^^^^^^^^ ambiguous link
-help: to link to the macro, prefix with the item type
-   |
-LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
-   |      ^^^^^^^^^^^^^^^^^^^^^^
 help: to link to the struct, prefix with the item type
    |
 LL | /// [`struct@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
@@ -49,6 +45,10 @@ help: to link to the function, add parentheses
    |
 LL | /// [`multi_conflict()`] is a three-way conflict. //~ERROR `multi_conflict`
    |      ^^^^^^^^^^^^^^^^^^
+help: to link to the macro, prefix with the item type
+   |
+LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
+   |      ^^^^^^^^^^^^^^^^^^^^^^
 
 error: `type_and_value` is both a module and a constant
   --> $DIR/intra-links-ambiguity.rs:33:16

From 3bb2275e164ff343c1c42998aaed65ed69723818 Mon Sep 17 00:00:00 2001
From: Andy Russell <arussell123@gmail.com>
Date: Sat, 9 Mar 2019 16:32:07 -0500
Subject: [PATCH 18/37] use `!` in macro disambiguation suggestion

---
 src/librustdoc/passes/collect_intra_doc_links.rs | 3 +++
 src/test/rustdoc-ui/intra-links-ambiguity.stderr | 6 +++---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index b105e0a0b6fcc..0fa6b6baec79d 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -528,6 +528,9 @@ fn ambiguity_error(
                     Def::Method(..) | Def::Fn(..) => {
                         ("add parentheses", format!("{}()", path_str))
                     }
+                    Def::Macro(..) => {
+                        ("add an exclamation mark", format!("{}!", path_str))
+                    }
                     _ => {
                         let type_ = match (def, ns) {
                             (Def::Const(..), _) => "const",
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
index b85161dc1469e..ad63f13493ddb 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
@@ -45,10 +45,10 @@ help: to link to the function, add parentheses
    |
 LL | /// [`multi_conflict()`] is a three-way conflict. //~ERROR `multi_conflict`
    |      ^^^^^^^^^^^^^^^^^^
-help: to link to the macro, prefix with the item type
+help: to link to the macro, add an exclamation mark
    |
-LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict`
-   |      ^^^^^^^^^^^^^^^^^^^^^^
+LL | /// [`multi_conflict!`] is a three-way conflict. //~ERROR `multi_conflict`
+   |      ^^^^^^^^^^^^^^^^^
 
 error: `type_and_value` is both a module and a constant
   --> $DIR/intra-links-ambiguity.rs:33:16

From e25df326caf38c1a8559fc6fa633ad60ab401e12 Mon Sep 17 00:00:00 2001
From: newpavlov <newpavlov@gmail.com>
Date: Mon, 11 Mar 2019 17:53:22 +0300
Subject: [PATCH 19/37] consistent naming for duration_float methods and
 additional f32 methods

---
 src/libcore/time.rs | 130 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 121 insertions(+), 9 deletions(-)

diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index 91161ca477e39..c8f23fd90bd7a 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -22,6 +22,7 @@ const NANOS_PER_MICRO: u32 = 1_000;
 const MILLIS_PER_SEC: u64 = 1_000;
 const MICROS_PER_SEC: u64 = 1_000_000;
 const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64;
+const MAX_NANOS_F32: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f32;
 
 /// A `Duration` type to represent a span of time, typically used for system
 /// timeouts.
@@ -510,15 +511,34 @@ impl Duration {
     /// use std::time::Duration;
     ///
     /// let dur = Duration::new(2, 700_000_000);
-    /// assert_eq!(dur.as_float_secs(), 2.7);
+    /// assert_eq!(dur.as_secs_f64(), 2.7);
     /// ```
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]
-    pub const fn as_float_secs(&self) -> f64 {
+    pub const fn as_secs_f64(&self) -> f64 {
         (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
     }
 
-    /// Creates a new `Duration` from the specified number of seconds.
+    /// Returns the number of seconds contained by this `Duration` as `f32`.
+    ///
+    /// The returned value does include the fractional (nanosecond) part of the duration.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_float)]
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::new(2, 700_000_000);
+    /// assert_eq!(dur.as_secs_f32(), 2.7);
+    /// ```
+    #[unstable(feature = "duration_float", issue = "54361")]
+    #[inline]
+    pub const fn as_secs_f32(&self) -> f32 {
+        (self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32)
+    }
+
+    /// Creates a new `Duration` from the specified number of seconds represented
+    /// as `f64`.
     ///
     /// # Panics
     /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
@@ -528,12 +548,12 @@ impl Duration {
     /// #![feature(duration_float)]
     /// use std::time::Duration;
     ///
-    /// let dur = Duration::from_float_secs(2.7);
+    /// let dur = Duration::from_secs_f64(2.7);
     /// assert_eq!(dur, Duration::new(2, 700_000_000));
     /// ```
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]
-    pub fn from_float_secs(secs: f64) -> Duration {
+    pub fn from_secs_f64(secs: f64) -> Duration {
         let nanos =  secs * (NANOS_PER_SEC as f64);
         if !nanos.is_finite() {
             panic!("got non-finite value when converting float to duration");
@@ -551,6 +571,40 @@ impl Duration {
         }
     }
 
+    /// Creates a new `Duration` from the specified number of seconds represented
+    /// as `f32`.
+    ///
+    /// # Panics
+    /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_float)]
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::from_secs_f32(2.7);
+    /// assert_eq!(dur, Duration::new(2, 700_000_000));
+    /// ```
+    #[unstable(feature = "duration_float", issue = "54361")]
+    #[inline]
+    pub fn from_secs_f32(secs: f32) -> Duration {
+        let nanos =  secs * (NANOS_PER_SEC as f32);
+        if !nanos.is_finite() {
+            panic!("got non-finite value when converting float to duration");
+        }
+        if nanos >= MAX_NANOS_F32 {
+            panic!("overflow when converting float to duration");
+        }
+        if nanos < 0.0 {
+            panic!("underflow when converting float to duration");
+        }
+        let nanos =  nanos as u128;
+        Duration {
+            secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
+            nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+        }
+    }
+
     /// Multiplies `Duration` by `f64`.
     ///
     /// # Panics
@@ -568,7 +622,27 @@ impl Duration {
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]
     pub fn mul_f64(self, rhs: f64) -> Duration {
-        Duration::from_float_secs(rhs * self.as_float_secs())
+        Duration::from_secs_f64(rhs * self.as_secs_f64())
+    }
+
+    /// Multiplies `Duration` by `f32`.
+    ///
+    /// # Panics
+    /// This method will panic if result is not finite, negative or overflows `Duration`.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_float)]
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::new(2, 700_000_000);
+    /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_000));
+    /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 0));
+    /// ```
+    #[unstable(feature = "duration_float", issue = "54361")]
+    #[inline]
+    pub fn mul_f32(self, rhs: f32) -> Duration {
+        Duration::from_secs_f32(rhs * self.as_secs_f32())
     }
 
     /// Divide `Duration` by `f64`.
@@ -589,7 +663,28 @@ impl Duration {
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]
     pub fn div_f64(self, rhs: f64) -> Duration {
-        Duration::from_float_secs(self.as_float_secs() / rhs)
+        Duration::from_secs_f64(self.as_secs_f64() / rhs)
+    }
+
+    /// Divide `Duration` by `f32`.
+    ///
+    /// # Panics
+    /// This method will panic if result is not finite, negative or overflows `Duration`.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_float)]
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::new(2, 700_000_000);
+    /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_611));
+    /// // note that truncation is used, not rounding
+    /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598));
+    /// ```
+    #[unstable(feature = "duration_float", issue = "54361")]
+    #[inline]
+    pub fn div_f32(self, rhs: f32) -> Duration {
+        Duration::from_secs_f32(self.as_secs_f32() / rhs)
     }
 
     /// Divide `Duration` by `Duration` and return `f64`.
@@ -605,8 +700,25 @@ impl Duration {
     /// ```
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]
-    pub fn div_duration(self, rhs: Duration) -> f64 {
-        self.as_float_secs() / rhs.as_float_secs()
+    pub fn div_duration_f64(self, rhs: Duration) -> f64 {
+        self.as_secs_f64() / rhs.as_secs_f64()
+    }
+
+    /// Divide `Duration` by `Duration` and return `f32`.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_float)]
+    /// use std::time::Duration;
+    ///
+    /// let dur1 = Duration::new(2, 700_000_000);
+    /// let dur2 = Duration::new(5, 400_000_000);
+    /// assert_eq!(dur1.div_duration(dur2), 0.5);
+    /// ```
+    #[unstable(feature = "duration_float", issue = "54361")]
+    #[inline]
+    pub fn div_duration_f32(self, rhs: Duration) -> f32 {
+        self.as_secs_f32() / rhs.as_secs_f32()
     }
 }
 

From 35c19c5b3d1fe8675132ea96e014e37455653ce8 Mon Sep 17 00:00:00 2001
From: newpavlov <newpavlov@gmail.com>
Date: Mon, 11 Mar 2019 18:06:13 +0300
Subject: [PATCH 20/37] move MAX_NANOS_F64/32 to methods

---
 src/libcore/time.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index c8f23fd90bd7a..d3f80835c0175 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -21,8 +21,6 @@ const NANOS_PER_MILLI: u32 = 1_000_000;
 const NANOS_PER_MICRO: u32 = 1_000;
 const MILLIS_PER_SEC: u64 = 1_000;
 const MICROS_PER_SEC: u64 = 1_000_000;
-const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64;
-const MAX_NANOS_F32: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f32;
 
 /// A `Duration` type to represent a span of time, typically used for system
 /// timeouts.
@@ -554,6 +552,8 @@ impl Duration {
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]
     pub fn from_secs_f64(secs: f64) -> Duration {
+        const MAX_NANOS_F64: f64 =
+            ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64;
         let nanos =  secs * (NANOS_PER_SEC as f64);
         if !nanos.is_finite() {
             panic!("got non-finite value when converting float to duration");
@@ -588,6 +588,8 @@ impl Duration {
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]
     pub fn from_secs_f32(secs: f32) -> Duration {
+        const MAX_NANOS_F32: f32 =
+            ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f32;
         let nanos =  secs * (NANOS_PER_SEC as f32);
         if !nanos.is_finite() {
             panic!("got non-finite value when converting float to duration");

From 980871af270314d1e4dd42828d9a7c76d6e0c89a Mon Sep 17 00:00:00 2001
From: newpavlov <newpavlov@gmail.com>
Date: Mon, 11 Mar 2019 19:57:53 +0300
Subject: [PATCH 21/37] fix tests

---
 src/libcore/time.rs | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index d3f80835c0175..c4d4c4622f3a4 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -638,8 +638,10 @@ impl Duration {
     /// use std::time::Duration;
     ///
     /// let dur = Duration::new(2, 700_000_000);
-    /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_000));
-    /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 0));
+    /// // note that due to rounding errors result is slightly different
+    /// // from 8.478
+    /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640));
+    /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 64_000_000));
     /// ```
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]
@@ -679,7 +681,9 @@ impl Duration {
     /// use std::time::Duration;
     ///
     /// let dur = Duration::new(2, 700_000_000);
-    /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_611));
+    /// // note that due to rounding errors result is slightly
+    /// // different from 0.859_872_611
+    /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_576));
     /// // note that truncation is used, not rounding
     /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598));
     /// ```
@@ -698,7 +702,7 @@ impl Duration {
     ///
     /// let dur1 = Duration::new(2, 700_000_000);
     /// let dur2 = Duration::new(5, 400_000_000);
-    /// assert_eq!(dur1.div_duration(dur2), 0.5);
+    /// assert_eq!(dur1.div_duration_f64(dur2), 0.5);
     /// ```
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]
@@ -715,7 +719,7 @@ impl Duration {
     ///
     /// let dur1 = Duration::new(2, 700_000_000);
     /// let dur2 = Duration::new(5, 400_000_000);
-    /// assert_eq!(dur1.div_duration(dur2), 0.5);
+    /// assert_eq!(dur1.div_duration_f32(dur2), 0.5);
     /// ```
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]

From 197efb05243976a631107f1d6ad88bff65fd43e9 Mon Sep 17 00:00:00 2001
From: Artyom Pavlov <newpavlov@gmail.com>
Date: Mon, 11 Mar 2019 18:59:41 +0000
Subject: [PATCH 22/37] fix test

---
 src/libcore/time.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index c4d4c4622f3a4..f106d06d2ffc1 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -639,9 +639,9 @@ impl Duration {
     ///
     /// let dur = Duration::new(2, 700_000_000);
     /// // note that due to rounding errors result is slightly different
-    /// // from 8.478
+    /// // from 8.478 anf 847800.0
     /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640));
-    /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 64_000_000));
+    /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256));
     /// ```
     #[unstable(feature = "duration_float", issue = "54361")]
     #[inline]

From b9d12edd6ce7b364fb1a4de53f7541d536df0940 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 11 Mar 2019 15:07:07 -0700
Subject: [PATCH 23/37] Be more discerning on when to attempt suggesting a
 comma in a macro invocation

---
 src/libsyntax/tokenstream.rs            |  8 +++++---
 src/test/ui/macros/missing-comma.rs     |  7 +++++++
 src/test/ui/macros/missing-comma.stderr | 21 +++++++++++++++------
 3 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 4ce308d015c00..5caa59a53f92b 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -178,9 +178,11 @@ impl TokenStream {
             while let Some((pos, ts)) = iter.next() {
                 if let Some((_, next)) = iter.peek() {
                     let sp = match (&ts, &next) {
-                        ((TokenTree::Token(_, token::Token::Comma), NonJoint), _) |
-                        (_, (TokenTree::Token(_, token::Token::Comma), NonJoint)) => continue,
-                        ((TokenTree::Token(sp, _), NonJoint), _) => *sp,
+                        (_, (TokenTree::Token(_, token::Token::Comma), _)) => continue,
+                        ((TokenTree::Token(sp, token_left), NonJoint),
+                         (TokenTree::Token(_, token_right), _))
+                        if token_left.is_ident() || token_left.is_lit() &&
+                            token_right.is_ident() || token_right.is_lit() => *sp,
                         ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(),
                         _ => continue,
                     };
diff --git a/src/test/ui/macros/missing-comma.rs b/src/test/ui/macros/missing-comma.rs
index 1e146875bcc76..2b411aba8a2ee 100644
--- a/src/test/ui/macros/missing-comma.rs
+++ b/src/test/ui/macros/missing-comma.rs
@@ -6,6 +6,11 @@ macro_rules! foo {
     ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => ();
 }
 
+macro_rules! bar {
+    ($lvl:expr, $($arg:tt)+) => {}
+}
+
+
 fn main() {
     println!("{}" a);
     //~^ ERROR expected token: `,`
@@ -17,4 +22,6 @@ fn main() {
     //~^ ERROR no rules expected the token `d`
     foo!(a, b, c d e);
     //~^ ERROR no rules expected the token `d`
+    bar!(Level::Error, );
+    //~^ ERROR unexpected end of macro invocation
 }
diff --git a/src/test/ui/macros/missing-comma.stderr b/src/test/ui/macros/missing-comma.stderr
index 5881e0b7b68c6..424fefd00f873 100644
--- a/src/test/ui/macros/missing-comma.stderr
+++ b/src/test/ui/macros/missing-comma.stderr
@@ -1,11 +1,11 @@
 error: expected token: `,`
-  --> $DIR/missing-comma.rs:10:19
+  --> $DIR/missing-comma.rs:15:19
    |
 LL |     println!("{}" a);
    |                   ^
 
 error: no rules expected the token `b`
-  --> $DIR/missing-comma.rs:12:12
+  --> $DIR/missing-comma.rs:17:12
    |
 LL | macro_rules! foo {
    | ---------------- when calling this macro
@@ -16,7 +16,7 @@ LL |     foo!(a b);
    |           help: missing comma here
 
 error: no rules expected the token `e`
-  --> $DIR/missing-comma.rs:14:21
+  --> $DIR/missing-comma.rs:19:21
    |
 LL | macro_rules! foo {
    | ---------------- when calling this macro
@@ -27,7 +27,7 @@ LL |     foo!(a, b, c, d e);
    |                    help: missing comma here
 
 error: no rules expected the token `d`
-  --> $DIR/missing-comma.rs:16:18
+  --> $DIR/missing-comma.rs:21:18
    |
 LL | macro_rules! foo {
    | ---------------- when calling this macro
@@ -38,7 +38,7 @@ LL |     foo!(a, b, c d, e);
    |                 help: missing comma here
 
 error: no rules expected the token `d`
-  --> $DIR/missing-comma.rs:18:18
+  --> $DIR/missing-comma.rs:23:18
    |
 LL | macro_rules! foo {
    | ---------------- when calling this macro
@@ -46,5 +46,14 @@ LL | macro_rules! foo {
 LL |     foo!(a, b, c d e);
    |                  ^ no rules expected this token in macro call
 
-error: aborting due to 5 previous errors
+error: unexpected end of macro invocation
+  --> $DIR/missing-comma.rs:25:23
+   |
+LL | macro_rules! bar {
+   | ---------------- when calling this macro
+...
+LL |     bar!(Level::Error, );
+   |                       ^ missing tokens in macro arguments
+
+error: aborting due to 6 previous errors
 

From 78b248dc4c17581211aaed5c3a449e5b07ebdb52 Mon Sep 17 00:00:00 2001
From: Artyom Pavlov <newpavlov@gmail.com>
Date: Tue, 12 Mar 2019 16:42:18 +0300
Subject: [PATCH 24/37] fix typo

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

diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index f106d06d2ffc1..ae6d8078fd236 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -639,7 +639,7 @@ impl Duration {
     ///
     /// let dur = Duration::new(2, 700_000_000);
     /// // note that due to rounding errors result is slightly different
-    /// // from 8.478 anf 847800.0
+    /// // from 8.478 and 847800.0
     /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640));
     /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256));
     /// ```

From 1ae131211be24a337877e6dbcd9b6c52a86b9511 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 12 Mar 2019 14:43:49 +0100
Subject: [PATCH 25/37] Explain the bits of `UndefMask`

---
 src/librustc/mir/interpret/allocation.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index 004804f7c211e..2ce9a4a0f204d 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -613,6 +613,8 @@ impl<Tag> DerefMut for Relocations<Tag> {
 
 type Block = u64;
 
+/// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte
+/// is defined. If it is `false` the byte is undefined.
 #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
 pub struct UndefMask {
     blocks: Vec<Block>,

From 2a1eb1cef1a36c6f0a9d2e347529561c1293044e Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 12 Mar 2019 15:00:12 +0100
Subject: [PATCH 26/37] Document the precomputation algorithm's purpose

---
 src/librustc_mir/interpret/memory.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index fba0a9af21392..6ea200d4e4fad 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -791,6 +791,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
         let undef_mask = &self.get(src.alloc_id)?.undef_mask;
 
+        // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
+        // a naive undef mask copying algorithm would repeatedly have to read the undef mask from
+        // the source and write it to the destination. Even if we optimized the memory accesses,
+        // we'd be doing all of this `repeat` times.
+        // Therefor we precompute a compressed version of the undef mask of the source value and
+        // then write it back `repeat` times without computing any more information from the source.
+
         // a precomputed cache for ranges of defined/undefined bits
         // 0000010010001110 will become
         // [5, 1, 2, 1, 3, 3, 1]

From 795d307f10ec0fd3851b18a3365755d76b7403e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 12 Mar 2019 14:57:13 -0700
Subject: [PATCH 27/37] Suggest return lifetime when there's only one named
 lifetime

---
 src/librustc/middle/resolve_lifetime.rs       | 37 +++++++++++++++++--
 .../ui/suggestions/return-without-lifetime.rs |  8 ++++
 .../return-without-lifetime.stderr            | 19 ++++++++++
 3 files changed, 60 insertions(+), 4 deletions(-)
 create mode 100644 src/test/ui/suggestions/return-without-lifetime.rs
 create mode 100644 src/test/ui/suggestions/return-without-lifetime.stderr

diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index f862b690f8806..35bca04d1e623 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -2298,6 +2298,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let span = lifetime_refs[0].span;
         let mut late_depth = 0;
         let mut scope = self.scope;
+        let mut lifetime_names = FxHashSet::default();
         let error = loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
@@ -2310,7 +2311,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     scope = s;
                 }
 
-                Scope::Elision { ref elide, .. } => {
+                Scope::Elision { ref elide, ref s, .. } => {
                     let lifetime = match *elide {
                         Elide::FreshLateAnon(ref counter) => {
                             for lifetime_ref in lifetime_refs {
@@ -2320,7 +2321,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                             return;
                         }
                         Elide::Exact(l) => l.shifted(late_depth),
-                        Elide::Error(ref e) => break Some(e),
+                        Elide::Error(ref e) => {
+                            if let Scope::Binder { ref lifetimes, .. } = s {
+                                for name in lifetimes.keys() {
+                                    if let hir::ParamName::Plain(name) = name {
+                                        lifetime_names.insert(*name);
+                                    }
+                                }
+                            }
+                            break Some(e);
+                        }
                     };
                     for lifetime_ref in lifetime_refs {
                         self.insert_lifetime(lifetime_ref, lifetime);
@@ -2343,7 +2353,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         }
         if add_label {
-            add_missing_lifetime_specifiers_label(&mut err, span, lifetime_refs.len());
+            add_missing_lifetime_specifiers_label(
+                &mut err,
+                span,
+                lifetime_refs.len(),
+                &lifetime_names,
+                self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()),
+            );
         }
 
         err.emit();
@@ -2884,10 +2900,23 @@ fn add_missing_lifetime_specifiers_label(
     err: &mut DiagnosticBuilder<'_>,
     span: Span,
     count: usize,
+    lifetime_names: &FxHashSet<ast::Ident>,
+    snippet: Option<&str>,
 ) {
     if count > 1 {
         err.span_label(span, format!("expected {} lifetime parameters", count));
+    } else if let (1, Some(name), Some("&")) = (
+        lifetime_names.len(),
+        lifetime_names.iter().next(),
+        snippet,
+    ) {
+        err.span_suggestion(
+            span,
+            &format!("consider using the named lifetime `{}`", name),
+            format!("&{} ", name),
+            Applicability::MaybeIncorrect,
+        );
     } else {
         err.span_label(span, "expected lifetime parameter");
-    };
+    }
 }
diff --git a/src/test/ui/suggestions/return-without-lifetime.rs b/src/test/ui/suggestions/return-without-lifetime.rs
new file mode 100644
index 0000000000000..5f19e93013acf
--- /dev/null
+++ b/src/test/ui/suggestions/return-without-lifetime.rs
@@ -0,0 +1,8 @@
+struct Thing<'a>(&'a ());
+
+fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
+//~^ ERROR missing lifetime specifier
+fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
+//~^ ERROR missing lifetime specifier
+
+fn main() {}
diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr
new file mode 100644
index 0000000000000..72f1c142d028f
--- /dev/null
+++ b/src/test/ui/suggestions/return-without-lifetime.stderr
@@ -0,0 +1,19 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/return-without-lifetime.rs:3:34
+   |
+LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
+   |                                  ^ help: consider using the named lifetime `'a`: `&'a`
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/return-without-lifetime.rs:5:35
+   |
+LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
+   |                                   ^ help: consider using the named lifetime `'a`: `&'a`
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0106`.

From f9234767e4ff9b682437464efc9a6ff59db4cff9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 12 Mar 2019 15:34:16 -0700
Subject: [PATCH 28/37] review comments

---
 src/librustc/middle/resolve_lifetime.rs                | 2 +-
 src/test/ui/suggestions/return-without-lifetime.stderr | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 35bca04d1e623..d03268df5e148 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -2912,7 +2912,7 @@ fn add_missing_lifetime_specifiers_label(
     ) {
         err.span_suggestion(
             span,
-            &format!("consider using the named lifetime `{}`", name),
+            "consider using the named lifetime",
             format!("&{} ", name),
             Applicability::MaybeIncorrect,
         );
diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr
index 72f1c142d028f..1ffe91bce05a5 100644
--- a/src/test/ui/suggestions/return-without-lifetime.stderr
+++ b/src/test/ui/suggestions/return-without-lifetime.stderr
@@ -2,7 +2,7 @@ error[E0106]: missing lifetime specifier
   --> $DIR/return-without-lifetime.rs:3:34
    |
 LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
-   |                                  ^ help: consider using the named lifetime `'a`: `&'a`
+   |                                  ^ help: consider using the named lifetime: `&'a`
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from
 
@@ -10,7 +10,7 @@ error[E0106]: missing lifetime specifier
   --> $DIR/return-without-lifetime.rs:5:35
    |
 LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
-   |                                   ^ help: consider using the named lifetime `'a`: `&'a`
+   |                                   ^ help: consider using the named lifetime: `&'a`
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from
 

From adbd0a66457159ffcdd02ee0b553581298968847 Mon Sep 17 00:00:00 2001
From: Jethro Beekman <jethro@fortanix.com>
Date: Tue, 12 Mar 2019 16:09:20 -0700
Subject: [PATCH 29/37] Make std time tests more robust for platform
 differences

---
 src/libstd/time.rs | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/src/libstd/time.rs b/src/libstd/time.rs
index 6d7093ac33ea7..4c86f70ad871d 100644
--- a/src/libstd/time.rs
+++ b/src/libstd/time.rs
@@ -712,13 +712,6 @@ mod tests {
         assert_almost_eq!(a - second + second, a);
         assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
 
-        // A difference of 80 and 800 years cannot fit inside a 32-bit time_t
-        if !(cfg!(unix) && crate::mem::size_of::<libc::time_t>() <= 4) {
-            let eighty_years = second * 60 * 60 * 24 * 365 * 80;
-            assert_almost_eq!(a - eighty_years + eighty_years, a);
-            assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a);
-        }
-
         let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
         let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000)
             + Duration::new(0, 500_000_000);
@@ -747,8 +740,8 @@ mod tests {
     #[test]
     fn since_epoch() {
         let ts = SystemTime::now();
-        let a = ts.duration_since(UNIX_EPOCH).unwrap();
-        let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap();
+        let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap();
+        let b = ts.duration_since(UNIX_EPOCH).unwrap();
         assert!(b > a);
         assert_eq!(b - a, Duration::new(1, 0));
 

From 0ea9b58029bc7c3da3f213eb9e39acdefcf12647 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 12 Mar 2019 18:18:24 -0700
Subject: [PATCH 30/37] Suggest adding lifetime to struct field

---
 src/librustc/middle/resolve_lifetime.rs              |  9 ++++++++-
 src/test/ui/suggestions/return-without-lifetime.rs   |  2 ++
 .../ui/suggestions/return-without-lifetime.stderr    | 12 +++++++++---
 3 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index d03268df5e148..c9ff84ab2f08a 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -2306,7 +2306,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
                 Scope::Root => break None,
 
-                Scope::Binder { s, .. } => {
+                Scope::Binder { s, ref lifetimes, .. } => {
+                    // collect named lifetimes for suggestions
+                    for name in lifetimes.keys() {
+                        if let hir::ParamName::Plain(name) = name {
+                            lifetime_names.insert(*name);
+                        }
+                    }
                     late_depth += 1;
                     scope = s;
                 }
@@ -2323,6 +2329,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                         Elide::Exact(l) => l.shifted(late_depth),
                         Elide::Error(ref e) => {
                             if let Scope::Binder { ref lifetimes, .. } = s {
+                                // collect named lifetimes for suggestions
                                 for name in lifetimes.keys() {
                                     if let hir::ParamName::Plain(name) = name {
                                         lifetime_names.insert(*name);
diff --git a/src/test/ui/suggestions/return-without-lifetime.rs b/src/test/ui/suggestions/return-without-lifetime.rs
index 5f19e93013acf..9bfce11be9ea3 100644
--- a/src/test/ui/suggestions/return-without-lifetime.rs
+++ b/src/test/ui/suggestions/return-without-lifetime.rs
@@ -1,4 +1,6 @@
 struct Thing<'a>(&'a ());
+struct Foo<'a>(&usize);
+//~^ ERROR missing lifetime specifier
 
 fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
 //~^ ERROR missing lifetime specifier
diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr
index 1ffe91bce05a5..7f5ff95938e30 100644
--- a/src/test/ui/suggestions/return-without-lifetime.stderr
+++ b/src/test/ui/suggestions/return-without-lifetime.stderr
@@ -1,5 +1,11 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-without-lifetime.rs:3:34
+  --> $DIR/return-without-lifetime.rs:2:16
+   |
+LL | struct Foo<'a>(&usize);
+   |                ^ help: consider using the named lifetime: `&'a`
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/return-without-lifetime.rs:5:34
    |
 LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
    |                                  ^ help: consider using the named lifetime: `&'a`
@@ -7,13 +13,13 @@ LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-without-lifetime.rs:5:35
+  --> $DIR/return-without-lifetime.rs:7:35
    |
 LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
    |                                   ^ help: consider using the named lifetime: `&'a`
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0106`.

From 266ca31f74ae343fc773b88f3bb77b601034babf Mon Sep 17 00:00:00 2001
From: Steven Malis <smmalis37@gmail.com>
Date: Tue, 12 Mar 2019 21:00:37 -0700
Subject: [PATCH 31/37] Stabilize Range*::contains.

---
 src/libcore/ops/range.rs         | 49 +++++++++++++-------------------
 src/librustc_codegen_llvm/lib.rs |  1 -
 src/librustc_errors/lib.rs       |  1 -
 src/librustc_mir/lib.rs          |  1 -
 src/libstd/lib.rs                |  2 +-
 5 files changed, 20 insertions(+), 34 deletions(-)

diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs
index 998b597d5e113..cb82ad38eb87d 100644
--- a/src/libcore/ops/range.rs
+++ b/src/libcore/ops/range.rs
@@ -67,7 +67,7 @@ impl fmt::Debug for RangeFull {
 /// assert_eq!(arr[1..3], [     'b', 'c'     ]);  // Range
 /// ```
 #[doc(alias = "..")]
-#[derive(Clone, PartialEq, Eq, Hash)]  // not Copy -- see #27186
+#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Range<Idx> {
     /// The lower bound of the range (inclusive).
@@ -91,8 +91,6 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(range_contains)]
-    ///
     /// use std::f32;
     ///
     /// assert!(!(3..5).contains(&2));
@@ -108,7 +106,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
     /// assert!(!(0.0..f32::NAN).contains(&0.5));
     /// assert!(!(f32::NAN..1.0).contains(&0.5));
     /// ```
-    #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+    #[stable(feature = "range_contains", since = "1.35.0")]
     pub fn contains<U>(&self, item: &U) -> bool
     where
         Idx: PartialOrd<U>,
@@ -169,7 +167,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
 ///
 /// [`Iterator`]: ../iter/trait.IntoIterator.html
 #[doc(alias = "..")]
-#[derive(Clone, PartialEq, Eq, Hash)]  // not Copy -- see #27186
+#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RangeFrom<Idx> {
     /// The lower bound of the range (inclusive).
@@ -190,8 +188,6 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(range_contains)]
-    ///
     /// use std::f32;
     ///
     /// assert!(!(3..).contains(&2));
@@ -202,7 +198,7 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
     /// assert!(!(0.0..).contains(&f32::NAN));
     /// assert!(!(f32::NAN..).contains(&0.5));
     /// ```
-    #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+    #[stable(feature = "range_contains", since = "1.35.0")]
     pub fn contains<U>(&self, item: &U) -> bool
     where
         Idx: PartialOrd<U>,
@@ -272,8 +268,6 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(range_contains)]
-    ///
     /// use std::f32;
     ///
     /// assert!( (..5).contains(&-1_000_000_000));
@@ -284,7 +278,7 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
     /// assert!(!(..1.0).contains(&f32::NAN));
     /// assert!(!(..f32::NAN).contains(&0.5));
     /// ```
-    #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+    #[stable(feature = "range_contains", since = "1.35.0")]
     pub fn contains<U>(&self, item: &U) -> bool
     where
         Idx: PartialOrd<U>,
@@ -317,7 +311,7 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
 /// assert_eq!(arr[1..=2], [  1,2  ]);  // RangeInclusive
 /// ```
 #[doc(alias = "..=")]
-#[derive(Clone)]  // not Copy -- see #27186
+#[derive(Clone)] // not Copy -- see #27186
 #[stable(feature = "inclusive_range", since = "1.26.0")]
 pub struct RangeInclusive<Idx> {
     pub(crate) start: Idx,
@@ -353,7 +347,8 @@ impl<T: PartialOrd> RangeInclusiveEquality for T {
 impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
-        self.start == other.start && self.end == other.end
+        self.start == other.start
+            && self.end == other.end
             && RangeInclusiveEquality::canonicalized_is_empty(self)
                 == RangeInclusiveEquality::canonicalized_is_empty(other)
     }
@@ -385,7 +380,11 @@ impl<Idx> RangeInclusive<Idx> {
     #[inline]
     #[rustc_promotable]
     pub const fn new(start: Idx, end: Idx) -> Self {
-        Self { start, end, is_empty: None }
+        Self {
+            start,
+            end,
+            is_empty: None,
+        }
     }
 
     /// Returns the lower bound of the range (inclusive).
@@ -466,8 +465,6 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(range_contains)]
-    ///
     /// use std::f32;
     ///
     /// assert!(!(3..=5).contains(&2));
@@ -484,7 +481,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
     /// assert!(!(0.0..=f32::NAN).contains(&0.0));
     /// assert!(!(f32::NAN..=1.0).contains(&1.0));
     /// ```
-    #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+    #[stable(feature = "range_contains", since = "1.35.0")]
     pub fn contains<U>(&self, item: &U) -> bool
     where
         Idx: PartialOrd<U>,
@@ -593,15 +590,12 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
     }
 }
 
-#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
 impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
     /// Returns `true` if `item` is contained in the range.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(range_contains)]
-    ///
     /// use std::f32;
     ///
     /// assert!( (..=5).contains(&-1_000_000_000));
@@ -612,7 +606,7 @@ impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
     /// assert!(!(..=1.0).contains(&f32::NAN));
     /// assert!(!(..=f32::NAN).contains(&0.5));
     /// ```
-    #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+    #[stable(feature = "range_contains", since = "1.35.0")]
     pub fn contains<U>(&self, item: &U) -> bool
     where
         Idx: PartialOrd<U>,
@@ -714,14 +708,11 @@ pub trait RangeBounds<T: ?Sized> {
     #[stable(feature = "collections_range", since = "1.28.0")]
     fn end_bound(&self) -> Bound<&T>;
 
-
     /// Returns `true` if `item` is contained in the range.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(range_contains)]
-    ///
     /// use std::f32;
     ///
     /// assert!( (3..5).contains(&4));
@@ -731,7 +722,7 @@ pub trait RangeBounds<T: ?Sized> {
     /// assert!(!(0.0..1.0).contains(&f32::NAN));
     /// assert!(!(0.0..f32::NAN).contains(&0.5));
     /// assert!(!(f32::NAN..1.0).contains(&0.5));
-    #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+    #[stable(feature = "range_contains", since = "1.35.0")]
     fn contains<U>(&self, item: &U) -> bool
     where
         T: PartialOrd<U>,
@@ -741,9 +732,7 @@ pub trait RangeBounds<T: ?Sized> {
             Included(ref start) => *start <= item,
             Excluded(ref start) => *start < item,
             Unbounded => true,
-        })
-        &&
-        (match self.end_bound() {
+        }) && (match self.end_bound() {
             Included(ref end) => item <= *end,
             Excluded(ref end) => item < *end,
             Unbounded => true,
@@ -819,7 +808,7 @@ impl<T> RangeBounds<T> for (Bound<T>, Bound<T>) {
         match *self {
             (Included(ref start), _) => Included(start),
             (Excluded(ref start), _) => Excluded(start),
-            (Unbounded, _)           => Unbounded,
+            (Unbounded, _) => Unbounded,
         }
     }
 
@@ -827,7 +816,7 @@ impl<T> RangeBounds<T> for (Bound<T>, Bound<T>) {
         match *self {
             (_, Included(ref end)) => Included(end),
             (_, Excluded(ref end)) => Excluded(end),
-            (_, Unbounded)         => Unbounded,
+            (_, Unbounded) => Unbounded,
         }
     }
 }
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 7b2b9ec24ea0f..b396c6b54db3f 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -15,7 +15,6 @@
 #![allow(unused_attributes)]
 #![feature(libc)]
 #![feature(nll)]
-#![feature(range_contains)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(optin_builtin_traits)]
 #![feature(concat_idents)]
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 7c7698ddd3d73..6b4b437930d26 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -2,7 +2,6 @@
 
 #![feature(custom_attribute)]
 #![allow(unused_attributes)]
-#![feature(range_contains)]
 #![cfg_attr(unix, feature(libc))]
 #![feature(nll)]
 #![feature(optin_builtin_traits)]
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 0b735b4b39cf5..c45e694ebf832 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -14,7 +14,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(const_fn)]
 #![feature(decl_macro)]
 #![feature(exhaustive_patterns)]
-#![feature(range_contains)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_attrs)]
 #![feature(never_type)]
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index e31680f23f1da..307e0c63f3415 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -221,7 +221,7 @@
 
 #![cfg_attr(test, feature(print_internals, set_stdio, test, update_panic_count))]
 #![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"),
-            feature(global_asm, range_contains, slice_index_methods,
+            feature(global_asm, slice_index_methods,
                     decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))]
 
 // std is implemented with unstable features, many of which are internal

From 27abd52170b2d2769f5fbed665795bdb9a3facef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 13 Mar 2019 00:10:16 -0700
Subject: [PATCH 32/37] Fix operator precedence

---
 src/libsyntax/tokenstream.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 5caa59a53f92b..80a7bde606afa 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -181,8 +181,8 @@ impl TokenStream {
                         (_, (TokenTree::Token(_, token::Token::Comma), _)) => continue,
                         ((TokenTree::Token(sp, token_left), NonJoint),
                          (TokenTree::Token(_, token_right), _))
-                        if token_left.is_ident() || token_left.is_lit() &&
-                            token_right.is_ident() || token_right.is_lit() => *sp,
+                        if (token_left.is_ident() || token_left.is_lit()) &&
+                            (token_right.is_ident() || token_right.is_lit()) => *sp,
                         ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(),
                         _ => continue,
                     };

From 9d938f69362e9568c14955d7df801c21a2266e66 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Wed, 13 Mar 2019 12:38:10 +0100
Subject: [PATCH 33/37] Add test for #55809.

This commit adds a regression test for #55809 which checks that a
overflow does not occur when evaluating a requirement for async
functions and `&mut` arguments in some specific circumstances.
---
 src/test/run-pass/issue-55809.rs | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 src/test/run-pass/issue-55809.rs

diff --git a/src/test/run-pass/issue-55809.rs b/src/test/run-pass/issue-55809.rs
new file mode 100644
index 0000000000000..86b0977bebe1d
--- /dev/null
+++ b/src/test/run-pass/issue-55809.rs
@@ -0,0 +1,30 @@
+// edition:2018
+// run-pass
+
+#![feature(async_await, await_macro, futures_api)]
+
+trait Foo { }
+
+impl Foo for () { }
+
+impl<'a, T> Foo for &'a mut T where T: Foo { }
+
+async fn foo_async<T>(_v: T) -> u8 where T: Foo {
+    0
+}
+
+async fn bad<T>(v: T) -> u8 where T: Foo {
+    await!(foo_async(v))
+}
+
+async fn async_main() {
+    let mut v = ();
+
+    let _ = await!(bad(&mut v));
+    let _ = await!(foo_async(&mut v));
+    let _ = await!(bad(v));
+}
+
+fn main() {
+    let _ = async_main();
+}

From 311025e6a5aad80d028f0771970c43cb4ed025a8 Mon Sep 17 00:00:00 2001
From: Angelos Oikonomopoulos <a.oikonomopoulos@vu.nl>
Date: Thu, 7 Mar 2019 18:30:26 +0100
Subject: [PATCH 34/37] Fix generic argument lookup for Self

Rewrite the SelfCtor early and use the replacement Def when
calculating the path_segs.

Note that this also changes which def is seen by the code that
computes user_self_ty and is_alias_variant_ctor; I don't see a
immediate issue with that, but I'm not 100% clear on the
implications.

Fixes #57924
---
 src/librustc_typeck/check/mod.rs        | 119 ++++++++++++------------
 src/test/run-pass/issues/issue-57924.rs |   9 ++
 2 files changed, 69 insertions(+), 59 deletions(-)
 create mode 100644 src/test/run-pass/issues/issue-57924.rs

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 301d7d3ac5623..7dfe9f40d318f 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5302,6 +5302,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         Some(original_span.with_lo(original_span.hi() - BytePos(1)))
     }
 
+    // Rewrite `SelfCtor` to `StructCtor`
+    pub fn rewrite_self_ctor(&self, def: Def, span: Span) -> (Def, DefId, Ty<'tcx>) {
+        let tcx = self.tcx;
+        if let Def::SelfCtor(impl_def_id) = def {
+            let ty = self.impl_self_ty(span, impl_def_id).ty;
+            let adt_def = ty.ty_adt_def();
+
+            match adt_def {
+                Some(adt_def) if adt_def.has_ctor() => {
+                    let variant = adt_def.non_enum_variant();
+                    let def = Def::StructCtor(variant.did, variant.ctor_kind);
+                    (def, variant.did, tcx.type_of(variant.did))
+                }
+                _ => {
+                    let mut err = tcx.sess.struct_span_err(span,
+                        "the `Self` constructor can only be used with tuple or unit structs");
+                    if let Some(adt_def) = adt_def {
+                        match adt_def.adt_kind() {
+                            AdtKind::Enum => {
+                                err.help("did you mean to use one of the enum's variants?");
+                            },
+                            AdtKind::Struct |
+                            AdtKind::Union => {
+                                err.span_suggestion(
+                                    span,
+                                    "use curly brackets",
+                                    String::from("Self { /* fields */ }"),
+                                    Applicability::HasPlaceholders,
+                                );
+                            }
+                        }
+                    }
+                    err.emit();
+
+                    (def, impl_def_id, tcx.types.err)
+                }
+            }
+        } else {
+            let def_id = def.def_id();
+
+            // The things we are substituting into the type should not contain
+            // escaping late-bound regions, and nor should the base type scheme.
+            let ty = tcx.type_of(def_id);
+            (def, def_id, ty)
+        }
+    }
+
     // Instantiates the given path, which must refer to an item with the given
     // number of type parameters and type.
     pub fn instantiate_value_path(&self,
@@ -5321,6 +5368,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let tcx = self.tcx;
 
+        match def {
+            Def::Local(nid) | Def::Upvar(nid, ..) => {
+                let hid = self.tcx.hir().node_to_hir_id(nid);
+                let ty = self.local_ty(span, hid).decl_ty;
+                let ty = self.normalize_associated_types_in(span, &ty);
+                self.write_ty(hir_id, ty);
+                return (ty, def);
+            }
+            _ => {}
+        }
+
+        let (def, def_id, ty) = self.rewrite_self_ctor(def, span);
         let path_segs = AstConv::def_ids_for_path_segments(self, segments, self_ty, def);
 
         let mut user_self_ty = None;
@@ -5382,17 +5441,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             user_self_ty = None;
         }
 
-        match def {
-            Def::Local(nid) | Def::Upvar(nid, ..) => {
-                let hid = self.tcx.hir().node_to_hir_id(nid);
-                let ty = self.local_ty(span, hid).decl_ty;
-                let ty = self.normalize_associated_types_in(span, &ty);
-                self.write_ty(hir_id, ty);
-                return (ty, def);
-            }
-            _ => {}
-        }
-
         // Now we have to compare the types that the user *actually*
         // provided against the types that were *expected*. If the user
         // did not provide any types, then we want to substitute inference
@@ -5425,53 +5473,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             tcx.generics_of(*def_id).has_self
         }).unwrap_or(false);
 
-        let mut new_def = def;
-        let (def_id, ty) = match def {
-            Def::SelfCtor(impl_def_id) => {
-                let ty = self.impl_self_ty(span, impl_def_id).ty;
-                let adt_def = ty.ty_adt_def();
-
-                match adt_def {
-                    Some(adt_def) if adt_def.has_ctor() => {
-                        let variant = adt_def.non_enum_variant();
-                        new_def = Def::StructCtor(variant.did, variant.ctor_kind);
-                        (variant.did, tcx.type_of(variant.did))
-                    }
-                    _ => {
-                        let mut err = tcx.sess.struct_span_err(span,
-                            "the `Self` constructor can only be used with tuple or unit structs");
-                        if let Some(adt_def) = adt_def {
-                            match adt_def.adt_kind() {
-                                AdtKind::Enum => {
-                                    err.help("did you mean to use one of the enum's variants?");
-                                },
-                                AdtKind::Struct |
-                                AdtKind::Union => {
-                                    err.span_suggestion(
-                                        span,
-                                        "use curly brackets",
-                                        String::from("Self { /* fields */ }"),
-                                        Applicability::HasPlaceholders,
-                                    );
-                                }
-                            }
-                        }
-                        err.emit();
-
-                        (impl_def_id, tcx.types.err)
-                    }
-                }
-            }
-            _ => {
-                let def_id = def.def_id();
-
-                // The things we are substituting into the type should not contain
-                // escaping late-bound regions, and nor should the base type scheme.
-                let ty = tcx.type_of(def_id);
-                (def_id, ty)
-            }
-        };
-
         let substs = AstConv::create_substs_for_generic_args(
             tcx,
             def_id,
@@ -5587,7 +5588,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                ty_substituted);
         self.write_substs(hir_id, substs);
 
-        (ty_substituted, new_def)
+        (ty_substituted, def)
     }
 
     fn check_rustc_args_require_const(&self,
diff --git a/src/test/run-pass/issues/issue-57924.rs b/src/test/run-pass/issues/issue-57924.rs
new file mode 100644
index 0000000000000..232596334b0ed
--- /dev/null
+++ b/src/test/run-pass/issues/issue-57924.rs
@@ -0,0 +1,9 @@
+pub struct Gcm<E>(E);
+
+impl<E> Gcm<E> {
+    pub fn crash(e: E) -> Self {
+        Self::<E>(e)
+    }
+}
+
+fn main() {}

From 4e5692d9858d298f27757579688c71ba494cb5c3 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Fri, 18 Jan 2019 12:18:57 +0100
Subject: [PATCH 35/37] test that wildcard type `_` is not duplicated by `type
 Foo<X> = (X, X);` and potentially instantiated at different types.

(Updated to reflect changes in diagnostic output and compiletest infrastructure.)
---
 ...ssue-55748-pat-types-constrain-bindings.rs | 70 +++++++++++++++++++
 ...-55748-pat-types-constrain-bindings.stderr | 29 ++++++++
 2 files changed, 99 insertions(+)
 create mode 100644 src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs
 create mode 100644 src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr

diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs
new file mode 100644
index 0000000000000..3d042d442d531
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs
@@ -0,0 +1,70 @@
+// This test is ensuring that type ascriptions on let bindings
+// constrain both:
+//
+// 1. the input expression on the right-hand side (after any potential
+//    coercion, and allowing for covariance), *and*
+//
+// 2. the bindings (if any) nested within the pattern on the left-hand
+//    side (and here, the type-constraint is *invariant*).
+
+#![feature(nll)]
+
+#![allow(dead_code, unused_mut)]
+type PairUncoupled<'a, 'b, T> = (&'a T, &'b T);
+type PairCoupledRegions<'a, T> = (&'a T, &'a T);
+type PairCoupledTypes<T> = (T, T);
+
+fn uncoupled_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((mut y, mut _z),): (PairUncoupled<u32>,) = ((s, &_x),); // ok
+    // Above compiling does *not* imply below would compile.
+    // ::std::mem::swap(&mut y, &mut _z);
+    y
+}
+
+fn swap_regions((mut y, mut _z): PairCoupledRegions<u32>) {
+    ::std::mem::swap(&mut y, &mut _z);
+}
+
+fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((y, _z),): (PairCoupledRegions<u32>,) = ((s, &_x),);
+    // If above line compiled, so should line below ...
+
+    // swap_regions((y, _z));
+
+    // ... but the ascribed type also invalidates this use of `y`
+    y //~ ERROR lifetime may not live long enough
+}
+
+fn swap_types((mut y, mut _z): PairCoupledTypes<&u32>) {
+    ::std::mem::swap(&mut y, &mut _z);
+}
+
+fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((y, _z),): (PairCoupledTypes<&u32>,) = ((s, &_x),);
+    // If above line compiled, so should line below ...
+
+    // swap_types((y, _z));
+
+    // ... but the ascribed type also invalidates this use of `y`
+    y //~ ERROR lifetime may not live long enough
+}
+
+fn swap_wilds((mut y, mut _z): PairCoupledTypes<&u32>) {
+    ::std::mem::swap(&mut y, &mut _z);
+}
+
+fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((y, _z),): (PairCoupledTypes<_>,) = ((s, &_x),);
+    // If above line compiled, so should line below
+    // swap_wilds((y, _z));
+
+    // ... but the ascribed type also invalidates this use of `y`
+    y //~ ERROR lifetime may not live long enough
+}
+
+fn main() {
+    uncoupled_lhs(&3, &4);
+    coupled_regions_lhs(&3, &4);
+    coupled_types_lhs(&3, &4);
+    coupled_wilds_lhs(&3, &4);
+}
diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr
new file mode 100644
index 0000000000000..5929707e41e10
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr
@@ -0,0 +1,29 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-55748-pat-types-constrain-bindings.rs:35:5
+   |
+LL | fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+   |                        -- lifetime `'a` defined here
+...
+LL |     y
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-55748-pat-types-constrain-bindings.rs:49:5
+   |
+LL | fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+   |                      -- lifetime `'a` defined here
+...
+LL |     y
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-55748-pat-types-constrain-bindings.rs:62:5
+   |
+LL | fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+   |                      -- lifetime `'a` defined here
+...
+LL |     y
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 3 previous errors
+

From 88d43a052a9230230bb263ff0b7b072134203510 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= <john.kare.alsaker@gmail.com>
Date: Thu, 14 Mar 2019 05:53:44 +0100
Subject: [PATCH 36/37] Don't run test launching `echo` since that doesn't
 exist on Windows

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

diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 568400093440c..ad86acbb47de4 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -8,7 +8,7 @@
 //!
 //! The [`Command`] struct is used to configure and spawn processes:
 //!
-//! ```
+//! ```no_run
 //! use std::process::Command;
 //!
 //! let output = Command::new("echo")

From 41cdf07483ed39ccd85ce1c9ae7512ceb3bbb657 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= <john.kare.alsaker@gmail.com>
Date: Thu, 14 Mar 2019 06:35:48 +0100
Subject: [PATCH 37/37] Run RustdocUi earlier

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

diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index ffd23e72e80a6..daa6749f87f3e 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -408,11 +408,11 @@ impl<'a> Builder<'a> {
                 test::RustdocJSStd,
                 test::RustdocJSNotStd,
                 test::RustdocTheme,
+                test::RustdocUi,
                 // Run bootstrap close to the end as it's unlikely to fail
                 test::Bootstrap,
                 // Run run-make last, since these won't pass without make on Windows
                 test::RunMake,
-                test::RustdocUi
             ),
             Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
             Kind::Doc => describe!(