From 37570e82baf12951f8bb408884e31640b0d29dae Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Thu, 28 May 2020 22:07:13 -0400
Subject: [PATCH 01/66] Substantial refactor to the design of LineWriter

This commit redesigns LineWriter to work more directly on the internals
of BufWriter. This interface change is to enable a future Pull Request
in which Stdout can be switched between Line and Block buffered mode.
---
 src/libstd/io/buffered.rs | 352 ++++++++++++++++++++++++++++----------
 1 file changed, 259 insertions(+), 93 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 046b1a6888024..fff4d0df7e769 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -449,6 +449,12 @@ impl<R: Seek> Seek for BufReader<R> {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
     inner: Option<W>,
+    // FIXME: Replace this with a VecDeque. Because VecDeque is a Ring buffer,
+    // this would enable BufWriter to operate without any interior copies.
+    // It was also allow a much simpler implementation of flush_buf. The main
+    // blocker here is that VecDeque doesn't currently have the same
+    // slice-specific specializations (extend_from_slice, `Extend`
+    // specializations)
     buf: Vec<u8>,
     // #30888: If the inner writer panics in a call to write, we don't want to
     // write the buffered data a second time in BufWriter's destructor. This
@@ -519,6 +525,13 @@ impl<W: Write> BufWriter<W> {
         BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false }
     }
 
+    /// Send data in our local buffer into the inner writer, looping as
+    /// necessary until either it's all been sent or an error occurs.
+    ///
+    /// Because all the data in the buffer has been reported to our owner as
+    /// "successfully written" (by returning nonzero success values from
+    /// `write`), any 0-length writes from `inner` must be reported as i/o
+    /// errors from this method.
     fn flush_buf(&mut self) -> io::Result<()> {
         let mut written = 0;
         let len = self.buf.len();
@@ -548,6 +561,17 @@ impl<W: Write> BufWriter<W> {
         ret
     }
 
+    /// Buffer some data without flushing it, regardless of the size of the
+    /// data. Writes as much as possible without exceeding capacity. Returns
+    /// the number of bytes written.
+    #[inline]
+    fn write_to_buffer(&mut self, buf: &[u8]) -> usize {
+        let available = self.buf.capacity() - self.buf.len();
+        let amt_to_buffer = available.min(buf.len());
+        self.buf.extend_from_slice(&buf[..amt_to_buffer]);
+        amt_to_buffer
+    }
+
     /// Gets a reference to the underlying writer.
     ///
     /// # Examples
@@ -665,7 +689,22 @@ impl<W: Write> Write for BufWriter<W> {
             self.panicked = false;
             r
         } else {
-            self.buf.write(buf)
+            Ok(self.write_to_buffer(buf))
+        }
+    }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        if self.buf.len() + buf.len() > self.buf.capacity() {
+            self.flush_buf()?;
+        }
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write_all(buf);
+            self.panicked = false;
+            r
+        } else {
+            self.write_to_buffer(buf);
+            Ok(())
         }
     }
 
@@ -818,6 +857,200 @@ impl<W> fmt::Display for IntoInnerError<W> {
     }
 }
 
+/// Private helper struct for implementing the line-buffered writing logic.
+/// This shim temporarily wraps a BufWriter, and uses its internals to
+/// implement a line-buffered writer (specifically by using the internal
+/// methods like write_to_buffer and flush_buffer). In this way, a more
+/// efficient abstraction can be created than one that only had access to
+/// `write` and `flush`, without needlessly duplicating a lot of the
+/// implementation details of BufWriter. This also allows existing
+/// `BufWriters` to be temporarily given line-buffering logic; this is what
+/// enables Stdout to be alternately in line-buffered or block-buffered mode.
+#[derive(Debug)]
+pub(super) struct LineWriterShim<'a, W: Write> {
+    inner: &'a mut BufWriter<W>,
+}
+
+impl<'a, W: Write> LineWriterShim<'a, W> {
+    pub fn new(inner: &'a mut BufWriter<W>) -> Self {
+        Self { inner }
+    }
+}
+
+impl<'a, W: Write> Write for LineWriterShim<'a, W> {
+    /// Write some data into this BufReader with line buffering. This means
+    /// that, if any newlines are present in the data, the data up to the last
+    /// newline is sent directly to the underlying writer, and data after it
+    /// is buffered. Returns the number of bytes written.
+    ///
+    /// This function operates on a "best effort basis"; in keeping with the
+    /// convention of `Write::write`, it makes at most one attempt to write
+    /// new data to the underlying writer. If that write only reports a partial
+    /// success, the remaining data will be buffered.
+    ///
+    /// Because this function attempts to send completed lines to the underlying
+    /// writer, it will also flush the existing buffer if it contains any
+    /// newlines, even if the incoming data does not contain any newlines.
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        // If there are no new newlines (that is, if this write is less than
+        // one line), just do a regular buffered write
+        let newline_idx = match memchr::memrchr(b'\n', buf) {
+            None => {
+                // Check for prior partial line writes that need to be retried
+                if memchr::memchr(b'\n', &self.inner.buffer()).is_some() {
+                    self.inner.flush_buf()?;
+                }
+                return self.inner.write(buf);
+            }
+            Some(i) => i,
+        };
+
+        // Flush existing content to prepare for our write
+        self.inner.flush_buf()?;
+
+        // This is what we're going to try to write directly to the inner
+        // writer. The rest will be buffered, if nothing goes wrong.
+        let lines = &buf[..newline_idx + 1];
+
+        // Write `lines` directly to the inner writer. In keeping with the
+        // `write` convention, make at most one attempt to add new (unbuffered)
+        // data. Because this write doesn't touch the BufWriter state directly,
+        // and the buffer is known to be empty, we don't need to worry about
+        // self.panicked here.
+        let flushed = self.inner.get_mut().write(lines)?;
+
+        // Now that the write has succeeded, buffer the rest (or as much of
+        // the rest as possible). If there were any unwritten newlines, we
+        // only buffer out to the last unwritten newline; this helps prevent
+        // flushing partial lines on subsequent calls to write_buffered_lines.
+        let tail = &buf[flushed..];
+        let buffered = match memchr::memrchr(b'\n', tail) {
+            None => self.inner.write_to_buffer(tail),
+            Some(i) => self.inner.write_to_buffer(&tail[..i + 1]),
+        };
+        Ok(flushed + buffered)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.inner.flush()
+    }
+
+    /// Write some vectored data into this BufReader with line buffering. This
+    /// means that, if any newlines are present in the data, the data up to
+    /// and including the buffer containing the last newline is sent directly
+    /// to the inner writer, and the data after it is buffered. Returns the
+    /// number of bytes written.
+    ///
+    /// This function operates on a "best effort basis"; in keeping with the
+    /// convention of `Write::write`, it makes at most one attempt to write
+    /// new data to the underlying writer.
+    ///
+    /// Because this function attempts to send completed lines to the underlying
+    /// writer, it will also flush the existing buffer if it contains any
+    /// newlines.
+    ///
+    /// Because sorting through an array of `IoSlice` can be a bit convoluted,
+    /// This method differs from write in the following ways:
+    ///
+    /// - It attempts to write all the buffers up to and including the one
+    ///   containing the last newline. This means that it may attempt to
+    ///   write a partial line.
+    /// - If the write only reports partial success, it does not attempt to
+    ///   find the precise location of the written bytes and buffer the rest.
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        // Find the buffer containing the last newline
+        let last_newline_buf_idx = bufs
+            .iter()
+            .enumerate()
+            .rev()
+            .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i));
+
+        // If there are no new newlines (that is, if this write is less than
+        // one line), just do a regular buffered write
+        let last_newline_buf_idx = match last_newline_buf_idx {
+            // No newlines; just do a normal buffered write
+            None => {
+                // Check for prior partial line writes that need to be retried
+                if memchr::memchr(b'\n', &self.inner.buffer()).is_some() {
+                    self.inner.flush_buf()?;
+                }
+                return self.inner.write_vectored(bufs);
+            }
+            Some(i) => i,
+        };
+
+        // Flush existing content to prepare for our write
+        self.inner.flush_buf()?;
+
+        // This is what we're going to try to write directly to the inner
+        // writer. The rest will be buffered, if nothing goes wrong.
+        let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1);
+
+        // Write `lines` directly to the inner writer. In keeping with the
+        // `write` convention, make at most one attempt to add new (unbuffered)
+        // data. Because this write doesn't touch the BufWriter state directly,
+        // and the buffer is known to be empty, we don't need to worry about
+        // self.panicked here.
+        let flushed = self.inner.write_vectored(lines)?;
+
+        // Don't try to reconstruct the exact amount written; just bail
+        // in the event of a partial write
+        let lines_len = lines.iter().map(|buf| buf.len()).sum();
+        if flushed < lines_len {
+            return Ok(flushed);
+        }
+
+        // Now that the write has succeeded, buffer the rest (or as much of the
+        // rest as possible)
+        let buffered: usize =
+            tail.iter().map(|buf| self.inner.write_to_buffer(buf)).take_while(|&n| n > 0).sum();
+
+        Ok(flushed + buffered)
+    }
+
+    fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
+
+    /// Write some data into this BufReader with line buffering. This means
+    /// that, if any newlines are present in the data, the data up to the last
+    /// newline is sent directly to the underlying writer, and data after it
+    /// is buffered.
+    ///
+    /// Because this function attempts to send completed lines to the underlying
+    /// writer, it will also flush the existing buffer if it contains any
+    /// newlines, even if the incoming data does not contain any newlines.
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        // If there are no new newlines (that is, if this write is less than
+        // one line), just do a regular buffered write
+        let newline_idx = match memchr::memrchr(b'\n', buf) {
+            None => {
+                // Check for prior partial line writes that need to be retried
+                if memchr::memchr(b'\n', &self.inner.buffer()).is_some() {
+                    self.inner.flush_buf()?;
+                }
+                return self.inner.write_all(buf);
+            }
+            Some(i) => i,
+        };
+
+        // Flush existing content to prepare for our write
+        self.inner.flush_buf()?;
+
+        // This is what we're going to try to write directly to the inner
+        // writer. The rest will be buffered, if nothing goes wrong.
+        let (lines, tail) = buf.split_at(newline_idx + 1);
+
+        // Write `lines` directly to the inner writer, bypassing the buffer.
+        self.inner.get_mut().write_all(lines)?;
+
+        // Now that the write has succeeded, buffer the rest with BufWriter::write_all.
+        // This will buffer as much as possible, but continue flushing as
+        // necessary if our tail is huge.
+        self.inner.write_all(tail)
+    }
+}
+
 /// Wraps a writer and buffers output to it, flushing whenever a newline
 /// (`0x0a`, `'\n'`) is detected.
 ///
@@ -885,7 +1118,6 @@ impl<W> fmt::Display for IntoInnerError<W> {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct LineWriter<W: Write> {
     inner: BufWriter<W>,
-    need_flush: bool,
 }
 
 impl<W: Write> LineWriter<W> {
@@ -926,7 +1158,7 @@ impl<W: Write> LineWriter<W> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> {
-        LineWriter { inner: BufWriter::with_capacity(capacity, inner), need_flush: false }
+        LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
     }
 
     /// Gets a reference to the underlying writer.
@@ -1000,110 +1232,40 @@ impl<W: Write> LineWriter<W> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
-        self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
-            IntoInnerError(LineWriter { inner: buf, need_flush: false }, e)
-        })
+        self.inner
+            .into_inner()
+            .map_err(|IntoInnerError(buf, e)| IntoInnerError(LineWriter { inner: buf }, e))
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<W: Write> Write for LineWriter<W> {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        if self.need_flush {
-            self.flush()?;
-        }
-
-        // Find the last newline character in the buffer provided. If found then
-        // we're going to write all the data up to that point and then flush,
-        // otherwise we just write the whole block to the underlying writer.
-        let i = match memchr::memrchr(b'\n', buf) {
-            Some(i) => i,
-            None => return self.inner.write(buf),
-        };
-
-        // Ok, we're going to write a partial amount of the data given first
-        // followed by flushing the newline. After we've successfully written
-        // some data then we *must* report that we wrote that data, so future
-        // errors are ignored. We set our internal `need_flush` flag, though, in
-        // case flushing fails and we need to try it first next time.
-        let n = self.inner.write(&buf[..=i])?;
-        self.need_flush = true;
-        if self.flush().is_err() || n != i + 1 {
-            return Ok(n);
-        }
+        LineWriterShim::new(&mut self.inner).write(buf)
+    }
 
-        // At this point we successfully wrote `i + 1` bytes and flushed it out,
-        // meaning that the entire line is now flushed out on the screen. While
-        // we can attempt to finish writing the rest of the data provided.
-        // Remember though that we ignore errors here as we've successfully
-        // written data, so we need to report that.
-        match self.inner.write(&buf[i + 1..]) {
-            Ok(i) => Ok(n + i),
-            Err(_) => Ok(n),
-        }
+    fn flush(&mut self) -> io::Result<()> {
+        self.inner.flush()
     }
 
-    // Vectored writes are very similar to the writes above, but adjusted for
-    // the list of buffers that we have to write.
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        if self.need_flush {
-            self.flush()?;
-        }
+        LineWriterShim::new(&mut self.inner).write_vectored(bufs)
+    }
 
-        // Find the last newline, and failing that write the whole buffer
-        let last_newline = bufs.iter().enumerate().rev().find_map(|(i, buf)| {
-            let pos = memchr::memrchr(b'\n', buf)?;
-            Some((i, pos))
-        });
-        let (i, j) = match last_newline {
-            Some(pair) => pair,
-            None => return self.inner.write_vectored(bufs),
-        };
-        let (prefix, suffix) = bufs.split_at(i);
-        let (buf, suffix) = suffix.split_at(1);
-        let buf = &buf[0];
-
-        // Write everything up to the last newline, flushing afterwards. Note
-        // that only if we finished our entire `write_vectored` do we try the
-        // subsequent
-        // `write`
-        let mut n = 0;
-        let prefix_amt = prefix.iter().map(|i| i.len()).sum();
-        if prefix_amt > 0 {
-            n += self.inner.write_vectored(prefix)?;
-            self.need_flush = true;
-        }
-        if n == prefix_amt {
-            match self.inner.write(&buf[..=j]) {
-                Ok(m) => n += m,
-                Err(e) if n == 0 => return Err(e),
-                Err(_) => return Ok(n),
-            }
-            self.need_flush = true;
-        }
-        if self.flush().is_err() || n != j + 1 + prefix_amt {
-            return Ok(n);
-        }
+    fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
 
-        // ... and now write out everything remaining
-        match self.inner.write(&buf[j + 1..]) {
-            Ok(i) => n += i,
-            Err(_) => return Ok(n),
-        }
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        LineWriterShim::new(&mut self.inner).write_all(buf)
+    }
 
-        if suffix.iter().map(|s| s.len()).sum::<usize>() == 0 {
-            return Ok(n);
-        }
-        match self.inner.write_vectored(suffix) {
-            Ok(i) => Ok(n + i),
-            Err(_) => Ok(n),
-        }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        LineWriterShim::new(&mut self.inner).write_all_vectored(bufs)
     }
 
-    fn flush(&mut self) -> io::Result<()> {
-        self.inner.flush()?;
-        self.need_flush = false;
-        Ok(())
+    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+        LineWriterShim::new(&mut self.inner).write_fmt(fmt)
     }
 }
 
@@ -1137,7 +1299,11 @@ mod tests {
 
     impl Read for ShortReader {
         fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
-            if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) }
+            if self.lengths.is_empty() {
+                Ok(0)
+            } else {
+                Ok(self.lengths.remove(0))
+            }
         }
     }
 

From 0f3815886a0d7aaefd222b4592c3ef2ccfd0ebc2 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Sun, 31 May 2020 01:29:48 -0400
Subject: [PATCH 02/66] Updated comments; only pre-flush newline terminated
 buffers

---
 src/libstd/io/buffered.rs | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index fff4d0df7e769..0ae5db0df1778 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -896,8 +896,10 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         // one line), just do a regular buffered write
         let newline_idx = match memchr::memrchr(b'\n', buf) {
             None => {
-                // Check for prior partial line writes that need to be retried
-                if memchr::memchr(b'\n', &self.inner.buffer()).is_some() {
+                // Check for prior partial line writes that need to be retried.
+                // Only retry if the buffer contains a completed line, to
+                // avoid flushing partial lines.
+                if let Some(b'\n') = self.inner.buffer().last().copied() {
                     self.inner.flush_buf()?;
                 }
                 return self.inner.write(buf);
@@ -916,13 +918,13 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         // `write` convention, make at most one attempt to add new (unbuffered)
         // data. Because this write doesn't touch the BufWriter state directly,
         // and the buffer is known to be empty, we don't need to worry about
-        // self.panicked here.
+        // self.inner.panicked here.
         let flushed = self.inner.get_mut().write(lines)?;
 
         // Now that the write has succeeded, buffer the rest (or as much of
         // the rest as possible). If there were any unwritten newlines, we
         // only buffer out to the last unwritten newline; this helps prevent
-        // flushing partial lines on subsequent calls to write_buffered_lines.
+        // flushing partial lines on subsequent calls to LineWriterShim::write.
         let tail = &buf[flushed..];
         let buffered = match memchr::memrchr(b'\n', tail) {
             None => self.inner.write_to_buffer(tail),
@@ -970,8 +972,10 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         let last_newline_buf_idx = match last_newline_buf_idx {
             // No newlines; just do a normal buffered write
             None => {
-                // Check for prior partial line writes that need to be retried
-                if memchr::memchr(b'\n', &self.inner.buffer()).is_some() {
+                // Check for prior partial line writes that need to be retried.
+                // Only retry if the buffer contains a completed line, to
+                // avoid flushing partial lines.
+                if let Some(b'\n') = self.inner.buffer().last().copied() {
                     self.inner.flush_buf()?;
                 }
                 return self.inner.write_vectored(bufs);
@@ -1025,8 +1029,10 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         // one line), just do a regular buffered write
         let newline_idx = match memchr::memrchr(b'\n', buf) {
             None => {
-                // Check for prior partial line writes that need to be retried
-                if memchr::memchr(b'\n', &self.inner.buffer()).is_some() {
+                // Check for prior partial line writes that need to be retried.
+                // Only retry if the buffer contains a completed line, to
+                // avoid flushing partial lines.
+                if let Some(b'\n') = self.inner.buffer().last().copied() {
                     self.inner.flush_buf()?;
                 }
                 return self.inner.write_all(buf);

From 4a1597f7a77b17e42217d02750af2ae8012430af Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Sun, 31 May 2020 02:37:36 -0400
Subject: [PATCH 03/66] Expressionify `LineWriterShim::write`

---
 src/libstd/io/buffered.rs | 62 ++++++++++++++++++++-------------------
 1 file changed, 32 insertions(+), 30 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 0ae5db0df1778..6098416df19b2 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -892,9 +892,9 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     /// writer, it will also flush the existing buffer if it contains any
     /// newlines, even if the incoming data does not contain any newlines.
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        // If there are no new newlines (that is, if this write is less than
-        // one line), just do a regular buffered write
-        let newline_idx = match memchr::memrchr(b'\n', buf) {
+        match memchr::memrchr(b'\n', buf) {
+            // If there are no new newlines (that is, if this write is less than
+            // one line), just do a regular buffered write
             None => {
                 // Check for prior partial line writes that need to be retried.
                 // Only retry if the buffer contains a completed line, to
@@ -902,35 +902,37 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
                 if let Some(b'\n') = self.inner.buffer().last().copied() {
                     self.inner.flush_buf()?;
                 }
-                return self.inner.write(buf);
+                self.inner.write(buf)
+            }
+            // Otherwise, arrange for the lines to be written directly to the
+            // inner writer.
+            Some(newline_idx) => {
+                // Flush existing content to prepare for our write
+                self.inner.flush_buf()?;
+
+                // This is what we're going to try to write directly to the inner
+                // writer. The rest will be buffered, if nothing goes wrong.
+                let lines = &buf[..newline_idx + 1];
+
+                // Write `lines` directly to the inner writer. In keeping with the
+                // `write` convention, make at most one attempt to add new (unbuffered)
+                // data. Because this write doesn't touch the BufWriter state directly,
+                // and the buffer is known to be empty, we don't need to worry about
+                // self.inner.panicked here.
+                let flushed = self.inner.get_mut().write(lines)?;
+
+                // Now that the write has succeeded, buffer the rest (or as much of
+                // the rest as possible). If there were any unwritten newlines, we
+                // only buffer out to the last unwritten newline; this helps prevent
+                // flushing partial lines on subsequent calls to LineWriterShim::write.
+                let tail = &buf[flushed..];
+                let buffered = match memchr::memrchr(b'\n', tail) {
+                    None => self.inner.write_to_buffer(tail),
+                    Some(i) => self.inner.write_to_buffer(&tail[..i + 1]),
+                };
+                Ok(flushed + buffered)
             }
-            Some(i) => i,
-        };
-
-        // Flush existing content to prepare for our write
-        self.inner.flush_buf()?;
-
-        // This is what we're going to try to write directly to the inner
-        // writer. The rest will be buffered, if nothing goes wrong.
-        let lines = &buf[..newline_idx + 1];
-
-        // Write `lines` directly to the inner writer. In keeping with the
-        // `write` convention, make at most one attempt to add new (unbuffered)
-        // data. Because this write doesn't touch the BufWriter state directly,
-        // and the buffer is known to be empty, we don't need to worry about
-        // self.inner.panicked here.
-        let flushed = self.inner.get_mut().write(lines)?;
-
-        // Now that the write has succeeded, buffer the rest (or as much of
-        // the rest as possible). If there were any unwritten newlines, we
-        // only buffer out to the last unwritten newline; this helps prevent
-        // flushing partial lines on subsequent calls to LineWriterShim::write.
-        let tail = &buf[flushed..];
-        let buffered = match memchr::memrchr(b'\n', tail) {
-            None => self.inner.write_to_buffer(tail),
-            Some(i) => self.inner.write_to_buffer(&tail[..i + 1]),
         };
-        Ok(flushed + buffered)
     }
 
     fn flush(&mut self) -> io::Result<()> {

From 5edad37b04d4daac62b01946142589e0f69aa22c Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Sun, 31 May 2020 03:21:51 -0400
Subject: [PATCH 04/66] Expressionify write_all

---
 src/libstd/io/buffered.rs | 40 ++++++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 19 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 6098416df19b2..de2a32345f1c9 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -932,7 +932,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
                 };
                 Ok(flushed + buffered)
             }
-        };
+        }
     }
 
     fn flush(&mut self) -> io::Result<()> {
@@ -1027,9 +1027,9 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     /// writer, it will also flush the existing buffer if it contains any
     /// newlines, even if the incoming data does not contain any newlines.
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        // If there are no new newlines (that is, if this write is less than
-        // one line), just do a regular buffered write
-        let newline_idx = match memchr::memrchr(b'\n', buf) {
+        match memchr::memrchr(b'\n', buf) {
+            // If there are no new newlines (that is, if this write is less than
+            // one line), just do a regular buffered write
             None => {
                 // Check for prior partial line writes that need to be retried.
                 // Only retry if the buffer contains a completed line, to
@@ -1037,25 +1037,27 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
                 if let Some(b'\n') = self.inner.buffer().last().copied() {
                     self.inner.flush_buf()?;
                 }
-                return self.inner.write_all(buf);
+                self.inner.write_all(buf)
             }
-            Some(i) => i,
-        };
-
-        // Flush existing content to prepare for our write
-        self.inner.flush_buf()?;
+            // Otherwise, arrange for the lines to be written directly to the
+            // inner writer.
+            Some(newline_idx) => {
+                // Flush existing content to prepare for our write
+                self.inner.flush_buf()?;
 
-        // This is what we're going to try to write directly to the inner
-        // writer. The rest will be buffered, if nothing goes wrong.
-        let (lines, tail) = buf.split_at(newline_idx + 1);
+                // This is what we're going to try to write directly to the inner
+                // writer. The rest will be buffered, if nothing goes wrong.
+                let (lines, tail) = buf.split_at(newline_idx + 1);
 
-        // Write `lines` directly to the inner writer, bypassing the buffer.
-        self.inner.get_mut().write_all(lines)?;
+                // Write `lines` directly to the inner writer, bypassing the buffer.
+                self.inner.get_mut().write_all(lines)?;
 
-        // Now that the write has succeeded, buffer the rest with BufWriter::write_all.
-        // This will buffer as much as possible, but continue flushing as
-        // necessary if our tail is huge.
-        self.inner.write_all(tail)
+                // Now that the write has succeeded, buffer the rest with BufWriter::write_all.
+                // This will buffer as much as possible, but continue flushing as
+                // necessary if our tail is huge.
+                self.inner.write_all(tail)
+            }
+        }
     }
 }
 

From 1bf8ba3546aace5a16852d5f58fd9206934cc829 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Sun, 31 May 2020 03:28:07 -0400
Subject: [PATCH 05/66] x.py fmt

---
 src/libstd/io/buffered.rs | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index de2a32345f1c9..35434979b85ad 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -1309,11 +1309,7 @@ mod tests {
 
     impl Read for ShortReader {
         fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
-            if self.lengths.is_empty() {
-                Ok(0)
-            } else {
-                Ok(self.lengths.remove(0))
-            }
+            if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) }
         }
     }
 

From e0dfdc683def9573f28d7f2f077790bc3c52132b Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Mon, 1 Jun 2020 00:26:48 -0400
Subject: [PATCH 06/66] Added check for `is_write_vectored`

---
 src/libstd/io/buffered.rs | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 35434979b85ad..4ae2a5eaf95a9 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -961,7 +961,19 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     ///   write a partial line.
     /// - If the write only reports partial success, it does not attempt to
     ///   find the precise location of the written bytes and buffer the rest.
+    ///
+    /// If the underlying vector doesn't support vectored writing, we instead
+    /// simply write the first non-empty buffer with `write`. This way, we
+    /// get the benefits of more granular partial-line handling without losing
+    /// anything in efficiency
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        if !self.is_write_vectored() {
+            return match bufs.iter().find(|buf| !buf.is_empty()) {
+                Some(buf) => self.write(buf),
+                None => Ok(0),
+            }
+        }
+
         // Find the buffer containing the last newline
         let last_newline_buf_idx = bufs
             .iter()

From 2c3024b368cb2810e390f980c3f9820cc07389e8 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Mon, 1 Jun 2020 00:36:31 -0400
Subject: [PATCH 07/66] Add comment describing erroneous_flush_retried

---
 src/libstd/io/buffered.rs | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 4ae2a5eaf95a9..04c1cbf5a17d3 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -1766,6 +1766,15 @@ mod tests {
         }
     }
 
+    /// Previously the `LineWriter` could successfully write some bytes but
+    /// then fail to report that it has done so. Additionally, an erroneous
+    /// flush after a successful write was permanently ignored.
+    ///
+    /// Test that a line writer correctly reports the number of written bytes,
+    /// and that it attempts to flush buffered lines from previous writes
+    /// before processing new data
+    ///
+    /// Regression test for #37807
     #[test]
     fn erroneous_flush_retried() {
         let a = AcceptOneThenFail { written: false, flushed: false };

From e89e2e42f9269fe401b1eef0288ff12c7941544f Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Mon, 1 Jun 2020 01:04:33 -0400
Subject: [PATCH 08/66] Added test stubs

---
 src/libstd/io/buffered.rs | 109 ++++++++++++++++++++++++++++++--------
 1 file changed, 86 insertions(+), 23 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 04c1cbf5a17d3..09b24d810c526 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -971,7 +971,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
             return match bufs.iter().find(|buf| !buf.is_empty()) {
                 Some(buf) => self.write(buf),
                 None => Ok(0),
-            }
+            };
         }
 
         // Find the buffer containing the last newline
@@ -1321,7 +1321,11 @@ mod tests {
 
     impl Read for ShortReader {
         fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
-            if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) }
+            if self.lengths.is_empty() {
+                Ok(0)
+            } else {
+                Ok(self.lengths.remove(0))
+            }
         }
     }
 
@@ -1742,27 +1746,48 @@ mod tests {
         b.iter(|| BufWriter::new(io::sink()));
     }
 
-    struct AcceptOneThenFail {
-        written: bool,
+    #[derive(Default, Clone)]
+    struct ProgrammableSink {
+        // Writes append to this slice
+        buffer: Vec<u8>,
+
+        // Flushes set this flag
         flushed: bool,
+
+        // If true, writes & flushes will always be an error
+        return_error: bool,
+
+        // If set, only up to this number of bytes will be written in a single
+        // call to `write`
+        accept_prefix: Option<usize>,
+
+        // If set, counts down with each write, and writes return an error
+        // when it hits 0
+        max_writes: Option<usize>,
     }
 
-    impl Write for AcceptOneThenFail {
+    impl Write for ProgrammableSink {
         fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-            if !self.written {
-                assert_eq!(data, b"a\nb\n");
-                self.written = true;
-                Ok(data.len())
+            if self.return_error {
+                Err(io::Error::new(io::ErrorKind::Other, "test"))
             } else {
-                Err(io::Error::new(io::ErrorKind::NotFound, "test"))
+                let len = match self.accept_prefix {
+                    None => data.len(),
+                    Some(prefix) => prefix.min(prefix),
+                };
+                let data = &data[..len];
+                self.buffer.extend_from_slice(data);
+                Ok(len)
             }
         }
 
         fn flush(&mut self) -> io::Result<()> {
-            assert!(self.written);
-            assert!(!self.flushed);
-            self.flushed = true;
-            Err(io::Error::new(io::ErrorKind::Other, "test"))
+            if self.return_error {
+                Err(io::Error::new(io::ErrorKind::Other, "test"))
+            } else {
+                self.flushed = true;
+                Ok(())
+            }
         }
     }
 
@@ -1777,15 +1802,7 @@ mod tests {
     /// Regression test for #37807
     #[test]
     fn erroneous_flush_retried() {
-        let a = AcceptOneThenFail { written: false, flushed: false };
-
-        let mut l = LineWriter::new(a);
-        assert_eq!(l.write(b"a\nb\na").unwrap(), 4);
-        assert!(l.get_ref().written);
-        assert!(l.get_ref().flushed);
-        l.get_mut().flushed = false;
-
-        assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other)
+        todo!()
     }
 
     #[test]
@@ -1895,4 +1912,50 @@ mod tests {
             io::Error::new(io::ErrorKind::Other, "x")
         }
     }
+
+    /// Test that, given this input:
+    ///
+    /// Line 1\n
+    /// Line 2\n
+    /// Line 3\n
+    /// Line 4
+    ///
+    /// And given a result that only writes to midway through Line 2
+    ///
+    /// That only up to the end of Line 3 is buffered
+    ///
+    /// This behavior is desirable because it prevents flushing partial lines
+    #[test]
+    fn test_partial_write_buffers_line() {
+        todo!()
+    }
+
+    /// Test that, given this input:
+    ///
+    /// Line 1\n
+    /// Line 2\n
+    /// Line 3
+    ///
+    /// And given that the full write of lines 1 and 2 was successful
+    /// That data up to Line 3 is buffered
+    #[test]
+    fn test_partial_line_buffered_after_line_write() {
+        todo!()
+    }
+
+    /// Test that, given a partial line that exceeds the length of
+    /// LineBuffer's buffer (that is, without a trailing newline), that that
+    /// line is written to the inner writer
+    #[test]
+    fn test_long_line_flushed() {
+        todo!()
+    }
+
+    /// Test that, given a very long partial line *after* successfully
+    /// flushing a complete line, that that line is buffered unconditionally,
+    /// and no additional writes take place
+    #[test]
+    fn test_long_tail_not_flushed() {
+        todo!()
+    }
 }

From f0a08073e47cc4a832cea66a7ef6bd9506061a72 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Mon, 1 Jun 2020 17:36:55 -0400
Subject: [PATCH 09/66] Various testing & implementation updates:

- Added a bunch of new unit tests
- Removed test_line_buffer_fail_flush
- Updated erroneous_flush_retried
- Added helper methods to LineWriterShim for code clarity, to distinguish "self.buffer" (the BufWriter) from self.inner (the thing wrapped by the BufWriter)
- Un-expressionized write & write_all
- Added clause to bail early on Ok(0)
---
 src/libstd/io/buffered.rs | 344 +++++++++++++++++++++++++-------------
 1 file changed, 232 insertions(+), 112 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 09b24d810c526..730ae8a0ee471 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -868,12 +868,30 @@ impl<W> fmt::Display for IntoInnerError<W> {
 /// enables Stdout to be alternately in line-buffered or block-buffered mode.
 #[derive(Debug)]
 pub(super) struct LineWriterShim<'a, W: Write> {
-    inner: &'a mut BufWriter<W>,
+    buffer: &'a mut BufWriter<W>,
 }
 
 impl<'a, W: Write> LineWriterShim<'a, W> {
-    pub fn new(inner: &'a mut BufWriter<W>) -> Self {
-        Self { inner }
+    pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
+        Self { buffer }
+    }
+
+    /// Get a reference to the inner writer (that is, the writer wrapped by
+    /// the BufWriter)
+    fn inner(&self) -> &W {
+        self.buffer.get_ref()
+    }
+
+    /// Get a mutable reference to the inner writer (that is, the writer
+    /// wrapped by the BufWriter). Be careful with this writer, as writes to
+    /// it will bypass the buffer.
+    fn inner_mut(&mut self) -> &mut W {
+        self.buffer.get_mut()
+    }
+
+    /// Get the content currently buffered in self.buffer
+    fn buffered(&self) -> &[u8] {
+        self.buffer.buffer()
     }
 }
 
@@ -892,51 +910,58 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     /// writer, it will also flush the existing buffer if it contains any
     /// newlines, even if the incoming data does not contain any newlines.
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        match memchr::memrchr(b'\n', buf) {
+        let newline_idx = match memchr::memrchr(b'\n', buf) {
             // If there are no new newlines (that is, if this write is less than
             // one line), just do a regular buffered write
             None => {
                 // Check for prior partial line writes that need to be retried.
                 // Only retry if the buffer contains a completed line, to
                 // avoid flushing partial lines.
-                if let Some(b'\n') = self.inner.buffer().last().copied() {
-                    self.inner.flush_buf()?;
+                if let Some(b'\n') = self.buffered().last().copied() {
+                    self.buffer.flush_buf()?;
                 }
-                self.inner.write(buf)
+                return self.buffer.write(buf);
             }
             // Otherwise, arrange for the lines to be written directly to the
             // inner writer.
-            Some(newline_idx) => {
-                // Flush existing content to prepare for our write
-                self.inner.flush_buf()?;
-
-                // This is what we're going to try to write directly to the inner
-                // writer. The rest will be buffered, if nothing goes wrong.
-                let lines = &buf[..newline_idx + 1];
-
-                // Write `lines` directly to the inner writer. In keeping with the
-                // `write` convention, make at most one attempt to add new (unbuffered)
-                // data. Because this write doesn't touch the BufWriter state directly,
-                // and the buffer is known to be empty, we don't need to worry about
-                // self.inner.panicked here.
-                let flushed = self.inner.get_mut().write(lines)?;
-
-                // Now that the write has succeeded, buffer the rest (or as much of
-                // the rest as possible). If there were any unwritten newlines, we
-                // only buffer out to the last unwritten newline; this helps prevent
-                // flushing partial lines on subsequent calls to LineWriterShim::write.
-                let tail = &buf[flushed..];
-                let buffered = match memchr::memrchr(b'\n', tail) {
-                    None => self.inner.write_to_buffer(tail),
-                    Some(i) => self.inner.write_to_buffer(&tail[..i + 1]),
-                };
-                Ok(flushed + buffered)
-            }
+            Some(newline_idx) => newline_idx,
+        };
+
+        // Flush existing content to prepare for our write
+        self.buffer.flush_buf()?;
+
+        // This is what we're going to try to write directly to the inner
+        // writer. The rest will be buffered, if nothing goes wrong.
+        let lines = &buf[..newline_idx + 1];
+
+        // Write `lines` directly to the inner writer. In keeping with the
+        // `write` convention, make at most one attempt to add new (unbuffered)
+        // data. Because this write doesn't touch the BufWriter state directly,
+        // and the buffer is known to be empty, we don't need to worry about
+        // self.buffer.panicked here.
+        let flushed = self.inner_mut().write(lines)?;
+
+        // If buffer returns Ok(0), propagate that to the caller without
+        // doing additional buffering; otherwise we're just guaranteeing
+        // an "ErrorKind::WriteZero" later.
+        if flushed == 0 {
+            return Ok(0);
         }
+
+        // Now that the write has succeeded, buffer the rest (or as much of
+        // the rest as possible). If there were any unwritten newlines, we
+        // only buffer out to the last unwritten newline; this helps prevent
+        // flushing partial lines on subsequent calls to LineWriterShim::write.
+        let tail = &buf[flushed..];
+        let buffered = match memchr::memrchr(b'\n', tail) {
+            None => self.buffer.write_to_buffer(tail),
+            Some(i) => self.buffer.write_to_buffer(&tail[..i + 1]),
+        };
+        Ok(flushed + buffered)
     }
 
     fn flush(&mut self) -> io::Result<()> {
-        self.inner.flush()
+        self.buffer.flush()
     }
 
     /// Write some vectored data into this BufReader with line buffering. This
@@ -967,6 +992,8 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     /// get the benefits of more granular partial-line handling without losing
     /// anything in efficiency
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        // If there's no specialized behavior for write_vectored, just use
+        // write. This has the benefit of more granular partial-line handling.
         if !self.is_write_vectored() {
             return match bufs.iter().find(|buf| !buf.is_empty()) {
                 Some(buf) => self.write(buf),
@@ -989,16 +1016,16 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
                 // Check for prior partial line writes that need to be retried.
                 // Only retry if the buffer contains a completed line, to
                 // avoid flushing partial lines.
-                if let Some(b'\n') = self.inner.buffer().last().copied() {
-                    self.inner.flush_buf()?;
+                if let Some(b'\n') = self.buffered().last().copied() {
+                    self.buffer.flush_buf()?;
                 }
-                return self.inner.write_vectored(bufs);
+                return self.buffer.write_vectored(bufs);
             }
             Some(i) => i,
         };
 
         // Flush existing content to prepare for our write
-        self.inner.flush_buf()?;
+        self.buffer.flush_buf()?;
 
         // This is what we're going to try to write directly to the inner
         // writer. The rest will be buffered, if nothing goes wrong.
@@ -1009,7 +1036,14 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         // data. Because this write doesn't touch the BufWriter state directly,
         // and the buffer is known to be empty, we don't need to worry about
         // self.panicked here.
-        let flushed = self.inner.write_vectored(lines)?;
+        let flushed = self.inner_mut().write_vectored(lines)?;
+
+        // If inner returns Ok(0), propagate that to the caller without
+        // doing additional buffering; otherwise we're just guaranteeing
+        // an "ErrorKind::WriteZero" later.
+        if flushed == 0 {
+            return Ok(0);
+        }
 
         // Don't try to reconstruct the exact amount written; just bail
         // in the event of a partial write
@@ -1021,13 +1055,15 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         // Now that the write has succeeded, buffer the rest (or as much of the
         // rest as possible)
         let buffered: usize =
-            tail.iter().map(|buf| self.inner.write_to_buffer(buf)).take_while(|&n| n > 0).sum();
+            tail.iter().map(|buf| self.buffer.write_to_buffer(buf)).take_while(|&n| n > 0).sum();
 
         Ok(flushed + buffered)
     }
 
     fn is_write_vectored(&self) -> bool {
-        self.inner.is_write_vectored()
+        // It's hard to imagine these diverging, but it's worth checking
+        // just in case, because we call `write_vectored` on both.
+        self.buffer.is_write_vectored() && self.inner().is_write_vectored()
     }
 
     /// Write some data into this BufReader with line buffering. This means
@@ -1039,37 +1075,37 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     /// writer, it will also flush the existing buffer if it contains any
     /// newlines, even if the incoming data does not contain any newlines.
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        match memchr::memrchr(b'\n', buf) {
+        let newline_idx = match memchr::memrchr(b'\n', buf) {
             // If there are no new newlines (that is, if this write is less than
             // one line), just do a regular buffered write
             None => {
                 // Check for prior partial line writes that need to be retried.
                 // Only retry if the buffer contains a completed line, to
                 // avoid flushing partial lines.
-                if let Some(b'\n') = self.inner.buffer().last().copied() {
-                    self.inner.flush_buf()?;
+                if let Some(b'\n') = self.buffered().last().copied() {
+                    self.buffer.flush_buf()?;
                 }
-                self.inner.write_all(buf)
+                return self.buffer.write_all(buf);
             }
             // Otherwise, arrange for the lines to be written directly to the
             // inner writer.
-            Some(newline_idx) => {
-                // Flush existing content to prepare for our write
-                self.inner.flush_buf()?;
+            Some(newline_idx) => newline_idx,
+        };
 
-                // This is what we're going to try to write directly to the inner
-                // writer. The rest will be buffered, if nothing goes wrong.
-                let (lines, tail) = buf.split_at(newline_idx + 1);
+        // Flush existing content to prepare for our write
+        self.buffer.flush_buf()?;
 
-                // Write `lines` directly to the inner writer, bypassing the buffer.
-                self.inner.get_mut().write_all(lines)?;
+        // This is what we're going to try to write directly to the inner
+        // writer. The rest will be buffered, if nothing goes wrong.
+        let (lines, tail) = buf.split_at(newline_idx + 1);
 
-                // Now that the write has succeeded, buffer the rest with BufWriter::write_all.
-                // This will buffer as much as possible, but continue flushing as
-                // necessary if our tail is huge.
-                self.inner.write_all(tail)
-            }
-        }
+        // Write `lines` directly to the inner writer, bypassing the buffer.
+        self.inner_mut().write_all(lines)?;
+
+        // Now that the write has succeeded, buffer the rest with
+        // BufWriter::write_all. This will buffer as much as possible, but
+        // continue flushing as necessary if our tail is huge.
+        self.buffer.write_all(tail)
     }
 }
 
@@ -1310,7 +1346,7 @@ where
 #[cfg(test)]
 mod tests {
     use crate::io::prelude::*;
-    use crate::io::{self, BufReader, BufWriter, IoSlice, LineWriter, SeekFrom};
+    use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom};
     use crate::sync::atomic::{AtomicUsize, Ordering};
     use crate::thread;
 
@@ -1598,34 +1634,6 @@ mod tests {
         assert_eq!(v, []);
     }
 
-    #[test]
-    fn test_line_buffer_fail_flush() {
-        // Issue #32085
-        struct FailFlushWriter<'a>(&'a mut Vec<u8>);
-
-        impl Write for FailFlushWriter<'_> {
-            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-                self.0.extend_from_slice(buf);
-                Ok(buf.len())
-            }
-            fn flush(&mut self) -> io::Result<()> {
-                Err(io::Error::new(io::ErrorKind::Other, "flush failed"))
-            }
-        }
-
-        let mut buf = Vec::new();
-        {
-            let mut writer = LineWriter::new(FailFlushWriter(&mut buf));
-            let to_write = b"abc\ndef";
-            if let Ok(written) = writer.write(to_write) {
-                assert!(written < to_write.len(), "didn't flush on new line");
-                // PASS
-                return;
-            }
-        }
-        assert!(buf.is_empty(), "write returned an error but wrote data");
-    }
-
     #[test]
     fn test_line_buffer() {
         let mut writer = LineWriter::new(Vec::new());
@@ -1746,44 +1754,62 @@ mod tests {
         b.iter(|| BufWriter::new(io::sink()));
     }
 
+    /// A simple `Write` target, designed to be wrapped by `LineWriter` /
+    /// `BufWriter` / etc, that can have its `write` & `flush` behavior
+    /// configured
     #[derive(Default, Clone)]
     struct ProgrammableSink {
         // Writes append to this slice
-        buffer: Vec<u8>,
+        pub buffer: Vec<u8>,
 
-        // Flushes set this flag
-        flushed: bool,
+        // Flush sets this flag
+        pub flushed: bool,
 
         // If true, writes & flushes will always be an error
-        return_error: bool,
+        pub always_error: bool,
 
         // If set, only up to this number of bytes will be written in a single
         // call to `write`
-        accept_prefix: Option<usize>,
+        pub accept_prefix: Option<usize>,
 
         // If set, counts down with each write, and writes return an error
         // when it hits 0
-        max_writes: Option<usize>,
+        pub max_writes: Option<usize>,
+
+        // If set, attempting to write when max_writes == Some(0) will be an
+        // error; otherwise, it will return Ok(0).
+        pub error_after_max_writes: bool,
     }
 
     impl Write for ProgrammableSink {
         fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-            if self.return_error {
-                Err(io::Error::new(io::ErrorKind::Other, "test"))
-            } else {
-                let len = match self.accept_prefix {
-                    None => data.len(),
-                    Some(prefix) => prefix.min(prefix),
-                };
-                let data = &data[..len];
-                self.buffer.extend_from_slice(data);
-                Ok(len)
+            if self.always_error {
+                return Err(io::Error::new(io::ErrorKind::Other, "test - write always_error"));
+            }
+
+            match self.max_writes {
+                Some(0) if self.error_after_max_writes => {
+                    return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes"))
+                }
+                Some(0) => return Ok(0),
+                Some(ref mut count) => *count -= 1,
+                None => {}
             }
+
+            let len = match self.accept_prefix {
+                None => data.len(),
+                Some(prefix) => data.len().min(prefix),
+            };
+
+            let data = &data[..len];
+            self.buffer.extend_from_slice(data);
+
+            Ok(len)
         }
 
         fn flush(&mut self) -> io::Result<()> {
-            if self.return_error {
-                Err(io::Error::new(io::ErrorKind::Other, "test"))
+            if self.always_error {
+                Err(io::Error::new(io::ErrorKind::Other, "test - flush always_error"))
             } else {
                 self.flushed = true;
                 Ok(())
@@ -1802,7 +1828,27 @@ mod tests {
     /// Regression test for #37807
     #[test]
     fn erroneous_flush_retried() {
-        todo!()
+        let writer = ProgrammableSink {
+            // Only write up to 4 bytes at a time
+            accept_prefix: Some(4),
+
+            // Accept the first two writes, then error the others
+            max_writes: Some(2),
+            error_after_max_writes: true,
+
+            ..Default::default()
+        };
+
+        // This should write the first 4 bytes. The rest will be buffered, out
+        // to the last newline.
+        let mut writer = LineWriter::new(writer);
+        assert_eq!(writer.write(b"a\nb\nc\nd\ne").unwrap(), 8);
+
+        // This write should attempt to flush "c\nd\n", then buffer "e". No
+        // errors should happen here because no further writes should be
+        // attempted against `writer`.
+        assert_eq!(writer.write(b"e").unwrap(), 1);
+        assert_eq!(&writer.get_ref().buffer, b"a\nb\nc\nd\n");
     }
 
     #[test]
@@ -1927,7 +1973,14 @@ mod tests {
     /// This behavior is desirable because it prevents flushing partial lines
     #[test]
     fn test_partial_write_buffers_line() {
-        todo!()
+        let writer = ProgrammableSink { accept_prefix: Some(13), ..Default::default() };
+        let mut writer = LineWriter::new(writer);
+
+        assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3\nLine4").unwrap(), 21);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2");
+
+        assert_eq!(writer.write(b"Line 4").unwrap(), 6);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
     }
 
     /// Test that, given this input:
@@ -1940,7 +1993,14 @@ mod tests {
     /// That data up to Line 3 is buffered
     #[test]
     fn test_partial_line_buffered_after_line_write() {
-        todo!()
+        let writer = ProgrammableSink::default();
+        let mut writer = LineWriter::new(writer);
+
+        assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3").unwrap(), 20);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\n");
+
+        assert!(writer.flush().is_ok());
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3");
     }
 
     /// Test that, given a partial line that exceeds the length of
@@ -1948,14 +2008,74 @@ mod tests {
     /// line is written to the inner writer
     #[test]
     fn test_long_line_flushed() {
-        todo!()
+        let writer = ProgrammableSink::default();
+        let mut writer = LineWriter::with_capacity(5, writer);
+
+        assert_eq!(writer.write(b"0123456789").unwrap(), 10);
+        assert_eq!(&writer.get_ref().buffer, b"0123456789");
     }
 
     /// Test that, given a very long partial line *after* successfully
     /// flushing a complete line, that that line is buffered unconditionally,
-    /// and no additional writes take place
+    /// and no additional writes take place. This assures the property that
+    /// `write` should make at-most-one attempt to write new data.
     #[test]
     fn test_long_tail_not_flushed() {
-        todo!()
+        let writer = ProgrammableSink::default();
+        let mut writer = LineWriter::with_capacity(5, writer);
+
+        // Assert that Line 1\n is flushed, and 01234 is buffered
+        assert_eq!(writer.write(b"Line 1\n0123456789").unwrap(), 12);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+
+        // Because the buffer is full, this subsequent write will flush it
+        assert_eq!(writer.write(b"5").unwrap(), 1);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\n01234");
+    }
+
+    /// Test that, if an attempt to pre-flush buffered data returns Ok(0),
+    /// this is propagated as an error.
+    #[test]
+    fn test_line_buffer_write0_error() {
+        let writer = ProgrammableSink {
+            // Accept one write, then return Ok(0) on subsequent ones
+            max_writes: Some(1),
+
+            ..Default::default()
+        };
+        let mut writer = LineWriter::new(writer);
+
+        // This should write "Line 1\n" and buffer "Partial"
+        assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+
+        // This will attempt to flush "partial", which will return Ok(0), which
+        // needs to be an error, because we've already informed the client
+        // that we accepted the write.
+        let err = writer.write(b" Line End\n").unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::WriteZero);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+    }
+
+    /// Test that, if a write returns Ok(0) after a successful pre-flush, this
+    /// is propogated as Ok(0)
+    #[test]
+    fn test_line_buffer_write0_normal() {
+        let writer = ProgrammableSink {
+            // Accept two writes, then return Ok(0) on subsequent ones
+            max_writes: Some(2),
+
+            ..Default::default()
+        };
+        let mut writer = LineWriter::new(writer);
+
+        // This should write "Line 1\n" and buffer "Partial"
+        assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+
+        // This will flush partial, which will succeed, but then return Ok(0)
+        // when flushing " Line End\n"
+        assert_eq!(writer.write(b" Line End\n").unwrap(), 0);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial");
     }
 }

From b6296e88f0176255e67672a70c9761729e20f33f Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 00:43:06 -0400
Subject: [PATCH 10/66] Tons of testing updates, other minor changes

- Cleaned up BufWriter::seek
- Updated line_vectored test
- Updated line_vectored_partial_and_errors test
- Added several new tests
---
 src/libstd/io/buffered.rs | 130 +++++++++++++++++++++++++++++++-------
 1 file changed, 106 insertions(+), 24 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 730ae8a0ee471..ced84b777ce77 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -751,7 +751,8 @@ impl<W: Write + Seek> Seek for BufWriter<W> {
     ///
     /// Seeking always writes out the internal buffer before seeking.
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
-        self.flush_buf().and_then(|_| self.get_mut().seek(pos))
+        self.flush_buf()?;
+        self.get_mut().seek(pos)
     }
 }
 
@@ -1862,12 +1863,13 @@ mod tests {
                 IoSlice::new(b"a"),
             ])
             .unwrap(),
-            2,
+            1,
         );
         assert_eq!(a.get_ref(), b"\n");
 
         assert_eq!(
             a.write_vectored(&[
+                IoSlice::new(b"a"),
                 IoSlice::new(&[]),
                 IoSlice::new(b"b"),
                 IoSlice::new(&[]),
@@ -1876,7 +1878,7 @@ mod tests {
                 IoSlice::new(b"c"),
             ])
             .unwrap(),
-            3,
+            4,
         );
         assert_eq!(a.get_ref(), b"\n");
         a.flush().unwrap();
@@ -1893,17 +1895,21 @@ mod tests {
             0,
         );
         assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3);
-        assert_eq!(a.get_ref(), b"\nabaca\n");
+        assert_eq!(a.get_ref(), b"\nabaca\nb");
     }
 
     #[test]
     fn line_vectored_partial_and_errors() {
+        use crate::collections::VecDeque;
+
         enum Call {
             Write { inputs: Vec<&'static [u8]>, output: io::Result<usize> },
             Flush { output: io::Result<()> },
         }
+
+        #[derive(Default)]
         struct Writer {
-            calls: Vec<Call>,
+            calls: VecDeque<Call>,
         }
 
         impl Write for Writer {
@@ -1912,19 +1918,23 @@ mod tests {
             }
 
             fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result<usize> {
-                match self.calls.pop().unwrap() {
+                match self.calls.pop_front().expect("unexpected call to write") {
                     Call::Write { inputs, output } => {
                         assert_eq!(inputs, buf.iter().map(|b| &**b).collect::<Vec<_>>());
                         output
                     }
-                    _ => panic!("unexpected call to write"),
+                    Call::Flush { .. } => panic!("unexpected call to write; expected a flush"),
                 }
             }
 
+            fn is_write_vectored(&self) -> bool {
+                true
+            }
+
             fn flush(&mut self) -> io::Result<()> {
-                match self.calls.pop().unwrap() {
+                match self.calls.pop_front().expect("Unexpected call to flush") {
                     Call::Flush { output } => output,
-                    _ => panic!("unexpected call to flush"),
+                    Call::Write { .. } => panic!("unexpected call to flush; expected a write"),
                 }
             }
         }
@@ -1938,20 +1948,22 @@ mod tests {
         }
 
         // partial writes keep going
-        let mut a = LineWriter::new(Writer { calls: Vec::new() });
+        let mut a = LineWriter::new(Writer::default());
         a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap();
-        a.get_mut().calls.push(Call::Flush { output: Ok(()) });
-        a.get_mut().calls.push(Call::Write { inputs: vec![b"bcx\n"], output: Ok(4) });
-        a.get_mut().calls.push(Call::Write { inputs: vec![b"abcx\n"], output: Ok(1) });
+
+        a.get_mut().calls.push_back(Call::Write { inputs: vec![b"abc"], output: Ok(1) });
+        a.get_mut().calls.push_back(Call::Write { inputs: vec![b"bc"], output: Ok(2) });
+        a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\n"], output: Ok(2) });
+
         a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap();
-        a.get_mut().calls.push(Call::Flush { output: Ok(()) });
+
+        a.get_mut().calls.push_back(Call::Flush { output: Ok(()) });
         a.flush().unwrap();
 
         // erroneous writes stop and don't write more
-        a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Err(err()) });
-        assert_eq!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).unwrap(), 2);
-        a.get_mut().calls.push(Call::Flush { output: Ok(()) });
-        a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Ok(2) });
+        a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\na"], output: Err(err()) });
+        a.get_mut().calls.push_back(Call::Flush { output: Ok(()) });
+        assert!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).is_err());
         a.flush().unwrap();
 
         fn err() -> io::Error {
@@ -1959,6 +1971,41 @@ mod tests {
         }
     }
 
+    /// Test that, in cases where vectored writing is not enabled, the
+    /// LineWriter uses the normal `write` call, which more-corectly handles
+    /// partial lines
+    #[test]
+    fn line_vectored_ignored() {
+        let writer = ProgrammableSink::default();
+        let mut writer = LineWriter::new(writer);
+
+        let content = [
+            IoSlice::new(b"Line 1\nLine"),
+            IoSlice::new(b" 2\nLine 3\nL"),
+            IoSlice::new(b"ine 4"),
+            IoSlice::new(b"\nLine 5\n"),
+        ];
+
+        let count = writer.write_vectored(&content).unwrap();
+        assert_eq!(count, 11);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
+
+        let count = writer.write_vectored(&content[1..]).unwrap();
+        assert_eq!(count, 11);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
+
+        let count = writer.write_vectored(&content[2..]).unwrap();
+        assert_eq!(count, 5);
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
+
+        let count = writer.write_vectored(&content[3..]).unwrap();
+        assert_eq!(count, 8);
+        assert_eq!(
+            writer.get_ref().buffer.as_slice(),
+            b"Line 1\nLine 2\nLine 3\nLine 4\n Line 5".as_ref()
+        );
+    }
+
     /// Test that, given this input:
     ///
     /// Line 1\n
@@ -1972,7 +2019,7 @@ mod tests {
     ///
     /// This behavior is desirable because it prevents flushing partial lines
     #[test]
-    fn test_partial_write_buffers_line() {
+    fn partial_write_buffers_line() {
         let writer = ProgrammableSink { accept_prefix: Some(13), ..Default::default() };
         let mut writer = LineWriter::new(writer);
 
@@ -1992,7 +2039,7 @@ mod tests {
     /// And given that the full write of lines 1 and 2 was successful
     /// That data up to Line 3 is buffered
     #[test]
-    fn test_partial_line_buffered_after_line_write() {
+    fn partial_line_buffered_after_line_write() {
         let writer = ProgrammableSink::default();
         let mut writer = LineWriter::new(writer);
 
@@ -2007,7 +2054,7 @@ mod tests {
     /// LineBuffer's buffer (that is, without a trailing newline), that that
     /// line is written to the inner writer
     #[test]
-    fn test_long_line_flushed() {
+    fn long_line_flushed() {
         let writer = ProgrammableSink::default();
         let mut writer = LineWriter::with_capacity(5, writer);
 
@@ -2020,7 +2067,7 @@ mod tests {
     /// and no additional writes take place. This assures the property that
     /// `write` should make at-most-one attempt to write new data.
     #[test]
-    fn test_long_tail_not_flushed() {
+    fn line_long_tail_not_flushed() {
         let writer = ProgrammableSink::default();
         let mut writer = LineWriter::with_capacity(5, writer);
 
@@ -2036,7 +2083,7 @@ mod tests {
     /// Test that, if an attempt to pre-flush buffered data returns Ok(0),
     /// this is propagated as an error.
     #[test]
-    fn test_line_buffer_write0_error() {
+    fn line_buffer_write0_error() {
         let writer = ProgrammableSink {
             // Accept one write, then return Ok(0) on subsequent ones
             max_writes: Some(1),
@@ -2060,7 +2107,7 @@ mod tests {
     /// Test that, if a write returns Ok(0) after a successful pre-flush, this
     /// is propogated as Ok(0)
     #[test]
-    fn test_line_buffer_write0_normal() {
+    fn line_buffer_write0_normal() {
         let writer = ProgrammableSink {
             // Accept two writes, then return Ok(0) on subsequent ones
             max_writes: Some(2),
@@ -2078,4 +2125,39 @@ mod tests {
         assert_eq!(writer.write(b" Line End\n").unwrap(), 0);
         assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial");
     }
+
+    /// LineWriter has a custom `write_all`; make sure it works correctly
+    #[test]
+    fn line_write_all() {
+        let writer = ProgrammableSink {
+            // Only write 5 bytes at a time
+            accept_prefix: Some(5),
+            ..Default::default()
+        };
+        let mut writer = LineWriter::new(writer);
+
+        writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial").unwrap();
+        assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\nLine 4\n");
+        writer.write_all(b" Line 5\n").unwrap();
+        assert_eq!(
+            writer.get_ref().buffer.as_slice(),
+            b"Line 1\nLine 2\nLine 3\nLine 4\nPartial Line 5\n".as_ref(),
+        );
+    }
+
+    #[test]
+    fn line_write_all_error() {
+        let writer = ProgrammableSink {
+            // Only accept up to 3 writes of up to 5 bytes each
+            accept_prefix: Some(5),
+            max_writes: Some(3),
+            ..Default::default()
+        };
+
+        let mut writer = LineWriter::new(writer);
+        let res = writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial");
+        assert!(res.is_err());
+        // An error from write_all leaves everything in an indeterminate state,
+        // so there's nothing else to test here
+    }
 }

From e022d3452de74b5596810f0aa26193e262de725b Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 00:44:16 -0400
Subject: [PATCH 11/66] Fixed typo in test

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

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index ced84b777ce77..abfc2fc37c4f9 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -2002,7 +2002,7 @@ mod tests {
         assert_eq!(count, 8);
         assert_eq!(
             writer.get_ref().buffer.as_slice(),
-            b"Line 1\nLine 2\nLine 3\nLine 4\n Line 5".as_ref()
+            b"Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n".as_ref()
         );
     }
 

From e4328ae54573aa42051246b675bf5280ea58eddf Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 01:01:30 -0400
Subject: [PATCH 12/66] Code review updates: all minor style fixes

- Renamed write_to_buffer to write_to_buf, for consistency
- Fixed references to flush_buf
- Optimized `write` to use one less `memchr` call
---
 src/libstd/io/buffered.rs | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index abfc2fc37c4f9..7b7c8c6e3177a 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -565,7 +565,7 @@ impl<W: Write> BufWriter<W> {
     /// data. Writes as much as possible without exceeding capacity. Returns
     /// the number of bytes written.
     #[inline]
-    fn write_to_buffer(&mut self, buf: &[u8]) -> usize {
+    fn write_to_buf(&mut self, buf: &[u8]) -> usize {
         let available = self.buf.capacity() - self.buf.len();
         let amt_to_buffer = available.min(buf.len());
         self.buf.extend_from_slice(&buf[..amt_to_buffer]);
@@ -689,7 +689,7 @@ impl<W: Write> Write for BufWriter<W> {
             self.panicked = false;
             r
         } else {
-            Ok(self.write_to_buffer(buf))
+            Ok(self.write_to_buf(buf))
         }
     }
 
@@ -703,7 +703,7 @@ impl<W: Write> Write for BufWriter<W> {
             self.panicked = false;
             r
         } else {
-            self.write_to_buffer(buf);
+            self.write_to_buf(buf);
             Ok(())
         }
     }
@@ -861,7 +861,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
 /// Private helper struct for implementing the line-buffered writing logic.
 /// This shim temporarily wraps a BufWriter, and uses its internals to
 /// implement a line-buffered writer (specifically by using the internal
-/// methods like write_to_buffer and flush_buffer). In this way, a more
+/// methods like write_to_buf and flush_buf). In this way, a more
 /// efficient abstraction can be created than one that only had access to
 /// `write` and `flush`, without needlessly duplicating a lot of the
 /// implementation details of BufWriter. This also allows existing
@@ -925,7 +925,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
             }
             // Otherwise, arrange for the lines to be written directly to the
             // inner writer.
-            Some(newline_idx) => newline_idx,
+            Some(newline_idx) => newline_idx + 1,
         };
 
         // Flush existing content to prepare for our write
@@ -933,7 +933,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
 
         // This is what we're going to try to write directly to the inner
         // writer. The rest will be buffered, if nothing goes wrong.
-        let lines = &buf[..newline_idx + 1];
+        let lines = &buf[..newline_idx];
 
         // Write `lines` directly to the inner writer. In keeping with the
         // `write` convention, make at most one attempt to add new (unbuffered)
@@ -953,11 +953,10 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         // the rest as possible). If there were any unwritten newlines, we
         // only buffer out to the last unwritten newline; this helps prevent
         // flushing partial lines on subsequent calls to LineWriterShim::write.
-        let tail = &buf[flushed..];
-        let buffered = match memchr::memrchr(b'\n', tail) {
-            None => self.buffer.write_to_buffer(tail),
-            Some(i) => self.buffer.write_to_buffer(&tail[..i + 1]),
-        };
+        let tail =
+            if flushed < newline_idx { &buf[flushed..newline_idx] } else { &buf[newline_idx..] };
+
+        let buffered = self.buffer.write_to_buf(tail);
         Ok(flushed + buffered)
     }
 
@@ -1056,7 +1055,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         // Now that the write has succeeded, buffer the rest (or as much of the
         // rest as possible)
         let buffered: usize =
-            tail.iter().map(|buf| self.buffer.write_to_buffer(buf)).take_while(|&n| n > 0).sum();
+            tail.iter().map(|buf| self.buffer.write_to_buf(buf)).take_while(|&n| n > 0).sum();
 
         Ok(flushed + buffered)
     }
@@ -1076,6 +1075,9 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     /// writer, it will also flush the existing buffer if it contains any
     /// newlines, even if the incoming data does not contain any newlines.
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        // The default `write_all` calls `write` in a loop; we can do better
+        // by simply calling self.inner().write_all directly. This avoids
+        // round trips to `self.buffer` in the event of partial writes.
         let newline_idx = match memchr::memrchr(b'\n', buf) {
             // If there are no new newlines (that is, if this write is less than
             // one line), just do a regular buffered write

From f7650fe3f955863e810ef7816edbe78f88393d87 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 01:07:34 -0400
Subject: [PATCH 13/66] Add comment

---
 src/libstd/io/buffered.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 7b7c8c6e3177a..b9839c318b75a 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -1358,6 +1358,9 @@ mod tests {
         lengths: Vec<usize>,
     }
 
+    // FIXME: rustfmt and tidy disagree about the correct formatting of this
+    // function. This leads to issues for users with editors configured to
+    // rustfmt-on-save.
     impl Read for ShortReader {
         fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
             if self.lengths.is_empty() {

From 7a6a12bdf42804e2e2ef6437bed6a45a1ede51b2 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 01:09:55 -0400
Subject: [PATCH 14/66] Tidy fixes

---
 src/libstd/io/buffered.rs | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index b9839c318b75a..560c8f2369846 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -1363,11 +1363,7 @@ mod tests {
     // rustfmt-on-save.
     impl Read for ShortReader {
         fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
-            if self.lengths.is_empty() {
-                Ok(0)
-            } else {
-                Ok(self.lengths.remove(0))
-            }
+            if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) }
         }
     }
 
@@ -1795,7 +1791,7 @@ mod tests {
 
             match self.max_writes {
                 Some(0) if self.error_after_max_writes => {
-                    return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes"))
+                    return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes"));
                 }
                 Some(0) => return Ok(0),
                 Some(ref mut count) => *count -= 1,

From 338a2c02e4b9cc5b1fae698ab019724340b26967 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 01:28:31 -0400
Subject: [PATCH 15/66] Reimplement flush_buf with a Guard. Longer, but
 cleaner.

---
 src/libstd/io/buffered.rs | 67 +++++++++++++++++++++++++++++----------
 1 file changed, 50 insertions(+), 17 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 560c8f2369846..b7e848b04d721 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -448,6 +448,9 @@ impl<R: Seek> Seek for BufReader<R> {
 /// [`flush`]: #method.flush
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
+    // FIXME: Can this just be W, instead of Option<W>? I don't see any code
+    // paths that lead to this being None, or that ever check if it IS none,
+    // even in drop implementations.
     inner: Option<W>,
     // FIXME: Replace this with a VecDeque. Because VecDeque is a Ring buffer,
     // this would enable BufWriter to operate without any interior copies.
@@ -533,32 +536,62 @@ impl<W: Write> BufWriter<W> {
     /// `write`), any 0-length writes from `inner` must be reported as i/o
     /// errors from this method.
     fn flush_buf(&mut self) -> io::Result<()> {
-        let mut written = 0;
-        let len = self.buf.len();
-        let mut ret = Ok(());
-        while written < len {
+        /// Helper struct to ensure the buffer is updated after all the writes
+        /// are complete
+        struct BufGuard<'a> {
+            buffer: &'a mut Vec<u8>,
+            written: usize,
+        }
+
+        impl<'a> BufGuard<'a> {
+            fn new(buffer: &'a mut Vec<u8>) -> Self {
+                Self { buffer, written: 0 }
+            }
+
+            /// The unwritten part of the buffer
+            fn remaining(&self) -> &[u8] {
+                &self.buffer[self.written..]
+            }
+
+            /// Flag some bytes as removed from the front of the buffer
+            fn consume(&mut self, amt: usize) {
+                self.written += amt;
+            }
+
+            /// true if all of the bytes have been written
+            fn done(&self) -> bool {
+                self.written >= self.buffer.len()
+            }
+        }
+
+        impl Drop for BufGuard<'_> {
+            fn drop(&mut self) {
+                if self.written > 0 {
+                    self.buffer.drain(..self.written);
+                }
+            }
+        }
+
+        let mut guard = BufGuard::new(&mut self.buf);
+        let inner = self.inner.as_mut().unwrap();
+        while !guard.done() {
             self.panicked = true;
-            let r = self.inner.as_mut().unwrap().write(&self.buf[written..]);
+            let r = inner.write(guard.remaining());
             self.panicked = false;
 
             match r {
                 Ok(0) => {
-                    ret =
-                        Err(Error::new(ErrorKind::WriteZero, "failed to write the buffered data"));
-                    break;
+                    return Err(Error::new(
+                        ErrorKind::WriteZero,
+                        "failed to write the buffered data",
+                    ))
                 }
-                Ok(n) => written += n,
+                Ok(n) => guard.consume(n),
                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => {
-                    ret = Err(e);
-                    break;
-                }
+                Err(e) => return Err(e),
             }
         }
-        if written > 0 {
-            self.buf.drain(..written);
-        }
-        ret
+        Ok(())
     }
 
     /// Buffer some data without flushing it, regardless of the size of the

From c869638cba8e9ab8392016b11675706c4e514b6e Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 01:30:40 -0400
Subject: [PATCH 16/66] Added comment about BufWrite::write_all

---
 src/libstd/io/buffered.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index b7e848b04d721..f9bde7897e997 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -727,6 +727,10 @@ impl<W: Write> Write for BufWriter<W> {
     }
 
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        // Normally, `write_all` just calls `write` in a loop. We can do better
+        // by calling `self.get_mut().write_all()` directly, which avoids
+        // round trips through the buffer in the event of a series of partial
+        // writes.
         if self.buf.len() + buf.len() > self.buf.capacity() {
             self.flush_buf()?;
         }

From 61f591e1738845911048ff43d956bb9d39987910 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 01:36:40 -0400
Subject: [PATCH 17/66] Improved line_vectored_ignored. Added stylistic
 semicolon.

---
 src/libstd/io/buffered.rs | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index f9bde7897e997..02615bffe3bd1 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -584,7 +584,7 @@ impl<W: Write> BufWriter<W> {
                     return Err(Error::new(
                         ErrorKind::WriteZero,
                         "failed to write the buffered data",
-                    ))
+                    ));
                 }
                 Ok(n) => guard.consume(n),
                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
@@ -2018,8 +2018,11 @@ mod tests {
         let mut writer = LineWriter::new(writer);
 
         let content = [
+            IoSlice::new(&[]),
             IoSlice::new(b"Line 1\nLine"),
             IoSlice::new(b" 2\nLine 3\nL"),
+            IoSlice::new(&[]),
+            IoSlice::new(&[]),
             IoSlice::new(b"ine 4"),
             IoSlice::new(b"\nLine 5\n"),
         ];
@@ -2028,15 +2031,15 @@ mod tests {
         assert_eq!(count, 11);
         assert_eq!(&writer.get_ref().buffer, b"Line 1\n");
 
-        let count = writer.write_vectored(&content[1..]).unwrap();
+        let count = writer.write_vectored(&content[2..]).unwrap();
         assert_eq!(count, 11);
         assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
 
-        let count = writer.write_vectored(&content[2..]).unwrap();
+        let count = writer.write_vectored(&content[5..]).unwrap();
         assert_eq!(count, 5);
         assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n");
 
-        let count = writer.write_vectored(&content[3..]).unwrap();
+        let count = writer.write_vectored(&content[6..]).unwrap();
         assert_eq!(count, 8);
         assert_eq!(
             writer.get_ref().buffer.as_slice(),

From 2d22c7741816aa391f619f31b14b1ca01cc31b61 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 01:43:10 -0400
Subject: [PATCH 18/66] Fixed bug in write_vectored & empty buffers

---
 src/libstd/io/buffered.rs | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 02615bffe3bd1..5189b39aaae68 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -1091,8 +1091,12 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
 
         // Now that the write has succeeded, buffer the rest (or as much of the
         // rest as possible)
-        let buffered: usize =
-            tail.iter().map(|buf| self.buffer.write_to_buf(buf)).take_while(|&n| n > 0).sum();
+        let buffered: usize = tail
+            .iter()
+            .filter(|buf| !buf.is_empty())
+            .map(|buf| self.buffer.write_to_buf(buf))
+            .take_while(|&n| n > 0)
+            .sum();
 
         Ok(flushed + buffered)
     }

From 2c23b9066f761e07f1c4db6ca8d8f0bf48e4e296 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 11:56:02 -0400
Subject: [PATCH 19/66] Comment updates

---
 src/libstd/io/buffered.rs | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 5189b39aaae68..51098f6ff6af5 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -730,7 +730,7 @@ impl<W: Write> Write for BufWriter<W> {
         // Normally, `write_all` just calls `write` in a loop. We can do better
         // by calling `self.get_mut().write_all()` directly, which avoids
         // round trips through the buffer in the event of a series of partial
-        // writes.
+        // writes in some circumstances.
         if self.buf.len() + buf.len() > self.buf.capacity() {
             self.flush_buf()?;
         }
@@ -1116,9 +1116,6 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     /// writer, it will also flush the existing buffer if it contains any
     /// newlines, even if the incoming data does not contain any newlines.
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        // The default `write_all` calls `write` in a loop; we can do better
-        // by simply calling self.inner().write_all directly. This avoids
-        // round trips to `self.buffer` in the event of partial writes.
         let newline_idx = match memchr::memrchr(b'\n', buf) {
             // If there are no new newlines (that is, if this write is less than
             // one line), just do a regular buffered write

From e999ca5ac3a21183fdc8cc99350752d0f1ef0bdd Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 12:00:12 -0400
Subject: [PATCH 20/66] Remove inline from write_to_buf

---
 src/libstd/io/buffered.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 51098f6ff6af5..a66fa6ea36a28 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -597,7 +597,6 @@ impl<W: Write> BufWriter<W> {
     /// Buffer some data without flushing it, regardless of the size of the
     /// data. Writes as much as possible without exceeding capacity. Returns
     /// the number of bytes written.
-    #[inline]
     fn write_to_buf(&mut self, buf: &[u8]) -> usize {
         let available = self.buf.capacity() - self.buf.len();
         let amt_to_buffer = available.min(buf.len());

From 70ba320052669c06e2285d16b4a36af83f9c83da Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 12:40:05 -0400
Subject: [PATCH 21/66] More minor changes

- Fixed test after write_vectored bugfix
- Some comments
---
 src/libstd/io/buffered.rs | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index a66fa6ea36a28..c599bd8b55127 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -715,6 +715,7 @@ impl<W: Write> Write for BufWriter<W> {
         if self.buf.len() + buf.len() > self.buf.capacity() {
             self.flush_buf()?;
         }
+        // FIXME: Why no len > capacity? Why not buffer len == capacity?
         if buf.len() >= self.buf.capacity() {
             self.panicked = true;
             let r = self.get_mut().write(buf);
@@ -733,6 +734,7 @@ impl<W: Write> Write for BufWriter<W> {
         if self.buf.len() + buf.len() > self.buf.capacity() {
             self.flush_buf()?;
         }
+        // FIXME: Why no len > capacity? Why not buffer len == capacity?
         if buf.len() >= self.buf.capacity() {
             self.panicked = true;
             let r = self.get_mut().write_all(buf);
@@ -749,6 +751,7 @@ impl<W: Write> Write for BufWriter<W> {
         if self.buf.len() + total_len > self.buf.capacity() {
             self.flush_buf()?;
         }
+        // FIXME: Why no len > capacity? Why not buffer len == capacity?
         if total_len >= self.buf.capacity() {
             self.panicked = true;
             let r = self.get_mut().write_vectored(bufs);
@@ -1901,13 +1904,12 @@ mod tests {
                 IoSlice::new(b"a"),
             ])
             .unwrap(),
-            1,
+            2,
         );
         assert_eq!(a.get_ref(), b"\n");
 
         assert_eq!(
             a.write_vectored(&[
-                IoSlice::new(b"a"),
                 IoSlice::new(&[]),
                 IoSlice::new(b"b"),
                 IoSlice::new(&[]),
@@ -1916,7 +1918,7 @@ mod tests {
                 IoSlice::new(b"c"),
             ])
             .unwrap(),
-            4,
+            3,
         );
         assert_eq!(a.get_ref(), b"\n");
         a.flush().unwrap();

From 5b1a40c18168a8049eb9f3af3178ec1846e64730 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 12:58:49 -0400
Subject: [PATCH 22/66] BufWriter::write* methods now use fewer runtime checks

---
 src/libstd/io/buffered.rs | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index c599bd8b55127..1998cdde8d08e 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -722,7 +722,8 @@ impl<W: Write> Write for BufWriter<W> {
             self.panicked = false;
             r
         } else {
-            Ok(self.write_to_buf(buf))
+            self.buf.extend_from_slice(buf);
+            Ok(buf.len())
         }
     }
 
@@ -741,7 +742,7 @@ impl<W: Write> Write for BufWriter<W> {
             self.panicked = false;
             r
         } else {
-            self.write_to_buf(buf);
+            self.buf.extend_from_slice(buf);
             Ok(())
         }
     }
@@ -758,7 +759,8 @@ impl<W: Write> Write for BufWriter<W> {
             self.panicked = false;
             r
         } else {
-            self.buf.write_vectored(bufs)
+            bufs.iter().for_each(|b| self.buf.extend_from_slice(b));
+            Ok(total_len)
         }
     }
 
@@ -1403,7 +1405,11 @@ mod tests {
     // rustfmt-on-save.
     impl Read for ShortReader {
         fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
-            if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) }
+            if self.lengths.is_empty() {
+                Ok(0)
+            } else {
+                Ok(self.lengths.remove(0))
+            }
         }
     }
 

From 8df5ae0fffc9de2884e0c916bdcd74cb69949b1c Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 14:36:03 -0400
Subject: [PATCH 23/66] x.py fix AGAIN

---
 src/libstd/io/buffered.rs | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 1998cdde8d08e..61ad5d0c274ff 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -1405,11 +1405,7 @@ mod tests {
     // rustfmt-on-save.
     impl Read for ShortReader {
         fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
-            if self.lengths.is_empty() {
-                Ok(0)
-            } else {
-                Ok(self.lengths.remove(0))
-            }
+            if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) }
         }
     }
 

From 60ab99f9bdcb33ea025aca6a94e34f2ae5b5b75e Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 15:57:20 -0400
Subject: [PATCH 24/66] Fixed corner case related to partial-line buffering

- Fixed partial-line buffering issue
- Added tests

Thanks @the8472 for catching!
---
 src/libstd/io/buffered.rs | 93 +++++++++++++++++++++++++++++++++++----
 1 file changed, 85 insertions(+), 8 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 61ad5d0c274ff..d094f19b5a5ff 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -994,8 +994,26 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         // the rest as possible). If there were any unwritten newlines, we
         // only buffer out to the last unwritten newline; this helps prevent
         // flushing partial lines on subsequent calls to LineWriterShim::write.
-        let tail =
-            if flushed < newline_idx { &buf[flushed..newline_idx] } else { &buf[newline_idx..] };
+
+        // Handle the cases in order of most-common to least-common, under
+        // the presumption that most writes succeed in totality, and that most
+        // writes are smaller than the buffer.
+        // - Is this a partial line (ie, no newlines left in the unwritten tail)
+        // - If not, does the data out to the last unwritten newline fit in
+        //   the buffer?
+        // - If not, scan for the last newline that *does* fit in the buffer
+        let tail = if flushed >= newline_idx {
+            &buf[flushed..]
+        } else if newline_idx - flushed <= self.buffer.capacity() {
+            &buf[flushed..newline_idx]
+        } else {
+            let scan_area = &buf[flushed..];
+            let scan_area = &scan_area[..self.buffer.capacity()];
+            match memchr::memrchr(b'\n', scan_area) {
+                Some(newline_idx) => &scan_area[..newline_idx + 1],
+                None => scan_area,
+            }
+        };
 
         let buffered = self.buffer.write_to_buf(tail);
         Ok(flushed + buffered)
@@ -1809,8 +1827,11 @@ mod tests {
         // Flush sets this flag
         pub flushed: bool,
 
-        // If true, writes & flushes will always be an error
-        pub always_error: bool,
+        // If true, writes will always be an error
+        pub always_write_error: bool,
+
+        // If true, flushes will always be an error
+        pub always_flush_error: bool,
 
         // If set, only up to this number of bytes will be written in a single
         // call to `write`
@@ -1827,8 +1848,8 @@ mod tests {
 
     impl Write for ProgrammableSink {
         fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-            if self.always_error {
-                return Err(io::Error::new(io::ErrorKind::Other, "test - write always_error"));
+            if self.always_write_error {
+                return Err(io::Error::new(io::ErrorKind::Other, "test - always_write_error"));
             }
 
             match self.max_writes {
@@ -1852,8 +1873,8 @@ mod tests {
         }
 
         fn flush(&mut self) -> io::Result<()> {
-            if self.always_error {
-                Err(io::Error::new(io::ErrorKind::Other, "test - flush always_error"))
+            if self.always_flush_error {
+                Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error"))
             } else {
                 self.flushed = true;
                 Ok(())
@@ -2205,4 +2226,60 @@ mod tests {
         // An error from write_all leaves everything in an indeterminate state,
         // so there's nothing else to test here
     }
+
+    /// Under certain circumstances, the old implementation of LineWriter
+    /// would try to buffer "to the last newline" but be forced to buffer
+    /// less than that, leading to inappropriate partial line writes.
+    /// Regression test for that issue.
+    #[test]
+    fn partial_multiline_buffering() {
+        let writer = ProgrammableSink {
+            // Write only up to 5 bytes at a time
+            accept_prefix: Some(5),
+            ..Default::default()
+        };
+
+        let mut writer = LineWriter::with_capacity(10, writer);
+
+        let content = b"AAAAABBBBB\nCCCCDDDDDD\nEEE";
+
+        // When content is written, LineWriter will try to write blocks A, B,
+        // C, and D. Only block A will succeed. Under the old behavior, LineWriter
+        // would then try to buffer B, C and D, but because its capacity is 10,
+        // it will only be able to buffer B and C. We don't want it to buffer
+        // partial lines if it can avoid it, so the correct behavior is to
+        // only buffer block B (with its newline).
+        assert_eq!(writer.write(content).unwrap(), 11);
+        assert_eq!(writer.get_ref().buffer, *b"AAAAA");
+
+        writer.flush().unwrap();
+        assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB\n");
+    }
+
+    /// Same as test_partial_multiline_buffering, but in the event NO full lines
+    /// fit in the buffer, just buffer as much as possible
+    #[test]
+    fn partial_multiline_buffering_without_full_line() {
+        let writer = ProgrammableSink {
+            // Write only up to 5 bytes at a time
+            accept_prefix: Some(5),
+            ..Default::default()
+        };
+
+        let mut writer = LineWriter::with_capacity(5, writer);
+
+        let content = b"AAAAABBBBBBBBBB\nCCCCC\nDDDDD";
+
+        // When content is written, LineWriter will try to write blocks A, B,
+        // and C. Only block A will succeed. Under the old behavior, LineWriter
+        // would then try to buffer B and C, but because its capacity is 5,
+        // it will only be able to buffer part of B. Because it's not possible
+        // for it to buffer any complete lines, it should buffer as much of B as
+        // possible
+        assert_eq!(writer.write(content).unwrap(), 10);
+        assert_eq!(writer.get_ref().buffer, *b"AAAAA");
+
+        writer.flush().unwrap();
+        assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB");
+    }
 }

From 38017a31e7728c359487817008c913a8e461a857 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 16:17:42 -0400
Subject: [PATCH 25/66] Update comments with relevant issue numbers

---
 src/libstd/io/buffered.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index d094f19b5a5ff..1048c9d078d86 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -450,7 +450,7 @@ impl<R: Seek> Seek for BufReader<R> {
 pub struct BufWriter<W: Write> {
     // FIXME: Can this just be W, instead of Option<W>? I don't see any code
     // paths that lead to this being None, or that ever check if it IS none,
-    // even in drop implementations.
+    // even in drop implementations. #72925.
     inner: Option<W>,
     // FIXME: Replace this with a VecDeque. Because VecDeque is a Ring buffer,
     // this would enable BufWriter to operate without any interior copies.
@@ -715,7 +715,7 @@ impl<W: Write> Write for BufWriter<W> {
         if self.buf.len() + buf.len() > self.buf.capacity() {
             self.flush_buf()?;
         }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity?
+        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
         if buf.len() >= self.buf.capacity() {
             self.panicked = true;
             let r = self.get_mut().write(buf);
@@ -735,7 +735,7 @@ impl<W: Write> Write for BufWriter<W> {
         if self.buf.len() + buf.len() > self.buf.capacity() {
             self.flush_buf()?;
         }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity?
+        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
         if buf.len() >= self.buf.capacity() {
             self.panicked = true;
             let r = self.get_mut().write_all(buf);
@@ -752,7 +752,7 @@ impl<W: Write> Write for BufWriter<W> {
         if self.buf.len() + total_len > self.buf.capacity() {
             self.flush_buf()?;
         }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity?
+        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
         if total_len >= self.buf.capacity() {
             self.panicked = true;
             let r = self.get_mut().write_vectored(bufs);

From 59710fb716d2810c6eada13275039274b6279065 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Tue, 2 Jun 2020 18:16:02 -0400
Subject: [PATCH 26/66] Clarified comment in `partial_multiline_buffering` test

---
 src/libstd/io/buffered.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 1048c9d078d86..c8c9ee4a4b47c 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -2246,9 +2246,9 @@ mod tests {
         // When content is written, LineWriter will try to write blocks A, B,
         // C, and D. Only block A will succeed. Under the old behavior, LineWriter
         // would then try to buffer B, C and D, but because its capacity is 10,
-        // it will only be able to buffer B and C. We don't want it to buffer
-        // partial lines if it can avoid it, so the correct behavior is to
-        // only buffer block B (with its newline).
+        // it will only be able to buffer B and C. We don't want to buffer
+        // partial lines concurrent with whole lines, so the correct behavior
+        // is to buffer only block B (out to the newline)
         assert_eq!(writer.write(content).unwrap(), 11);
         assert_eq!(writer.get_ref().buffer, *b"AAAAA");
 

From 2e21af2859854668448ac96f335986a19011e571 Mon Sep 17 00:00:00 2001
From: Alexis Bourget <alexis.bourget@gmail.com>
Date: Mon, 29 Jun 2020 19:18:40 +0200
Subject: [PATCH 27/66] Document the union keyword

---
 src/libstd/keyword_docs.rs | 67 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 65 insertions(+), 2 deletions(-)

diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index d972cf6db18cf..cbfaac8c4b317 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -1624,8 +1624,71 @@ mod dyn_keyword {}
 //
 /// The [Rust equivalent of a C-style union][union].
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// A `union` looks like a [`struct`] in terms of declaration, but all of its
+/// fields exist simultaneously, superimposed over one another. For instance,
+/// if we wanted some bits in memory that we sometimes interpret as a `u32` and
+/// sometimes as an `f32`, we would write:
+///
+/// ```rust
+/// union IntOrFloat {
+///     i: u32,
+///     f: f32,
+/// }
+///
+/// let mut u = IntOrFloat { f: 1.0 };
+/// // Reading the fields of an union is always unsafe
+/// assert_eq!(unsafe { u.i }, 1065353216);
+/// // Updating through any of the field will modify all of them
+/// u.i = 1073741824;
+/// assert_eq!(unsafe { u.f }, 2.0);
+/// ```
+///
+/// # Matching on unions
+///
+/// It is possible to use pattern matching on `union`s. A single field name must
+/// be used and it must match the name of one of the `union`'s field.
+///
+/// ```rust
+/// union IntOrFloat {
+///     i: u32,
+///     f: f32,
+/// }
+///
+/// let u = IntOrFloat { f: 1.0 };
+///
+/// unsafe {
+///     match u {
+///         IntOrFloat { i: 10 } => println!("Found exactly ten !"),
+///         // The field name is used to deduce the type
+///         IntOrFloat { f } => println!("Found f = {} !", f),
+///     }
+/// }
+/// ```
+///
+/// # References to union fields
+///
+/// All fields in a union are all at the same place in memory which means
+/// borrowing one borrows all of them, for the same duration:
+///
+/// ```rust,compile_fail,E0502
+/// union IntOrFloat {
+///     i: u32,
+///     f: f32,
+/// }
 ///
+/// let mut u = IntOrFloat { f: 1.0 };
+///
+/// let f = unsafe { &u.f };
+/// // This will not compile because the field has already been borrowed, even
+/// // if only immutably
+/// let i = unsafe { &mut u.i };
+///
+/// *i = 10;
+/// println!("f = {} and i = {}", f, i);
+/// ```
+///
+/// See the [Reference][union] for more informations on `union`s.
+///
+/// [`struct`]: keyword.struct.html
 /// [union]: ../reference/items/unions.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
 mod union_keyword {}

From 614f7738ba65ac37f2dc61afa8c68fc3768fdffc Mon Sep 17 00:00:00 2001
From: Poliorcetics <poliorcetics@users.noreply.github.com>
Date: Tue, 30 Jun 2020 11:14:45 +0200
Subject: [PATCH 28/66] Clarify some parts by applying the suggestions from
 review

Co-authored-by: Josh Triplett <josh@joshtriplett.org>
---
 src/libstd/keyword_docs.rs | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index cbfaac8c4b317..51b21ce572a3f 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -1625,9 +1625,9 @@ mod dyn_keyword {}
 /// The [Rust equivalent of a C-style union][union].
 ///
 /// A `union` looks like a [`struct`] in terms of declaration, but all of its
-/// fields exist simultaneously, superimposed over one another. For instance,
+/// fields exist in the same memory, superimposed over one another. For instance,
 /// if we wanted some bits in memory that we sometimes interpret as a `u32` and
-/// sometimes as an `f32`, we would write:
+/// sometimes as an `f32`, we could write:
 ///
 /// ```rust
 /// union IntOrFloat {
@@ -1647,6 +1647,7 @@ mod dyn_keyword {}
 ///
 /// It is possible to use pattern matching on `union`s. A single field name must
 /// be used and it must match the name of one of the `union`'s field.
+/// Like reading from a `union`, pattern matching on a `union` requires `unsafe`.
 ///
 /// ```rust
 /// union IntOrFloat {
@@ -1658,8 +1659,8 @@ mod dyn_keyword {}
 ///
 /// unsafe {
 ///     match u {
-///         IntOrFloat { i: 10 } => println!("Found exactly ten !"),
-///         // The field name is used to deduce the type
+///         IntOrFloat { i: 10 } => println!("Found exactly ten!"),
+///         // Matching the field `f` provides an `f32`.
 ///         IntOrFloat { f } => println!("Found f = {} !", f),
 ///     }
 /// }
@@ -1667,8 +1668,8 @@ mod dyn_keyword {}
 ///
 /// # References to union fields
 ///
-/// All fields in a union are all at the same place in memory which means
-/// borrowing one borrows all of them, for the same duration:
+/// All fields in a `union` are all at the same place in memory which means
+/// borrowing one borrows the entire `union`, for the same lifetime:
 ///
 /// ```rust,compile_fail,E0502
 /// union IntOrFloat {

From 310c97b6ba7e6b8d4e3e7f337db0cff97f45f5c0 Mon Sep 17 00:00:00 2001
From: Eric Huss <eric@huss.org>
Date: Sat, 4 Jul 2020 14:46:04 -0700
Subject: [PATCH 29/66] Fix caching issue when building tools.

---
 src/bootstrap/bin/rustc.rs |  4 ++++
 src/bootstrap/builder.rs   | 18 ++++++++++++++----
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 3072a4a1ae7c0..fd36cd9bd8beb 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -76,6 +76,10 @@ fn main() {
         cmd.env("RUST_BACKTRACE", "1");
     }
 
+    if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") {
+        cmd.args(lint_flags.split_whitespace());
+    }
+
     if target.is_some() {
         // The stage0 compiler has a special sysroot distinct from what we
         // actually downloaded, so we just always pass the `--sysroot` option,
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 3cbecbbaa06cb..557fb1aa550a5 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1130,22 +1130,32 @@ impl<'a> Builder<'a> {
         cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
 
         if source_type == SourceType::InTree {
+            let mut lint_flags = Vec::new();
             // When extending this list, add the new lints to the RUSTFLAGS of the
             // build_bootstrap function of src/bootstrap/bootstrap.py as well as
             // some code doesn't go through this `rustc` wrapper.
-            rustflags.arg("-Wrust_2018_idioms");
-            rustflags.arg("-Wunused_lifetimes");
+            lint_flags.push("-Wrust_2018_idioms");
+            lint_flags.push("-Wunused_lifetimes");
 
             if self.config.deny_warnings {
-                rustflags.arg("-Dwarnings");
+                lint_flags.push("-Dwarnings");
             }
 
             // FIXME(#58633) hide "unused attribute" errors in incremental
             // builds of the standard library, as the underlying checks are
             // not yet properly integrated with incremental recompilation.
             if mode == Mode::Std && compiler.stage == 0 && self.config.incremental {
-                rustflags.arg("-Aunused-attributes");
+                lint_flags.push("-Aunused-attributes");
             }
+            // This does not use RUSTFLAGS due to caching issues with Cargo.
+            // Clippy is treated as an "in tree" tool, but shares the same
+            // cache as other "submodule" tools. With these options set in
+            // RUSTFLAGS, that causes *every* shared dependency to be rebuilt.
+            // By injecting this into the rustc wrapper, this circumvents
+            // Cargo's fingerprint detection. This is fine because lint flags
+            // are always ignored in dependencies. Eventually this should be
+            // fixed via better support from Cargo.
+            cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" "));
         }
 
         if let Mode::Rustc | Mode::Codegen = mode {

From c478b5473d6623622d318d058477f5f09e2eeb52 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Fri, 3 Jul 2020 11:58:05 +0200
Subject: [PATCH 30/66] add as_ptr method to raw slices

---
 src/libcore/ptr/const_ptr.rs | 21 +++++++++++++++++++++
 src/libcore/ptr/mut_ptr.rs   | 21 +++++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs
index d1d7a71523822..f926befb4b323 100644
--- a/src/libcore/ptr/const_ptr.rs
+++ b/src/libcore/ptr/const_ptr.rs
@@ -826,6 +826,27 @@ impl<T> *const [T] {
         // Only `std` can make this guarantee.
         unsafe { Repr { rust: self }.raw }.len
     }
+
+    /// Returns a raw pointer to the slice's buffer.
+    ///
+    /// This is equivalent to casting `self` to `*const T`, but more type-safe.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(slice_ptr_ptr)]
+    ///
+    /// use std::ptr;
+    ///
+    /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3);
+    /// assert_eq!(slice.as_ptr(), 0 as *const i8);
+    /// ```
+    #[inline]
+    #[unstable(feature = "slice_ptr_ptr", issue = "none")]
+    #[rustc_const_unstable(feature = "const_slice_ptr_ptr", issue = "none")]
+    pub const fn as_ptr(self) -> *const T {
+        self as *const T
+    }
 }
 
 // Equality for pointers
diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs
index 7d4b6339b511f..7fc4805c9211b 100644
--- a/src/libcore/ptr/mut_ptr.rs
+++ b/src/libcore/ptr/mut_ptr.rs
@@ -1028,6 +1028,27 @@ impl<T> *mut [T] {
         // Only `std` can make this guarantee.
         unsafe { Repr { rust_mut: self }.raw }.len
     }
+
+    /// Returns a raw pointer to the slice's buffer.
+    ///
+    /// This is equivalent to casting `self` to `*mut T`, but more type-safe.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(slice_ptr_ptr)]
+    ///
+    /// use std::ptr;
+    ///
+    /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
+    /// assert_eq!(slice.as_ptr(), 0 as *mut i8);
+    /// ```
+    #[inline]
+    #[unstable(feature = "slice_ptr_ptr", issue = "none")]
+    #[rustc_const_unstable(feature = "const_slice_ptr_ptr", issue = "none")]
+    pub const fn as_ptr(self) -> *mut T {
+        self as *mut T
+    }
 }
 
 // Equality for pointers

From 3b1d5e6d792fb47c9a95c4ea210ce88174f18b13 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Fri, 3 Jul 2020 12:04:36 +0200
Subject: [PATCH 31/66] call the mut version as_mut_ptr and also add an
 as_ptr-like method to NonNull slices

---
 src/libcore/lib.rs          |  1 +
 src/libcore/ptr/mut_ptr.rs  |  4 ++--
 src/libcore/ptr/non_null.rs | 20 ++++++++++++++++++++
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 50c56434fa9a1..66a1bea0c44b5 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -93,6 +93,7 @@
 #![feature(const_slice_ptr_len)]
 #![feature(const_type_name)]
 #![feature(const_likely)]
+#![feature(const_slice_ptr_ptr)]
 #![feature(custom_inner_attributes)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs
index 7fc4805c9211b..70a81f85da8f4 100644
--- a/src/libcore/ptr/mut_ptr.rs
+++ b/src/libcore/ptr/mut_ptr.rs
@@ -1041,12 +1041,12 @@ impl<T> *mut [T] {
     /// use std::ptr;
     ///
     /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
-    /// assert_eq!(slice.as_ptr(), 0 as *mut i8);
+    /// assert_eq!(slice.as_mut_ptr(), 0 as *mut i8);
     /// ```
     #[inline]
     #[unstable(feature = "slice_ptr_ptr", issue = "none")]
     #[rustc_const_unstable(feature = "const_slice_ptr_ptr", issue = "none")]
-    pub const fn as_ptr(self) -> *mut T {
+    pub const fn as_mut_ptr(self) -> *mut T {
         self as *mut T
     }
 }
diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs
index c2d31bfb6a4ee..3461d224c46b9 100644
--- a/src/libcore/ptr/non_null.rs
+++ b/src/libcore/ptr/non_null.rs
@@ -204,6 +204,26 @@ impl<T> NonNull<[T]> {
     pub const fn len(self) -> usize {
         self.as_ptr().len()
     }
+
+    /// Returns a non-null pointer to the slice's buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(slice_ptr_ptr, nonnull_slice_from_raw_parts)]
+    ///
+    /// use std::ptr::NonNull;
+    ///
+    /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
+    /// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap());
+    /// ```
+    #[inline]
+    #[unstable(feature = "slice_ptr_ptr", issue = "none")]
+    #[rustc_const_unstable(feature = "const_slice_ptr_ptr", issue = "none")]
+    pub const fn as_non_null_ptr(self) -> NonNull<T> {
+        // SAFETY: We know `self` is non-null.
+        unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) }
+    }
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]

From 90580c7b0e51050c892613664db79493df7a2af5 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 5 Jul 2020 18:02:00 +0200
Subject: [PATCH 32/66] make unchecked slice indexing helper methods use raw
 pointers

---
 src/libcore/slice/mod.rs | 111 ++++++++++++++--------------
 src/libcore/str/mod.rs   | 152 +++++++++++++++++++--------------------
 2 files changed, 134 insertions(+), 129 deletions(-)

diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index e7a2d7adedea0..88deeac00ff14 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -310,8 +310,10 @@ impl<T> [T] {
     where
         I: SliceIndex<Self>,
     {
-        // SAFETY: the caller must uphold the safety requirements for `get_unchecked`.
-        unsafe { index.get_unchecked(self) }
+        // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &*index.get_unchecked(self) }
     }
 
     /// Returns a mutable reference to an element or subslice, without doing
@@ -342,8 +344,10 @@ impl<T> [T] {
     where
         I: SliceIndex<Self>,
     {
-        // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`.
-        unsafe { index.get_unchecked_mut(self) }
+        // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &mut *index.get_unchecked_mut(self) }
     }
 
     /// Returns a raw pointer to the slice's buffer.
@@ -2910,6 +2914,9 @@ mod private_slice_index {
 }
 
 /// A helper trait used for indexing operations.
+///
+/// Implementations of this trait have to promise that if the argument
+/// to `get_(mut_)unchecked` is a safe reference, then so is the result.
 #[stable(feature = "slice_get_slice", since = "1.28.0")]
 #[rustc_on_unimplemented(
     on(T = "str", label = "string indices are ranges of `usize`",),
@@ -2921,7 +2928,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
     message = "the type `{T}` cannot be indexed by `{Self}`",
     label = "slice indices are of type `usize` or ranges of `usize`"
 )]
-pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
+pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
     /// The output type returned by methods.
     #[stable(feature = "slice_get_slice", since = "1.28.0")]
     type Output: ?Sized;
@@ -2938,21 +2945,21 @@ pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
 
     /// Returns a shared reference to the output at this location, without
     /// performing any bounds checking.
-    /// Calling this method with an out-of-bounds index is *[undefined behavior]*
-    /// even if the resulting reference is not used.
+    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
+    /// is *[undefined behavior]* even if the resulting reference is not used.
     ///
     /// [undefined behavior]: ../../reference/behavior-considered-undefined.html
     #[unstable(feature = "slice_index_methods", issue = "none")]
-    unsafe fn get_unchecked(self, slice: &T) -> &Self::Output;
+    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
 
     /// Returns a mutable reference to the output at this location, without
     /// performing any bounds checking.
-    /// Calling this method with an out-of-bounds index is *[undefined behavior]*
-    /// even if the resulting reference is not used.
+    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
+    /// is *[undefined behavior]* even if the resulting reference is not used.
     ///
     /// [undefined behavior]: ../../reference/behavior-considered-undefined.html
     #[unstable(feature = "slice_index_methods", issue = "none")]
-    unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output;
+    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output;
 
     /// Returns a shared reference to the output at this location, panicking
     /// if out of bounds.
@@ -2968,33 +2975,32 @@ pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for usize {
+unsafe impl<T> SliceIndex<[T]> for usize {
     type Output = T;
 
     #[inline]
     fn get(self, slice: &[T]) -> Option<&T> {
-        if self < slice.len() { unsafe { Some(self.get_unchecked(slice)) } } else { None }
+        if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
     }
 
     #[inline]
     fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
-        if self < slice.len() { unsafe { Some(self.get_unchecked_mut(slice)) } } else { None }
+        if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None }
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &T {
-        // SAFETY: `slice` cannot be longer than `isize::MAX` and
-        // the caller guarantees that `self` is in bounds of `slice`
-        // so `self` cannot overflow an `isize`, so the call to `add` is safe.
-        // The obtained pointer comes from a reference which is guaranteed
-        // to be valid.
-        unsafe { &*slice.as_ptr().add(self) }
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
+        // SAFETY: the caller guarantees that `slice` is not dangling, so it
+        // cannot be longer than `isize::MAX`. They also guarantee that
+        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+        // so the call to `add` is safe.
+        unsafe { slice.as_ptr().add(self) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut T {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
         // SAFETY: see comments for `get_unchecked` above.
-        unsafe { &mut *slice.as_mut_ptr().add(self) }
+        unsafe { slice.as_mut_ptr().add(self) }
     }
 
     #[inline]
@@ -3011,7 +3017,7 @@ impl<T> SliceIndex<[T]> for usize {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for ops::Range<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
     type Output = [T];
 
     #[inline]
@@ -3019,7 +3025,7 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
         if self.start > self.end || self.end > slice.len() {
             None
         } else {
-            unsafe { Some(self.get_unchecked(slice)) }
+            unsafe { Some(&*self.get_unchecked(slice)) }
         }
     }
 
@@ -3028,24 +3034,25 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
         if self.start > self.end || self.end > slice.len() {
             None
         } else {
-            unsafe { Some(self.get_unchecked_mut(slice)) }
+            unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
         }
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
-        // SAFETY: `slice` cannot be longer than `isize::MAX` and
-        // the caller guarantees that `self` is in bounds of `slice`
-        // so `self` cannot overflow an `isize`, so the call to `add` is safe.
-        // Also, since the caller guarantees that `self` is in bounds of `slice`,
-        // `from_raw_parts` will give a subslice of `slice` which is always safe.
-        unsafe { from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller guarantees that `slice` is not dangling, so it
+        // cannot be longer than `isize::MAX`. They also guarantee that
+        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+        // so the call to `add` is safe.
+        unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: see comments for `get_unchecked` above.
-        unsafe { from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) }
+        unsafe {
+            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
+        }
     }
 
     #[inline]
@@ -3055,7 +3062,7 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
         } else if self.end > slice.len() {
             slice_index_len_fail(self.end, slice.len());
         }
-        unsafe { self.get_unchecked(slice) }
+        unsafe { &*self.get_unchecked(slice) }
     }
 
     #[inline]
@@ -3065,12 +3072,12 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
         } else if self.end > slice.len() {
             slice_index_len_fail(self.end, slice.len());
         }
-        unsafe { self.get_unchecked_mut(slice) }
+        unsafe { &mut *self.get_unchecked_mut(slice) }
     }
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
     type Output = [T];
 
     #[inline]
@@ -3084,13 +3091,13 @@ impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
         unsafe { (0..self.end).get_unchecked(slice) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
         unsafe { (0..self.end).get_unchecked_mut(slice) }
     }
@@ -3107,7 +3114,7 @@ impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
     type Output = [T];
 
     #[inline]
@@ -3121,13 +3128,13 @@ impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
         unsafe { (self.start..slice.len()).get_unchecked(slice) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
         unsafe { (self.start..slice.len()).get_unchecked_mut(slice) }
     }
@@ -3144,7 +3151,7 @@ impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for ops::RangeFull {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
     type Output = [T];
 
     #[inline]
@@ -3158,12 +3165,12 @@ impl<T> SliceIndex<[T]> for ops::RangeFull {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         slice
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         slice
     }
 
@@ -3179,7 +3186,7 @@ impl<T> SliceIndex<[T]> for ops::RangeFull {
 }
 
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
     type Output = [T];
 
     #[inline]
@@ -3197,13 +3204,13 @@ impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
         unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
         unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
     }
@@ -3226,7 +3233,7 @@ impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
 }
 
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
     type Output = [T];
 
     #[inline]
@@ -3240,13 +3247,13 @@ impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
         unsafe { (0..=self.end).get_unchecked(slice) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
         unsafe { (0..=self.end).get_unchecked_mut(slice) }
     }
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 0014501d2c4d0..5c4134b0749b9 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -1731,7 +1731,8 @@ Section: Trait implementations
 mod traits {
     use crate::cmp::Ordering;
     use crate::ops;
-    use crate::slice::{self, SliceIndex};
+    use crate::ptr;
+    use crate::slice::SliceIndex;
 
     /// Implements ordering of strings.
     ///
@@ -1822,7 +1823,7 @@ mod traits {
     ///
     /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    impl SliceIndex<str> for ops::RangeFull {
+    unsafe impl SliceIndex<str> for ops::RangeFull {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -1833,11 +1834,11 @@ mod traits {
             Some(slice)
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
             slice
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
             slice
         }
         #[inline]
@@ -1886,7 +1887,7 @@ mod traits {
     /// // &s[3 .. 100];
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    impl SliceIndex<str> for ops::Range<usize> {
+    unsafe impl SliceIndex<str> for ops::Range<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -1894,8 +1895,10 @@ mod traits {
                 && slice.is_char_boundary(self.start)
                 && slice.is_char_boundary(self.end)
             {
-                // SAFETY: just checked that `start` and `end` are on a char boundary.
-                Some(unsafe { self.get_unchecked(slice) })
+                // SAFETY: just checked that `start` and `end` are on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                // We also checked char boundaries, so this is valid UTF-8.
+                Some(unsafe { &*self.get_unchecked(slice) })
             } else {
                 None
             }
@@ -1907,34 +1910,28 @@ mod traits {
                 && slice.is_char_boundary(self.end)
             {
                 // SAFETY: just checked that `start` and `end` are on a char boundary.
-                Some(unsafe { self.get_unchecked_mut(slice) })
+                // We know the pointer is unique because we got it from `slice`.
+                Some(unsafe { &mut *self.get_unchecked_mut(slice) })
             } else {
                 None
             }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+            let slice = slice as *const [u8];
             // SAFETY: the caller guarantees that `self` is in bounds of `slice`
             // which satisfies all the conditions for `add`.
             let ptr = unsafe { slice.as_ptr().add(self.start) };
             let len = self.end - self.start;
-            // SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
-            // we can safely construct a subslice with `from_raw_parts` and use it
-            // since we return a shared thus immutable reference.
-            // The call to `from_utf8_unchecked` is safe since the data comes from
-            // a `str` which is guaranteed to be valid utf8, since the caller
-            // must guarantee that `self.start` and `self.end` are char boundaries.
-            unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
+            ptr::slice_from_raw_parts(ptr, len) as *const str
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+            let slice = slice as *mut [u8];
             // SAFETY: see comments for `get_unchecked`.
             let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
             let len = self.end - self.start;
-            // SAFETY: mostly identical to the comments for `get_unchecked`, except that we
-            // can return a mutable reference since the caller passed a mutable reference
-            // and is thus guaranteed to have exclusive write access to `slice`.
-            unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
+            ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -1949,8 +1946,9 @@ mod traits {
                 && slice.is_char_boundary(self.start)
                 && slice.is_char_boundary(self.end)
             {
-                // SAFETY: just checked that `start` and `end` are on a char boundary.
-                unsafe { self.get_unchecked_mut(slice) }
+                // SAFETY: just checked that `start` and `end` are on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                unsafe { &mut *self.get_unchecked_mut(slice) }
             } else {
                 super::slice_error_fail(slice, self.start, self.end)
             }
@@ -1973,13 +1971,14 @@ mod traits {
     /// Panics if `end` does not point to the starting byte offset of a
     /// character (as defined by `is_char_boundary`), or if `end > len`.
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    impl SliceIndex<str> for ops::RangeTo<usize> {
+    unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
             if slice.is_char_boundary(self.end) {
-                // SAFETY: just checked that `end` is on a char boundary.
-                Some(unsafe { self.get_unchecked(slice) })
+                // SAFETY: just checked that `end` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                Some(unsafe { &*self.get_unchecked(slice) })
             } else {
                 None
             }
@@ -1987,30 +1986,24 @@ mod traits {
         #[inline]
         fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
             if slice.is_char_boundary(self.end) {
-                // SAFETY: just checked that `end` is on a char boundary.
-                Some(unsafe { self.get_unchecked_mut(slice) })
+                // SAFETY: just checked that `end` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                Some(unsafe { &mut *self.get_unchecked_mut(slice) })
             } else {
                 None
             }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+            let slice = slice as *const [u8];
             let ptr = slice.as_ptr();
-            // SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
-            // we can safely construct a subslice with `from_raw_parts` and use it
-            // since we return a shared thus immutable reference.
-            // The call to `from_utf8_unchecked` is safe since the data comes from
-            // a `str` which is guaranteed to be valid utf8, since the caller
-            // must guarantee that `self.end` is a char boundary.
-            unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) }
+            ptr::slice_from_raw_parts(ptr, self.end) as *const str
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+            let slice = slice as *mut [u8];
             let ptr = slice.as_mut_ptr();
-            // SAFETY: mostly identical to `get_unchecked`, except that we can safely
-            // return a mutable reference since the caller passed a mutable reference
-            // and is thus guaranteed to have exclusive write access to `slice`.
-            unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) }
+            ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -2020,8 +2013,9 @@ mod traits {
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
             if slice.is_char_boundary(self.end) {
-                // SAFETY: just checked that `end` is on a char boundary.
-                unsafe { self.get_unchecked_mut(slice) }
+                // SAFETY: just checked that `end` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                unsafe { &mut *self.get_unchecked_mut(slice) }
             } else {
                 super::slice_error_fail(slice, 0, self.end)
             }
@@ -2045,13 +2039,14 @@ mod traits {
     /// Panics if `begin` does not point to the starting byte offset of
     /// a character (as defined by `is_char_boundary`), or if `begin >= len`.
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    impl SliceIndex<str> for ops::RangeFrom<usize> {
+    unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
             if slice.is_char_boundary(self.start) {
-                // SAFETY: just checked that `start` is on a char boundary.
-                Some(unsafe { self.get_unchecked(slice) })
+                // SAFETY: just checked that `start` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                Some(unsafe { &*self.get_unchecked(slice) })
             } else {
                 None
             }
@@ -2059,35 +2054,29 @@ mod traits {
         #[inline]
         fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
             if slice.is_char_boundary(self.start) {
-                // SAFETY: just checked that `start` is on a char boundary.
-                Some(unsafe { self.get_unchecked_mut(slice) })
+                // SAFETY: just checked that `start` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                Some(unsafe { &mut *self.get_unchecked_mut(slice) })
             } else {
                 None
             }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+            let slice = slice as *const [u8];
             // SAFETY: the caller guarantees that `self` is in bounds of `slice`
             // which satisfies all the conditions for `add`.
             let ptr = unsafe { slice.as_ptr().add(self.start) };
             let len = slice.len() - self.start;
-            // SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
-            // we can safely construct a subslice with `from_raw_parts` and use it
-            // since we return a shared thus immutable reference.
-            // The call to `from_utf8_unchecked` is safe since the data comes from
-            // a `str` which is guaranteed to be valid utf8, since the caller
-            // must guarantee that `self.start` is a char boundary.
-            unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
+            ptr::slice_from_raw_parts(ptr, len) as *const str
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+            let slice = slice as *mut [u8];
             // SAFETY: identical to `get_unchecked`.
             let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
             let len = slice.len() - self.start;
-            // SAFETY: mostly identical to `get_unchecked`, except that we can safely
-            // return a mutable reference since the caller passed a mutable reference
-            // and is thus guaranteed to have exclusive write access to `slice`.
-            unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
+            ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -2097,8 +2086,9 @@ mod traits {
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
             if slice.is_char_boundary(self.start) {
-                // SAFETY: just checked that `start` is on a char boundary.
-                unsafe { self.get_unchecked_mut(slice) }
+                // SAFETY: just checked that `start` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                unsafe { &mut *self.get_unchecked_mut(slice) }
             } else {
                 super::slice_error_fail(slice, self.start, slice.len())
             }
@@ -2122,7 +2112,7 @@ mod traits {
     /// to the ending byte offset of a character (`end + 1` is either a starting
     /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
     #[stable(feature = "inclusive_range", since = "1.26.0")]
-    impl SliceIndex<str> for ops::RangeInclusive<usize> {
+    unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -2141,12 +2131,12 @@ mod traits {
             }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
             // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
             unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
             // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
             unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
         }
@@ -2181,7 +2171,7 @@ mod traits {
     /// (`end + 1` is either a starting byte offset as defined by
     /// `is_char_boundary`, or equal to `len`), or if `end >= len`.
     #[stable(feature = "inclusive_range", since = "1.26.0")]
-    impl SliceIndex<str> for ops::RangeToInclusive<usize> {
+    unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -2192,12 +2182,12 @@ mod traits {
             if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
             // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
             unsafe { (..self.end + 1).get_unchecked(slice) }
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
             // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
             unsafe { (..self.end + 1).get_unchecked_mut(slice) }
         }
@@ -2560,8 +2550,10 @@ impl str {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
-        // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
-        unsafe { i.get_unchecked(self) }
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &*i.get_unchecked(self) }
     }
 
     /// Returns a mutable, unchecked subslice of `str`.
@@ -2593,8 +2585,10 @@ impl str {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
-        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
-        unsafe { i.get_unchecked_mut(self) }
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &mut *i.get_unchecked_mut(self) }
     }
 
     /// Creates a string slice from another string slice, bypassing safety
@@ -2644,8 +2638,10 @@ impl str {
     #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")]
     #[inline]
     pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
-        // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
-        unsafe { (begin..end).get_unchecked(self) }
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &*(begin..end).get_unchecked(self) }
     }
 
     /// Creates a string slice from another string slice, bypassing safety
@@ -2676,8 +2672,10 @@ impl str {
     #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")]
     #[inline]
     pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
-        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
-        unsafe { (begin..end).get_unchecked_mut(self) }
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &mut *(begin..end).get_unchecked_mut(self) }
     }
 
     /// Divide one string slice into two at an index.

From 5f5c98bd8a27b5313d0b1a5830076139c562b6b6 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 5 Jul 2020 18:39:04 +0200
Subject: [PATCH 33/66] add (unchecked) indexing methods to raw pointers and
 NonNull

---
 src/libcore/lib.rs           |  2 +-
 src/libcore/ptr/const_ptr.rs | 37 ++++++++++++++++++++++++++++----
 src/libcore/ptr/mut_ptr.rs   | 38 ++++++++++++++++++++++++++++-----
 src/libcore/ptr/non_null.rs  | 41 +++++++++++++++++++++++++++++++-----
 4 files changed, 103 insertions(+), 15 deletions(-)

diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 66a1bea0c44b5..1f906650dfa56 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -93,7 +93,6 @@
 #![feature(const_slice_ptr_len)]
 #![feature(const_type_name)]
 #![feature(const_likely)]
-#![feature(const_slice_ptr_ptr)]
 #![feature(custom_inner_attributes)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
@@ -149,6 +148,7 @@
 #![feature(associated_type_bounds)]
 #![feature(const_type_id)]
 #![feature(const_caller_location)]
+#![feature(slice_ptr_get)]
 #![feature(no_niche)] // rust-lang/rust#68303
 #![feature(unsafe_block_in_unsafe_fn)]
 #![deny(unsafe_op_in_unsafe_fn)]
diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs
index f926befb4b323..22c741d4651a5 100644
--- a/src/libcore/ptr/const_ptr.rs
+++ b/src/libcore/ptr/const_ptr.rs
@@ -2,6 +2,7 @@ use super::*;
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::intrinsics;
 use crate::mem;
+use crate::slice::SliceIndex;
 
 #[lang = "const_ptr"]
 impl<T: ?Sized> *const T {
@@ -834,19 +835,47 @@ impl<T> *const [T] {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(slice_ptr_ptr)]
-    ///
+    /// #![feature(slice_ptr_get)]
     /// use std::ptr;
     ///
     /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3);
     /// assert_eq!(slice.as_ptr(), 0 as *const i8);
     /// ```
     #[inline]
-    #[unstable(feature = "slice_ptr_ptr", issue = "none")]
-    #[rustc_const_unstable(feature = "const_slice_ptr_ptr", issue = "none")]
+    #[unstable(feature = "slice_ptr_get", issue = "none")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "none")]
     pub const fn as_ptr(self) -> *const T {
         self as *const T
     }
+
+    /// Returns a raw pointer to an element or subslice, without doing bounds
+    /// checking.
+    ///
+    /// Calling this method with an out-of-bounds index or when `self` is not dereferencable
+    /// is *[undefined behavior]* even if the resulting pointer is not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// let x = &[1, 2, 4] as *const [i32];
+    ///
+    /// unsafe {
+    ///     assert_eq!(x.get_unchecked(1), x.as_ptr().add(1));
+    /// }
+    /// ```
+    #[unstable(feature = "slice_ptr_get", issue = "none")]
+    #[inline]
+    pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
+    where
+        I: SliceIndex<[T]>,
+    {
+        // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
+        unsafe { index.get_unchecked(self) }
+    }
 }
 
 // Equality for pointers
diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs
index 70a81f85da8f4..56bade706942a 100644
--- a/src/libcore/ptr/mut_ptr.rs
+++ b/src/libcore/ptr/mut_ptr.rs
@@ -1,6 +1,7 @@
 use super::*;
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::intrinsics;
+use crate::slice::SliceIndex;
 
 #[lang = "mut_ptr"]
 impl<T: ?Sized> *mut T {
@@ -1014,7 +1015,6 @@ impl<T> *mut [T] {
     ///
     /// ```rust
     /// #![feature(slice_ptr_len)]
-    ///
     /// use std::ptr;
     ///
     /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
@@ -1036,19 +1036,47 @@ impl<T> *mut [T] {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(slice_ptr_ptr)]
-    ///
+    /// #![feature(slice_ptr_get)]
     /// use std::ptr;
     ///
     /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
     /// assert_eq!(slice.as_mut_ptr(), 0 as *mut i8);
     /// ```
     #[inline]
-    #[unstable(feature = "slice_ptr_ptr", issue = "none")]
-    #[rustc_const_unstable(feature = "const_slice_ptr_ptr", issue = "none")]
+    #[unstable(feature = "slice_ptr_get", issue = "none")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "none")]
     pub const fn as_mut_ptr(self) -> *mut T {
         self as *mut T
     }
+
+    /// Returns a raw pointer to an element or subslice, without doing bounds
+    /// checking.
+    ///
+    /// Calling this method with an out-of-bounds index or when `self` is not dereferencable
+    /// is *[undefined behavior]* even if the resulting pointer is not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// let x = &mut [1, 2, 4] as *mut [i32];
+    ///
+    /// unsafe {
+    ///     assert_eq!(x.get_unchecked_mut(1), x.as_mut_ptr().add(1));
+    /// }
+    /// ```
+    #[unstable(feature = "slice_ptr_get", issue = "none")]
+    #[inline]
+    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
+    where
+        I: SliceIndex<[T]>,
+    {
+        // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
+        unsafe { index.get_unchecked_mut(self) }
+    }
 }
 
 // Equality for pointers
diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs
index 3461d224c46b9..f59da631b46ab 100644
--- a/src/libcore/ptr/non_null.rs
+++ b/src/libcore/ptr/non_null.rs
@@ -6,6 +6,7 @@ use crate::marker::Unsize;
 use crate::mem;
 use crate::ops::{CoerceUnsized, DispatchFromDyn};
 use crate::ptr::Unique;
+use crate::slice::SliceIndex;
 
 /// `*mut T` but non-zero and covariant.
 ///
@@ -192,7 +193,6 @@ impl<T> NonNull<[T]> {
     ///
     /// ```rust
     /// #![feature(slice_ptr_len, nonnull_slice_from_raw_parts)]
-    ///
     /// use std::ptr::NonNull;
     ///
     /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
@@ -210,20 +210,51 @@ impl<T> NonNull<[T]> {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(slice_ptr_ptr, nonnull_slice_from_raw_parts)]
-    ///
+    /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
     /// use std::ptr::NonNull;
     ///
     /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
     /// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap());
     /// ```
     #[inline]
-    #[unstable(feature = "slice_ptr_ptr", issue = "none")]
-    #[rustc_const_unstable(feature = "const_slice_ptr_ptr", issue = "none")]
+    #[unstable(feature = "slice_ptr_get", issue = "none")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "none")]
     pub const fn as_non_null_ptr(self) -> NonNull<T> {
         // SAFETY: We know `self` is non-null.
         unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) }
     }
+
+    /// Returns a raw pointer to an element or subslice, without doing bounds
+    /// checking.
+    ///
+    /// Calling this method with an out-of-bounds index or when `self` is not dereferencable
+    /// is *[undefined behavior]* even if the resulting pointer is not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
+    /// use std::ptr::NonNull;
+    ///
+    /// let x = &mut [1, 2, 4];
+    /// let x = NonNull::slice_from_raw_parts(NonNull::new(x.as_mut_ptr()).unwrap(), x.len());
+    ///
+    /// unsafe {
+    ///     assert_eq!(x.get_unchecked_mut(1).as_ptr(), x.as_non_null_ptr().as_ptr().add(1));
+    /// }
+    /// ```
+    #[unstable(feature = "slice_ptr_get", issue = "none")]
+    #[inline]
+    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
+    where
+        I: SliceIndex<[T]>,
+    {
+        // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
+        // As a consequence, the resulting pointer cannot be NULL.
+        unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) }
+    }
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]

From 00980b6ccda5ca6d8039cd493a7aa7f487c47c0d Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Tue, 7 Jul 2020 14:13:03 +0200
Subject: [PATCH 34/66] clean up E0718 explanation

---
 src/librustc_error_codes/error_codes/E0718.md | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/librustc_error_codes/error_codes/E0718.md b/src/librustc_error_codes/error_codes/E0718.md
index e7ae51ca58835..bb401ef6e2d4c 100644
--- a/src/librustc_error_codes/error_codes/E0718.md
+++ b/src/librustc_error_codes/error_codes/E0718.md
@@ -1,7 +1,6 @@
-This error indicates that a `#[lang = ".."]` attribute was placed
-on the wrong type of item.
+A `#[lang = ".."]` attribute was placed on the wrong type of item.
 
-Examples of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0718
 #![feature(lang_items)]

From c8b16cdbd0f06c66467c082b9d3e190255fa295d Mon Sep 17 00:00:00 2001
From: Dennis Hamester <dennis.hamester@gmail.com>
Date: Wed, 8 Jul 2020 07:39:49 +0200
Subject: [PATCH 35/66] rustdoc: Allow linking from private items to private
 types

Fixes #74134

After PR #72771 this would trigger an intra_doc_link_resolution_failure warning
when rustdoc is invoked without --document-private-items. Links from private
items to private types are however never actually generated in that case and
thus shouldn't produce a warning. These links are in fact a very useful tool to
document crate internals.

Tests are added for all 4 combinations of public/private items and link
targets. Test 1 is the case mentioned above and fails without this commit. Tests
2 - 4 passed before already but are added nonetheless to prevent regressions.
---
 src/librustdoc/passes/collect_intra_doc_links.rs |  1 +
 src/test/rustdoc/issue-74134-1.rs                | 10 ++++++++++
 src/test/rustdoc/issue-74134-2.rs                | 11 +++++++++++
 src/test/rustdoc/issue-74134-3.rs                | 11 +++++++++++
 src/test/rustdoc/issue-74134-4.rs                | 11 +++++++++++
 5 files changed, 44 insertions(+)
 create mode 100644 src/test/rustdoc/issue-74134-1.rs
 create mode 100644 src/test/rustdoc/issue-74134-2.rs
 create mode 100644 src/test/rustdoc/issue-74134-3.rs
 create mode 100644 src/test/rustdoc/issue-74134-4.rs

diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index f1d1bf439f171..86f94af0c6e31 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -796,6 +796,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 
                     let hir_id = self.cx.tcx.hir().as_local_hir_id(local);
                     if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id)
+                        && (item.visibility == Visibility::Public)
                         && !self.cx.render_options.document_private
                     {
                         let item_name = item.name.as_deref().unwrap_or("<unknown>");
diff --git a/src/test/rustdoc/issue-74134-1.rs b/src/test/rustdoc/issue-74134-1.rs
new file mode 100644
index 0000000000000..72d38638a794c
--- /dev/null
+++ b/src/test/rustdoc/issue-74134-1.rs
@@ -0,0 +1,10 @@
+#![deny(intra_doc_link_resolution_failure)]
+
+// Linking from a private item to a private type is fine without --document-private-items.
+
+struct Private;
+
+pub struct Public {
+    /// [`Private`]
+    private: Private,
+}
diff --git a/src/test/rustdoc/issue-74134-2.rs b/src/test/rustdoc/issue-74134-2.rs
new file mode 100644
index 0000000000000..f665e360b4982
--- /dev/null
+++ b/src/test/rustdoc/issue-74134-2.rs
@@ -0,0 +1,11 @@
+// compile-flags: --document-private-items
+#![deny(intra_doc_link_resolution_failure)]
+
+// Linking from a private item to a private type is fine with --document-private-items.
+
+struct Private;
+
+pub struct Public {
+    /// [`Private`]
+    private: Private,
+}
diff --git a/src/test/rustdoc/issue-74134-3.rs b/src/test/rustdoc/issue-74134-3.rs
new file mode 100644
index 0000000000000..b2709ecdaddda
--- /dev/null
+++ b/src/test/rustdoc/issue-74134-3.rs
@@ -0,0 +1,11 @@
+// should-fail
+#![deny(intra_doc_link_resolution_failure)]
+
+// Linking from a public item to a private type fails without --document-private-items.
+
+struct Private;
+
+pub struct Public {
+    /// [`Private`]
+    pub public: u32,
+}
diff --git a/src/test/rustdoc/issue-74134-4.rs b/src/test/rustdoc/issue-74134-4.rs
new file mode 100644
index 0000000000000..efff74f279721
--- /dev/null
+++ b/src/test/rustdoc/issue-74134-4.rs
@@ -0,0 +1,11 @@
+// compile-flags: --document-private-items
+#![deny(intra_doc_link_resolution_failure)]
+
+// Linking from a public item to a private type is fine with --document-private-items.
+
+struct Private;
+
+pub struct Public {
+    /// [`Private`]
+    pub public: u32,
+}

From 23d7b3f6f1a345ad95f0812c85613627164b6c39 Mon Sep 17 00:00:00 2001
From: Erik Desjardins <erikdesjardins@users.noreply.github.com>
Date: Fri, 10 Jul 2020 19:02:10 -0400
Subject: [PATCH 36/66] Remove an unwrap in layout computation

---
 src/librustc_middle/ty/layout.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs
index 39b8566e7a873..efdb5f27afb2a 100644
--- a/src/librustc_middle/ty/layout.rs
+++ b/src/librustc_middle/ty/layout.rs
@@ -774,12 +774,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     (present_variants.next(), present_variants.next())
                 };
                 let present_first = match present_first {
-                    present_first @ Some(_) => present_first,
+                    Some(present_first) => present_first,
                     // Uninhabited because it has no variants, or only absent ones.
                     None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)),
                     // If it's a struct, still compute a layout so that we can still compute the
                     // field offsets.
-                    None => Some(VariantIdx::new(0)),
+                    None => VariantIdx::new(0),
                 };
 
                 let is_struct = !def.is_enum() ||
@@ -791,7 +791,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     // Struct, or univariant enum equivalent to a struct.
                     // (Typechecking will reject discriminant-sizing attrs.)
 
-                    let v = present_first.unwrap();
+                    let v = present_first;
                     let kind = if def.is_enum() || variants[v].is_empty() {
                         StructKind::AlwaysSized
                     } else {

From fe1d7585a4464d1582b6a784f93682ed81a3c246 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 10 Jul 2020 14:53:48 -0700
Subject: [PATCH 37/66] Suggest borrowing unsized argument types

---
 src/librustc_middle/traits/mod.rs              |  2 +-
 src/librustc_middle/traits/structural_impls.rs |  2 +-
 .../traits/error_reporting/suggestions.rs      | 18 +++++++++++++++---
 src/librustc_typeck/check/expr.rs              |  2 +-
 src/librustc_typeck/check/mod.rs               |  5 +++--
 src/test/ui/issues/issue-38954.stderr          |  5 ++++-
 src/test/ui/issues/issue-41229-ref-str.stderr  |  5 ++++-
 src/test/ui/issues/issue-42312.stderr          | 10 ++++++++--
 8 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs
index fc37cb2504daa..db81dc19c08f4 100644
--- a/src/librustc_middle/traits/mod.rs
+++ b/src/librustc_middle/traits/mod.rs
@@ -215,7 +215,7 @@ pub enum ObligationCauseCode<'tcx> {
     /// Type of each variable must be `Sized`.
     VariableType(hir::HirId),
     /// Argument type must be `Sized`.
-    SizedArgumentType,
+    SizedArgumentType(Option<Span>),
     /// Return type must be `Sized`.
     SizedReturnType,
     /// Yield type must be `Sized`.
diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs
index faaa576f17903..e2a0e3dfa3057 100644
--- a/src/librustc_middle/traits/structural_impls.rs
+++ b/src/librustc_middle/traits/structural_impls.rs
@@ -151,7 +151,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
             super::VariableType(id) => Some(super::VariableType(id)),
             super::ReturnValue(id) => Some(super::ReturnValue(id)),
             super::ReturnType => Some(super::ReturnType),
-            super::SizedArgumentType => Some(super::SizedArgumentType),
+            super::SizedArgumentType(sp) => Some(super::SizedArgumentType(sp)),
             super::SizedReturnType => Some(super::SizedReturnType),
             super::SizedYieldType => Some(super::SizedYieldType),
             super::InlineAsmSized => Some(super::InlineAsmSized),
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index cdfe5f9f92db0..679721e7909a4 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -1823,9 +1823,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     err.help("unsized locals are gated as an unstable feature");
                 }
             }
-            ObligationCauseCode::SizedArgumentType => {
-                err.note("all function arguments must have a statically known size");
-                if !self.tcx.features().unsized_locals {
+            ObligationCauseCode::SizedArgumentType(sp) => {
+                if let Some(span) = sp {
+                    err.span_suggestion_verbose(
+                        span.shrink_to_lo(),
+                        "function arguments must have a statically known size, borrowed types \
+                         always have a known size",
+                        "&".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    err.note("all function arguments must have a statically known size");
+                }
+                if tcx.sess.opts.unstable_features.is_nightly_build()
+                    && !self.tcx.features().unsized_locals
+                {
                     err.help("unsized locals are gated as an unstable feature");
                 }
             }
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 1eaa5a6c31e20..2455e4aedb62f 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -487,7 +487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.require_type_is_sized_deferred(
                         input,
                         expr.span,
-                        traits::SizedArgumentType,
+                        traits::SizedArgumentType(None),
                     );
                 }
             }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index fa7360ce90051..aa768f1d251b5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1342,14 +1342,15 @@ fn check_fn<'a, 'tcx>(
     let inputs_fn = fn_sig.inputs().iter().copied();
     for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
         // Check the pattern.
-        fcx.check_pat_top(&param.pat, param_ty, try { inputs_hir?.get(idx)?.span }, false);
+        let ty_span = try { inputs_hir?.get(idx)?.span };
+        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
 
         // Check that argument is Sized.
         // The check for a non-trivial pattern is a hack to avoid duplicate warnings
         // for simple cases like `fn foo(x: Trait)`,
         // where we would error once on the parameter as a whole, and once on the binding `x`.
         if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
-            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType);
+            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
         }
 
         fcx.write_ty(param.hir_id, param_ty);
diff --git a/src/test/ui/issues/issue-38954.stderr b/src/test/ui/issues/issue-38954.stderr
index d3168ef9e4aaf..93133bc94bbcf 100644
--- a/src/test/ui/issues/issue-38954.stderr
+++ b/src/test/ui/issues/issue-38954.stderr
@@ -6,8 +6,11 @@ LL | fn _test(ref _p: str) {}
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn _test(ref _p: &str) {}
+   |                  ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-41229-ref-str.stderr b/src/test/ui/issues/issue-41229-ref-str.stderr
index 9d854e4be9ead..1b908ca49de43 100644
--- a/src/test/ui/issues/issue-41229-ref-str.stderr
+++ b/src/test/ui/issues/issue-41229-ref-str.stderr
@@ -6,8 +6,11 @@ LL | pub fn example(ref s: str) {}
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | pub fn example(ref s: &str) {}
+   |                       ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr
index 0d4797a7a0673..58eb3afee81de 100644
--- a/src/test/ui/issues/issue-42312.stderr
+++ b/src/test/ui/issues/issue-42312.stderr
@@ -6,12 +6,15 @@ LL |     fn baz(_: Self::Target) where Self: Deref {}
    |
    = help: the trait `std::marker::Sized` is not implemented for `<Self as std::ops::Deref>::Target`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 help: consider further restricting the associated type
    |
 LL |     fn baz(_: Self::Target) where Self: Deref, <Self as std::ops::Deref>::Target: std::marker::Sized {}
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     fn baz(_: &Self::Target) where Self: Deref {}
+   |               ^
 
 error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time
   --> $DIR/issue-42312.rs:8:10
@@ -21,8 +24,11 @@ LL | pub fn f(_: dyn ToString) {}
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | pub fn f(_: &dyn ToString) {}
+   |             ^
 
 error: aborting due to 2 previous errors
 

From 2185b0b7ab6c7ddfc3ac27a65a81c86d57bd2f53 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 10 Jul 2020 14:54:48 -0700
Subject: [PATCH 38/66] Point at type on E0275 instead of whole field

---
 src/librustc_typeck/check/wfcheck.rs            | 2 +-
 src/test/ui/traits/cycle-cache-err-60010.stderr | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index d1a86a7ee89a8..a641b881e3186 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -1326,7 +1326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .iter()
             .map(|field| {
                 let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id));
-                let field_ty = self.normalize_associated_types_in(field.span, &field_ty);
+                let field_ty = self.normalize_associated_types_in(field.ty.span, &field_ty);
                 let field_ty = self.resolve_vars_if_possible(&field_ty);
                 debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
                 AdtField { ty: field_ty, span: field.span }
diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr
index 3188ee83e7d39..324316ceaf6ba 100644
--- a/src/test/ui/traits/cycle-cache-err-60010.stderr
+++ b/src/test/ui/traits/cycle-cache-err-60010.stderr
@@ -1,8 +1,8 @@
 error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
-  --> $DIR/cycle-cache-err-60010.rs:27:5
+  --> $DIR/cycle-cache-err-60010.rs:27:13
    |
 LL |     _parse: <ParseQuery as Query<RootDatabase>>::Data,
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
 

From 689e360d8273ed13e433ce3e7ae1046e33894234 Mon Sep 17 00:00:00 2001
From: Dennis Hamester <dennis.hamester@gmail.com>
Date: Sat, 11 Jul 2020 09:26:26 +0200
Subject: [PATCH 39/66] test: rustdoc-ui: Add issue-74134, replacing
 test/rustdoc/issue-74134-*

As per the discussion in PR #74147, the 4 individual tests are replaced by a
single one.

The test is expanded to cover all 4 public/private cases, each with and without
--document-private-items.
---
 src/test/rustdoc-ui/issue-74134.public.stderr | 10 +++++++
 src/test/rustdoc-ui/issue-74134.rs            | 26 +++++++++++++++++++
 src/test/rustdoc/issue-74134-1.rs             | 10 -------
 src/test/rustdoc/issue-74134-2.rs             | 11 --------
 src/test/rustdoc/issue-74134-3.rs             | 11 --------
 src/test/rustdoc/issue-74134-4.rs             | 11 --------
 6 files changed, 36 insertions(+), 43 deletions(-)
 create mode 100644 src/test/rustdoc-ui/issue-74134.public.stderr
 create mode 100644 src/test/rustdoc-ui/issue-74134.rs
 delete mode 100644 src/test/rustdoc/issue-74134-1.rs
 delete mode 100644 src/test/rustdoc/issue-74134-2.rs
 delete mode 100644 src/test/rustdoc/issue-74134-3.rs
 delete mode 100644 src/test/rustdoc/issue-74134-4.rs

diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr
new file mode 100644
index 0000000000000..03f95f19d326e
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-74134.public.stderr
@@ -0,0 +1,10 @@
+warning: `[PrivateType]` public documentation for `public_item` links to a private item
+  --> $DIR/issue-74134.rs:19:10
+   |
+LL |     /// [`PrivateType`]
+   |          ^^^^^^^^^^^^^ this item is private
+   |
+   = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/issue-74134.rs b/src/test/rustdoc-ui/issue-74134.rs
new file mode 100644
index 0000000000000..d0747817580da
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-74134.rs
@@ -0,0 +1,26 @@
+// revisions: public private
+// [private]compile-flags: --document-private-items
+// check-pass
+
+// There are 4 cases here:
+// 1. public item  -> public type:  no warning
+// 2. public item  -> private type: warning, if --document-private-items is not passed
+// 3. private item -> public type:  no warning
+// 4. private item -> private type: no warning
+// All 4 cases are tested with and without --document-private-items.
+//
+// Case 4 without --document-private-items is the one described in issue #74134.
+
+struct PrivateType;
+pub struct PublicType;
+
+pub struct Public {
+    /// [`PublicType`]
+    /// [`PrivateType`]
+    //[public]~^ WARNING `[PrivateType]` public documentation for `public_item` links to a private item
+    pub public_item: u32,
+
+    /// [`PublicType`]
+    /// [`PrivateType`]
+    private_item: u32,
+}
diff --git a/src/test/rustdoc/issue-74134-1.rs b/src/test/rustdoc/issue-74134-1.rs
deleted file mode 100644
index 72d38638a794c..0000000000000
--- a/src/test/rustdoc/issue-74134-1.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![deny(intra_doc_link_resolution_failure)]
-
-// Linking from a private item to a private type is fine without --document-private-items.
-
-struct Private;
-
-pub struct Public {
-    /// [`Private`]
-    private: Private,
-}
diff --git a/src/test/rustdoc/issue-74134-2.rs b/src/test/rustdoc/issue-74134-2.rs
deleted file mode 100644
index f665e360b4982..0000000000000
--- a/src/test/rustdoc/issue-74134-2.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// compile-flags: --document-private-items
-#![deny(intra_doc_link_resolution_failure)]
-
-// Linking from a private item to a private type is fine with --document-private-items.
-
-struct Private;
-
-pub struct Public {
-    /// [`Private`]
-    private: Private,
-}
diff --git a/src/test/rustdoc/issue-74134-3.rs b/src/test/rustdoc/issue-74134-3.rs
deleted file mode 100644
index b2709ecdaddda..0000000000000
--- a/src/test/rustdoc/issue-74134-3.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// should-fail
-#![deny(intra_doc_link_resolution_failure)]
-
-// Linking from a public item to a private type fails without --document-private-items.
-
-struct Private;
-
-pub struct Public {
-    /// [`Private`]
-    pub public: u32,
-}
diff --git a/src/test/rustdoc/issue-74134-4.rs b/src/test/rustdoc/issue-74134-4.rs
deleted file mode 100644
index efff74f279721..0000000000000
--- a/src/test/rustdoc/issue-74134-4.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// compile-flags: --document-private-items
-#![deny(intra_doc_link_resolution_failure)]
-
-// Linking from a public item to a private type is fine with --document-private-items.
-
-struct Private;
-
-pub struct Public {
-    /// [`Private`]
-    pub public: u32,
-}

From b8632e15483420784e9f4b95c882d24839dbada9 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Sat, 11 Jul 2020 03:37:14 -0400
Subject: [PATCH 40/66] Removed FIXME

---
 src/libstd/io/buffered.rs | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index c8c9ee4a4b47c..03a9fb91e5d96 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -448,9 +448,6 @@ impl<R: Seek> Seek for BufReader<R> {
 /// [`flush`]: #method.flush
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
-    // FIXME: Can this just be W, instead of Option<W>? I don't see any code
-    // paths that lead to this being None, or that ever check if it IS none,
-    // even in drop implementations. #72925.
     inner: Option<W>,
     // FIXME: Replace this with a VecDeque. Because VecDeque is a Ring buffer,
     // this would enable BufWriter to operate without any interior copies.

From 140bfc58aa9d193aeca1cce905a00195f8f23f3b Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Sat, 11 Jul 2020 03:41:06 -0400
Subject: [PATCH 41/66] Removed another FIXME

---
 src/libstd/io/buffered.rs | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 03a9fb91e5d96..2f2a67b0be96d 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -449,12 +449,6 @@ impl<R: Seek> Seek for BufReader<R> {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
     inner: Option<W>,
-    // FIXME: Replace this with a VecDeque. Because VecDeque is a Ring buffer,
-    // this would enable BufWriter to operate without any interior copies.
-    // It was also allow a much simpler implementation of flush_buf. The main
-    // blocker here is that VecDeque doesn't currently have the same
-    // slice-specific specializations (extend_from_slice, `Extend`
-    // specializations)
     buf: Vec<u8>,
     // #30888: If the inner writer panics in a call to write, we don't want to
     // write the buffered data a second time in BufWriter's destructor. This

From 97048595e1e7bf3fc270ecf14ccaaac4cc71a241 Mon Sep 17 00:00:00 2001
From: Dennis Hamester <dennis.hamester@gmail.com>
Date: Sat, 11 Jul 2020 10:02:18 +0200
Subject: [PATCH 42/66] test: rustdoc-ui: Expand issue-74134 to cover types in
 a private module

---
 src/test/rustdoc-ui/issue-74134.rs | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/src/test/rustdoc-ui/issue-74134.rs b/src/test/rustdoc-ui/issue-74134.rs
index d0747817580da..ad6ace43071a3 100644
--- a/src/test/rustdoc-ui/issue-74134.rs
+++ b/src/test/rustdoc-ui/issue-74134.rs
@@ -24,3 +24,18 @@ pub struct Public {
     /// [`PrivateType`]
     private_item: u32,
 }
+
+// The following cases are identical to the ones above, except that they are in a private
+// module. Thus they all fall into cases 3 and 4 and should not produce a warning.
+
+mod private {
+    pub struct Public {
+        /// [`super::PublicType`]
+        /// [`super::PrivateType`]
+        pub public_item: u32,
+
+        /// [`super::PublicType`]
+        /// [`super::PrivateType`]
+        private_item: u32,
+    }
+}

From 87895251ea372a8a776a229c45dd703b4e5b22eb Mon Sep 17 00:00:00 2001
From: Dennis Hamester <dennis.hamester@gmail.com>
Date: Sat, 11 Jul 2020 10:31:27 +0200
Subject: [PATCH 43/66] test: rustdoc-ui: issue-74134: Shorten a too long line

---
 src/test/rustdoc-ui/issue-74134.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/rustdoc-ui/issue-74134.rs b/src/test/rustdoc-ui/issue-74134.rs
index ad6ace43071a3..d561c2dd89015 100644
--- a/src/test/rustdoc-ui/issue-74134.rs
+++ b/src/test/rustdoc-ui/issue-74134.rs
@@ -17,7 +17,7 @@ pub struct PublicType;
 pub struct Public {
     /// [`PublicType`]
     /// [`PrivateType`]
-    //[public]~^ WARNING `[PrivateType]` public documentation for `public_item` links to a private item
+    //[public]~^ WARNING public documentation for `public_item` links to a private
     pub public_item: u32,
 
     /// [`PublicType`]

From 0979545330689186dff27e22f539c1a06887981f Mon Sep 17 00:00:00 2001
From: Andy Russell <arussell123@gmail.com>
Date: Sun, 28 Jun 2020 18:20:06 -0400
Subject: [PATCH 44/66] rustdoc: insert newlines between attributes

---
 src/librustdoc/html/render.rs  | 21 +++++++++++++--------
 src/test/rustdoc/attributes.rs |  4 ++--
 2 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 8bba21a2e7ace..301896fd2c1ad 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -42,6 +42,7 @@ use std::str;
 use std::string::ToString;
 use std::sync::Arc;
 
+use itertools::Itertools;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::flock;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -3170,15 +3171,19 @@ const ALLOWED_ATTRIBUTES: &[Symbol] = &[
 //     bar: usize,
 // }
 fn render_attributes(w: &mut Buffer, it: &clean::Item, top: bool) {
-    let mut attrs = String::new();
-
-    for attr in &it.attrs.other_attrs {
-        if !ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
-            continue;
-        }
+    let attrs = it
+        .attrs
+        .other_attrs
+        .iter()
+        .filter_map(|attr| {
+            if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
+                Some(pprust::attribute_to_string(&attr))
+            } else {
+                None
+            }
+        })
+        .join("\n");
 
-        attrs.push_str(&pprust::attribute_to_string(&attr));
-    }
     if !attrs.is_empty() {
         write!(
             w,
diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs
index e9cd3514a07e2..54c5939f908d4 100644
--- a/src/test/rustdoc/attributes.rs
+++ b/src/test/rustdoc/attributes.rs
@@ -8,8 +8,8 @@ pub extern "C" fn f() {}
 #[export_name = "bar"]
 pub extern "C" fn g() {}
 
-// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[repr(i64)]'
-// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[must_use]'
+// @matches foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' \
+//      '(?m)\A#\[repr\(i64\)\]\n#\[must_use\]\Z'
 #[repr(i64)]
 #[must_use]
 pub enum Foo {

From 472843834491b28b8dda558c50da2763574b4839 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Sat, 11 Jul 2020 17:34:11 +0200
Subject: [PATCH 45/66] Improve wording

---
 src/librustc_error_codes/error_codes/E0718.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_error_codes/error_codes/E0718.md b/src/librustc_error_codes/error_codes/E0718.md
index bb401ef6e2d4c..1fe62ecf1f4e0 100644
--- a/src/librustc_error_codes/error_codes/E0718.md
+++ b/src/librustc_error_codes/error_codes/E0718.md
@@ -1,4 +1,4 @@
-A `#[lang = ".."]` attribute was placed on the wrong type of item.
+A `#[lang = ".."]` attribute was placed on the wrong item type.
 
 Erroneous code example:
 

From 997accc214f3a915541b06f3126568d367161882 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Sat, 11 Jul 2020 14:45:22 -0400
Subject: [PATCH 46/66] Remove doubled "is_write_vectored"

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

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 2f2a67b0be96d..597bad0c2eeba 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -1117,7 +1117,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     fn is_write_vectored(&self) -> bool {
         // It's hard to imagine these diverging, but it's worth checking
         // just in case, because we call `write_vectored` on both.
-        self.buffer.is_write_vectored() && self.inner().is_write_vectored()
+        self.buffer.is_write_vectored()
     }
 
     /// Write some data into this BufReader with line buffering. This means

From 13800269d788b5fc2a3fa2f9d586c05572f6f4e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 10 Jul 2020 15:13:49 -0700
Subject: [PATCH 47/66] Suggest boxing or borrowing unsized fields

---
 src/librustc_middle/traits/mod.rs             |   1 +
 .../traits/structural_impls.rs                |   4 +-
 .../traits/error_reporting/suggestions.rs     |  53 +++--
 src/librustc_typeck/check/wfcheck.rs          |   3 +-
 .../array-size-in-generic-struct-param.stderr |   4 +-
 src/test/ui/error-codes/E0478.stderr          |   4 +-
 ...-infer_static_outlives_requirements.stderr |   4 +-
 src/test/ui/issues/issue-19380.stderr         |   4 +-
 src/test/ui/issues/issue-22874.stderr         |   4 +-
 src/test/ui/issues/issue-27060-2.stderr       |  13 +-
 src/test/ui/issues/issue-35988.stderr         |   9 +
 .../issue-57739.stderr                        |   4 +-
 .../lifetime-doesnt-live-long-enough.stderr   |   4 +-
 ...unds-on-objects-and-type-parameters.stderr |   4 +-
 .../ui/regions/regions-wf-trait-object.stderr |   4 +-
 .../dont-infer-static.stderr                  |   4 +-
 ...adt-param-with-implicit-sized-bound.stderr |   4 +-
 .../trait-bounds-on-structs-and-enums.stderr  |  12 +-
 src/test/ui/union/union-sized-field.stderr    |  35 ++-
 src/test/ui/union/union-unsized.stderr        |  26 ++-
 src/test/ui/unsized/unsized-enum2.stderr      | 220 ++++++++++++++++--
 src/test/ui/unsized5.stderr                   |  74 +++++-
 src/test/ui/wf/wf-array-elem-sized.stderr     |   4 +-
 .../wf/wf-enum-fields-struct-variant.stderr   |   4 +-
 src/test/ui/wf/wf-in-fn-type-arg.stderr       |   4 +-
 src/test/ui/wf/wf-in-fn-type-ret.stderr       |   4 +-
 src/test/ui/wf/wf-in-fn-type-static.stderr    |   8 +-
 src/test/ui/wf/wf-in-obj-type-static.stderr   |   4 +-
 src/test/ui/wf/wf-in-obj-type-trait.stderr    |   4 +-
 src/test/ui/wf/wf-struct-field.stderr         |   4 +-
 30 files changed, 424 insertions(+), 106 deletions(-)

diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs
index db81dc19c08f4..c15c31a53f0c9 100644
--- a/src/librustc_middle/traits/mod.rs
+++ b/src/librustc_middle/traits/mod.rs
@@ -229,6 +229,7 @@ pub enum ObligationCauseCode<'tcx> {
     /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
     FieldSized {
         adt_kind: AdtKind,
+        span: Span,
         last: bool,
     },
 
diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs
index e2a0e3dfa3057..334462790edbc 100644
--- a/src/librustc_middle/traits/structural_impls.rs
+++ b/src/librustc_middle/traits/structural_impls.rs
@@ -156,7 +156,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
             super::SizedYieldType => Some(super::SizedYieldType),
             super::InlineAsmSized => Some(super::InlineAsmSized),
             super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
-            super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
+            super::FieldSized { adt_kind, span, last } => {
+                Some(super::FieldSized { adt_kind, span, last })
+            }
             super::ConstSized => Some(super::ConstSized),
             super::ConstPatternStructural => Some(super::ConstPatternStructural),
             super::SharedStatic => Some(super::SharedStatic),
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index 679721e7909a4..68124f72ad9d4 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -1856,26 +1856,43 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ObligationCauseCode::StructInitializerSized => {
                 err.note("structs must have a statically known size to be initialized");
             }
-            ObligationCauseCode::FieldSized { adt_kind: ref item, last } => match *item {
-                AdtKind::Struct => {
-                    if last {
-                        err.note(
-                            "the last field of a packed struct may only have a \
-                             dynamically sized type if it does not need drop to be run",
-                        );
-                    } else {
-                        err.note(
-                            "only the last field of a struct may have a dynamically sized type",
-                        );
+            ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => {
+                match *item {
+                    AdtKind::Struct => {
+                        if last {
+                            err.note(
+                                "the last field of a packed struct may only have a \
+                                dynamically sized type if it does not need drop to be run",
+                            );
+                        } else {
+                            err.note(
+                                "only the last field of a struct may have a dynamically sized type",
+                            );
+                        }
+                    }
+                    AdtKind::Union => {
+                        err.note("no field of a union may have a dynamically sized type");
+                    }
+                    AdtKind::Enum => {
+                        err.note("no field of an enum variant may have a dynamically sized type");
                     }
                 }
-                AdtKind::Union => {
-                    err.note("no field of a union may have a dynamically sized type");
-                }
-                AdtKind::Enum => {
-                    err.note("no field of an enum variant may have a dynamically sized type");
-                }
-            },
+                err.help("change the field's type to have a statically known size");
+                err.span_suggestion(
+                    span.shrink_to_lo(),
+                    "borrowed types always have a statically known size",
+                    "&".to_string(),
+                    Applicability::MachineApplicable,
+                );
+                err.multipart_suggestion(
+                    "heap allocated types always have a statically known size",
+                    vec![
+                        (span.shrink_to_lo(), "Box<".to_string()),
+                        (span.shrink_to_hi(), ">".to_string()),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            }
             ObligationCauseCode::ConstSized => {
                 err.note("constant expressions must have a statically known size");
             }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index a641b881e3186..19c556942afc1 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -394,6 +394,7 @@ fn check_type_defn<'tcx, F>(
                                 Some(i) => i,
                                 None => bug!(),
                             },
+                            span: field.span,
                             last,
                         },
                     ),
@@ -1329,7 +1330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let field_ty = self.normalize_associated_types_in(field.ty.span, &field_ty);
                 let field_ty = self.resolve_vars_if_possible(&field_ty);
                 debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
-                AdtField { ty: field_ty, span: field.span }
+                AdtField { ty: field_ty, span: field.ty.span }
             })
             .collect();
         AdtVariant { fields, explicit_discr: None }
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr
index 14cf64eeb7ac6..ad67a87265bd3 100644
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr
@@ -16,10 +16,10 @@ LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/array-size-in-generic-struct-param.rs:14:5
+  --> $DIR/array-size-in-generic-struct-param.rs:14:10
    |
 LL |     arr: [u8; CFG.arr_size],
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^
    |
    = note: this may fail depending on what value the parameter takes
 
diff --git a/src/test/ui/error-codes/E0478.stderr b/src/test/ui/error-codes/E0478.stderr
index 1380840e0db2d..38736de8d9ac7 100644
--- a/src/test/ui/error-codes/E0478.stderr
+++ b/src/test/ui/error-codes/E0478.stderr
@@ -1,8 +1,8 @@
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/E0478.rs:4:5
+  --> $DIR/E0478.rs:4:12
    |
 LL |     child: Box<dyn Wedding<'kiss> + 'SnowWhite>,
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'SnowWhite` as defined on the struct at 3:22
   --> $DIR/E0478.rs:3:22
diff --git a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr
index 2beeba8184a7d..987cde191cbb9 100644
--- a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr
+++ b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr
@@ -1,10 +1,10 @@
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:5
+  --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:10
    |
 LL | struct Foo<U> {
    |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
-   |     ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-19380.stderr b/src/test/ui/issues/issue-19380.stderr
index 0a080171a7951..63f0701974b8b 100644
--- a/src/test/ui/issues/issue-19380.stderr
+++ b/src/test/ui/issues/issue-19380.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Qiz` cannot be made into an object
-  --> $DIR/issue-19380.rs:11:3
+  --> $DIR/issue-19380.rs:11:9
    |
 LL | trait Qiz {
    |       --- this trait cannot be made into an object...
@@ -7,7 +7,7 @@ LL |   fn qiz();
    |      --- ...because associated function `qiz` has no `self` parameter
 ...
 LL |   foos: &'static [&'static (dyn Qiz + 'static)]
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object
    |
 help: consider turning `qiz` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
    |
diff --git a/src/test/ui/issues/issue-22874.stderr b/src/test/ui/issues/issue-22874.stderr
index 229f99f90640b..9a74bc0313169 100644
--- a/src/test/ui/issues/issue-22874.stderr
+++ b/src/test/ui/issues/issue-22874.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the size for values of type `[std::string::String]` cannot be known at compilation time
-  --> $DIR/issue-22874.rs:2:5
+  --> $DIR/issue-22874.rs:2:11
    |
 LL |     rows: [[String]],
-   |     ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |           ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[std::string::String]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr
index 1ddea73e00ae0..8b64128fb01da 100644
--- a/src/test/ui/issues/issue-27060-2.stderr
+++ b/src/test/ui/issues/issue-27060-2.stderr
@@ -1,14 +1,23 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/issue-27060-2.rs:3:5
+  --> $DIR/issue-27060-2.rs:3:11
    |
 LL | pub struct Bad<T: ?Sized> {
    |                - this type parameter needs to be `std::marker::Sized`
 LL |     data: T,
-   |     ^^^^^^^ doesn't have a size known at compile-time
+   |           ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     data: &T,
+   |           ^
+help: heap allocated types always have a statically known size
+   |
+LL |     data: Box<T>,
+   |           ^^^^ ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-35988.stderr b/src/test/ui/issues/issue-35988.stderr
index 825c0de5e53ea..52660eb7cdac9 100644
--- a/src/test/ui/issues/issue-35988.stderr
+++ b/src/test/ui/issues/issue-35988.stderr
@@ -7,6 +7,15 @@ LL |     V([Box<E>]),
    = help: the trait `std::marker::Sized` is not implemented for `[std::boxed::Box<E>]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     V(&[Box<E>]),
+   |       ^
+help: heap allocated types always have a statically known size
+   |
+LL |     V(Box<[Box<E>]>),
+   |       ^^^^        ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lazy_normalization_consts/issue-57739.stderr b/src/test/ui/lazy_normalization_consts/issue-57739.stderr
index 1987f5890c041..ce0495dd8b0cb 100644
--- a/src/test/ui/lazy_normalization_consts/issue-57739.stderr
+++ b/src/test/ui/lazy_normalization_consts/issue-57739.stderr
@@ -8,10 +8,10 @@ LL | #![feature(lazy_normalization_consts)]
    = note: see issue #72219 <https://github.com/rust-lang/rust/issues/72219> for more information
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-57739.rs:12:5
+  --> $DIR/issue-57739.rs:12:12
    |
 LL |     array: [u8; T::SIZE],
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^
    |
    = note: this may fail depending on what value the parameter takes
 
diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
index d682478db0eef..e5083e3a088b6 100644
--- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
+++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
@@ -1,10 +1,10 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:19:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:19:10
    |
 LL | struct Foo<T> {
    |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     foo: &'static T
-   |     ^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |          ^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
 
 error[E0309]: the parameter type `K` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19
diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
index ea9be77a3e8b5..22586b5de91ff 100644
--- a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
+++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
@@ -5,10 +5,10 @@ LL |     z: Box<dyn Is<'a>+'b+'c>,
    |                          ^^
 
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:5
+  --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:8
    |
 LL |     z: Box<dyn Is<'a>+'b+'c>,
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 11:15
   --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:15
diff --git a/src/test/ui/regions/regions-wf-trait-object.stderr b/src/test/ui/regions/regions-wf-trait-object.stderr
index 9f39508604110..1ddbf73a46372 100644
--- a/src/test/ui/regions/regions-wf-trait-object.stderr
+++ b/src/test/ui/regions/regions-wf-trait-object.stderr
@@ -1,8 +1,8 @@
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/regions-wf-trait-object.rs:7:5
+  --> $DIR/regions-wf-trait-object.rs:7:8
    |
 LL |     x: Box<dyn TheTrait<'a>+'b>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 6:15
   --> $DIR/regions-wf-trait-object.rs:6:15
diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr
index 2bb51731583a6..a449fac11930d 100644
--- a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr
@@ -1,10 +1,10 @@
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/dont-infer-static.rs:8:5
+  --> $DIR/dont-infer-static.rs:8:10
    |
 LL | struct Foo<U> {
    |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
-   |     ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
index ee08f51f80270..03877e60e2b72 100644
--- a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
+++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/adt-param-with-implicit-sized-bound.rs:25:5
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:25:9
    |
 LL | struct X<T>(T);
    |          - required by this bound in `X`
@@ -7,7 +7,7 @@ LL | struct X<T>(T);
 LL | struct Struct5<T: ?Sized>{
    |                - this type parameter needs to be `std::marker::Sized`
 LL |     _t: X<T>,
-   |     ^^^^^^^^ doesn't have a size known at compile-time
+   |         ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr
index 271ed07ce42ab..d7549835a0905 100644
--- a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr
+++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr
@@ -13,13 +13,13 @@ LL | impl<T: Trait> Foo<T> {
    |       ^^^^^^^
 
 error[E0277]: the trait bound `isize: Trait` is not satisfied
-  --> $DIR/trait-bounds-on-structs-and-enums.rs:19:5
+  --> $DIR/trait-bounds-on-structs-and-enums.rs:19:8
    |
 LL | struct Foo<T:Trait> {
    |              ----- required by this bound in `Foo`
 ...
 LL |     a: Foo<isize>,
-   |     ^^^^^^^^^^^^^ the trait `Trait` is not implemented for `isize`
+   |        ^^^^^^^^^^ the trait `Trait` is not implemented for `isize`
 
 error[E0277]: the trait bound `usize: Trait` is not satisfied
   --> $DIR/trait-bounds-on-structs-and-enums.rs:23:10
@@ -31,13 +31,13 @@ LL |     Quux(Bar<usize>),
    |          ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
 
 error[E0277]: the trait bound `U: Trait` is not satisfied
-  --> $DIR/trait-bounds-on-structs-and-enums.rs:27:5
+  --> $DIR/trait-bounds-on-structs-and-enums.rs:27:8
    |
 LL | struct Foo<T:Trait> {
    |              ----- required by this bound in `Foo`
 ...
 LL |     b: Foo<U>,
-   |     ^^^^^^^^^ the trait `Trait` is not implemented for `U`
+   |        ^^^^^^ the trait `Trait` is not implemented for `U`
    |
 help: consider restricting type parameter `U`
    |
@@ -68,13 +68,13 @@ LL |     Foo<i32>,
    |     ^^^^^^^^ the trait `Trait` is not implemented for `i32`
 
 error[E0277]: the trait bound `u8: Trait` is not satisfied
-  --> $DIR/trait-bounds-on-structs-and-enums.rs:39:22
+  --> $DIR/trait-bounds-on-structs-and-enums.rs:39:29
    |
 LL | enum Bar<T:Trait> {
    |            ----- required by this bound in `Bar`
 ...
 LL |     DictionaryLike { field: Bar<u8> },
-   |                      ^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u8`
+   |                             ^^^^^^^ the trait `Trait` is not implemented for `u8`
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr
index 62dacd064bed0..1bfc44e3eec62 100644
--- a/src/test/ui/union/union-sized-field.stderr
+++ b/src/test/ui/union/union-sized-field.stderr
@@ -1,26 +1,44 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/union-sized-field.rs:4:5
+  --> $DIR/union-sized-field.rs:4:12
    |
 LL | union Foo<T: ?Sized> {
    |           - this type parameter needs to be `std::marker::Sized`
 LL |     value: T,
-   |     ^^^^^^^^ doesn't have a size known at compile-time
+   |            ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     value: &T,
+   |            ^
+help: heap allocated types always have a statically known size
+   |
+LL |     value: Box<T>,
+   |            ^^^^ ^
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/union-sized-field.rs:9:5
+  --> $DIR/union-sized-field.rs:9:12
    |
 LL | struct Foo2<T: ?Sized> {
    |             - this type parameter needs to be `std::marker::Sized`
 LL |     value: T,
-   |     ^^^^^^^^ doesn't have a size known at compile-time
+   |            ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     value: &T,
+   |            ^
+help: heap allocated types always have a statically known size
+   |
+LL |     value: Box<T>,
+   |            ^^^^ ^
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/union-sized-field.rs:15:11
@@ -33,6 +51,15 @@ LL |     Value(T),
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     Value(&T),
+   |           ^
+help: heap allocated types always have a statically known size
+   |
+LL |     Value(Box<T>),
+   |           ^^^^ ^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/union/union-unsized.stderr b/src/test/ui/union/union-unsized.stderr
index e702f2c61bee3..442ea83f80168 100644
--- a/src/test/ui/union/union-unsized.stderr
+++ b/src/test/ui/union/union-unsized.stderr
@@ -1,22 +1,40 @@
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:4:5
+  --> $DIR/union-unsized.rs:4:8
    |
 LL |     a: str,
-   |     ^^^^^^ doesn't have a size known at compile-time
+   |        ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     a: &str,
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     a: Box<str>,
+   |        ^^^^   ^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:12:5
+  --> $DIR/union-unsized.rs:12:8
    |
 LL |     b: str,
-   |     ^^^^^^ doesn't have a size known at compile-time
+   |        ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     b: &str,
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     b: Box<str>,
+   |        ^^^^   ^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr
index bc3b3831f3269..fb89a6f45d234 100644
--- a/src/test/ui/unsized/unsized-enum2.stderr
+++ b/src/test/ui/unsized/unsized-enum2.stderr
@@ -10,19 +10,37 @@ LL |     VA(W),
    = help: the trait `std::marker::Sized` is not implemented for `W`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VA(&W),
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VA(Box<W>),
+   |        ^^^^ ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:25:8
+  --> $DIR/unsized-enum2.rs:25:11
    |
 LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
    |                   - this type parameter needs to be `std::marker::Sized`
 ...
 LL |     VB{x: X},
-   |        ^^^^ doesn't have a size known at compile-time
+   |           ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VB{x: &X},
+   |           ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VB{x: Box<X>},
+   |           ^^^^ ^
 
 error[E0277]: the size for values of type `Y` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:27:15
@@ -36,19 +54,37 @@ LL |     VC(isize, Y),
    = help: the trait `std::marker::Sized` is not implemented for `Y`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VC(isize, &Y),
+   |               ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VC(isize, Box<Y>),
+   |               ^^^^ ^
 
 error[E0277]: the size for values of type `Z` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:29:18
+  --> $DIR/unsized-enum2.rs:29:21
    |
 LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
    |                                         - this type parameter needs to be `std::marker::Sized`
 ...
 LL |     VD{u: isize, x: Z},
-   |                  ^^^^ doesn't have a size known at compile-time
+   |                     ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Z`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VD{u: isize, x: &Z},
+   |                     ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VD{u: isize, x: Box<Z>},
+   |                     ^^^^ ^
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:33:8
@@ -59,16 +95,34 @@ LL |     VE([u8]),
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VE(&[u8]),
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VE(Box<[u8]>),
+   |        ^^^^    ^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:35:8
+  --> $DIR/unsized-enum2.rs:35:11
    |
 LL |     VF{x: str},
-   |        ^^^^^^ doesn't have a size known at compile-time
+   |           ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VF{x: &str},
+   |           ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VF{x: Box<str>},
+   |           ^^^^   ^
 
 error[E0277]: the size for values of type `[f32]` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:37:15
@@ -79,16 +133,34 @@ LL |     VG(isize, [f32]),
    = help: the trait `std::marker::Sized` is not implemented for `[f32]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VG(isize, &[f32]),
+   |               ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VG(isize, Box<[f32]>),
+   |               ^^^^     ^
 
 error[E0277]: the size for values of type `[u32]` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:39:18
+  --> $DIR/unsized-enum2.rs:39:21
    |
 LL |     VH{u: isize, x: [u32]},
-   |                  ^^^^^^^^ doesn't have a size known at compile-time
+   |                     ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u32]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VH{u: isize, x: &[u32]},
+   |                     ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VH{u: isize, x: Box<[u32]>},
+   |                     ^^^^     ^
 
 error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:53:8
@@ -99,16 +171,34 @@ LL |     VM(dyn Foo),
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VM(&dyn Foo),
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VM(Box<dyn Foo>),
+   |        ^^^^       ^
 
 error[E0277]: the size for values of type `(dyn Bar + 'static)` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:55:8
+  --> $DIR/unsized-enum2.rs:55:11
    |
 LL |     VN{x: dyn Bar},
-   |        ^^^^^^^^^^ doesn't have a size known at compile-time
+   |           ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Bar + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VN{x: &dyn Bar},
+   |           ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VN{x: Box<dyn Bar>},
+   |           ^^^^       ^
 
 error[E0277]: the size for values of type `(dyn FooBar + 'static)` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:57:15
@@ -119,16 +209,34 @@ LL |     VO(isize, dyn FooBar),
    = help: the trait `std::marker::Sized` is not implemented for `(dyn FooBar + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VO(isize, &dyn FooBar),
+   |               ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VO(isize, Box<dyn FooBar>),
+   |               ^^^^          ^
 
 error[E0277]: the size for values of type `(dyn BarFoo + 'static)` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:59:18
+  --> $DIR/unsized-enum2.rs:59:21
    |
 LL |     VP{u: isize, x: dyn BarFoo},
-   |                  ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                     ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn BarFoo + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VP{u: isize, x: &dyn BarFoo},
+   |                     ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VP{u: isize, x: Box<dyn BarFoo>},
+   |                     ^^^^          ^
 
 error[E0277]: the size for values of type `[i8]` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:63:8
@@ -139,16 +247,34 @@ LL |     VQ(<&'static [i8] as Deref>::Target),
    = help: the trait `std::marker::Sized` is not implemented for `[i8]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VQ(&<&'static [i8] as Deref>::Target),
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VQ(Box<<&'static [i8] as Deref>::Target>),
+   |        ^^^^                                ^
 
 error[E0277]: the size for values of type `[char]` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:65:8
+  --> $DIR/unsized-enum2.rs:65:11
    |
 LL |     VR{x: <&'static [char] as Deref>::Target},
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[char]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VR{x: &<&'static [char] as Deref>::Target},
+   |           ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VR{x: Box<<&'static [char] as Deref>::Target>},
+   |           ^^^^                                  ^
 
 error[E0277]: the size for values of type `[f64]` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:67:15
@@ -159,16 +285,34 @@ LL |     VS(isize, <&'static [f64] as Deref>::Target),
    = help: the trait `std::marker::Sized` is not implemented for `[f64]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VS(isize, &<&'static [f64] as Deref>::Target),
+   |               ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VS(isize, Box<<&'static [f64] as Deref>::Target>),
+   |               ^^^^                                 ^
 
 error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:69:18
+  --> $DIR/unsized-enum2.rs:69:21
    |
 LL |     VT{u: isize, x: <&'static [i32] as Deref>::Target},
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i32]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VT{u: isize, x: &<&'static [i32] as Deref>::Target},
+   |                     ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VT{u: isize, x: Box<<&'static [i32] as Deref>::Target>},
+   |                     ^^^^                                 ^
 
 error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:43:8
@@ -180,17 +324,35 @@ LL |     VI(Path1),
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path1`
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VI(&Path1),
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VI(Box<Path1>),
+   |        ^^^^     ^
 
 error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:45:8
+  --> $DIR/unsized-enum2.rs:45:11
    |
 LL |     VJ{x: Path2},
-   |        ^^^^^^^^ doesn't have a size known at compile-time
+   |           ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper2 + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path2`
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VJ{x: &Path2},
+   |           ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VJ{x: Box<Path2>},
+   |           ^^^^     ^
 
 error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:47:15
@@ -202,17 +364,35 @@ LL |     VK(isize, Path3),
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path3`
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VK(isize, &Path3),
+   |               ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VK(isize, Box<Path3>),
+   |               ^^^^     ^
 
 error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:49:18
+  --> $DIR/unsized-enum2.rs:49:21
    |
 LL |     VL{u: isize, x: Path4},
-   |                  ^^^^^^^^ doesn't have a size known at compile-time
+   |                     ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper4 + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path4`
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VL{u: isize, x: &Path4},
+   |                     ^
+help: heap allocated types always have a statically known size
+   |
+LL |     VL{u: isize, x: Box<Path4>},
+   |                     ^^^^     ^
 
 error: aborting due to 20 previous errors
 
diff --git a/src/test/ui/unsized5.stderr b/src/test/ui/unsized5.stderr
index de4da309791c0..3eef1f4f6771e 100644
--- a/src/test/ui/unsized5.stderr
+++ b/src/test/ui/unsized5.stderr
@@ -1,47 +1,83 @@
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized5.rs:4:5
+  --> $DIR/unsized5.rs:4:9
    |
 LL | struct S1<X: ?Sized> {
    |           - this type parameter needs to be `std::marker::Sized`
 LL |     f1: X,
-   |     ^^^^^ doesn't have a size known at compile-time
+   |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     f1: &X,
+   |         ^
+help: heap allocated types always have a statically known size
+   |
+LL |     f1: Box<X>,
+   |         ^^^^ ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized5.rs:10:5
+  --> $DIR/unsized5.rs:10:8
    |
 LL | struct S2<X: ?Sized> {
    |           - this type parameter needs to be `std::marker::Sized`
 LL |     f: isize,
 LL |     g: X,
-   |     ^^^^ doesn't have a size known at compile-time
+   |        ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     g: &X,
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     g: Box<X>,
+   |        ^^^^ ^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/unsized5.rs:15:5
+  --> $DIR/unsized5.rs:15:8
    |
 LL |     f: str,
-   |     ^^^^^^ doesn't have a size known at compile-time
+   |        ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     f: &str,
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     f: Box<str>,
+   |        ^^^^   ^
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/unsized5.rs:20:5
+  --> $DIR/unsized5.rs:20:8
    |
 LL |     f: [u8],
-   |     ^^^^^^^ doesn't have a size known at compile-time
+   |        ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     f: &[u8],
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     f: Box<[u8]>,
+   |        ^^^^    ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized5.rs:25:8
@@ -54,18 +90,36 @@ LL |     V1(X, isize),
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     V1(&X, isize),
+   |        ^
+help: heap allocated types always have a statically known size
+   |
+LL |     V1(Box<X>, isize),
+   |        ^^^^ ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized5.rs:29:8
+  --> $DIR/unsized5.rs:29:12
    |
 LL | enum F<X: ?Sized> {
    |        - this type parameter needs to be `std::marker::Sized`
 LL |     V2{f1: X, f: isize},
-   |        ^^^^^ doesn't have a size known at compile-time
+   |            ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     V2{f1: &X, f: isize},
+   |            ^
+help: heap allocated types always have a statically known size
+   |
+LL |     V2{f1: Box<X>, f: isize},
+   |            ^^^^ ^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/wf/wf-array-elem-sized.stderr b/src/test/ui/wf/wf-array-elem-sized.stderr
index b222d07580eaf..b424c9f3ac981 100644
--- a/src/test/ui/wf/wf-array-elem-sized.stderr
+++ b/src/test/ui/wf/wf-array-elem-sized.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/wf-array-elem-sized.rs:7:5
+  --> $DIR/wf-array-elem-sized.rs:7:10
    |
 LL |     foo: [[u8]],
-   |     ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |          ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
diff --git a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr
index 0a3665fcf0436..1eb7010c77a79 100644
--- a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr
+++ b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied
-  --> $DIR/wf-enum-fields-struct-variant.rs:13:9
+  --> $DIR/wf-enum-fields-struct-variant.rs:13:12
    |
 LL | struct IsCopy<T:Copy> {
    |                 ---- required by this bound in `IsCopy`
 ...
 LL |         f: IsCopy<A>
-   |         ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
+   |            ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
    |
 help: consider restricting type parameter `A`
    |
diff --git a/src/test/ui/wf/wf-in-fn-type-arg.stderr b/src/test/ui/wf/wf-in-fn-type-arg.stderr
index c0bb3a50b1f1e..212c61e1e5e07 100644
--- a/src/test/ui/wf/wf-in-fn-type-arg.stderr
+++ b/src/test/ui/wf/wf-in-fn-type-arg.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
-  --> $DIR/wf-in-fn-type-arg.rs:9:5
+  --> $DIR/wf-in-fn-type-arg.rs:9:8
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ---- required by this bound in `MustBeCopy`
 ...
 LL |     x: fn(MustBeCopy<T>)
-   |     ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |        ^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/wf/wf-in-fn-type-ret.stderr b/src/test/ui/wf/wf-in-fn-type-ret.stderr
index e203058250790..3fb05fe81763b 100644
--- a/src/test/ui/wf/wf-in-fn-type-ret.stderr
+++ b/src/test/ui/wf/wf-in-fn-type-ret.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
-  --> $DIR/wf-in-fn-type-ret.rs:9:5
+  --> $DIR/wf-in-fn-type-ret.rs:9:8
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ---- required by this bound in `MustBeCopy`
 ...
 LL |     x: fn() -> MustBeCopy<T>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |        ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/wf/wf-in-fn-type-static.stderr b/src/test/ui/wf/wf-in-fn-type-static.stderr
index a79c446247794..44cacf4ef4dfe 100644
--- a/src/test/ui/wf/wf-in-fn-type-static.stderr
+++ b/src/test/ui/wf/wf-in-fn-type-static.stderr
@@ -1,20 +1,20 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/wf-in-fn-type-static.rs:13:5
+  --> $DIR/wf-in-fn-type-static.rs:13:8
    |
 LL | struct Foo<T> {
    |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // needs T: 'static
 LL |     x: fn() -> &'static T
-   |     ^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |        ^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/wf-in-fn-type-static.rs:18:5
+  --> $DIR/wf-in-fn-type-static.rs:18:8
    |
 LL | struct Bar<T> {
    |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // needs T: Copy
 LL |     x: fn(&'static T)
-   |     ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |        ^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/wf/wf-in-obj-type-static.stderr b/src/test/ui/wf/wf-in-obj-type-static.stderr
index c0057f3c82977..c50a6bb6e4d87 100644
--- a/src/test/ui/wf/wf-in-obj-type-static.stderr
+++ b/src/test/ui/wf/wf-in-obj-type-static.stderr
@@ -1,11 +1,11 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/wf-in-obj-type-static.rs:14:5
+  --> $DIR/wf-in-obj-type-static.rs:14:8
    |
 LL | struct Foo<T> {
    |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // needs T: 'static
 LL |     x: dyn Object<&'static T>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |        ^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-in-obj-type-trait.stderr b/src/test/ui/wf/wf-in-obj-type-trait.stderr
index 6d85cdde7f991..129f9484df29b 100644
--- a/src/test/ui/wf/wf-in-obj-type-trait.stderr
+++ b/src/test/ui/wf/wf-in-obj-type-trait.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
-  --> $DIR/wf-in-obj-type-trait.rs:11:5
+  --> $DIR/wf-in-obj-type-trait.rs:11:8
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ---- required by this bound in `MustBeCopy`
 ...
 LL |     x: dyn Object<MustBeCopy<T>>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/wf/wf-struct-field.stderr b/src/test/ui/wf/wf-struct-field.stderr
index cda3b8fe4fddb..d7d0b7a0820a8 100644
--- a/src/test/ui/wf/wf-struct-field.stderr
+++ b/src/test/ui/wf/wf-struct-field.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied
-  --> $DIR/wf-struct-field.rs:12:5
+  --> $DIR/wf-struct-field.rs:12:11
    |
 LL | struct IsCopy<T:Copy> {
    |                 ---- required by this bound in `IsCopy`
 ...
 LL |     data: IsCopy<A>
-   |     ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
+   |           ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
    |
 help: consider restricting type parameter `A`
    |

From 675507613237f18aa54cb1a4a2343e0a47628065 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 10 Jul 2020 16:05:35 -0700
Subject: [PATCH 48/66] Remove `Sized` `on_unimplemented` note

---
 src/libcore/marker.rs                         |  5 +----
 src/test/ui/asm/type-check-1.stderr           |  3 ---
 .../associated-types-unsized.stderr           |  1 -
 .../defaults-suitability.stderr               |  1 -
 .../ui/associated-types/issue-63593.stderr    |  1 -
 ...with-supertraits-needing-sized-self.stderr |  1 -
 .../issue-72590-type-error-sized.stderr       |  1 -
 src/test/ui/bad/bad-sized.stderr              |  2 --
 src/test/ui/box-into-boxed-slice-fail.stderr  |  4 ----
 src/test/ui/chalkify/impl_wf.stderr           |  1 -
 src/test/ui/consts/const-unsized.stderr       |  4 ----
 src/test/ui/dst/dst-bad-assign-2.stderr       |  1 -
 src/test/ui/dst/dst-bad-assign-3.stderr       |  1 -
 src/test/ui/dst/dst-bad-assign.stderr         |  1 -
 src/test/ui/dst/dst-bad-deep-2.stderr         |  1 -
 src/test/ui/dst/dst-bad-deep.stderr           |  1 -
 .../dst/dst-object-from-unsized-type.stderr   |  4 ----
 src/test/ui/dst/dst-sized-trait-param.stderr  |  2 --
 src/test/ui/error-codes/E0277.stderr          |  3 +--
 .../ui/extern/extern-types-unsized.stderr     |  4 ----
 .../issue-36122-accessing-externed-dst.stderr |  1 -
 .../feature-gate-trivial_bounds.stderr        |  3 ---
 .../feature-gate-unsized_locals.stderr        |  1 -
 src/test/ui/generator/sized-yield.stderr      |  2 --
 ...e-param-can-reference-self-in-trait.stderr |  1 -
 ...n-trait-return-should-be-impl-trait.stderr |  2 --
 src/test/ui/issues/issue-10412.stderr         |  1 -
 src/test/ui/issues/issue-14366.stderr         |  1 -
 src/test/ui/issues/issue-15756.stderr         |  1 -
 src/test/ui/issues/issue-17651.stderr         |  2 --
 src/test/ui/issues/issue-18919.stderr         |  1 -
 src/test/ui/issues/issue-20005.stderr         |  1 -
 src/test/ui/issues/issue-20433.stderr         |  1 -
 src/test/ui/issues/issue-20605.stderr         |  1 -
 src/test/ui/issues/issue-22874.stderr         |  1 -
 src/test/ui/issues/issue-23281.stderr         |  1 -
 src/test/ui/issues/issue-24446.stderr         |  1 -
 src/test/ui/issues/issue-27060-2.stderr       |  1 -
 src/test/ui/issues/issue-27078.stderr         |  1 -
 src/test/ui/issues/issue-30355.stderr         |  1 -
 src/test/ui/issues/issue-35988.stderr         |  1 -
 src/test/ui/issues/issue-38954.stderr         |  1 -
 src/test/ui/issues/issue-41229-ref-str.stderr |  1 -
 src/test/ui/issues/issue-42312.stderr         |  2 --
 src/test/ui/issues/issue-54410.stderr         |  1 -
 src/test/ui/issues/issue-5883.stderr          |  2 --
 src/test/ui/issues/issue-65673.stderr         |  1 -
 ...ture-gate-lazy_normalization_consts.stderr |  1 -
 .../ui/mismatched_types/cast-rfc0401.stderr   |  2 --
 src/test/ui/range/range-1.stderr              |  1 -
 src/test/ui/resolve/issue-5035-2.stderr       |  1 -
 src/test/ui/str/str-array-assignment.stderr   |  1 -
 src/test/ui/str/str-mut-idx.stderr            |  2 --
 src/test/ui/substs-ppaux.normal.stderr        |  1 -
 src/test/ui/substs-ppaux.verbose.stderr       |  1 -
 ...adt-param-with-implicit-sized-bound.stderr |  5 -----
 src/test/ui/suggestions/path-by-value.stderr  |  3 +--
 .../trait-bounds-not-on-bare-trait.stderr     |  1 -
 .../traits/trait-suggest-where-clause.stderr  |  4 ----
 .../trivial-bounds/trivial-bounds-leak.stderr |  1 -
 src/test/ui/union/union-sized-field.stderr    |  3 ---
 src/test/ui/union/union-unsized.stderr        |  2 --
 .../issue-30276-feature-flagged.stderr        |  1 -
 src/test/ui/unsized-locals/issue-30276.stderr |  1 -
 .../issue-50940-with-feature.stderr           |  1 -
 src/test/ui/unsized-locals/issue-50940.stderr |  1 -
 .../ui/unsized-locals/unsized-exprs.stderr    |  3 ---
 .../ui/unsized-locals/unsized-exprs3.stderr   |  1 -
 .../ui/unsized/unsized-bare-typaram.stderr    |  1 -
 src/test/ui/unsized/unsized-enum.stderr       |  1 -
 src/test/ui/unsized/unsized-enum2.stderr      | 20 -------------------
 src/test/ui/unsized/unsized-fn-param.stderr   |  4 ----
 .../unsized-inherent-impl-self-type.stderr    |  1 -
 src/test/ui/unsized/unsized-struct.stderr     |  2 --
 .../unsized-trait-impl-self-type.stderr       |  1 -
 .../unsized-trait-impl-trait-arg.stderr       |  1 -
 src/test/ui/unsized3.stderr                   |  6 ------
 src/test/ui/unsized5.stderr                   |  6 ------
 src/test/ui/unsized6.stderr                   | 13 ------------
 src/test/ui/unsized7.stderr                   |  1 -
 src/test/ui/wf/wf-array-elem-sized.stderr     |  1 -
 src/test/ui/wf/wf-fn-where-clause.stderr      |  1 -
 82 files changed, 3 insertions(+), 169 deletions(-)

diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index fdcfae8530a3b..6ddd41a26f122 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -84,11 +84,8 @@ impl<T: ?Sized> !Send for *mut T {}
 #[stable(feature = "rust1", since = "1.0.0")]
 #[lang = "sized"]
 #[rustc_on_unimplemented(
-    on(parent_trait = "std::path::Path", label = "borrow the `Path` instead"),
     message = "the size for values of type `{Self}` cannot be known at compilation time",
-    label = "doesn't have a size known at compile-time",
-    note = "to learn more, visit <https://doc.rust-lang.org/book/\
-            ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>"
+    label = "doesn't have a size known at compile-time"
 )]
 #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
 #[rustc_specialization_trait]
diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr
index 7c9c041f45784..1f11d19c70ea2 100644
--- a/src/test/ui/asm/type-check-1.stderr
+++ b/src/test/ui/asm/type-check-1.stderr
@@ -17,7 +17,6 @@ LL |         asm!("{}", in(reg) v[..]);
    |                            ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u64]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all inline asm arguments must have a statically known size
 
 error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
@@ -27,7 +26,6 @@ LL |         asm!("{}", out(reg) v[..]);
    |                             ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u64]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all inline asm arguments must have a statically known size
 
 error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
@@ -37,7 +35,6 @@ LL |         asm!("{}", inout(reg) v[..]);
    |                               ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u64]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all inline asm arguments must have a statically known size
 
 error: aborting due to 5 previous errors
diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr
index 6daba54ac6969..e96d0e0eff719 100644
--- a/src/test/ui/associated-types/associated-types-unsized.stderr
+++ b/src/test/ui/associated-types/associated-types-unsized.stderr
@@ -5,7 +5,6 @@ LL |     let x = t.get();
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `<T as Get>::Value`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 help: consider further restricting the associated type
diff --git a/src/test/ui/associated-types/defaults-suitability.stderr b/src/test/ui/associated-types/defaults-suitability.stderr
index 8676c1fa22319..de0acc88324a5 100644
--- a/src/test/ui/associated-types/defaults-suitability.stderr
+++ b/src/test/ui/associated-types/defaults-suitability.stderr
@@ -139,7 +139,6 @@ LL | pub struct Vec<T> {
    |                - required by this bound in `std::vec::Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr
index 82e76ff0b7cb5..c3db950c75844 100644
--- a/src/test/ui/associated-types/issue-63593.stderr
+++ b/src/test/ui/associated-types/issue-63593.stderr
@@ -7,7 +7,6 @@ LL |     type This = Self;
    |     ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL | trait MyTrait: std::marker::Sized {
diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
index a37573dffff44..f2ed2d32bd1e0 100644
--- a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
+++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
@@ -10,7 +10,6 @@ LL | pub trait Add<Rhs = Self> {
    |               --- required by this bound in `std::ops::Add`
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + std::marker::Sized {}
diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.stderr b/src/test/ui/async-await/issue-72590-type-error-sized.stderr
index 603895b598c16..95ed9513f357b 100644
--- a/src/test/ui/async-await/issue-72590-type-error-sized.stderr
+++ b/src/test/ui/async-await/issue-72590-type-error-sized.stderr
@@ -17,7 +17,6 @@ LL |     async fn frob(self) {}
    |                   ^^^^ doesn't have a size known at compile-time
    |
    = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Foo`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr
index 5c169af4eb8ae..47d8cc1f06fd1 100644
--- a/src/test/ui/bad/bad-sized.stderr
+++ b/src/test/ui/bad/bad-sized.stderr
@@ -21,7 +21,6 @@ LL | pub struct Vec<T> {
    |                - required by this bound in `std::vec::Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn Trait`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
   --> $DIR/bad-sized.rs:4:37
@@ -30,7 +29,6 @@ LL |     let x: Vec<dyn Trait + Sized> = Vec::new();
    |                                     ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn Trait`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::vec::Vec::<T>::new`
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/box-into-boxed-slice-fail.stderr b/src/test/ui/box-into-boxed-slice-fail.stderr
index dfc4999958a57..b3e7b5b4feea4 100644
--- a/src/test/ui/box-into-boxed-slice-fail.stderr
+++ b/src/test/ui/box-into-boxed-slice-fail.stderr
@@ -5,7 +5,6 @@ LL |     let _ = Box::into_boxed_slice(boxed_slice);
    |                                   ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::boxed::Box::<T>::into_boxed_slice`
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
@@ -15,7 +14,6 @@ LL |     let _ = Box::into_boxed_slice(boxed_slice);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: slice and array elements must have `Sized` type
 
 error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
@@ -25,7 +23,6 @@ LL |     let _ = Box::into_boxed_slice(boxed_trait);
    |                                   ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::boxed::Box::<T>::into_boxed_slice`
 
 error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
@@ -35,7 +32,6 @@ LL |     let _ = Box::into_boxed_slice(boxed_trait);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: slice and array elements must have `Sized` type
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/chalkify/impl_wf.stderr b/src/test/ui/chalkify/impl_wf.stderr
index e5d7615e43e31..fb2e0fc1a6169 100644
--- a/src/test/ui/chalkify/impl_wf.stderr
+++ b/src/test/ui/chalkify/impl_wf.stderr
@@ -8,7 +8,6 @@ LL | impl Foo for str { }
    |      ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the trait bound `f32: Foo` is not satisfied
   --> $DIR/impl_wf.rs:27:17
diff --git a/src/test/ui/consts/const-unsized.stderr b/src/test/ui/consts/const-unsized.stderr
index beeea87bfb1d3..bf2844cfb70d6 100644
--- a/src/test/ui/consts/const-unsized.stderr
+++ b/src/test/ui/consts/const-unsized.stderr
@@ -5,7 +5,6 @@ LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync));
    |                ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> $DIR/const-unsized.rs:6:18
@@ -14,7 +13,6 @@ LL | const CONST_FOO: str = *"foo";
    |                  ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time
   --> $DIR/const-unsized.rs:9:18
@@ -23,7 +21,6 @@ LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
    |                  ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> $DIR/const-unsized.rs:12:20
@@ -32,7 +29,6 @@ LL | static STATIC_BAR: str = *"bar";
    |                    ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/dst/dst-bad-assign-2.stderr b/src/test/ui/dst/dst-bad-assign-2.stderr
index 4e1e67c7f4809..a5374aedab86b 100644
--- a/src/test/ui/dst/dst-bad-assign-2.stderr
+++ b/src/test/ui/dst/dst-bad-assign-2.stderr
@@ -5,7 +5,6 @@ LL |     f5.ptr = *z;
    |     ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the left-hand-side of an assignment must have a statically known size
 
 error: aborting due to previous error
diff --git a/src/test/ui/dst/dst-bad-assign-3.stderr b/src/test/ui/dst/dst-bad-assign-3.stderr
index 0b6f9df2d83ee..f8d9300f11a31 100644
--- a/src/test/ui/dst/dst-bad-assign-3.stderr
+++ b/src/test/ui/dst/dst-bad-assign-3.stderr
@@ -14,7 +14,6 @@ LL |     f5.2 = Bar1 {f: 36};
    |     ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the left-hand-side of an assignment must have a statically known size
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/dst/dst-bad-assign.stderr b/src/test/ui/dst/dst-bad-assign.stderr
index 434c460759fb4..8e3eeefb9ea66 100644
--- a/src/test/ui/dst/dst-bad-assign.stderr
+++ b/src/test/ui/dst/dst-bad-assign.stderr
@@ -14,7 +14,6 @@ LL |     f5.ptr = Bar1 {f: 36};
    |     ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the left-hand-side of an assignment must have a statically known size
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/dst/dst-bad-deep-2.stderr b/src/test/ui/dst/dst-bad-deep-2.stderr
index cb2735147a35b..d9d6ca3292311 100644
--- a/src/test/ui/dst/dst-bad-deep-2.stderr
+++ b/src/test/ui/dst/dst-bad-deep-2.stderr
@@ -5,7 +5,6 @@ LL |     let h: &(([isize],),) = &(*g,);
    |                              ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `(([isize],),)`, the trait `std::marker::Sized` is not implemented for `[isize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `([isize],)`
    = note: required because it appears within the type `(([isize],),)`
    = note: tuples must have a statically known size to be initialized
diff --git a/src/test/ui/dst/dst-bad-deep.stderr b/src/test/ui/dst/dst-bad-deep.stderr
index 521adf601cc70..1304f04f82062 100644
--- a/src/test/ui/dst/dst-bad-deep.stderr
+++ b/src/test/ui/dst/dst-bad-deep.stderr
@@ -5,7 +5,6 @@ LL |     let h: &Fat<Fat<[isize]>> = &Fat { ptr: *g };
    |                                  ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Fat<Fat<[isize]>>`, the trait `std::marker::Sized` is not implemented for `[isize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Fat<[isize]>`
    = note: required because it appears within the type `Fat<Fat<[isize]>>`
    = note: structs must have a statically known size to be initialized
diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr
index 80d188bf2f89b..d6e9aaab7cf39 100644
--- a/src/test/ui/dst/dst-object-from-unsized-type.stderr
+++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr
@@ -7,7 +7,6 @@ LL |     let u: &dyn Foo = t;
    |                       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
@@ -19,7 +18,6 @@ LL |     let v: &dyn Foo = t as &dyn Foo;
    |                       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -29,7 +27,6 @@ LL |     let _: &[&dyn Foo] = &["hi"];
    |                            ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
@@ -39,7 +36,6 @@ LL |     let _: &dyn Foo = x as &dyn Foo;
    |                       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/dst/dst-sized-trait-param.stderr b/src/test/ui/dst/dst-sized-trait-param.stderr
index 006a334021b14..7e90e9ce1792d 100644
--- a/src/test/ui/dst/dst-sized-trait-param.stderr
+++ b/src/test/ui/dst/dst-sized-trait-param.stderr
@@ -8,7 +8,6 @@ LL | impl Foo<[isize]> for usize { }
    |      ^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[isize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is sized
@@ -24,7 +23,6 @@ LL | impl Foo<isize> for [usize] { }
    |      ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[usize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr
index a9ea85d14cff5..8789bb9609bd4 100644
--- a/src/test/ui/error-codes/E0277.stderr
+++ b/src/test/ui/error-codes/E0277.stderr
@@ -2,10 +2,9 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
   --> $DIR/E0277.rs:13:6
    |
 LL | fn f(p: Path) { }
-   |      ^ borrow the `Path` instead
+   |      ^ doesn't have a size known at compile-time
    |
    = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `std::path::Path`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr
index 0c7995fde3273..8938afd33ffde 100644
--- a/src/test/ui/extern/extern-types-unsized.stderr
+++ b/src/test/ui/extern/extern-types-unsized.stderr
@@ -8,7 +8,6 @@ LL |     assert_sized::<A>();
    |                    ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `A`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn assert_sized<T: ?Sized>() { }
@@ -24,7 +23,6 @@ LL |     assert_sized::<Foo>();
    |     ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Foo`
 help: consider relaxing the implicit `Sized` restriction
    |
@@ -41,7 +39,6 @@ LL |     assert_sized::<Bar<A>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Bar<A>`, the trait `std::marker::Sized` is not implemented for `A`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<A>`
 help: consider relaxing the implicit `Sized` restriction
    |
@@ -58,7 +55,6 @@ LL |     assert_sized::<Bar<Bar<A>>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Bar<Bar<A>>`, the trait `std::marker::Sized` is not implemented for `A`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<A>`
    = note: required because it appears within the type `Bar<Bar<A>>`
 help: consider relaxing the implicit `Sized` restriction
diff --git a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr
index add3a8e79267d..5a58e57d36c70 100644
--- a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr
+++ b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr
@@ -5,7 +5,6 @@ LL |         static symbol: [usize];
    |                        ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[usize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
index b4d4c992c9086..d4c09ec40fd92 100644
--- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
+++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
@@ -95,7 +95,6 @@ LL | struct TwoStrs(str, str) where str: Sized;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = help: see issue #48214
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
@@ -108,7 +107,6 @@ LL | | }
    | |_^ doesn't have a size known at compile-time
    |
    = help: within `Dst<(dyn A + 'static)>`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Dst<(dyn A + 'static)>`
    = help: see issue #48214
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
@@ -122,7 +120,6 @@ LL | | }
    | |_^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = help: see issue #48214
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
diff --git a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr
index d20b9e2981e8c..0775431a9d350 100644
--- a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr
@@ -5,7 +5,6 @@ LL | fn f(f: dyn FnOnce()) {}
    |      ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr
index 79aeec2ec0280..379bd8ebd1cad 100644
--- a/src/test/ui/generator/sized-yield.stderr
+++ b/src/test/ui/generator/sized-yield.stderr
@@ -9,7 +9,6 @@ LL | |    };
    | |____^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the yield type of a generator must have a statically known size
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -19,7 +18,6 @@ LL |    Pin::new(&mut gen).resume(());
    |                       ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr
index 95f4aa9e6dbaa..7a6c07d4e082e 100644
--- a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr
+++ b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr
@@ -8,7 +8,6 @@ LL | impl Tsized for () {}
    |      ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[()]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index c55dbd7d2fafe..96f961a2aaf6b 100644
--- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -16,7 +16,6 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) }
    |             doesn't have a size known at compile-time
    |
    = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
    = note: the return type of a function must have a statically known size
 
@@ -38,7 +37,6 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
    |             doesn't have a size known at compile-time
    |
    = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr
index d7a4bf4f21f18..d241e6406d579 100644
--- a/src/test/ui/issues/issue-10412.stderr
+++ b/src/test/ui/issues/issue-10412.stderr
@@ -56,7 +56,6 @@ LL | impl<'self> Serializable<str> for &'self str {
    |             ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait Serializable<'self, T: ?Sized> {
diff --git a/src/test/ui/issues/issue-14366.stderr b/src/test/ui/issues/issue-14366.stderr
index 542d8a904c4e3..4e41acf433e59 100644
--- a/src/test/ui/issues/issue-14366.stderr
+++ b/src/test/ui/issues/issue-14366.stderr
@@ -5,7 +5,6 @@ LL |     let _x = "test" as &dyn (::std::any::Any);
    |              ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::any::Any`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-15756.stderr b/src/test/ui/issues/issue-15756.stderr
index 987bc512163d6..68ceebc5b651d 100644
--- a/src/test/ui/issues/issue-15756.stderr
+++ b/src/test/ui/issues/issue-15756.stderr
@@ -5,7 +5,6 @@ LL |     &mut something
    |          ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[T]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/issues/issue-17651.stderr b/src/test/ui/issues/issue-17651.stderr
index c3445024c3752..812778911a865 100644
--- a/src/test/ui/issues/issue-17651.stderr
+++ b/src/test/ui/issues/issue-17651.stderr
@@ -5,7 +5,6 @@ LL |     (|| Box::new(*(&[0][..])))();
    |                  ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::boxed::Box::<T>::new`
 
 error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time
@@ -15,7 +14,6 @@ LL |     (|| Box::new(*(&[0][..])))();
    |         ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr
index 383cdd4979ad9..3b5dfd1ad158c 100644
--- a/src/test/ui/issues/issue-18919.stderr
+++ b/src/test/ui/issues/issue-18919.stderr
@@ -8,7 +8,6 @@ LL | enum Option<T> {
    |             - required by this bound in `Option`
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/issue-18919.rs:7:13
    |
diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr
index 775f9702401a6..7bd2578344458 100644
--- a/src/test/ui/issues/issue-20005.stderr
+++ b/src/test/ui/issues/issue-20005.stderr
@@ -8,7 +8,6 @@ LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self> {
    |                                                 ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self>, Self: std::marker::Sized {
diff --git a/src/test/ui/issues/issue-20433.stderr b/src/test/ui/issues/issue-20433.stderr
index 1dab637e489db..0e96b12066937 100644
--- a/src/test/ui/issues/issue-20433.stderr
+++ b/src/test/ui/issues/issue-20433.stderr
@@ -10,7 +10,6 @@ LL | pub struct Vec<T> {
    |                - required by this bound in `std::vec::Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr
index 5e050f27ac546..5e06e3bc95c36 100644
--- a/src/test/ui/issues/issue-20605.stderr
+++ b/src/test/ui/issues/issue-20605.stderr
@@ -5,7 +5,6 @@ LL |     for item in *things { *item = 0 }
    |                 ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator<Item = &'a mut u8>`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::iter::IntoIterator::into_iter`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-22874.stderr b/src/test/ui/issues/issue-22874.stderr
index 9a74bc0313169..6f22fe6a99717 100644
--- a/src/test/ui/issues/issue-22874.stderr
+++ b/src/test/ui/issues/issue-22874.stderr
@@ -5,7 +5,6 @@ LL |     rows: [[String]],
    |           ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[std::string::String]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: slice and array elements must have `Sized` type
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-23281.stderr b/src/test/ui/issues/issue-23281.stderr
index cffa52361696c..46b4be6fd3649 100644
--- a/src/test/ui/issues/issue-23281.stderr
+++ b/src/test/ui/issues/issue-23281.stderr
@@ -8,7 +8,6 @@ LL | struct Vec<T> {
    |            - required by this bound in `Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/issue-23281.rs:8:12
    |
diff --git a/src/test/ui/issues/issue-24446.stderr b/src/test/ui/issues/issue-24446.stderr
index 344443e783038..d2714408d8a39 100644
--- a/src/test/ui/issues/issue-24446.stderr
+++ b/src/test/ui/issues/issue-24446.stderr
@@ -5,7 +5,6 @@ LL |     static foo: dyn Fn() -> u32 = || -> u32 {
    |                 ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() -> u32 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr
index 8b64128fb01da..881fae1942335 100644
--- a/src/test/ui/issues/issue-27060-2.stderr
+++ b/src/test/ui/issues/issue-27060-2.stderr
@@ -7,7 +7,6 @@ LL |     data: T,
    |           ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr
index 3eb9d3c62039f..313c294e8a1a5 100644
--- a/src/test/ui/issues/issue-27078.stderr
+++ b/src/test/ui/issues/issue-27078.stderr
@@ -5,7 +5,6 @@ LL |     fn foo(self) -> &'static i32 {
    |            ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 help: consider further restricting `Self`
diff --git a/src/test/ui/issues/issue-30355.stderr b/src/test/ui/issues/issue-30355.stderr
index 48b151c73c956..98de768a5a819 100644
--- a/src/test/ui/issues/issue-30355.stderr
+++ b/src/test/ui/issues/issue-30355.stderr
@@ -5,7 +5,6 @@ LL |     &X(*Y)
    |      ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/issues/issue-35988.stderr b/src/test/ui/issues/issue-35988.stderr
index 52660eb7cdac9..a137549693844 100644
--- a/src/test/ui/issues/issue-35988.stderr
+++ b/src/test/ui/issues/issue-35988.stderr
@@ -5,7 +5,6 @@ LL |     V([Box<E>]),
    |       ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[std::boxed::Box<E>]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/issues/issue-38954.stderr b/src/test/ui/issues/issue-38954.stderr
index 93133bc94bbcf..e96bbe1a99312 100644
--- a/src/test/ui/issues/issue-38954.stderr
+++ b/src/test/ui/issues/issue-38954.stderr
@@ -5,7 +5,6 @@ LL | fn _test(ref _p: str) {}
    |          ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = help: unsized locals are gated as an unstable feature
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
diff --git a/src/test/ui/issues/issue-41229-ref-str.stderr b/src/test/ui/issues/issue-41229-ref-str.stderr
index 1b908ca49de43..35aa1acdc1c9b 100644
--- a/src/test/ui/issues/issue-41229-ref-str.stderr
+++ b/src/test/ui/issues/issue-41229-ref-str.stderr
@@ -5,7 +5,6 @@ LL | pub fn example(ref s: str) {}
    |                ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = help: unsized locals are gated as an unstable feature
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr
index 58eb3afee81de..fbe87aa2dbee5 100644
--- a/src/test/ui/issues/issue-42312.stderr
+++ b/src/test/ui/issues/issue-42312.stderr
@@ -5,7 +5,6 @@ LL |     fn baz(_: Self::Target) where Self: Deref {}
    |            ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `<Self as std::ops::Deref>::Target`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = help: unsized locals are gated as an unstable feature
 help: consider further restricting the associated type
    |
@@ -23,7 +22,6 @@ LL | pub fn f(_: dyn ToString) {}
    |          ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = help: unsized locals are gated as an unstable feature
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
diff --git a/src/test/ui/issues/issue-54410.stderr b/src/test/ui/issues/issue-54410.stderr
index 992c691bf21ef..9205a518c8c3a 100644
--- a/src/test/ui/issues/issue-54410.stderr
+++ b/src/test/ui/issues/issue-54410.stderr
@@ -5,7 +5,6 @@ LL |     pub static mut symbol: [i8];
    |                            ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr
index d886ecc11d17b..149d882af78ff 100644
--- a/src/test/ui/issues/issue-5883.stderr
+++ b/src/test/ui/issues/issue-5883.stderr
@@ -5,7 +5,6 @@ LL | fn new_struct(r: dyn A + 'static)
    |               ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -19,7 +18,6 @@ LL |     Struct { r: r }
    |     --------------- this returned value is of type `Struct`
    |
    = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Struct`
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/issues/issue-65673.stderr b/src/test/ui/issues/issue-65673.stderr
index 114f2d62e561a..fef64ebf2d365 100644
--- a/src/test/ui/issues/issue-65673.stderr
+++ b/src/test/ui/issues/issue-65673.stderr
@@ -10,7 +10,6 @@ LL |     type Ctx = dyn Alias<T>;
    |                ^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
index 6e19251c72800..97c7417839825 100644
--- a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
+++ b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
@@ -10,7 +10,6 @@ LL |     let _: [u8; sof::<T>()];
    |                       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | pub const fn sof<T: ?Sized>() -> usize {
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index 95936de218b8f..71abda520653e 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -209,7 +209,6 @@ LL |     let _ = fat_v as *const dyn Foo;
    |             ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -219,7 +218,6 @@ LL |     let _ = a as *const dyn Foo;
    |             ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0606]: casting `&{float}` as `f32` is invalid
diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr
index 05009358106fa..e179feba7a799 100644
--- a/src/test/ui/range/range-1.stderr
+++ b/src/test/ui/range/range-1.stderr
@@ -19,7 +19,6 @@ LL |     let range = *arr..;
    |                 ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::ops::RangeFrom`
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr
index 89eb3d97ce0a5..ec2882d6c6d73 100644
--- a/src/test/ui/resolve/issue-5035-2.stderr
+++ b/src/test/ui/resolve/issue-5035-2.stderr
@@ -5,7 +5,6 @@ LL | fn foo(_x: K) {}
    |        ^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn I + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr
index cc767de3845d2..0b1832d70ff86 100644
--- a/src/test/ui/str/str-array-assignment.stderr
+++ b/src/test/ui/str/str-array-assignment.stderr
@@ -24,7 +24,6 @@ LL |   let v = s[..2];
    |       doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr
index 2fd805e646991..7c834165e7f1c 100644
--- a/src/test/ui/str/str-mut-idx.stderr
+++ b/src/test/ui/str/str-mut-idx.stderr
@@ -8,7 +8,6 @@ LL |     s[1..2] = bot();
    |               ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn bot<T: ?Sized>() -> T { loop {} }
@@ -21,7 +20,6 @@ LL |     s[1..2] = bot();
    |     ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the left-hand-side of an assignment must have a statically known size
 
 error[E0277]: the type `str` cannot be indexed by `usize`
diff --git a/src/test/ui/substs-ppaux.normal.stderr b/src/test/ui/substs-ppaux.normal.stderr
index bcdeed262ecba..8dab8add80b8a 100644
--- a/src/test/ui/substs-ppaux.normal.stderr
+++ b/src/test/ui/substs-ppaux.normal.stderr
@@ -80,7 +80,6 @@ LL |     <str as Foo<u8>>::bar;
    |     ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because of the requirements on the impl of `Foo<'_, '_, u8>` for `str`
 
 error: aborting due to 5 previous errors
diff --git a/src/test/ui/substs-ppaux.verbose.stderr b/src/test/ui/substs-ppaux.verbose.stderr
index fb5e6fbcfe712..a40d5e4bf7ba1 100644
--- a/src/test/ui/substs-ppaux.verbose.stderr
+++ b/src/test/ui/substs-ppaux.verbose.stderr
@@ -80,7 +80,6 @@ LL |     <str as Foo<u8>>::bar;
    |     ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because of the requirements on the impl of `Foo<'_#0r, '_#1r, u8>` for `str`
 
 error: aborting due to 5 previous errors
diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
index 03877e60e2b72..0b08b4a16a692 100644
--- a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
+++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
@@ -10,7 +10,6 @@ LL |     _t: X<T>,
    |         ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
    |
@@ -29,7 +28,6 @@ LL | struct Struct1<T>{
    |                - required by this bound in `Struct1`
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL |     fn func1() -> Struct1<Self> where Self: std::marker::Sized;
@@ -49,7 +47,6 @@ LL | struct Struct2<'a, T>{
    |                    - required by this bound in `Struct2`
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL |     fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized;
@@ -69,7 +66,6 @@ LL | struct Struct3<T>{
    |                - required by this bound in `Struct3`
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16
    |
@@ -92,7 +88,6 @@ LL | struct Struct4<T>{
    |                - required by this bound in `Struct4`
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL |     fn func4() -> Struct4<Self> where Self: std::marker::Sized;
diff --git a/src/test/ui/suggestions/path-by-value.stderr b/src/test/ui/suggestions/path-by-value.stderr
index b073e10749cc1..5bd50fea1cb6c 100644
--- a/src/test/ui/suggestions/path-by-value.stderr
+++ b/src/test/ui/suggestions/path-by-value.stderr
@@ -2,10 +2,9 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
   --> $DIR/path-by-value.rs:3:6
    |
 LL | fn f(p: Path) { }
-   |      ^ borrow the `Path` instead
+   |      ^ doesn't have a size known at compile-time
    |
    = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `std::path::Path`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr
index 5e685105b45a3..082d787fb0b7b 100644
--- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr
+++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr
@@ -13,7 +13,6 @@ LL | fn foo(_x: Foo + Send) {
    |        ^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + std::marker::Send + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr
index 4dddcd68f26c9..b8069f9ddb0f6 100644
--- a/src/test/ui/traits/trait-suggest-where-clause.stderr
+++ b/src/test/ui/traits/trait-suggest-where-clause.stderr
@@ -13,7 +13,6 @@ LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
    |
    = help: the trait `std::marker::Sized` is not implemented for `U`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `U` cannot be known at compilation time
   --> $DIR/trait-suggest-where-clause.rs:10:5
@@ -30,7 +29,6 @@ LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
    |
    = help: within `Misc<U>`, the trait `std::marker::Sized` is not implemented for `U`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Misc<U>`
 
 error[E0277]: the trait bound `u64: std::convert::From<T>` is not satisfied
@@ -69,7 +67,6 @@ LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
    |
    = help: the trait `std::marker::Sized` is not implemented for `[T]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `[&U]` cannot be known at compilation time
   --> $DIR/trait-suggest-where-clause.rs:31:5
@@ -83,7 +80,6 @@ LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
    |
    = help: the trait `std::marker::Sized` is not implemented for `[&U]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr
index 006fa933d34ca..4f4695612de0b 100644
--- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr
+++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr
@@ -5,7 +5,6 @@ LL | fn cant_return_str() -> str {
    |                         ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the return type of a function must have a statically known size
 
 error[E0599]: no method named `test` found for type `i32` in the current scope
diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr
index 1bfc44e3eec62..eb169987ccdb9 100644
--- a/src/test/ui/union/union-sized-field.stderr
+++ b/src/test/ui/union/union-sized-field.stderr
@@ -7,7 +7,6 @@ LL |     value: T,
    |            ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of a union may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -28,7 +27,6 @@ LL |     value: T,
    |            ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -49,7 +47,6 @@ LL |     Value(T),
    |           ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/union/union-unsized.stderr b/src/test/ui/union/union-unsized.stderr
index 442ea83f80168..574f182ecc687 100644
--- a/src/test/ui/union/union-unsized.stderr
+++ b/src/test/ui/union/union-unsized.stderr
@@ -5,7 +5,6 @@ LL |     a: str,
    |        ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of a union may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -24,7 +23,6 @@ LL |     b: str,
    |        ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of a union may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr
index 35f63a91b2b53..2ed35dc0e2c12 100644
--- a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr
+++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr
@@ -5,7 +5,6 @@ LL |     let _x: fn(_) -> Test = Test;
    |                             ^^^^ doesn't have a size known at compile-time
    |
    = help: within `Test`, the trait `std::marker::Sized` is not implemented for `[i32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Test`
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/unsized-locals/issue-30276.stderr b/src/test/ui/unsized-locals/issue-30276.stderr
index d42fddb3a4a26..461efcf3dbf29 100644
--- a/src/test/ui/unsized-locals/issue-30276.stderr
+++ b/src/test/ui/unsized-locals/issue-30276.stderr
@@ -5,7 +5,6 @@ LL |     let _x: fn(_) -> Test = Test;
    |                             ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr
index 7b6c2d11ea169..04a8de1b5dc5b 100644
--- a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr
+++ b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr
@@ -5,7 +5,6 @@ LL |     A as fn(str) -> A<str>;
    |     ^ doesn't have a size known at compile-time
    |
    = help: within `main::A<str>`, the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `main::A<str>`
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/unsized-locals/issue-50940.stderr b/src/test/ui/unsized-locals/issue-50940.stderr
index be006c09d6f5c..8e5f753082734 100644
--- a/src/test/ui/unsized-locals/issue-50940.stderr
+++ b/src/test/ui/unsized-locals/issue-50940.stderr
@@ -5,7 +5,6 @@ LL |     A as fn(str) -> A<str>;
    |     ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr
index 43c35cdd7b5b0..0a9b43dac3344 100644
--- a/src/test/ui/unsized-locals/unsized-exprs.stderr
+++ b/src/test/ui/unsized-locals/unsized-exprs.stderr
@@ -5,7 +5,6 @@ LL |     udrop::<(i32, [u8])>((42, *foo()));
    |                          ^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `({integer}, [u8])`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `({integer}, [u8])`
    = note: tuples must have a statically known size to be initialized
 
@@ -16,7 +15,6 @@ LL |     udrop::<A<[u8]>>(A { 0: *foo() });
    |                      ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `A<[u8]>`
    = note: structs must have a statically known size to be initialized
 
@@ -27,7 +25,6 @@ LL |     udrop::<A<[u8]>>(A(*foo()));
    |                      ^ doesn't have a size known at compile-time
    |
    = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `A<[u8]>`
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/unsized-locals/unsized-exprs3.stderr b/src/test/ui/unsized-locals/unsized-exprs3.stderr
index f9a7452a5ebf2..11435ec0353bc 100644
--- a/src/test/ui/unsized-locals/unsized-exprs3.stderr
+++ b/src/test/ui/unsized-locals/unsized-exprs3.stderr
@@ -5,7 +5,6 @@ LL |     udrop as fn([u8]);
    |     ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr
index 3ff6f30db2a84..998cd7a527c9b 100644
--- a/src/test/ui/unsized/unsized-bare-typaram.stderr
+++ b/src/test/ui/unsized/unsized-bare-typaram.stderr
@@ -9,7 +9,6 @@ LL | fn foo<T: ?Sized>() { bar::<T>() }
    |        this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr
index 1908aee25ea7b..cb06e707dcaa8 100644
--- a/src/test/ui/unsized/unsized-enum.stderr
+++ b/src/test/ui/unsized/unsized-enum.stderr
@@ -10,7 +10,6 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |         this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box<U>`
   --> $DIR/unsized-enum.rs:4:10
    |
diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr
index fb89a6f45d234..82f395740d5ad 100644
--- a/src/test/ui/unsized/unsized-enum2.stderr
+++ b/src/test/ui/unsized/unsized-enum2.stderr
@@ -8,7 +8,6 @@ LL |     VA(W),
    |        ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `W`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -30,7 +29,6 @@ LL |     VB{x: X},
    |           ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -52,7 +50,6 @@ LL |     VC(isize, Y),
    |               ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Y`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -74,7 +71,6 @@ LL |     VD{u: isize, x: Z},
    |                     ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Z`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -93,7 +89,6 @@ LL |     VE([u8]),
    |        ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -112,7 +107,6 @@ LL |     VF{x: str},
    |           ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -131,7 +125,6 @@ LL |     VG(isize, [f32]),
    |               ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[f32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -150,7 +143,6 @@ LL |     VH{u: isize, x: [u32]},
    |                     ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -169,7 +161,6 @@ LL |     VM(dyn Foo),
    |        ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -188,7 +179,6 @@ LL |     VN{x: dyn Bar},
    |           ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Bar + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -207,7 +197,6 @@ LL |     VO(isize, dyn FooBar),
    |               ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn FooBar + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -226,7 +215,6 @@ LL |     VP{u: isize, x: dyn BarFoo},
    |                     ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn BarFoo + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -245,7 +233,6 @@ LL |     VQ(<&'static [i8] as Deref>::Target),
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -264,7 +251,6 @@ LL |     VR{x: <&'static [char] as Deref>::Target},
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[char]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -283,7 +269,6 @@ LL |     VS(isize, <&'static [f64] as Deref>::Target),
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[f64]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -302,7 +287,6 @@ LL |     VT{u: isize, x: <&'static [i32] as Deref>::Target},
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -321,7 +305,6 @@ LL |     VI(Path1),
    |        ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper1 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path1`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
@@ -341,7 +324,6 @@ LL |     VJ{x: Path2},
    |           ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper2 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path2`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
@@ -361,7 +343,6 @@ LL |     VK(isize, Path3),
    |               ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper3 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path3`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
@@ -381,7 +362,6 @@ LL |     VL{u: isize, x: Path4},
    |                     ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper4 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path4`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr
index ed2c2e75cbd44..6b54db7148a74 100644
--- a/src/test/ui/unsized/unsized-fn-param.stderr
+++ b/src/test/ui/unsized/unsized-fn-param.stderr
@@ -5,7 +5,6 @@ LL |     foo11("bar", &"baz");
    |           ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::convert::AsRef<std::path::Path>`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -15,7 +14,6 @@ LL |     foo12(&"bar", "baz");
    |                   ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::convert::AsRef<std::path::Path>`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -25,7 +23,6 @@ LL |     foo21("bar", &"baz");
    |           ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::convert::AsRef<str>`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -35,7 +32,6 @@ LL |     foo22(&"bar", "baz");
    |                   ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::convert::AsRef<str>`
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
index e0f077d66f99c..0d08f70c558be 100644
--- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
@@ -10,7 +10,6 @@ LL | impl<X: ?Sized> S5<X> {
    |      this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
   --> $DIR/unsized-inherent-impl-self-type.rs:5:11
    |
diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr
index d92d1d9113e5c..d796fcd1a6b64 100644
--- a/src/test/ui/unsized/unsized-struct.stderr
+++ b/src/test/ui/unsized/unsized-struct.stderr
@@ -10,7 +10,6 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |         this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/unsized-struct.rs:4:12
    |
@@ -31,7 +30,6 @@ LL | fn bar2<T: ?Sized>() { is_sized::<Bar<T>>() }
    |         this type parameter needs to be `std::marker::Sized`
    |
    = help: within `Bar<T>`, the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<T>`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
index 73c5439da53b6..623c83c4d6f07 100644
--- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
@@ -10,7 +10,6 @@ LL | impl<X: ?Sized> T3<X> for S5<X> {
    |      this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
   --> $DIR/unsized-trait-impl-self-type.rs:8:11
    |
diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
index e423a9bdeab6f..1dc9e313d91a6 100644
--- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
@@ -10,7 +10,6 @@ LL | impl<X: ?Sized> T2<X> for S4<X> {
    |      this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait T2<Z: ?Sized> {
diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr
index e0a0389dc4690..d5c79c71a2349 100644
--- a/src/test/ui/unsized3.stderr
+++ b/src/test/ui/unsized3.stderr
@@ -10,7 +10,6 @@ LL | fn f2<X>(x: &X) {
    |       - required by this bound in `f2`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f2<X: ?Sized>(x: &X) {
@@ -28,7 +27,6 @@ LL | fn f4<X: T>(x: &X) {
    |       - required by this bound in `f4`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f4<X: T + ?Sized>(x: &X) {
@@ -46,7 +44,6 @@ LL |     f5(x1);
    |        ^^ doesn't have a size known at compile-time
    |
    = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
 help: consider relaxing the implicit `Sized` restriction
    |
@@ -62,7 +59,6 @@ LL |     f5(&(*x1, 34));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
    = note: only the last element of a tuple may have a dynamically sized type
 
@@ -75,7 +71,6 @@ LL |     f5(&(32, *x1));
    |         ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
    = note: tuples must have a statically known size to be initialized
@@ -92,7 +87,6 @@ LL |     f5(&(32, *x1));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
 help: consider relaxing the implicit `Sized` restriction
diff --git a/src/test/ui/unsized5.stderr b/src/test/ui/unsized5.stderr
index 3eef1f4f6771e..9bdcc0399b833 100644
--- a/src/test/ui/unsized5.stderr
+++ b/src/test/ui/unsized5.stderr
@@ -7,7 +7,6 @@ LL |     f1: X,
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -29,7 +28,6 @@ LL |     g: X,
    |        ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -48,7 +46,6 @@ LL |     f: str,
    |        ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -67,7 +64,6 @@ LL |     f: [u8],
    |        ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -88,7 +84,6 @@ LL |     V1(X, isize),
    |        ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -109,7 +104,6 @@ LL |     V2{f1: X, f: isize},
    |            ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr
index 337afd2ee7e10..d566399e5ba00 100644
--- a/src/test/ui/unsized6.stderr
+++ b/src/test/ui/unsized6.stderr
@@ -8,7 +8,6 @@ LL |     let y: Y;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Y`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -22,7 +21,6 @@ LL |     let _: (isize, (X, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `Z` cannot be known at compilation time
@@ -35,7 +33,6 @@ LL |     let y: (isize, (Z, usize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Z`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
@@ -47,7 +44,6 @@ LL |     let y: X;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -61,7 +57,6 @@ LL |     let y: (isize, (Y, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Y`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
@@ -73,7 +68,6 @@ LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -87,7 +81,6 @@ LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -101,7 +94,6 @@ LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -114,7 +106,6 @@ LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -128,7 +119,6 @@ LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -142,7 +132,6 @@ LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -155,7 +144,6 @@ LL | fn g1<X: ?Sized>(x: X) {}
    |       this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -168,7 +156,6 @@ LL | fn g2<X: ?Sized + T>(x: X) {}
    |       this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr
index e616a5cf0f9c2..868c9ea429e24 100644
--- a/src/test/ui/unsized7.stderr
+++ b/src/test/ui/unsized7.stderr
@@ -10,7 +10,6 @@ LL | impl<X: ?Sized + T> T1<X> for S3<X> {
    |      this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait T1<Z: T + ?Sized> {
diff --git a/src/test/ui/wf/wf-array-elem-sized.stderr b/src/test/ui/wf/wf-array-elem-sized.stderr
index b424c9f3ac981..fedec1909fd33 100644
--- a/src/test/ui/wf/wf-array-elem-sized.stderr
+++ b/src/test/ui/wf/wf-array-elem-sized.stderr
@@ -5,7 +5,6 @@ LL |     foo: [[u8]],
    |          ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: slice and array elements must have `Sized` type
 
 error: aborting due to previous error
diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr
index 731d31ac34f62..938336d3ace76 100644
--- a/src/test/ui/wf/wf-fn-where-clause.stderr
+++ b/src/test/ui/wf/wf-fn-where-clause.stderr
@@ -22,7 +22,6 @@ LL | struct Vec<T> {
    |            - required by this bound in `Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/wf-fn-where-clause.rs:16:12
    |

From 424902abb4ce17ca876e0c35bd9d9b3b48330f4a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 10 Jul 2020 18:11:40 -0700
Subject: [PATCH 49/66] Suggest borrowing in more unsized fn param cases

---
 src/librustc_ast_lowering/expr.rs             |  2 +-
 src/librustc_ast_lowering/item.rs             |  2 +
 src/librustc_hir/hir.rs                       |  1 +
 .../traits/error_reporting/mod.rs             |  1 -
 .../traits/error_reporting/suggestions.rs     | 65 +++++++++----------
 .../issue-72590-type-error-sized.stderr       |  5 +-
 src/test/ui/error-codes/E0277.stderr          |  5 +-
 .../feature-gate-unsized_locals.stderr        |  5 +-
 src/test/ui/issues/issue-27078.stderr         |  5 +-
 src/test/ui/issues/issue-5883.stderr          |  5 +-
 src/test/ui/resolve/issue-5035-2.stderr       |  5 +-
 src/test/ui/str/str-array-assignment.stderr   |  8 ++-
 src/test/ui/suggestions/path-by-value.stderr  |  5 +-
 .../trait-bounds-not-on-bare-trait.stderr     |  5 +-
 src/test/ui/unsized6.stderr                   | 10 ++-
 15 files changed, 80 insertions(+), 49 deletions(-)

diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index 90a3a5ec64e0e..201972fcf264b 100644
--- a/src/librustc_ast_lowering/expr.rs
+++ b/src/librustc_ast_lowering/expr.rs
@@ -526,7 +526,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             Ident::with_dummy_span(sym::_task_context),
             hir::BindingAnnotation::Mutable,
         );
-        let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, span };
+        let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, ty_span: span, span };
         let params = arena_vec![self; param];
 
         let body_id = self.lower_body(move |this| {
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index 00665c4cafb6b..dd5e658102fac 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -972,6 +972,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             attrs: self.lower_attrs(&param.attrs),
             hir_id: self.lower_node_id(param.id),
             pat: self.lower_pat(&param.pat),
+            ty_span: param.ty.span,
             span: param.span,
         }
     }
@@ -1098,6 +1099,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     attrs: parameter.attrs,
                     hir_id: parameter.hir_id,
                     pat: new_parameter_pat,
+                    ty_span: parameter.ty_span,
                     span: parameter.span,
                 };
 
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index f3dfec7ca7215..07b489a756267 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -2148,6 +2148,7 @@ pub struct Param<'hir> {
     pub attrs: &'hir [Attribute],
     pub hir_id: HirId,
     pub pat: &'hir Pat<'hir>,
+    pub ty_span: Span,
     pub span: Span,
 }
 
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index ad6e81ed3e889..6fb07f5e1954c 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -403,7 +403,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         }
 
                         self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg);
-                        self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
                         self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
                         self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
                         self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index 68124f72ad9d4..9de168a10c464 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -43,12 +43,6 @@ pub trait InferCtxtExt<'tcx> {
         body_id: hir::HirId,
     );
 
-    fn suggest_borrow_on_unsized_slice(
-        &self,
-        code: &ObligationCauseCode<'tcx>,
-        err: &mut DiagnosticBuilder<'_>,
-    );
-
     fn suggest_dereferences(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -515,32 +509,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         }
     }
 
-    /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
-    /// suggestion to borrow the initializer in order to use have a slice instead.
-    fn suggest_borrow_on_unsized_slice(
-        &self,
-        code: &ObligationCauseCode<'tcx>,
-        err: &mut DiagnosticBuilder<'_>,
-    ) {
-        if let &ObligationCauseCode::VariableType(hir_id) = code {
-            let parent_node = self.tcx.hir().get_parent_node(hir_id);
-            if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) {
-                if let Some(ref expr) = local.init {
-                    if let hir::ExprKind::Index(_, _) = expr.kind {
-                        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
-                            err.span_suggestion(
-                                expr.span,
-                                "consider borrowing here",
-                                format!("&{}", snippet),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     /// Given a closure's `DefId`, return the given name of the closure.
     ///
     /// This doesn't account for reassignments, but it's only used for suggestions.
@@ -1817,8 +1785,37 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     }
                 }
             }
-            ObligationCauseCode::VariableType(_) => {
-                err.note("all local variables must have a statically known size");
+            ObligationCauseCode::VariableType(hir_id) => {
+                let parent_node = self.tcx.hir().get_parent_node(hir_id);
+                match self.tcx.hir().find(parent_node) {
+                    Some(Node::Local(hir::Local {
+                        init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }),
+                        ..
+                    })) => {
+                        // When encountering an assignment of an unsized trait, like
+                        // `let x = ""[..];`, provide a suggestion to borrow the initializer in
+                        // order to use have a slice instead.
+                        err.span_suggestion_verbose(
+                            span.shrink_to_lo(),
+                            "consider borrowing here",
+                            "&".to_owned(),
+                            Applicability::MachineApplicable,
+                        );
+                        err.note("all local variables must have a statically known size");
+                    }
+                    Some(Node::Param(param)) => {
+                        err.span_suggestion_verbose(
+                            param.ty_span.shrink_to_lo(),
+                            "function arguments must have a statically known size, borrowed types \
+                            always have a known size",
+                            "&".to_owned(),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                    _ => {
+                        err.note("all local variables must have a statically known size");
+                    }
+                }
                 if !self.tcx.features().unsized_locals {
                     err.help("unsized locals are gated as an unstable feature");
                 }
diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.stderr b/src/test/ui/async-await/issue-72590-type-error-sized.stderr
index 95ed9513f357b..762afa6450a95 100644
--- a/src/test/ui/async-await/issue-72590-type-error-sized.stderr
+++ b/src/test/ui/async-await/issue-72590-type-error-sized.stderr
@@ -18,8 +18,11 @@ LL |     async fn frob(self) {}
    |
    = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `str`
    = note: required because it appears within the type `Foo`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     async fn frob(&self) {}
+   |                   ^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr
index 8789bb9609bd4..203fc18915647 100644
--- a/src/test/ui/error-codes/E0277.stderr
+++ b/src/test/ui/error-codes/E0277.stderr
@@ -6,8 +6,11 @@ LL | fn f(p: Path) { }
    |
    = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]`
    = note: required because it appears within the type `std::path::Path`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn f(p: &Path) { }
+   |         ^
 
 error[E0277]: the trait bound `i32: Foo` is not satisfied
   --> $DIR/E0277.rs:17:15
diff --git a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr
index 0775431a9d350..0195cc1481e74 100644
--- a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr
@@ -5,8 +5,11 @@ LL | fn f(f: dyn FnOnce()) {}
    |      ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn f(f: &dyn FnOnce()) {}
+   |         ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr
index 313c294e8a1a5..4b031d26ad53b 100644
--- a/src/test/ui/issues/issue-27078.stderr
+++ b/src/test/ui/issues/issue-27078.stderr
@@ -5,12 +5,15 @@ LL |     fn foo(self) -> &'static i32 {
    |            ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 help: consider further restricting `Self`
    |
 LL |     fn foo(self) -> &'static i32 where Self: std::marker::Sized {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     fn foo(&self) -> &'static i32 {
+   |            ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr
index 149d882af78ff..897984d0ae410 100644
--- a/src/test/ui/issues/issue-5883.stderr
+++ b/src/test/ui/issues/issue-5883.stderr
@@ -5,8 +5,11 @@ LL | fn new_struct(r: dyn A + 'static)
    |               ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn new_struct(r: &dyn A + 'static)
+   |                  ^
 
 error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
   --> $DIR/issue-5883.rs:8:8
diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr
index ec2882d6c6d73..4ed93ad3279ad 100644
--- a/src/test/ui/resolve/issue-5035-2.stderr
+++ b/src/test/ui/resolve/issue-5035-2.stderr
@@ -5,8 +5,11 @@ LL | fn foo(_x: K) {}
    |        ^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn I + 'static)`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo(_x: &K) {}
+   |            ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr
index 0b1832d70ff86..52d3aefe125c0 100644
--- a/src/test/ui/str/str-array-assignment.stderr
+++ b/src/test/ui/str/str-array-assignment.stderr
@@ -19,13 +19,15 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/str-array-assignment.rs:7:7
    |
 LL |   let v = s[..2];
-   |       ^   ------ help: consider borrowing here: `&s[..2]`
-   |       |
-   |       doesn't have a size known at compile-time
+   |       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider borrowing here
+   |
+LL |   let v = &s[..2];
+   |           ^
 
 error[E0308]: mismatched types
   --> $DIR/str-array-assignment.rs:9:17
diff --git a/src/test/ui/suggestions/path-by-value.stderr b/src/test/ui/suggestions/path-by-value.stderr
index 5bd50fea1cb6c..2b7c29e20cd31 100644
--- a/src/test/ui/suggestions/path-by-value.stderr
+++ b/src/test/ui/suggestions/path-by-value.stderr
@@ -6,8 +6,11 @@ LL | fn f(p: Path) { }
    |
    = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]`
    = note: required because it appears within the type `std::path::Path`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn f(p: &Path) { }
+   |         ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr
index 082d787fb0b7b..daca91abff843 100644
--- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr
+++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr
@@ -13,8 +13,11 @@ LL | fn foo(_x: Foo + Send) {
    |        ^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + std::marker::Send + 'static)`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo(_x: &Foo + Send) {
+   |            ^
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr
index d566399e5ba00..82f1e87008d30 100644
--- a/src/test/ui/unsized6.stderr
+++ b/src/test/ui/unsized6.stderr
@@ -144,8 +144,11 @@ LL | fn g1<X: ?Sized>(x: X) {}
    |       this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn g1<X: ?Sized>(x: &X) {}
+   |                     ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:40:22
@@ -156,8 +159,11 @@ LL | fn g2<X: ?Sized + T>(x: X) {}
    |       this type parameter needs to be `std::marker::Sized`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn g2<X: ?Sized + T>(x: &X) {}
+   |                         ^
 
 error: aborting due to 13 previous errors
 

From 2d0f3ebcd06f259562b36fd39e42dd89f3ac883c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 10 Jul 2020 18:47:53 -0700
Subject: [PATCH 50/66] Remove redundant explanatory `note` for type parameters

---
 .../traits/error_reporting/mod.rs                   |  7 ++++++-
 .../defaults-unsound-62211-1.stderr                 |  4 ----
 .../defaults-unsound-62211-2.stderr                 |  4 ----
 src/test/ui/associated-types/issue-63593.stderr     |  1 -
 ...trait-with-supertraits-needing-sized-self.stderr |  1 -
 src/test/ui/async-await/issue-70818.stderr          |  1 -
 src/test/ui/bad/bad-method-typaram-kind.stderr      |  1 -
 src/test/ui/bound-suggestions.stderr                |  6 ------
 .../builtin-superkinds-double-superkind.stderr      |  2 --
 .../builtin-superkinds-in-metadata.stderr           |  1 -
 .../builtin-superkinds-typaram-not-send.stderr      |  1 -
 ...e-bounds-cant-promote-superkind-in-struct.stderr |  1 -
 src/test/ui/closures/closure-bounds-subtype.stderr  |  1 -
 src/test/ui/dst/dst-object-from-unsized-type.stderr |  2 --
 .../issue-68642-broken-llvm-ir.stderr               |  1 -
 .../issue-68643-broken-mir.stderr                   |  1 -
 .../issue-68644-codegen-selection.stderr            |  1 -
 .../issue-68645-codegen-fulfillment.stderr          |  1 -
 src/test/ui/issues/issue-20005.stderr               |  1 -
 src/test/ui/issues/issue-27060-2.stderr             |  1 -
 src/test/ui/issues/issue-27078.stderr               |  1 -
 src/test/ui/kindck/kindck-impl-type-params.stderr   |  2 --
 .../feature-gate-lazy_normalization_consts.stderr   |  1 -
 src/test/ui/phantom-oibit.stderr                    |  2 --
 .../deafult-generic-associated-type-bound.stderr    |  1 -
 .../adt-param-with-implicit-sized-bound.stderr      |  5 -----
 .../ui/suggestions/restrict-type-argument.stderr    |  6 ------
 .../ui/traits/trait-suggest-where-clause.stderr     |  3 ---
 .../generic_underconstrained2.stderr                |  2 --
 .../typeck-default-trait-impl-send-param.stderr     |  1 -
 src/test/ui/union/union-sized-field.stderr          |  3 ---
 src/test/ui/unsized/unsized-bare-typaram.stderr     |  2 --
 src/test/ui/unsized/unsized-enum.stderr             |  1 -
 src/test/ui/unsized/unsized-enum2.stderr            |  4 ----
 .../unsized/unsized-inherent-impl-self-type.stderr  |  1 -
 src/test/ui/unsized/unsized-struct.stderr           |  2 --
 .../ui/unsized/unsized-trait-impl-self-type.stderr  |  1 -
 .../ui/unsized/unsized-trait-impl-trait-arg.stderr  |  1 -
 src/test/ui/unsized3.stderr                         |  6 ------
 src/test/ui/unsized5.stderr                         |  4 ----
 src/test/ui/unsized6.stderr                         | 13 -------------
 src/test/ui/unsized7.stderr                         |  1 -
 42 files changed, 6 insertions(+), 96 deletions(-)

diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index 6fb07f5e1954c..4ade1ce91632f 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -376,7 +376,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             // If it has a custom `#[rustc_on_unimplemented]`
                             // error message, let's display it as the label!
                             err.span_label(span, s.as_str());
-                            err.help(&explanation);
+                            if !matches!(trait_ref.skip_binder().self_ty().kind, ty::Param(_)) {
+                                // When the self type is a type param We don't need to "the trait
+                                // `std::marker::Sized` is not implemented for `T`" as we will point
+                                // at the type param with a label to suggest constraining it.
+                                err.help(&explanation);
+                            }
                         } else {
                             err.span_label(span, explanation);
                         }
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
index 69c310766c1cc..2ba854eac4665 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
+++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
@@ -21,7 +21,6 @@ LL | trait UncheckedCopy: Sized {
 LL |     + AddAssign<&'static str>
    |       ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
    |
-   = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> {
@@ -50,7 +49,6 @@ LL | trait UncheckedCopy: Sized {
 LL |     + Display = Self;
    |       ^^^^^^^ `Self` cannot be formatted with the default formatter
    |
-   = help: the trait `std::fmt::Display` is not implemented for `Self`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider further restricting `Self`
    |
@@ -69,7 +67,6 @@ LL |     + Display = Self;
 LL | impl<T> UncheckedCopy for T {}
    |         ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
    |
-   = help: the trait `std::fmt::Display` is not implemented for `T`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider restricting type parameter `T`
    |
@@ -105,7 +102,6 @@ LL |     + AddAssign<&'static str>
 LL | impl<T> UncheckedCopy for T {}
    |         ^^^^^^^^^^^^^ no implementation for `T += &'static str`
    |
-   = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T`
 help: consider restricting type parameter `T`
    |
 LL | impl<T: std::ops::AddAssign<&'static str>> UncheckedCopy for T {}
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
index 84f0ba7529ea2..d4fd0ca98ee54 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
+++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
@@ -21,7 +21,6 @@ LL | trait UncheckedCopy: Sized {
 LL |     + AddAssign<&'static str>
    |       ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
    |
-   = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> {
@@ -50,7 +49,6 @@ LL | trait UncheckedCopy: Sized {
 LL |     + Display = Self;
    |       ^^^^^^^ `Self` cannot be formatted with the default formatter
    |
-   = help: the trait `std::fmt::Display` is not implemented for `Self`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider further restricting `Self`
    |
@@ -69,7 +67,6 @@ LL |     + Display = Self;
 LL | impl<T> UncheckedCopy for T {}
    |         ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
    |
-   = help: the trait `std::fmt::Display` is not implemented for `T`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider restricting type parameter `T`
    |
@@ -105,7 +102,6 @@ LL |     + AddAssign<&'static str>
 LL | impl<T> UncheckedCopy for T {}
    |         ^^^^^^^^^^^^^ no implementation for `T += &'static str`
    |
-   = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T`
 help: consider restricting type parameter `T`
    |
 LL | impl<T: std::ops::AddAssign<&'static str>> UncheckedCopy for T {}
diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr
index c3db950c75844..be3b61665b11f 100644
--- a/src/test/ui/associated-types/issue-63593.stderr
+++ b/src/test/ui/associated-types/issue-63593.stderr
@@ -6,7 +6,6 @@ LL | trait MyTrait {
 LL |     type This = Self;
    |     ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL | trait MyTrait: std::marker::Sized {
diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
index f2ed2d32bd1e0..7813d3b6596bf 100644
--- a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
+++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
@@ -9,7 +9,6 @@ LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self>
 LL | pub trait Add<Rhs = Self> {
    |               --- required by this bound in `std::ops::Add`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + std::marker::Sized {}
diff --git a/src/test/ui/async-await/issue-70818.stderr b/src/test/ui/async-await/issue-70818.stderr
index 5fb772fa10acb..2166420070a07 100644
--- a/src/test/ui/async-await/issue-70818.stderr
+++ b/src/test/ui/async-await/issue-70818.stderr
@@ -7,7 +7,6 @@ LL |
 LL |     async { (ty, ty1) }
    |     ------------------- this returned value is of type `impl std::future::Future`
    |
-   = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `U`
 note: captured value is not `Send`
   --> $DIR/issue-70818.rs:6:18
    |
diff --git a/src/test/ui/bad/bad-method-typaram-kind.stderr b/src/test/ui/bad/bad-method-typaram-kind.stderr
index 81fc961e3dea0..fd3999ae6fbec 100644
--- a/src/test/ui/bad/bad-method-typaram-kind.stderr
+++ b/src/test/ui/bad/bad-method-typaram-kind.stderr
@@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely
 LL |     1.bar::<T>();
    |       ^^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
 help: consider further restricting this bound
    |
 LL | fn foo<T:'static + std::marker::Send>() {
diff --git a/src/test/ui/bound-suggestions.stderr b/src/test/ui/bound-suggestions.stderr
index b9bc503f5301a..623252a8c1139 100644
--- a/src/test/ui/bound-suggestions.stderr
+++ b/src/test/ui/bound-suggestions.stderr
@@ -4,7 +4,6 @@ error[E0277]: `impl Sized` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", t);
    |                      ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `impl Sized`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting this bound
@@ -18,7 +17,6 @@ error[E0277]: `T` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", t);
    |                      ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `T`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider restricting type parameter `T`
@@ -32,7 +30,6 @@ error[E0277]: `T` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", t);
    |                      ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `T`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting this bound
@@ -46,7 +43,6 @@ error[E0277]: `Y` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?} {:?}", x, y);
    |                              ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `Y`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting type parameter `Y`
@@ -60,7 +56,6 @@ error[E0277]: `X` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", x);
    |                      ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `X`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting this bound
@@ -74,7 +69,6 @@ error[E0277]: `X` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", x);
    |                      ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `X`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting type parameter `X`
diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
index 4e7b513629d05..7ff986ec38109 100644
--- a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
+++ b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
@@ -7,7 +7,6 @@ LL |
 LL | impl <T: Sync+'static> Foo for (T,) { }
    |                        ^^^ `T` cannot be sent between threads safely
    |
-   = help: within `(T,)`, the trait `std::marker::Send` is not implemented for `T`
    = note: required because it appears within the type `(T,)`
 help: consider further restricting this bound
    |
@@ -23,7 +22,6 @@ LL | trait Foo : Send+Sync { }
 LL | impl <T: Send> Foo for (T,T) { }
    |                ^^^ `T` cannot be shared between threads safely
    |
-   = help: within `(T, T)`, the trait `std::marker::Sync` is not implemented for `T`
    = note: required because it appears within the type `(T, T)`
 help: consider further restricting this bound
    |
diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
index 3fb1af3a67cc2..9ee045edfe546 100644
--- a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
+++ b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
@@ -9,7 +9,6 @@ LL | impl <T:Sync+'static> RequiresRequiresShareAndSend for X<T> { }
 LL | pub trait RequiresRequiresShareAndSend : RequiresShare + Send { }
    |                                                          ---- required by this bound in `trait_superkinds_in_metadata::RequiresRequiresShareAndSend`
    |
-   = help: within `X<T>`, the trait `std::marker::Send` is not implemented for `T`
    = note: required because it appears within the type `X<T>`
 help: consider further restricting this bound
    |
diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
index 9c5073a1e49d7..ad80b3fa8d11f 100644
--- a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
+++ b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
@@ -7,7 +7,6 @@ LL |
 LL | impl <T: Sync+'static> Foo for T { }
    |                        ^^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
 help: consider further restricting this bound
    |
 LL | impl <T: Sync+'static + std::marker::Send> Foo for T { }
diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
index ffd70fac6b19b..273eae995538a 100644
--- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
+++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
@@ -7,7 +7,6 @@ LL | struct X<F> where F: FnOnce() + 'static + Send {
 LL | fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static {
    |                      ^^^^ `F` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `F`
 help: consider further restricting this bound
    |
 LL | fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static + std::marker::Send {
diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr
index 691864c9e1d45..7df29d5a098a0 100644
--- a/src/test/ui/closures/closure-bounds-subtype.stderr
+++ b/src/test/ui/closures/closure-bounds-subtype.stderr
@@ -7,7 +7,6 @@ LL | fn take_const_owned<F>(_: F) where F: FnOnce() + Sync + Send {
 LL |     take_const_owned(f);
    |                      ^ `F` cannot be shared between threads safely
    |
-   = help: the trait `std::marker::Sync` is not implemented for `F`
 help: consider further restricting this bound
    |
 LL | fn give_owned<F>(f: F) where F: FnOnce() + Send + std::marker::Sync {
diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr
index d6e9aaab7cf39..da8ead885c898 100644
--- a/src/test/ui/dst/dst-object-from-unsized-type.stderr
+++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr
@@ -6,7 +6,6 @@ LL | fn test1<T: ?Sized + Foo>(t: &T) {
 LL |     let u: &dyn Foo = t;
    |                       ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
@@ -17,7 +16,6 @@ LL | fn test2<T: ?Sized + Foo>(t: &T) {
 LL |     let v: &dyn Foo = t as &dyn Foo;
    |                       ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
index 89cc5dfd06018..2fab7ffb66050 100644
--- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
+++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
@@ -16,7 +16,6 @@ LL |     type F<'a>: Fn() -> u32;
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
    |
-   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
    = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
index efd3287853f03..186e142138be2 100644
--- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
+++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
@@ -16,7 +16,6 @@ LL |     type F<'a>: Fn() -> u32;
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
    |
-   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
    = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
index 5da924a512f00..d16bdcbbb6b00 100644
--- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
+++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
@@ -16,7 +16,6 @@ LL |     type F<'a>: Fn() -> u32;
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
    |
-   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
    = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
index 12d84ab6a369b..72c42917c83c9 100644
--- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
+++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
@@ -16,7 +16,6 @@ LL |     type F<'a>: Fn() -> u32;
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
    |
-   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
    = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr
index 7bd2578344458..cbaa7507244a3 100644
--- a/src/test/ui/issues/issue-20005.stderr
+++ b/src/test/ui/issues/issue-20005.stderr
@@ -7,7 +7,6 @@ LL | trait From<Src> {
 LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self> {
    |                                                 ^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self>, Self: std::marker::Sized {
diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr
index 881fae1942335..96696fabd9338 100644
--- a/src/test/ui/issues/issue-27060-2.stderr
+++ b/src/test/ui/issues/issue-27060-2.stderr
@@ -6,7 +6,6 @@ LL | pub struct Bad<T: ?Sized> {
 LL |     data: T,
    |           ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr
index 4b031d26ad53b..de1810e99aac6 100644
--- a/src/test/ui/issues/issue-27078.stderr
+++ b/src/test/ui/issues/issue-27078.stderr
@@ -4,7 +4,6 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
 LL |     fn foo(self) -> &'static i32 {
    |            ^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
    = help: unsized locals are gated as an unstable feature
 help: consider further restricting `Self`
    |
diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr
index cc98f1d9f34b8..ab9dfc9b8a779 100644
--- a/src/test/ui/kindck/kindck-impl-type-params.stderr
+++ b/src/test/ui/kindck/kindck-impl-type-params.stderr
@@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 help: consider restricting type parameter `T`
@@ -31,7 +30,6 @@ error[E0277]: `T` cannot be sent between threads safely
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 help: consider restricting type parameter `T`
diff --git a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
index 97c7417839825..98bf9923823d7 100644
--- a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
+++ b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
@@ -9,7 +9,6 @@ LL | fn test<T>() {
 LL |     let _: [u8; sof::<T>()];
    |                       ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | pub const fn sof<T: ?Sized>() -> usize {
diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-oibit.stderr
index fd0307f15c79a..e143747d637ee 100644
--- a/src/test/ui/phantom-oibit.stderr
+++ b/src/test/ui/phantom-oibit.stderr
@@ -7,7 +7,6 @@ LL | fn is_zen<T: Zen>(_: T) {}
 LL |     is_zen(x)
    |            ^ `T` cannot be shared between threads safely
    |
-   = help: the trait `std::marker::Sync` is not implemented for `T`
    = note: required because of the requirements on the impl of `Zen` for `&T`
    = note: required because it appears within the type `std::marker::PhantomData<&T>`
    = note: required because it appears within the type `Guard<'_, T>`
@@ -25,7 +24,6 @@ LL | fn is_zen<T: Zen>(_: T) {}
 LL |     is_zen(x)
    |            ^ `T` cannot be shared between threads safely
    |
-   = help: the trait `std::marker::Sync` is not implemented for `T`
    = note: required because of the requirements on the impl of `Zen` for `&T`
    = note: required because it appears within the type `std::marker::PhantomData<&T>`
    = note: required because it appears within the type `Guard<'_, T>`
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
index 7f3c49e753fd7..3da8725d88a0c 100644
--- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
+++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
@@ -24,7 +24,6 @@ LL |     type U<'a>: PartialEq<&'a Self>;
 LL |     default type U<'a> = &'a T;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T`
    |
-   = help: the trait `std::cmp::PartialEq` is not implemented for `T`
    = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T`
 help: consider further restricting this bound
    |
diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
index 0b08b4a16a692..f4c0d0f96c428 100644
--- a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
+++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
@@ -9,7 +9,6 @@ LL | struct Struct5<T: ?Sized>{
 LL |     _t: X<T>,
    |         ^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
    |
@@ -27,7 +26,6 @@ LL |     fn func1() -> Struct1<Self>;
 LL | struct Struct1<T>{
    |                - required by this bound in `Struct1`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL |     fn func1() -> Struct1<Self> where Self: std::marker::Sized;
@@ -46,7 +44,6 @@ LL |     fn func2<'a>() -> Struct2<'a, Self>;
 LL | struct Struct2<'a, T>{
    |                    - required by this bound in `Struct2`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL |     fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized;
@@ -65,7 +62,6 @@ LL |     fn func3() -> Struct3<Self>;
 LL | struct Struct3<T>{
    |                - required by this bound in `Struct3`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16
    |
@@ -87,7 +83,6 @@ LL |     fn func4() -> Struct4<Self>;
 LL | struct Struct4<T>{
    |                - required by this bound in `Struct4`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL |     fn func4() -> Struct4<Self> where Self: std::marker::Sized;
diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr
index 0c52778b0d886..33af13d943f74 100644
--- a/src/test/ui/suggestions/restrict-type-argument.stderr
+++ b/src/test/ui/suggestions/restrict-type-argument.stderr
@@ -7,7 +7,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `impl Sync` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `impl Sync`
 help: consider further restricting this bound
    |
 LL | fn use_impl_sync(val: impl Sync + std::marker::Send) {
@@ -22,7 +21,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider further restricting this bound
    |
 LL | fn use_where<S>(val: S) where S: Sync + std::marker::Send {
@@ -37,7 +35,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider further restricting this bound
    |
 LL | fn use_bound<S: Sync + std::marker::Send>(val: S) {
@@ -52,7 +49,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider further restricting this bound
    |
 LL |     Sync + std::marker::Send
@@ -67,7 +63,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider further restricting this bound
    |
 LL | fn use_bound_and_where<S: Sync>(val: S) where S: std::fmt::Debug + std::marker::Send {
@@ -82,7 +77,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider restricting type parameter `S`
    |
 LL | fn use_unbound<S: std::marker::Send>(val: S) {
diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr
index b8069f9ddb0f6..86a313baa5c38 100644
--- a/src/test/ui/traits/trait-suggest-where-clause.stderr
+++ b/src/test/ui/traits/trait-suggest-where-clause.stderr
@@ -11,8 +11,6 @@ LL |     mem::size_of::<U>();
    |
 LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
-   |
-   = help: the trait `std::marker::Sized` is not implemented for `U`
 
 error[E0277]: the size for values of type `U` cannot be known at compilation time
   --> $DIR/trait-suggest-where-clause.rs:10:5
@@ -28,7 +26,6 @@ LL |     mem::size_of::<Misc<U>>();
 LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
    |
-   = help: within `Misc<U>`, the trait `std::marker::Sized` is not implemented for `U`
    = note: required because it appears within the type `Misc<U>`
 
 error[E0277]: the trait bound `u64: std::convert::From<T>` is not satisfied
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
index 247d68ef2a1f0..28e30cbdd9d96 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
@@ -19,7 +19,6 @@ LL | type Underconstrained<T: std::fmt::Debug> = impl 'static;
 LL |     5u32
    |     ---- this returned value is of type `u32`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `U`
    = note: the return type of a function must have a statically known size
 help: consider restricting type parameter `U`
    |
@@ -35,7 +34,6 @@ LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static;
 LL |     5u32
    |     ---- this returned value is of type `u32`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `V`
    = note: the return type of a function must have a statically known size
 help: consider restricting type parameter `V`
    |
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
index 9cba3578449c3..7398b48a238d1 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
+++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
@@ -7,7 +7,6 @@ LL |     is_send::<T>()
 LL | fn is_send<T:Send>() {
    |              ---- required by this bound in `is_send`
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
 help: consider restricting type parameter `T`
    |
 LL | fn foo<T: std::marker::Send>() {
diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr
index eb169987ccdb9..d7224e46add3d 100644
--- a/src/test/ui/union/union-sized-field.stderr
+++ b/src/test/ui/union/union-sized-field.stderr
@@ -6,7 +6,6 @@ LL | union Foo<T: ?Sized> {
 LL |     value: T,
    |            ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: no field of a union may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -26,7 +25,6 @@ LL | struct Foo2<T: ?Sized> {
 LL |     value: T,
    |            ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -46,7 +44,6 @@ LL | enum Foo3<T: ?Sized> {
 LL |     Value(T),
    |           ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr
index 998cd7a527c9b..19978ae24cacb 100644
--- a/src/test/ui/unsized/unsized-bare-typaram.stderr
+++ b/src/test/ui/unsized/unsized-bare-typaram.stderr
@@ -7,8 +7,6 @@ LL | fn foo<T: ?Sized>() { bar::<T>() }
    |        -                    ^ doesn't have a size known at compile-time
    |        |
    |        this type parameter needs to be `std::marker::Sized`
-   |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr
index cb06e707dcaa8..fdfdb9b4e2a5b 100644
--- a/src/test/ui/unsized/unsized-enum.stderr
+++ b/src/test/ui/unsized/unsized-enum.stderr
@@ -9,7 +9,6 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |         |
    |         this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
 help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box<U>`
   --> $DIR/unsized-enum.rs:4:10
    |
diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr
index 82f395740d5ad..742abc39209e6 100644
--- a/src/test/ui/unsized/unsized-enum2.stderr
+++ b/src/test/ui/unsized/unsized-enum2.stderr
@@ -7,7 +7,6 @@ LL |     // parameter
 LL |     VA(W),
    |        ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `W`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -28,7 +27,6 @@ LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
 LL |     VB{x: X},
    |           ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -49,7 +47,6 @@ LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
 LL |     VC(isize, Y),
    |               ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Y`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -70,7 +67,6 @@ LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
 LL |     VD{u: isize, x: Z},
    |                     ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Z`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
index 0d08f70c558be..50b54593f3aa1 100644
--- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
@@ -9,7 +9,6 @@ LL | impl<X: ?Sized> S5<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
 help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
   --> $DIR/unsized-inherent-impl-self-type.rs:5:11
    |
diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr
index d796fcd1a6b64..0c8529bf1a9af 100644
--- a/src/test/ui/unsized/unsized-struct.stderr
+++ b/src/test/ui/unsized/unsized-struct.stderr
@@ -9,7 +9,6 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |         |
    |         this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/unsized-struct.rs:4:12
    |
@@ -29,7 +28,6 @@ LL | fn bar2<T: ?Sized>() { is_sized::<Bar<T>>() }
    |         |
    |         this type parameter needs to be `std::marker::Sized`
    |
-   = help: within `Bar<T>`, the trait `std::marker::Sized` is not implemented for `T`
    = note: required because it appears within the type `Bar<T>`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
index 623c83c4d6f07..4514208a90dc9 100644
--- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
@@ -9,7 +9,6 @@ LL | impl<X: ?Sized> T3<X> for S5<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
 help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
   --> $DIR/unsized-trait-impl-self-type.rs:8:11
    |
diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
index 1dc9e313d91a6..f48d4ef9f1461 100644
--- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
@@ -9,7 +9,6 @@ LL | impl<X: ?Sized> T2<X> for S4<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait T2<Z: ?Sized> {
diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr
index d5c79c71a2349..ddddae4eaba57 100644
--- a/src/test/ui/unsized3.stderr
+++ b/src/test/ui/unsized3.stderr
@@ -9,7 +9,6 @@ LL |     f2::<X>(x);
 LL | fn f2<X>(x: &X) {
    |       - required by this bound in `f2`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f2<X: ?Sized>(x: &X) {
@@ -26,7 +25,6 @@ LL |     f4::<X>(x);
 LL | fn f4<X: T>(x: &X) {
    |       - required by this bound in `f4`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f4<X: T + ?Sized>(x: &X) {
@@ -43,7 +41,6 @@ LL | fn f8<X: ?Sized>(x1: &S<X>, x2: &S<X>) {
 LL |     f5(x1);
    |        ^^ doesn't have a size known at compile-time
    |
-   = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
    = note: required because it appears within the type `S<X>`
 help: consider relaxing the implicit `Sized` restriction
    |
@@ -58,7 +55,6 @@ LL | fn f9<X: ?Sized>(x1: Box<S<X>>) {
 LL |     f5(&(*x1, 34));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
    = note: required because it appears within the type `S<X>`
    = note: only the last element of a tuple may have a dynamically sized type
 
@@ -70,7 +66,6 @@ LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
 LL |     f5(&(32, *x1));
    |         ^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
    = note: tuples must have a statically known size to be initialized
@@ -86,7 +81,6 @@ LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
 LL |     f5(&(32, *x1));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
 help: consider relaxing the implicit `Sized` restriction
diff --git a/src/test/ui/unsized5.stderr b/src/test/ui/unsized5.stderr
index 9bdcc0399b833..80cf4baeab794 100644
--- a/src/test/ui/unsized5.stderr
+++ b/src/test/ui/unsized5.stderr
@@ -6,7 +6,6 @@ LL | struct S1<X: ?Sized> {
 LL |     f1: X,
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -27,7 +26,6 @@ LL |     f: isize,
 LL |     g: X,
    |        ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -83,7 +81,6 @@ LL | enum E<X: ?Sized> {
 LL |     V1(X, isize),
    |        ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
@@ -103,7 +100,6 @@ LL | enum F<X: ?Sized> {
 LL |     V2{f1: X, f: isize},
    |            ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr
index 82f1e87008d30..f045bfe2444bc 100644
--- a/src/test/ui/unsized6.stderr
+++ b/src/test/ui/unsized6.stderr
@@ -7,7 +7,6 @@ LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
 LL |     let y: Y;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Y`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -20,7 +19,6 @@ LL |     let _: W; // <-- this is OK, no bindings created, no initializer.
 LL |     let _: (isize, (X, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `Z` cannot be known at compilation time
@@ -32,7 +30,6 @@ LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
 LL |     let y: (isize, (Z, usize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Z`
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
@@ -43,7 +40,6 @@ LL | fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
 LL |     let y: X;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -56,7 +52,6 @@ LL | fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
 LL |     let y: (isize, (Y, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Y`
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
@@ -67,7 +62,6 @@ LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -80,7 +74,6 @@ LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -93,7 +86,6 @@ LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -105,7 +97,6 @@ LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -118,7 +109,6 @@ LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -131,7 +121,6 @@ LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -143,7 +132,6 @@ LL | fn g1<X: ?Sized>(x: X) {}
    |       |
    |       this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = help: unsized locals are gated as an unstable feature
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
@@ -158,7 +146,6 @@ LL | fn g2<X: ?Sized + T>(x: X) {}
    |       |
    |       this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
    = help: unsized locals are gated as an unstable feature
 help: function arguments must have a statically known size, borrowed types always have a known size
    |
diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr
index 868c9ea429e24..7dbddd4ed2443 100644
--- a/src/test/ui/unsized7.stderr
+++ b/src/test/ui/unsized7.stderr
@@ -9,7 +9,6 @@ LL | impl<X: ?Sized + T> T1<X> for S3<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait T1<Z: T + ?Sized> {

From 6a7b5df55ffddd5a152ebbb865d490e52e93bec7 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Sat, 11 Jul 2020 15:33:45 -0400
Subject: [PATCH 51/66] Removed unused method

---
 src/libstd/io/buffered.rs | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 597bad0c2eeba..cedc993b46147 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -909,12 +909,6 @@ impl<'a, W: Write> LineWriterShim<'a, W> {
         Self { buffer }
     }
 
-    /// Get a reference to the inner writer (that is, the writer wrapped by
-    /// the BufWriter)
-    fn inner(&self) -> &W {
-        self.buffer.get_ref()
-    }
-
     /// Get a mutable reference to the inner writer (that is, the writer
     /// wrapped by the BufWriter). Be careful with this writer, as writes to
     /// it will bypass the buffer.

From 905b5ad80aca3e4a6d9d5f124978b0278ccdd48e Mon Sep 17 00:00:00 2001
From: Alex Gaynor <alex.gaynor@gmail.com>
Date: Sat, 11 Jul 2020 17:20:33 -0400
Subject: [PATCH 52/66] don't mark linux kernel module targets as a unix
 environment

---
 src/librustc_target/spec/linux_kernel_base.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/librustc_target/spec/linux_kernel_base.rs b/src/librustc_target/spec/linux_kernel_base.rs
index 201d6a0fff93b..6d929d1244789 100644
--- a/src/librustc_target/spec/linux_kernel_base.rs
+++ b/src/librustc_target/spec/linux_kernel_base.rs
@@ -17,7 +17,6 @@ pub fn opts() -> TargetOptions {
         needs_plt: true,
         relro_level: RelroLevel::Full,
         relocation_model: RelocModel::Static,
-        target_family: Some("unix".to_string()),
         pre_link_args,
 
         ..Default::default()

From 606593fecec5510a32b6aa3b0bc2bd5cf81f28e2 Mon Sep 17 00:00:00 2001
From: Nathan West <Lucretiel@gmail.com>
Date: Sun, 12 Jul 2020 01:00:22 -0400
Subject: [PATCH 53/66] Minor updates

- Remove outdated comment
- Refactor flush-retry behavior into its own method
- Some other comment updates
---
 src/libstd/io/buffered.rs | 40 +++++++++++++++++----------------------
 1 file changed, 17 insertions(+), 23 deletions(-)

diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index cedc993b46147..7d9c33582bca1 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -920,6 +920,16 @@ impl<'a, W: Write> LineWriterShim<'a, W> {
     fn buffered(&self) -> &[u8] {
         self.buffer.buffer()
     }
+
+    /// Flush the buffer iff the last byte is a newline (indicating that an
+    /// earlier write only succeeded partially, and we want to retry flushing
+    /// the buffered line before continuing with a subsequent write)
+    fn flush_if_completed_line(&mut self) -> io::Result<()> {
+        match self.buffered().last().copied() {
+            Some(b'\n') => self.buffer.flush_buf(),
+            _ => Ok(()),
+        }
+    }
 }
 
 impl<'a, W: Write> Write for LineWriterShim<'a, W> {
@@ -941,12 +951,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
             // If there are no new newlines (that is, if this write is less than
             // one line), just do a regular buffered write
             None => {
-                // Check for prior partial line writes that need to be retried.
-                // Only retry if the buffer contains a completed line, to
-                // avoid flushing partial lines.
-                if let Some(b'\n') = self.buffered().last().copied() {
-                    self.buffer.flush_buf()?;
-                }
+                self.flush_if_completed_line()?;
                 return self.buffer.write(buf);
             }
             // Otherwise, arrange for the lines to be written directly to the
@@ -1025,9 +1030,10 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     /// Because sorting through an array of `IoSlice` can be a bit convoluted,
     /// This method differs from write in the following ways:
     ///
-    /// - It attempts to write all the buffers up to and including the one
-    ///   containing the last newline. This means that it may attempt to
-    ///   write a partial line.
+    /// - It attempts to write the full content of all the buffers up to and
+    ///   including the one containing the last newline. This means that it
+    ///   may attempt to write a partial line, that buffer has data past the
+    ///   newline.
     /// - If the write only reports partial success, it does not attempt to
     ///   find the precise location of the written bytes and buffer the rest.
     ///
@@ -1057,12 +1063,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
         let last_newline_buf_idx = match last_newline_buf_idx {
             // No newlines; just do a normal buffered write
             None => {
-                // Check for prior partial line writes that need to be retried.
-                // Only retry if the buffer contains a completed line, to
-                // avoid flushing partial lines.
-                if let Some(b'\n') = self.buffered().last().copied() {
-                    self.buffer.flush_buf()?;
-                }
+                self.flush_if_completed_line()?;
                 return self.buffer.write_vectored(bufs);
             }
             Some(i) => i,
@@ -1109,8 +1110,6 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
     }
 
     fn is_write_vectored(&self) -> bool {
-        // It's hard to imagine these diverging, but it's worth checking
-        // just in case, because we call `write_vectored` on both.
         self.buffer.is_write_vectored()
     }
 
@@ -1127,12 +1126,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> {
             // If there are no new newlines (that is, if this write is less than
             // one line), just do a regular buffered write
             None => {
-                // Check for prior partial line writes that need to be retried.
-                // Only retry if the buffer contains a completed line, to
-                // avoid flushing partial lines.
-                if let Some(b'\n') = self.buffered().last().copied() {
-                    self.buffer.flush_buf()?;
-                }
+                self.flush_if_completed_line()?;
                 return self.buffer.write_all(buf);
             }
             // Otherwise, arrange for the lines to be written directly to the

From 8082fb988a5915e693f18e6d299deaae64834079 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 12 Jul 2020 11:37:11 +0200
Subject: [PATCH 54/66] rename fast_thread_local -> thread_local_dtor;
 thread_local -> thread_local_key

---
 src/libstd/sys/unix/mod.rs                    |  4 +-
 ...t_thread_local.rs => thread_local_dtor.rs} |  5 +-
 .../{thread_local.rs => thread_local_key.rs}  |  0
 src/libstd/sys/windows/mod.rs                 |  4 +-
 ...t_thread_local.rs => thread_local_dtor.rs} |  2 +-
 .../{thread_local.rs => thread_local_key.rs}  |  0
 src/libstd/sys_common/mod.rs                  |  3 +-
 src/libstd/sys_common/thread_local_dtor.rs    | 49 +++++++++++++++++++
 .../{thread_local.rs => thread_local_key.rs}  | 39 ++-------------
 src/libstd/thread/local.rs                    |  4 +-
 10 files changed, 65 insertions(+), 45 deletions(-)
 rename src/libstd/sys/unix/{fast_thread_local.rs => thread_local_dtor.rs} (94%)
 rename src/libstd/sys/unix/{thread_local.rs => thread_local_key.rs} (100%)
 rename src/libstd/sys/windows/{fast_thread_local.rs => thread_local_dtor.rs} (52%)
 rename src/libstd/sys/windows/{thread_local.rs => thread_local_key.rs} (100%)
 create mode 100644 src/libstd/sys_common/thread_local_dtor.rs
 rename src/libstd/sys_common/{thread_local.rs => thread_local_key.rs} (85%)

diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index b1688e74173d7..7cde02baedbe8 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -47,7 +47,6 @@ pub mod cmath;
 pub mod condvar;
 pub mod env;
 pub mod ext;
-pub mod fast_thread_local;
 pub mod fd;
 pub mod fs;
 pub mod io;
@@ -68,7 +67,8 @@ pub mod rwlock;
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_key;
+pub mod thread_local_dtor;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/thread_local_dtor.rs
similarity index 94%
rename from src/libstd/sys/unix/fast_thread_local.rs
rename to src/libstd/sys/unix/thread_local_dtor.rs
index 8730b4de8bed2..c3275eb6f0e50 100644
--- a/src/libstd/sys/unix/fast_thread_local.rs
+++ b/src/libstd/sys/unix/thread_local_dtor.rs
@@ -1,6 +1,9 @@
 #![cfg(target_thread_local)]
 #![unstable(feature = "thread_local_internals", issue = "none")]
 
+//! Provides thread-local destructors without an associated "key", which
+//! can be more efficient.
+
 // Since what appears to be glibc 2.18 this symbol has been shipped which
 // GCC and clang both use to invoke destructors in thread_local globals, so
 // let's do the same!
@@ -16,7 +19,7 @@
 ))]
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     use crate::mem;
-    use crate::sys_common::thread_local::register_dtor_fallback;
+    use crate::sys_common::thread_local_dtor::register_dtor_fallback;
 
     extern "C" {
         #[linkage = "extern_weak"]
diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local_key.rs
similarity index 100%
rename from src/libstd/sys/unix/thread_local.rs
rename to src/libstd/sys/unix/thread_local_key.rs
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 193ab5b47ef13..d6a8eec4b80cd 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -20,7 +20,6 @@ pub mod cmath;
 pub mod condvar;
 pub mod env;
 pub mod ext;
-pub mod fast_thread_local;
 pub mod fs;
 pub mod handle;
 pub mod io;
@@ -35,7 +34,8 @@ pub mod process;
 pub mod rand;
 pub mod rwlock;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_key;
+pub mod thread_local_dtor;
 pub mod time;
 cfg_if::cfg_if! {
     if #[cfg(not(target_vendor = "uwp"))] {
diff --git a/src/libstd/sys/windows/fast_thread_local.rs b/src/libstd/sys/windows/thread_local_dtor.rs
similarity index 52%
rename from src/libstd/sys/windows/fast_thread_local.rs
rename to src/libstd/sys/windows/thread_local_dtor.rs
index 191fa07f32a55..7be13bc4b2bc7 100644
--- a/src/libstd/sys/windows/fast_thread_local.rs
+++ b/src/libstd/sys/windows/thread_local_dtor.rs
@@ -1,4 +1,4 @@
 #![unstable(feature = "thread_local_internals", issue = "none")]
 #![cfg(target_thread_local)]
 
-pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
+pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor;
diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local_key.rs
similarity index 100%
rename from src/libstd/sys/windows/thread_local.rs
rename to src/libstd/sys/windows/thread_local_key.rs
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index e03e0fc83454b..1212b05c88aff 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -65,7 +65,8 @@ pub mod remutex;
 pub mod rwlock;
 pub mod thread;
 pub mod thread_info;
-pub mod thread_local;
+pub mod thread_local_key;
+pub mod thread_local_dtor;
 pub mod util;
 pub mod wtf8;
 
diff --git a/src/libstd/sys_common/thread_local_dtor.rs b/src/libstd/sys_common/thread_local_dtor.rs
new file mode 100644
index 0000000000000..6f5ebf4a27158
--- /dev/null
+++ b/src/libstd/sys_common/thread_local_dtor.rs
@@ -0,0 +1,49 @@
+//! Thread-local destructor
+//!
+//! Besides thread-local "keys" (pointer-sized non-adressable thread-local store
+//! with an associated destructor), many platforms also provide thread-local
+//! destructors that are not associated with any particular data. These are
+//! often more efficient.
+//!
+//! This module provides a fallback implementation for that interface, based
+//! on the less efficient thread-local "keys". Each platform provides
+//! a `thread_local_dtor` module which will either re-export the fallback,
+//! or implement something more efficient.
+
+#![unstable(feature = "thread_local_internals", issue = "none")]
+#![allow(dead_code)] // sys isn't exported yet
+
+use crate::ptr;
+use crate::sys_common::thread_local_key::StaticKey;
+
+pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+    // The fallback implementation uses a vanilla OS-based TLS key to track
+    // the list of destructors that need to be run for this thread. The key
+    // then has its own destructor which runs all the other destructors.
+    //
+    // The destructor for DTORS is a little special in that it has a `while`
+    // loop to continuously drain the list of registered destructors. It
+    // *should* be the case that this loop always terminates because we
+    // provide the guarantee that a TLS key cannot be set after it is
+    // flagged for destruction.
+
+    static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
+    type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+    if DTORS.get().is_null() {
+        let v: Box<List> = box Vec::new();
+        DTORS.set(Box::into_raw(v) as *mut u8);
+    }
+    let list: &mut List = &mut *(DTORS.get() as *mut List);
+    list.push((t, dtor));
+
+    unsafe extern "C" fn run_dtors(mut ptr: *mut u8) {
+        while !ptr.is_null() {
+            let list: Box<List> = Box::from_raw(ptr as *mut List);
+            for (ptr, dtor) in list.into_iter() {
+                dtor(ptr);
+            }
+            ptr = DTORS.get();
+            DTORS.set(ptr::null_mut());
+        }
+    }
+}
diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local_key.rs
similarity index 85%
rename from src/libstd/sys_common/thread_local.rs
rename to src/libstd/sys_common/thread_local_key.rs
index 756b8d044a20e..ac5b128298d78 100644
--- a/src/libstd/sys_common/thread_local.rs
+++ b/src/libstd/sys_common/thread_local_key.rs
@@ -4,7 +4,7 @@
 //! using the native OS-provided facilities (think `TlsAlloc` or
 //! `pthread_setspecific`). The interface of this differs from the other types
 //! of thread-local-storage provided in this crate in that OS-based TLS can only
-//! get/set pointers,
+//! get/set pointer-sized data, possibly with an associated destructor.
 //!
 //! This module also provides two flavors of TLS. One is intended for static
 //! initialization, and does not contain a `Drop` implementation to deallocate
@@ -14,7 +14,7 @@
 //! # Usage
 //!
 //! This module should likely not be used directly unless other primitives are
-//! being built on. types such as `thread_local::spawn::Key` are likely much
+//! being built on. Types such as `thread_local::spawn::Key` are likely much
 //! more useful in practice than this OS-based version which likely requires
 //! unsafe code to interoperate with.
 //!
@@ -48,9 +48,8 @@
 #![unstable(feature = "thread_local_internals", issue = "none")]
 #![allow(dead_code)] // sys isn't exported yet
 
-use crate::ptr;
 use crate::sync::atomic::{self, AtomicUsize, Ordering};
-use crate::sys::thread_local as imp;
+use crate::sys::thread_local_key as imp;
 use crate::sys_common::mutex::Mutex;
 
 /// A type for TLS keys that are statically allocated.
@@ -233,38 +232,6 @@ impl Drop for Key {
     }
 }
 
-pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
-    // The fallback implementation uses a vanilla OS-based TLS key to track
-    // the list of destructors that need to be run for this thread. The key
-    // then has its own destructor which runs all the other destructors.
-    //
-    // The destructor for DTORS is a little special in that it has a `while`
-    // loop to continuously drain the list of registered destructors. It
-    // *should* be the case that this loop always terminates because we
-    // provide the guarantee that a TLS key cannot be set after it is
-    // flagged for destruction.
-
-    static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
-    type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
-    if DTORS.get().is_null() {
-        let v: Box<List> = box Vec::new();
-        DTORS.set(Box::into_raw(v) as *mut u8);
-    }
-    let list: &mut List = &mut *(DTORS.get() as *mut List);
-    list.push((t, dtor));
-
-    unsafe extern "C" fn run_dtors(mut ptr: *mut u8) {
-        while !ptr.is_null() {
-            let list: Box<List> = Box::from_raw(ptr as *mut List);
-            for (ptr, dtor) in list.into_iter() {
-                dtor(ptr);
-            }
-            ptr = DTORS.get();
-            DTORS.set(ptr::null_mut());
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::{Key, StaticKey};
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index 094c468a6770e..ecd6fbc6b9395 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -363,7 +363,7 @@ pub mod fast {
     use crate::cell::Cell;
     use crate::fmt;
     use crate::mem;
-    use crate::sys::fast_thread_local::register_dtor;
+    use crate::sys::thread_local_dtor::register_dtor;
 
     #[derive(Copy, Clone)]
     enum DtorState {
@@ -468,7 +468,7 @@ pub mod os {
     use crate::fmt;
     use crate::marker;
     use crate::ptr;
-    use crate::sys_common::thread_local::StaticKey as OsStaticKey;
+    use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
 
     pub struct Key<T> {
         // OS-TLS key that we'll use to key off.

From 7dc388654d6ef038065db23340e8eff7a567e5b4 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 12 Jul 2020 11:45:04 +0200
Subject: [PATCH 55/66] adjust remaining targets

---
 src/libstd/sys/cloudabi/mod.rs                         |  4 ++--
 src/libstd/sys/hermit/mod.rs                           |  4 ++--
 .../{fast_thread_local.rs => thread_local_dtor.rs}     |  0
 .../thread_local.rs => hermit/thread_local_key.rs}     | 10 +++++-----
 src/libstd/sys/sgx/mod.rs                              |  2 +-
 .../sys/sgx/{thread_local.rs => thread_local_key.rs}   |  0
 src/libstd/sys/unix/mod.rs                             |  2 +-
 src/libstd/sys/vxworks/mod.rs                          |  4 ++--
 .../{fast_thread_local.rs => thread_local_dtor.rs}     |  4 ----
 .../vxworks/{thread_local.rs => thread_local_key.rs}   |  0
 src/libstd/sys/wasi/mod.rs                             |  8 ++++----
 src/libstd/sys/wasm/mod.rs                             |  4 ++--
 .../{fast_thread_local.rs => thread_local_dtor.rs}     |  0
 .../thread_local.rs => wasm/thread_local_key.rs}       |  0
 src/libstd/sys/windows/mod.rs                          |  2 +-
 src/libstd/sys_common/mod.rs                           |  2 +-
 16 files changed, 21 insertions(+), 25 deletions(-)
 rename src/libstd/sys/hermit/{fast_thread_local.rs => thread_local_dtor.rs} (100%)
 rename src/libstd/sys/{wasm/thread_local.rs => hermit/thread_local_key.rs} (54%)
 rename src/libstd/sys/sgx/{thread_local.rs => thread_local_key.rs} (100%)
 rename src/libstd/sys/vxworks/{fast_thread_local.rs => thread_local_dtor.rs} (82%)
 rename src/libstd/sys/vxworks/{thread_local.rs => thread_local_key.rs} (100%)
 rename src/libstd/sys/wasm/{fast_thread_local.rs => thread_local_dtor.rs} (100%)
 rename src/libstd/sys/{hermit/thread_local.rs => wasm/thread_local_key.rs} (100%)

diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs
index 8dbc31472d637..f7dd2c8d00fd2 100644
--- a/src/libstd/sys/cloudabi/mod.rs
+++ b/src/libstd/sys/cloudabi/mod.rs
@@ -16,8 +16,8 @@ pub mod rwlock;
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-#[path = "../unix/thread_local.rs"]
-pub mod thread_local;
+#[path = "../unix/thread_local_key.rs"]
+pub mod thread_local_key;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
diff --git a/src/libstd/sys/hermit/mod.rs b/src/libstd/sys/hermit/mod.rs
index 7bdc1be3b1702..675b82ceb775f 100644
--- a/src/libstd/sys/hermit/mod.rs
+++ b/src/libstd/sys/hermit/mod.rs
@@ -22,7 +22,6 @@ pub mod cmath;
 pub mod condvar;
 pub mod env;
 pub mod ext;
-pub mod fast_thread_local;
 pub mod fd;
 pub mod fs;
 pub mod io;
@@ -37,7 +36,8 @@ pub mod rwlock;
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod time;
 
 use crate::io::ErrorKind;
diff --git a/src/libstd/sys/hermit/fast_thread_local.rs b/src/libstd/sys/hermit/thread_local_dtor.rs
similarity index 100%
rename from src/libstd/sys/hermit/fast_thread_local.rs
rename to src/libstd/sys/hermit/thread_local_dtor.rs
diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/hermit/thread_local_key.rs
similarity index 54%
rename from src/libstd/sys/wasm/thread_local.rs
rename to src/libstd/sys/hermit/thread_local_key.rs
index f8be9863ed56f..bf1b49eb83b7e 100644
--- a/src/libstd/sys/wasm/thread_local.rs
+++ b/src/libstd/sys/hermit/thread_local_key.rs
@@ -2,25 +2,25 @@ pub type Key = usize;
 
 #[inline]
 pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on the hermit target");
 }
 
 #[inline]
 pub unsafe fn set(_key: Key, _value: *mut u8) {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on the hermit target");
 }
 
 #[inline]
 pub unsafe fn get(_key: Key) -> *mut u8 {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on the hermit target");
 }
 
 #[inline]
 pub unsafe fn destroy(_key: Key) {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on the hermit target");
 }
 
 #[inline]
 pub fn requires_synchronized_create() -> bool {
-    panic!("should not be used on the wasm target");
+    panic!("should not be used on the hermit target");
 }
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
index 397dd496ae8af..a4968ff7d4f54 100644
--- a/src/libstd/sys/sgx/mod.rs
+++ b/src/libstd/sys/sgx/mod.rs
@@ -30,7 +30,7 @@ pub mod rwlock;
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_key;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
diff --git a/src/libstd/sys/sgx/thread_local.rs b/src/libstd/sys/sgx/thread_local_key.rs
similarity index 100%
rename from src/libstd/sys/sgx/thread_local.rs
rename to src/libstd/sys/sgx/thread_local_key.rs
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 7cde02baedbe8..eddf00d3979f5 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -67,8 +67,8 @@ pub mod rwlock;
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local_key;
 pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs
index 0787e7098988c..1132a849e2f18 100644
--- a/src/libstd/sys/vxworks/mod.rs
+++ b/src/libstd/sys/vxworks/mod.rs
@@ -13,7 +13,6 @@ pub mod cmath;
 pub mod condvar;
 pub mod env;
 pub mod ext;
-pub mod fast_thread_local;
 pub mod fd;
 pub mod fs;
 pub mod io;
@@ -29,7 +28,8 @@ pub mod rwlock;
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/thread_local_dtor.rs
similarity index 82%
rename from src/libstd/sys/vxworks/fast_thread_local.rs
rename to src/libstd/sys/vxworks/thread_local_dtor.rs
index 098668cf521dd..3f73f6c490326 100644
--- a/src/libstd/sys/vxworks/fast_thread_local.rs
+++ b/src/libstd/sys/vxworks/thread_local_dtor.rs
@@ -5,7 +5,3 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     use crate::sys_common::thread_local::register_dtor_fallback;
     register_dtor_fallback(t, dtor);
 }
-
-pub fn requires_move_before_drop() -> bool {
-    false
-}
diff --git a/src/libstd/sys/vxworks/thread_local.rs b/src/libstd/sys/vxworks/thread_local_key.rs
similarity index 100%
rename from src/libstd/sys/vxworks/thread_local.rs
rename to src/libstd/sys/vxworks/thread_local_key.rs
diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs
index 4fe9661421b03..85f5282034ff1 100644
--- a/src/libstd/sys/wasi/mod.rs
+++ b/src/libstd/sys/wasi/mod.rs
@@ -36,8 +36,6 @@ pub mod net;
 pub mod os;
 pub use crate::sys_common::os_str_bytes as os_str;
 pub mod ext;
-#[path = "../wasm/fast_thread_local.rs"]
-pub mod fast_thread_local;
 pub mod path;
 pub mod pipe;
 pub mod process;
@@ -47,8 +45,10 @@ pub mod rwlock;
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-#[path = "../wasm/thread_local.rs"]
-pub mod thread_local;
+#[path = "../wasm/thread_local_dtor.rs"]
+pub mod thread_local_dtor;
+#[path = "../wasm/thread_local_key.rs"]
+pub mod thread_local_key;
 pub mod time;
 
 #[cfg(not(test))]
diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs
index 050e8099af4ba..6939596e52d78 100644
--- a/src/libstd/sys/wasm/mod.rs
+++ b/src/libstd/sys/wasm/mod.rs
@@ -20,7 +20,6 @@ pub mod alloc;
 pub mod args;
 pub mod cmath;
 pub mod env;
-pub mod fast_thread_local;
 pub mod fs;
 pub mod io;
 pub mod memchr;
@@ -32,7 +31,8 @@ pub mod process;
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
diff --git a/src/libstd/sys/wasm/fast_thread_local.rs b/src/libstd/sys/wasm/thread_local_dtor.rs
similarity index 100%
rename from src/libstd/sys/wasm/fast_thread_local.rs
rename to src/libstd/sys/wasm/thread_local_dtor.rs
diff --git a/src/libstd/sys/hermit/thread_local.rs b/src/libstd/sys/wasm/thread_local_key.rs
similarity index 100%
rename from src/libstd/sys/hermit/thread_local.rs
rename to src/libstd/sys/wasm/thread_local_key.rs
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index d6a8eec4b80cd..9a52371280e15 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -34,8 +34,8 @@ pub mod process;
 pub mod rand;
 pub mod rwlock;
 pub mod thread;
-pub mod thread_local_key;
 pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod time;
 cfg_if::cfg_if! {
     if #[cfg(not(target_vendor = "uwp"))] {
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index 1212b05c88aff..e57bb267cbd0f 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -65,8 +65,8 @@ pub mod remutex;
 pub mod rwlock;
 pub mod thread;
 pub mod thread_info;
-pub mod thread_local_key;
 pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod util;
 pub mod wtf8;
 

From ff5e1078fc911c6ca97c64fbaefe7a2aebedbb0d Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 12 Jul 2020 12:48:43 +0200
Subject: [PATCH 56/66] assign tracking issue

---
 src/libcore/ptr/const_ptr.rs | 6 +++---
 src/libcore/ptr/mut_ptr.rs   | 6 +++---
 src/libcore/ptr/non_null.rs  | 6 +++---
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs
index 22c741d4651a5..39d4aca636a05 100644
--- a/src/libcore/ptr/const_ptr.rs
+++ b/src/libcore/ptr/const_ptr.rs
@@ -842,8 +842,8 @@ impl<T> *const [T] {
     /// assert_eq!(slice.as_ptr(), 0 as *const i8);
     /// ```
     #[inline]
-    #[unstable(feature = "slice_ptr_get", issue = "none")]
-    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "none")]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
     pub const fn as_ptr(self) -> *const T {
         self as *const T
     }
@@ -867,7 +867,7 @@ impl<T> *const [T] {
     ///     assert_eq!(x.get_unchecked(1), x.as_ptr().add(1));
     /// }
     /// ```
-    #[unstable(feature = "slice_ptr_get", issue = "none")]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
     #[inline]
     pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
     where
diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs
index 56bade706942a..644465d7d17f8 100644
--- a/src/libcore/ptr/mut_ptr.rs
+++ b/src/libcore/ptr/mut_ptr.rs
@@ -1043,8 +1043,8 @@ impl<T> *mut [T] {
     /// assert_eq!(slice.as_mut_ptr(), 0 as *mut i8);
     /// ```
     #[inline]
-    #[unstable(feature = "slice_ptr_get", issue = "none")]
-    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "none")]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
     pub const fn as_mut_ptr(self) -> *mut T {
         self as *mut T
     }
@@ -1068,7 +1068,7 @@ impl<T> *mut [T] {
     ///     assert_eq!(x.get_unchecked_mut(1), x.as_mut_ptr().add(1));
     /// }
     /// ```
-    #[unstable(feature = "slice_ptr_get", issue = "none")]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
     #[inline]
     pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
     where
diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs
index f59da631b46ab..b362a49d604e7 100644
--- a/src/libcore/ptr/non_null.rs
+++ b/src/libcore/ptr/non_null.rs
@@ -217,8 +217,8 @@ impl<T> NonNull<[T]> {
     /// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap());
     /// ```
     #[inline]
-    #[unstable(feature = "slice_ptr_get", issue = "none")]
-    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "none")]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
     pub const fn as_non_null_ptr(self) -> NonNull<T> {
         // SAFETY: We know `self` is non-null.
         unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) }
@@ -245,7 +245,7 @@ impl<T> NonNull<[T]> {
     ///     assert_eq!(x.get_unchecked_mut(1).as_ptr(), x.as_non_null_ptr().as_ptr().add(1));
     /// }
     /// ```
-    #[unstable(feature = "slice_ptr_get", issue = "none")]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
     #[inline]
     pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
     where

From d512a6c5e0273c680ca32086eb8264ac58796da6 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Fri, 10 Jul 2020 19:00:38 +0200
Subject: [PATCH 57/66] Don't panic if the lhs of a div by zero is not
 statically known

---
 src/librustc_mir/transform/const_prop.rs      | 26 +++++++++++++++----
 .../const_prop/ice-assert-fail-div-by-zero.rs | 10 ++++---
 .../ice-assert-fail-div-by-zero.stderr        | 14 ++++++++++
 3 files changed, 41 insertions(+), 9 deletions(-)
 create mode 100644 src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr

diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index fbe3377d87500..237a5a64f8bf8 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -484,7 +484,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         lint: &'static lint::Lint,
         source_info: SourceInfo,
         message: &'static str,
-        panic: AssertKind<ConstInt>,
+        panic: AssertKind<impl std::fmt::Debug>,
     ) -> Option<()> {
         let lint_root = self.lint_root(source_info)?;
         self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
@@ -1004,11 +1004,27 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                     let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected));
                     let value_const = self.ecx.read_scalar(value).unwrap();
                     if expected != value_const {
+                        enum DbgVal<T> {
+                            Val(T),
+                            Underscore,
+                        }
+                        impl<T: std::fmt::Debug> std::fmt::Debug for DbgVal<T> {
+                            fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                                match self {
+                                    Self::Val(val) => val.fmt(fmt),
+                                    Self::Underscore => fmt.write_str("_"),
+                                }
+                            }
+                        }
                         let mut eval_to_int = |op| {
-                            let op = self
-                                .eval_operand(op, source_info)
-                                .expect("if we got here, it must be const");
-                            self.ecx.read_immediate(op).unwrap().to_const_int()
+                            // This can be `None` if the lhs wasn't const propagated and we just
+                            // triggered the assert on the value of the rhs.
+                            match self.eval_operand(op, source_info) {
+                                Some(op) => {
+                                    DbgVal::Val(self.ecx.read_immediate(op).unwrap().to_const_int())
+                                }
+                                None => DbgVal::Underscore,
+                            }
                         };
                         let msg = match msg {
                             AssertKind::DivisionByZero(op) => {
diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs
index 5f2d5e80243fe..a67510d15b09c 100644
--- a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs
+++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs
@@ -1,9 +1,11 @@
-// check-pass
+// build-pass
+
+// compile-flags: --crate-type lib
+
+#![warn(unconditional_panic)]
 
 pub struct Fixed64(i64);
 
 pub fn div(f: Fixed64) {
-    f.0 / 0;
+    f.0 / 0; //~ WARN will panic at runtime
 }
-
-fn main() {}
diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr
new file mode 100644
index 0000000000000..0b42f4abf344e
--- /dev/null
+++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr
@@ -0,0 +1,14 @@
+warning: this operation will panic at runtime
+  --> $DIR/ice-assert-fail-div-by-zero.rs:10:5
+   |
+LL |     f.0 / 0;
+   |     ^^^^^^^ attempt to divide _ by zero
+   |
+note: the lint level is defined here
+  --> $DIR/ice-assert-fail-div-by-zero.rs:5:9
+   |
+LL | #![warn(unconditional_panic)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+

From 5afbc5201c7bf82cadd69a1a0cea49cfe1e41172 Mon Sep 17 00:00:00 2001
From: David Wood <david@davidtw.co>
Date: Sun, 12 Jul 2020 16:40:22 +0100
Subject: [PATCH 58/66] typeck: report placeholder type error w/out span

This commit fixes a regression introduced in rust-lang/rust#70369 which
meant that an error was not being emitted for invalid placeholder types
when there wasn't a span available.

Signed-off-by: David Wood <david@davidtw.co>
---
 src/librustc_typeck/astconv.rs                |   4 +-
 src/librustc_typeck/collect.rs                |  16 ++-
 src/test/ui/issues/issue-74086.rs             |   4 +
 src/test/ui/issues/issue-74086.stderr         |  12 ++
 .../ui/typeck/typeck_type_placeholder_item.rs |   2 +
 .../typeck_type_placeholder_item.stderr       | 128 ++++++++++--------
 6 files changed, 103 insertions(+), 63 deletions(-)
 create mode 100644 src/test/ui/issues/issue-74086.rs
 create mode 100644 src/test/ui/issues/issue-74086.stderr

diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5d1949626dd84..7581940b6ac69 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -3049,14 +3049,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let bare_fn_ty =
             ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi));
 
-        if let (false, Some(ident_span)) = (self.allow_ty_infer(), ident_span) {
+        if !self.allow_ty_infer() {
             // We always collect the spans for placeholder types when evaluating `fn`s, but we
             // only want to emit an error complaining about them if infer types (`_`) are not
             // allowed. `allow_ty_infer` gates this behavior. We check for the presence of
             // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
             crate::collect::placeholder_type_error(
                 tcx,
-                ident_span.shrink_to_hi(),
+                ident_span.map(|sp| sp.shrink_to_hi()),
                 &generics.params[..],
                 visitor.0,
                 true,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 15481660a5218..625b72091a6cc 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -129,7 +129,7 @@ struct CollectItemTypesVisitor<'tcx> {
 /// all already existing generic type parameters to avoid suggesting a name that is already in use.
 crate fn placeholder_type_error(
     tcx: TyCtxt<'tcx>,
-    span: Span,
+    span: Option<Span>,
     generics: &[hir::GenericParam<'_>],
     placeholder_types: Vec<Span>,
     suggest: bool,
@@ -137,12 +137,15 @@ crate fn placeholder_type_error(
     if placeholder_types.is_empty() {
         return;
     }
-    let type_name = generics.next_type_param_name(None);
 
+    let type_name = generics.next_type_param_name(None);
     let mut sugg: Vec<_> =
         placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
+
     if generics.is_empty() {
-        sugg.push((span, format!("<{}>", type_name)));
+        if let Some(span) = span {
+            sugg.push((span, format!("<{}>", type_name)));
+        }
     } else if let Some(arg) = generics.iter().find(|arg| match arg.name {
         hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true,
         _ => false,
@@ -158,6 +161,7 @@ crate fn placeholder_type_error(
             format!(", {}", type_name),
         ));
     }
+
     let mut err = bad_placeholder_type(tcx, placeholder_types);
     if suggest {
         err.multipart_suggestion(
@@ -186,7 +190,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
     let mut visitor = PlaceholderHirTyCollector::default();
     visitor.visit_item(item);
 
-    placeholder_type_error(tcx, generics.span, &generics.params[..], visitor.0, suggest);
+    placeholder_type_error(tcx, Some(generics.span), &generics.params[..], visitor.0, suggest);
 }
 
 impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
@@ -722,7 +726,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::HirId) {
             // Account for `const C: _;` and `type T = _;`.
             let mut visitor = PlaceholderHirTyCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false);
+            placeholder_type_error(tcx, None, &[], visitor.0, false);
         }
 
         hir::TraitItemKind::Type(_, None) => {}
@@ -745,7 +749,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::HirId) {
             // Account for `type T = _;`
             let mut visitor = PlaceholderHirTyCollector::default();
             visitor.visit_impl_item(impl_item);
-            placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false);
+            placeholder_type_error(tcx, None, &[], visitor.0, false);
         }
         hir::ImplItemKind::Const(..) => {}
     }
diff --git a/src/test/ui/issues/issue-74086.rs b/src/test/ui/issues/issue-74086.rs
new file mode 100644
index 0000000000000..f68a665b2f38d
--- /dev/null
+++ b/src/test/ui/issues/issue-74086.rs
@@ -0,0 +1,4 @@
+fn main() {
+    static BUG: fn(_) -> u8 = |_| 8;
+    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121]
+}
diff --git a/src/test/ui/issues/issue-74086.stderr b/src/test/ui/issues/issue-74086.stderr
new file mode 100644
index 0000000000000..4127f48a093f4
--- /dev/null
+++ b/src/test/ui/issues/issue-74086.stderr
@@ -0,0 +1,12 @@
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/issue-74086.rs:2:20
+   |
+LL |     static BUG: fn(_) -> u8 = |_| 8;
+   |                    ^
+   |                    |
+   |                    not allowed in type signatures
+   |                    help: use type parameters instead: `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs
index 99a7023089283..133c5231031fd 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item.rs
+++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs
@@ -32,6 +32,7 @@ fn test7(x: _) { let _x: usize = x; }
 
 fn test8(_f: fn() -> _) { }
 //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures
 
 struct Test9;
 
@@ -98,6 +99,7 @@ pub fn main() {
 
     fn fn_test8(_f: fn() -> _) { }
     //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+    //~^^ ERROR the type placeholder `_` is not allowed within types on item signatures
 
     struct FnTest9;
 
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
index 6c0653d5fcb7c..a1945f2b9cf4e 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
@@ -1,35 +1,35 @@
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:152:18
+  --> $DIR/typeck_type_placeholder_item.rs:154:18
    |
 LL | struct BadStruct<_>(_);
    |                  ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:155:16
+  --> $DIR/typeck_type_placeholder_item.rs:157:16
    |
 LL | trait BadTrait<_> {}
    |                ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:165:19
+  --> $DIR/typeck_type_placeholder_item.rs:167:19
    |
 LL | struct BadStruct1<_, _>(_);
    |                   ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:165:22
+  --> $DIR/typeck_type_placeholder_item.rs:167:22
    |
 LL | struct BadStruct1<_, _>(_);
    |                      ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:170:19
+  --> $DIR/typeck_type_placeholder_item.rs:172:19
    |
 LL | struct BadStruct2<_, T>(_, T);
    |                   ^ expected identifier, found reserved identifier
 
 error: associated constant in `impl` without body
-  --> $DIR/typeck_type_placeholder_item.rs:201:5
+  --> $DIR/typeck_type_placeholder_item.rs:203:5
    |
 LL |     const C: _;
    |     ^^^^^^^^^^-
@@ -37,7 +37,7 @@ LL |     const C: _;
    |               help: provide a definition for the constant: `= <expr>;`
 
 error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/typeck_type_placeholder_item.rs:165:22
+  --> $DIR/typeck_type_placeholder_item.rs:167:22
    |
 LL | struct BadStruct1<_, _>(_);
    |                   -  ^ already used
@@ -131,6 +131,15 @@ help: use type parameters instead
 LL | fn test7<T>(x: T) { let _x: usize = x; }
    |         ^^^    ^
 
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:33:22
+   |
+LL | fn test8(_f: fn() -> _) { }
+   |                      ^
+   |                      |
+   |                      not allowed in type signatures
+   |                      help: use type parameters instead: `T`
+
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:33:22
    |
@@ -143,7 +152,7 @@ LL | fn test8<T>(_f: fn() -> T) { }
    |         ^^^             ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:46:26
+  --> $DIR/typeck_type_placeholder_item.rs:47:26
    |
 LL | fn test11(x: &usize) -> &_ {
    |                         -^
@@ -152,7 +161,7 @@ LL | fn test11(x: &usize) -> &_ {
    |                         help: replace with the correct return type: `&&usize`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:51:52
+  --> $DIR/typeck_type_placeholder_item.rs:52:52
    |
 LL | unsafe fn test12(x: *const usize) -> *const *const _ {
    |                                      --------------^
@@ -161,7 +170,7 @@ LL | unsafe fn test12(x: *const usize) -> *const *const _ {
    |                                      help: replace with the correct return type: `*const *const usize`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:65:8
+  --> $DIR/typeck_type_placeholder_item.rs:66:8
    |
 LL |     a: _,
    |        ^ not allowed in type signatures
@@ -180,13 +189,13 @@ LL |     b: (T, T),
    |
 
 error: missing type for `static` item
-  --> $DIR/typeck_type_placeholder_item.rs:71:12
+  --> $DIR/typeck_type_placeholder_item.rs:72:12
    |
 LL |     static A = 42;
    |            ^ help: provide a type for the item: `A: i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:73:15
+  --> $DIR/typeck_type_placeholder_item.rs:74:15
    |
 LL |     static B: _ = 42;
    |               ^
@@ -195,13 +204,13 @@ LL |     static B: _ = 42;
    |               help: replace `_` with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:75:15
+  --> $DIR/typeck_type_placeholder_item.rs:76:15
    |
 LL |     static C: Option<_> = Some(42);
    |               ^^^^^^^^^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:78:21
+  --> $DIR/typeck_type_placeholder_item.rs:79:21
    |
 LL |     fn fn_test() -> _ { 5 }
    |                     ^
@@ -210,7 +219,7 @@ LL |     fn fn_test() -> _ { 5 }
    |                     help: replace with the correct return type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:81:23
+  --> $DIR/typeck_type_placeholder_item.rs:82:23
    |
 LL |     fn fn_test2() -> (_, _) { (5, 5) }
    |                      -^--^-
@@ -220,7 +229,7 @@ LL |     fn fn_test2() -> (_, _) { (5, 5) }
    |                      help: replace with the correct return type: `(i32, i32)`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:84:22
+  --> $DIR/typeck_type_placeholder_item.rs:85:22
    |
 LL |     static FN_TEST3: _ = "test";
    |                      ^
@@ -229,7 +238,7 @@ LL |     static FN_TEST3: _ = "test";
    |                      help: replace `_` with the correct type: `&str`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:87:22
+  --> $DIR/typeck_type_placeholder_item.rs:88:22
    |
 LL |     static FN_TEST4: _ = 145;
    |                      ^
@@ -238,13 +247,13 @@ LL |     static FN_TEST4: _ = 145;
    |                      help: replace `_` with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:90:22
+  --> $DIR/typeck_type_placeholder_item.rs:91:22
    |
 LL |     static FN_TEST5: (_, _) = (1, 2);
    |                      ^^^^^^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:93:20
+  --> $DIR/typeck_type_placeholder_item.rs:94:20
    |
 LL |     fn fn_test6(_: _) { }
    |                    ^ not allowed in type signatures
@@ -255,7 +264,7 @@ LL |     fn fn_test6<T>(_: T) { }
    |                ^^^    ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:96:20
+  --> $DIR/typeck_type_placeholder_item.rs:97:20
    |
 LL |     fn fn_test7(x: _) { let _x: usize = x; }
    |                    ^ not allowed in type signatures
@@ -266,7 +275,16 @@ LL |     fn fn_test7<T>(x: T) { let _x: usize = x; }
    |                ^^^    ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:99:29
+  --> $DIR/typeck_type_placeholder_item.rs:100:29
+   |
+LL |     fn fn_test8(_f: fn() -> _) { }
+   |                             ^
+   |                             |
+   |                             not allowed in type signatures
+   |                             help: use type parameters instead: `T`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:100:29
    |
 LL |     fn fn_test8(_f: fn() -> _) { }
    |                             ^ not allowed in type signatures
@@ -277,7 +295,7 @@ LL |     fn fn_test8<T>(_f: fn() -> T) { }
    |                ^^^             ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:121:12
+  --> $DIR/typeck_type_placeholder_item.rs:123:12
    |
 LL |         a: _,
    |            ^ not allowed in type signatures
@@ -296,13 +314,13 @@ LL |         b: (T, T),
    |
 
 error[E0282]: type annotations needed
-  --> $DIR/typeck_type_placeholder_item.rs:126:18
+  --> $DIR/typeck_type_placeholder_item.rs:128:18
    |
 LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                  ^ cannot infer type
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:126:28
+  --> $DIR/typeck_type_placeholder_item.rs:128:28
    |
 LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                            ^  ^ not allowed in type signatures
@@ -310,7 +328,7 @@ LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                            not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:130:30
+  --> $DIR/typeck_type_placeholder_item.rs:132:30
    |
 LL |     fn fn_test12(x: i32) -> (_, _) { (x, x) }
    |                             -^--^-
@@ -320,7 +338,7 @@ LL |     fn fn_test12(x: i32) -> (_, _) { (x, x) }
    |                             help: replace with the correct return type: `(i32, i32)`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:133:33
+  --> $DIR/typeck_type_placeholder_item.rs:135:33
    |
 LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
    |                           ------^-
@@ -329,7 +347,7 @@ LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
    |                           help: replace with the correct return type: `(i32, i32)`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:152:21
+  --> $DIR/typeck_type_placeholder_item.rs:154:21
    |
 LL | struct BadStruct<_>(_);
    |                     ^ not allowed in type signatures
@@ -340,7 +358,7 @@ LL | struct BadStruct<T>(T);
    |                  ^  ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:157:15
+  --> $DIR/typeck_type_placeholder_item.rs:159:15
    |
 LL | impl BadTrait<_> for BadStruct<_> {}
    |               ^                ^ not allowed in type signatures
@@ -353,13 +371,13 @@ LL | impl<T> BadTrait<T> for BadStruct<T> {}
    |     ^^^          ^                ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:160:34
+  --> $DIR/typeck_type_placeholder_item.rs:162:34
    |
 LL | fn impl_trait() -> impl BadTrait<_> {
    |                                  ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:165:25
+  --> $DIR/typeck_type_placeholder_item.rs:167:25
    |
 LL | struct BadStruct1<_, _>(_);
    |                         ^ not allowed in type signatures
@@ -370,7 +388,7 @@ LL | struct BadStruct1<T, _>(T);
    |                   ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:170:25
+  --> $DIR/typeck_type_placeholder_item.rs:172:25
    |
 LL | struct BadStruct2<_, T>(_, T);
    |                         ^ not allowed in type signatures
@@ -381,13 +399,13 @@ LL | struct BadStruct2<U, T>(U, T);
    |                   ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:174:14
+  --> $DIR/typeck_type_placeholder_item.rs:176:14
    |
 LL | type X = Box<_>;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:42:27
+  --> $DIR/typeck_type_placeholder_item.rs:43:27
    |
 LL |     fn test10(&self, _x : _) { }
    |                           ^ not allowed in type signatures
@@ -398,7 +416,7 @@ LL |     fn test10<T>(&self, _x : T) { }
    |              ^^^             ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:138:31
+  --> $DIR/typeck_type_placeholder_item.rs:140:31
    |
 LL |     fn method_test1(&self, x: _);
    |                               ^ not allowed in type signatures
@@ -409,7 +427,7 @@ LL |     fn method_test1<T>(&self, x: T);
    |                    ^^^           ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:140:31
+  --> $DIR/typeck_type_placeholder_item.rs:142:31
    |
 LL |     fn method_test2(&self, x: _) -> _;
    |                               ^     ^ not allowed in type signatures
@@ -422,7 +440,7 @@ LL |     fn method_test2<T>(&self, x: T) -> T;
    |                    ^^^           ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:142:31
+  --> $DIR/typeck_type_placeholder_item.rs:144:31
    |
 LL |     fn method_test3(&self) -> _;
    |                               ^ not allowed in type signatures
@@ -433,7 +451,7 @@ LL |     fn method_test3<T>(&self) -> T;
    |                    ^^^           ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:144:26
+  --> $DIR/typeck_type_placeholder_item.rs:146:26
    |
 LL |     fn assoc_fn_test1(x: _);
    |                          ^ not allowed in type signatures
@@ -444,7 +462,7 @@ LL |     fn assoc_fn_test1<T>(x: T);
    |                      ^^^    ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:146:26
+  --> $DIR/typeck_type_placeholder_item.rs:148:26
    |
 LL |     fn assoc_fn_test2(x: _) -> _;
    |                          ^     ^ not allowed in type signatures
@@ -457,7 +475,7 @@ LL |     fn assoc_fn_test2<T>(x: T) -> T;
    |                      ^^^    ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:148:28
+  --> $DIR/typeck_type_placeholder_item.rs:150:28
    |
 LL |     fn assoc_fn_test3() -> _;
    |                            ^ not allowed in type signatures
@@ -468,7 +486,7 @@ LL |     fn assoc_fn_test3<T>() -> T;
    |                      ^^^      ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:60:37
+  --> $DIR/typeck_type_placeholder_item.rs:61:37
    |
 LL |     fn clone_from(&mut self, other: _) { *self = Test9; }
    |                                     ^ not allowed in type signatures
@@ -479,7 +497,7 @@ LL |     fn clone_from<T>(&mut self, other: T) { *self = Test9; }
    |                  ^^^                   ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:108:34
+  --> $DIR/typeck_type_placeholder_item.rs:110:34
    |
 LL |         fn fn_test10(&self, _x : _) { }
    |                                  ^ not allowed in type signatures
@@ -490,7 +508,7 @@ LL |         fn fn_test10<T>(&self, _x : T) { }
    |                     ^^^             ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:116:41
+  --> $DIR/typeck_type_placeholder_item.rs:118:41
    |
 LL |         fn clone_from(&mut self, other: _) { *self = FnTest9; }
    |                                         ^ not allowed in type signatures
@@ -501,25 +519,25 @@ LL |         fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
    |                      ^^^                   ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:180:21
+  --> $DIR/typeck_type_placeholder_item.rs:182:21
    |
 LL | type Y = impl Trait<_>;
    |                     ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:188:14
+  --> $DIR/typeck_type_placeholder_item.rs:190:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:190:14
+  --> $DIR/typeck_type_placeholder_item.rs:192:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:192:14
+  --> $DIR/typeck_type_placeholder_item.rs:194:14
    |
 LL |     const D: _ = 42;
    |              ^
@@ -528,7 +546,7 @@ LL |     const D: _ = 42;
    |              help: replace `_` with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:39:24
+  --> $DIR/typeck_type_placeholder_item.rs:40:24
    |
 LL |     fn test9(&self) -> _ { () }
    |                        ^
@@ -537,7 +555,7 @@ LL |     fn test9(&self) -> _ { () }
    |                        help: replace with the correct return type: `()`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:57:24
+  --> $DIR/typeck_type_placeholder_item.rs:58:24
    |
 LL |     fn clone(&self) -> _ { Test9 }
    |                        ^
@@ -546,7 +564,7 @@ LL |     fn clone(&self) -> _ { Test9 }
    |                        help: replace with the correct return type: `Test9`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:105:31
+  --> $DIR/typeck_type_placeholder_item.rs:107:31
    |
 LL |         fn fn_test9(&self) -> _ { () }
    |                               ^
@@ -555,7 +573,7 @@ LL |         fn fn_test9(&self) -> _ { () }
    |                               help: replace with the correct return type: `()`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:113:28
+  --> $DIR/typeck_type_placeholder_item.rs:115:28
    |
 LL |         fn clone(&self) -> _ { FnTest9 }
    |                            ^
@@ -564,25 +582,25 @@ LL |         fn clone(&self) -> _ { FnTest9 }
    |                            help: replace with the correct return type: `main::FnTest9`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:197:14
+  --> $DIR/typeck_type_placeholder_item.rs:199:14
    |
 LL |     type A = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:199:14
+  --> $DIR/typeck_type_placeholder_item.rs:201:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:201:14
+  --> $DIR/typeck_type_placeholder_item.rs:203:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:204:14
+  --> $DIR/typeck_type_placeholder_item.rs:206:14
    |
 LL |     const D: _ = 42;
    |              ^
@@ -590,7 +608,7 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace `_` with the correct type: `i32`
 
-error: aborting due to 64 previous errors
+error: aborting due to 66 previous errors
 
 Some errors have detailed explanations: E0121, E0282, E0403.
 For more information about an error, try `rustc --explain E0121`.

From 5daedea3dbeb8fb2639d3d142b008135f4fd2b43 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 8 Jul 2020 19:39:26 -0700
Subject: [PATCH 59/66] Detect tuple struct incorrectly used as struct pat

---
 Cargo.lock                                    |  1 +
 src/librustc_error_codes/error_codes.rs       |  1 +
 src/librustc_error_codes/error_codes/E0769.md | 39 ++++++++
 src/librustc_typeck/Cargo.toml                |  1 +
 src/librustc_typeck/check/pat.rs              | 91 ++++++++++++++++---
 .../missing-fields-in-struct-pattern.rs       |  3 +-
 .../missing-fields-in-struct-pattern.stderr   | 17 +---
 src/test/ui/type/type-check/issue-41314.rs    |  4 +-
 .../ui/type/type-check/issue-41314.stderr     | 17 +---
 src/test/ui/union/union-fields-2.stderr       | 12 +--
 10 files changed, 137 insertions(+), 49 deletions(-)
 create mode 100644 src/librustc_error_codes/error_codes/E0769.md

diff --git a/Cargo.lock b/Cargo.lock
index 2096a3dfff9ea..61a0b5caebec6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3996,6 +3996,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hir",
+ "rustc_hir_pretty",
  "rustc_index",
  "rustc_infer",
  "rustc_middle",
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index f687221d78e03..2e1b897216bb2 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -450,6 +450,7 @@ E0765: include_str!("./error_codes/E0765.md"),
 E0766: include_str!("./error_codes/E0766.md"),
 E0767: include_str!("./error_codes/E0767.md"),
 E0768: include_str!("./error_codes/E0768.md"),
+E0769: include_str!("./error_codes/E0769.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/src/librustc_error_codes/error_codes/E0769.md b/src/librustc_error_codes/error_codes/E0769.md
new file mode 100644
index 0000000000000..d1995be9899b1
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0769.md
@@ -0,0 +1,39 @@
+A tuple struct or tuple variant was used in a pattern as if it were a
+struct or struct variant.
+
+Erroneous code example:
+
+```compile_fail,E0769
+enum E {
+    A(i32),
+}
+let e = E::A(42);
+match e {
+    E::A { number } => println!("{}", x),
+}
+```
+
+To fix this error, you can use the tuple pattern:
+
+```
+# enum E {
+#     A(i32),
+# }
+# let e = E::A(42);
+match e {
+    E::A(number) => println!("{}", number),
+}
+```
+
+Alternatively, you can also use the struct pattern by using the correct
+field names and binding them to new identifiers:
+
+```
+# enum E {
+#     A(i32),
+# }
+# let e = E::A(42);
+match e {
+    E::A { 0: number } => println!("{}", number),
+}
+```
diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml
index 9329069c48dd1..93b503c976be4 100644
--- a/src/librustc_typeck/Cargo.toml
+++ b/src/librustc_typeck/Cargo.toml
@@ -18,6 +18,7 @@ rustc_attr = { path = "../librustc_attr" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_hir = { path = "../librustc_hir" }
+rustc_hir_pretty = { path = "../librustc_hir_pretty" }
 rustc_target = { path = "../librustc_target" }
 rustc_session = { path = "../librustc_session" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index ea47ae68ce7d3..a654fc3dfc2df 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -1082,20 +1082,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .filter(|ident| !used_fields.contains_key(&ident))
             .collect::<Vec<_>>();
 
-        if !inexistent_fields.is_empty() && !variant.recovered {
-            self.error_inexistent_fields(
+        let inexistent_fields_err = if !inexistent_fields.is_empty() && !variant.recovered {
+            Some(self.error_inexistent_fields(
                 adt.variant_descr(),
                 &inexistent_fields,
                 &mut unmentioned_fields,
                 variant,
-            );
-        }
+            ))
+        } else {
+            None
+        };
 
         // Require `..` if struct has non_exhaustive attribute.
         if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc {
             self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
         }
 
+        let mut unmentioned_err = None;
         // Report an error if incorrect number of the fields were specified.
         if adt.is_union() {
             if fields.len() != 1 {
@@ -1107,7 +1110,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
             }
         } else if !etc && !unmentioned_fields.is_empty() {
-            self.error_unmentioned_fields(pat.span, &unmentioned_fields, variant);
+            unmentioned_err = Some(self.error_unmentioned_fields(pat.span, &unmentioned_fields));
+        }
+        match (inexistent_fields_err, unmentioned_err) {
+            (Some(mut i), Some(mut u)) => {
+                if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
+                    // We don't want to show the inexistent fields error when this was
+                    // `Foo { a, b }` when it should have been `Foo(a, b)`.
+                    i.delay_as_bug();
+                    u.delay_as_bug();
+                    e.emit();
+                } else {
+                    i.emit();
+                    u.emit();
+                }
+            }
+            (None, Some(mut err)) | (Some(mut err), None) => {
+                err.emit();
+            }
+            (None, None) => {}
         }
         no_field_errors
     }
@@ -1154,7 +1175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         inexistent_fields: &[Ident],
         unmentioned_fields: &mut Vec<Ident>,
         variant: &ty::VariantDef,
-    ) {
+    ) -> DiagnosticBuilder<'tcx> {
         let tcx = self.tcx;
         let (field_names, t, plural) = if inexistent_fields.len() == 1 {
             (format!("a field named `{}`", inexistent_fields[0]), "this", "")
@@ -1221,15 +1242,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     it explicitly.",
             );
         }
-        err.emit();
+        err
+    }
+
+    fn error_tuple_variant_as_struct_pat(
+        &self,
+        pat: &Pat<'_>,
+        fields: &'tcx [hir::FieldPat<'tcx>],
+        variant: &ty::VariantDef,
+    ) -> Option<DiagnosticBuilder<'tcx>> {
+        if let (CtorKind::Fn, PatKind::Struct(qpath, ..)) = (variant.ctor_kind, &pat.kind) {
+            let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+                s.print_qpath(qpath, false)
+            });
+            let mut err = struct_span_err!(
+                self.tcx.sess,
+                pat.span,
+                E0769,
+                "tuple variant `{}` written as struct variant",
+                path
+            );
+            let (sugg, appl) = if fields.len() == variant.fields.len() {
+                (
+                    fields
+                        .iter()
+                        .map(|f| match self.tcx.sess.source_map().span_to_snippet(f.pat.span) {
+                            Ok(f) => f,
+                            Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+                                s.print_pat(f.pat)
+                            }),
+                        })
+                        .collect::<Vec<String>>()
+                        .join(", "),
+                    Applicability::MachineApplicable,
+                )
+            } else {
+                (
+                    variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
+                    Applicability::MaybeIncorrect,
+                )
+            };
+            err.span_suggestion(
+                pat.span,
+                "use the tuple variant pattern syntax instead",
+                format!("{}({})", path, sugg),
+                appl,
+            );
+            return Some(err);
+        }
+        None
     }
 
     fn error_unmentioned_fields(
         &self,
         span: Span,
         unmentioned_fields: &[Ident],
-        variant: &ty::VariantDef,
-    ) {
+    ) -> DiagnosticBuilder<'tcx> {
         let field_names = if unmentioned_fields.len() == 1 {
             format!("field `{}`", unmentioned_fields[0])
         } else {
@@ -1248,9 +1316,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             field_names
         );
         diag.span_label(span, format!("missing {}", field_names));
-        if variant.ctor_kind == CtorKind::Fn {
-            diag.note("trying to match a tuple variant with a struct variant pattern");
-        }
         if self.tcx.sess.teach(&diag.get_code().unwrap()) {
             diag.note(
                 "This error indicates that a pattern for a struct fails to specify a \
@@ -1259,7 +1324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ignore unwanted fields.",
             );
         }
-        diag.emit();
+        diag
     }
 
     fn check_pat_box(
diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.rs b/src/test/ui/missing/missing-fields-in-struct-pattern.rs
index 24b6b55db6692..40304a674a633 100644
--- a/src/test/ui/missing/missing-fields-in-struct-pattern.rs
+++ b/src/test/ui/missing/missing-fields-in-struct-pattern.rs
@@ -2,8 +2,7 @@ struct S(usize, usize, usize, usize);
 
 fn main() {
     if let S { a, b, c, d } = S(1, 2, 3, 4) {
-    //~^ ERROR struct `S` does not have fields named `a`, `b`, `c`, `d` [E0026]
-    //~| ERROR pattern does not mention fields `0`, `1`, `2`, `3` [E0027]
+    //~^ ERROR tuple variant `S` written as struct variant
         println!("hi");
     }
 }
diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr
index f7037468996f4..6583524aad18f 100644
--- a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr
+++ b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr
@@ -1,18 +1,9 @@
-error[E0026]: struct `S` does not have fields named `a`, `b`, `c`, `d`
-  --> $DIR/missing-fields-in-struct-pattern.rs:4:16
-   |
-LL |     if let S { a, b, c, d } = S(1, 2, 3, 4) {
-   |                ^  ^  ^  ^ struct `S` does not have these fields
-
-error[E0027]: pattern does not mention fields `0`, `1`, `2`, `3`
+error[E0769]: tuple variant `S` written as struct variant
   --> $DIR/missing-fields-in-struct-pattern.rs:4:12
    |
 LL |     if let S { a, b, c, d } = S(1, 2, 3, 4) {
-   |            ^^^^^^^^^^^^^^^^ missing fields `0`, `1`, `2`, `3`
-   |
-   = note: trying to match a tuple variant with a struct variant pattern
+   |            ^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `S(a, b, c, d)`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0026, E0027.
-For more information about an error, try `rustc --explain E0026`.
+For more information about this error, try `rustc --explain E0769`.
diff --git a/src/test/ui/type/type-check/issue-41314.rs b/src/test/ui/type/type-check/issue-41314.rs
index 856d4ff6334bc..cbd39f5f9e6ed 100644
--- a/src/test/ui/type/type-check/issue-41314.rs
+++ b/src/test/ui/type/type-check/issue-41314.rs
@@ -4,7 +4,7 @@ enum X {
 
 fn main() {
     match X::Y(0) {
-        X::Y { number } => {} //~ ERROR does not have a field named `number`
-        //~^ ERROR pattern does not mention field `0`
+        X::Y { number } => {}
+        //~^ ERROR tuple variant `X::Y` written as struct variant
     }
 }
diff --git a/src/test/ui/type/type-check/issue-41314.stderr b/src/test/ui/type/type-check/issue-41314.stderr
index c2bba98d10a83..bd4d2071c2059 100644
--- a/src/test/ui/type/type-check/issue-41314.stderr
+++ b/src/test/ui/type/type-check/issue-41314.stderr
@@ -1,18 +1,9 @@
-error[E0026]: variant `X::Y` does not have a field named `number`
-  --> $DIR/issue-41314.rs:7:16
-   |
-LL |         X::Y { number } => {}
-   |                ^^^^^^ variant `X::Y` does not have this field
-
-error[E0027]: pattern does not mention field `0`
+error[E0769]: tuple variant `X::Y` written as struct variant
   --> $DIR/issue-41314.rs:7:9
    |
 LL |         X::Y { number } => {}
-   |         ^^^^^^^^^^^^^^^ missing field `0`
-   |
-   = note: trying to match a tuple variant with a struct variant pattern
+   |         ^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `X::Y(number)`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0026, E0027.
-For more information about an error, try `rustc --explain E0026`.
+For more information about this error, try `rustc --explain E0769`.
diff --git a/src/test/ui/union/union-fields-2.stderr b/src/test/ui/union/union-fields-2.stderr
index 68cb66d89d218..48654347285d3 100644
--- a/src/test/ui/union/union-fields-2.stderr
+++ b/src/test/ui/union/union-fields-2.stderr
@@ -48,18 +48,18 @@ error: union patterns should have exactly one field
 LL |     let U { a, b } = u;
    |         ^^^^^^^^^^
 
-error[E0026]: union `U` does not have a field named `c`
-  --> $DIR/union-fields-2.rs:18:19
-   |
-LL |     let U { a, b, c } = u;
-   |                   ^ union `U` does not have this field
-
 error: union patterns should have exactly one field
   --> $DIR/union-fields-2.rs:18:9
    |
 LL |     let U { a, b, c } = u;
    |         ^^^^^^^^^^^^^
 
+error[E0026]: union `U` does not have a field named `c`
+  --> $DIR/union-fields-2.rs:18:19
+   |
+LL |     let U { a, b, c } = u;
+   |                   ^ union `U` does not have this field
+
 error: union patterns should have exactly one field
   --> $DIR/union-fields-2.rs:20:9
    |

From ed587f83cf721c8ad7d51ba76178e91d732e01c5 Mon Sep 17 00:00:00 2001
From: Adrian Cruceru <cruceruadrian@gmail.com>
Date: Sat, 11 Jul 2020 11:33:43 +0000
Subject: [PATCH 60/66] Update llvm-project to latest
 origin/rustc/10.0-2020-05-05 commit which includes LVI segfault fix

---
 src/llvm-project | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/llvm-project b/src/llvm-project
index d134a53927fa0..86b120e6f302d 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit d134a53927fa033ae7e0f3e8ee872ff2dc71468d
+Subproject commit 86b120e6f302d39cd6973b6391fb299d7bc22122

From c24b96dcb58a4f00d055128ea5caabd62f456b7f Mon Sep 17 00:00:00 2001
From: Jake Goulding <jake.goulding@gmail.com>
Date: Thu, 2 Jul 2020 17:00:19 -0400
Subject: [PATCH 61/66] Teach bootstrap about target files vs target triples

`rustc` allows passing in predefined target triples as well as JSON
target specification files. This change allows bootstrap to have the
first inkling about those differences. This allows building a
cross-compiler for an out-of-tree architecture (even though that
compiler won't work for other reasons).

Even if no one ever uses this functionality, I think the newtype
around the `Interned<String>` improves the readability of the code.
---
 src/bootstrap/builder.rs       |  59 +++++++++---------
 src/bootstrap/builder/tests.rs |  56 ++++++++---------
 src/bootstrap/cc_detect.rs     |  34 +++++-----
 src/bootstrap/check.rs         |  18 +++---
 src/bootstrap/clean.rs         |   2 +-
 src/bootstrap/compile.rs       |  45 +++++++-------
 src/bootstrap/config.rs        |  84 ++++++++++++++++++++++---
 src/bootstrap/dist.rs          |  79 +++++++++++------------
 src/bootstrap/doc.rs           |  30 ++++-----
 src/bootstrap/flags.rs         |  11 ++--
 src/bootstrap/install.rs       |  29 ++++-----
 src/bootstrap/lib.rs           | 110 +++++++++++++++++----------------
 src/bootstrap/native.rs        |  39 ++++++------
 src/bootstrap/sanity.rs        |   6 +-
 src/bootstrap/test.rs          |  69 +++++++++++----------
 src/bootstrap/tool.rs          |  26 ++++----
 src/bootstrap/util.rs          |  11 ++--
 17 files changed, 391 insertions(+), 317 deletions(-)

diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 3cbecbbaa06cb..10e8509c9bbdd 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -16,6 +16,7 @@ use build_helper::{output, t};
 use crate::cache::{Cache, Interned, INTERNER};
 use crate::check;
 use crate::compile;
+use crate::config::TargetSelection;
 use crate::dist;
 use crate::doc;
 use crate::flags::Subcommand;
@@ -86,8 +87,8 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
 
 pub struct RunConfig<'a> {
     pub builder: &'a Builder<'a>,
-    pub host: Interned<String>,
-    pub target: Interned<String>,
+    pub host: TargetSelection,
+    pub target: TargetSelection,
     pub path: PathBuf,
 }
 
@@ -576,7 +577,7 @@ impl<'a> Builder<'a> {
     /// not take `Compiler` since all `Compiler` instances are meant to be
     /// obtained through this function, since it ensures that they are valid
     /// (i.e., built and assembled).
-    pub fn compiler(&self, stage: u32, host: Interned<String>) -> Compiler {
+    pub fn compiler(&self, stage: u32, host: TargetSelection) -> Compiler {
         self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } })
     }
 
@@ -594,8 +595,8 @@ impl<'a> Builder<'a> {
     pub fn compiler_for(
         &self,
         stage: u32,
-        host: Interned<String>,
-        target: Interned<String>,
+        host: TargetSelection,
+        target: TargetSelection,
     ) -> Compiler {
         if self.build.force_use_stage1(Compiler { stage, host }, target) {
             self.compiler(1, self.config.build)
@@ -610,15 +611,11 @@ impl<'a> Builder<'a> {
 
     /// Returns the libdir where the standard library and other artifacts are
     /// found for a compiler's sysroot.
-    pub fn sysroot_libdir(
-        &self,
-        compiler: Compiler,
-        target: Interned<String>,
-    ) -> Interned<PathBuf> {
+    pub fn sysroot_libdir(&self, compiler: Compiler, target: TargetSelection) -> Interned<PathBuf> {
         #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
         struct Libdir {
             compiler: Compiler,
-            target: Interned<String>,
+            target: TargetSelection,
         }
         impl Step for Libdir {
             type Output = Interned<PathBuf>;
@@ -633,7 +630,7 @@ impl<'a> Builder<'a> {
                     .sysroot(self.compiler)
                     .join(lib)
                     .join("rustlib")
-                    .join(self.target)
+                    .join(self.target.triple)
                     .join("lib");
                 let _ = fs::remove_dir_all(&sysroot);
                 t!(fs::create_dir_all(&sysroot));
@@ -656,7 +653,7 @@ impl<'a> Builder<'a> {
                 Some(relative_libdir) if compiler.stage >= 1 => {
                     self.sysroot(compiler).join(relative_libdir)
                 }
-                _ => self.sysroot(compiler).join(libdir(&compiler.host)),
+                _ => self.sysroot(compiler).join(libdir(compiler.host)),
             }
         }
     }
@@ -668,11 +665,11 @@ impl<'a> Builder<'a> {
     /// Windows.
     pub fn libdir_relative(&self, compiler: Compiler) -> &Path {
         if compiler.is_snapshot(self) {
-            libdir(&self.config.build).as_ref()
+            libdir(self.config.build).as_ref()
         } else {
             match self.config.libdir_relative() {
                 Some(relative_libdir) if compiler.stage >= 1 => relative_libdir,
-                _ => libdir(&compiler.host).as_ref(),
+                _ => libdir(compiler.host).as_ref(),
             }
         }
     }
@@ -707,7 +704,7 @@ impl<'a> Builder<'a> {
         if compiler.is_snapshot(self) {
             self.initial_rustc.clone()
         } else {
-            self.sysroot(compiler).join("bin").join(exe("rustc", &compiler.host))
+            self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host))
         }
     }
 
@@ -741,7 +738,7 @@ impl<'a> Builder<'a> {
     ///
     /// Note that this returns `None` if LLVM is disabled, or if we're in a
     /// check build or dry-run, where there's no need to build all of LLVM.
-    fn llvm_config(&self, target: Interned<String>) -> Option<PathBuf> {
+    fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
         if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run {
             let llvm_config = self.ensure(native::Llvm { target });
             if llvm_config.is_file() {
@@ -763,7 +760,7 @@ impl<'a> Builder<'a> {
         compiler: Compiler,
         mode: Mode,
         source_type: SourceType,
-        target: Interned<String>,
+        target: TargetSelection,
         cmd: &str,
     ) -> Cargo {
         let mut cargo = Command::new(&self.initial_cargo);
@@ -794,7 +791,7 @@ impl<'a> Builder<'a> {
         }
 
         if cmd != "install" {
-            cargo.arg("--target").arg(target);
+            cargo.arg("--target").arg(target.rustc_target_arg());
         } else {
             assert_eq!(target, compiler.host);
         }
@@ -820,7 +817,7 @@ impl<'a> Builder<'a> {
             compiler.stage
         };
 
-        let mut rustflags = Rustflags::new(&target);
+        let mut rustflags = Rustflags::new(target);
         if stage != 0 {
             if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
                 cargo.args(s.split_whitespace());
@@ -993,7 +990,7 @@ impl<'a> Builder<'a> {
         // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
         // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
         // to change a flag in a binary?
-        if self.config.rust_rpath && util::use_host_linker(&target) {
+        if self.config.rust_rpath && util::use_host_linker(target) {
             let rpath = if target.contains("apple") {
                 // Note that we need to take one extra step on macOS to also pass
                 // `-Wl,-instal_name,@rpath/...` to get things to work right. To
@@ -1021,7 +1018,7 @@ impl<'a> Builder<'a> {
         }
 
         if let Some(target_linker) = self.linker(target, can_use_lld) {
-            let target = crate::envify(&target);
+            let target = crate::envify(&target.triple);
             cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker);
         }
         if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
@@ -1182,21 +1179,23 @@ impl<'a> Builder<'a> {
                 }
             };
             let cc = ccacheify(&self.cc(target));
-            cargo.env(format!("CC_{}", target), &cc);
+            cargo.env(format!("CC_{}", target.triple), &cc);
 
             let cflags = self.cflags(target, GitRepo::Rustc).join(" ");
-            cargo.env(format!("CFLAGS_{}", target), cflags.clone());
+            cargo.env(format!("CFLAGS_{}", target.triple), cflags.clone());
 
             if let Some(ar) = self.ar(target) {
                 let ranlib = format!("{} s", ar.display());
-                cargo.env(format!("AR_{}", target), ar).env(format!("RANLIB_{}", target), ranlib);
+                cargo
+                    .env(format!("AR_{}", target.triple), ar)
+                    .env(format!("RANLIB_{}", target.triple), ranlib);
             }
 
             if let Ok(cxx) = self.cxx(target) {
                 let cxx = ccacheify(&cxx);
                 cargo
-                    .env(format!("CXX_{}", target), &cxx)
-                    .env(format!("CXXFLAGS_{}", target), cflags);
+                    .env(format!("CXX_{}", target.triple), &cxx)
+                    .env(format!("CXXFLAGS_{}", target.triple), cflags);
             }
         }
 
@@ -1230,7 +1229,7 @@ impl<'a> Builder<'a> {
         // Environment variables *required* throughout the build
         //
         // FIXME: should update code to not require this env var
-        cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
+        cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple);
 
         // Set this for all builds to make sure doc builds also get it.
         cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel);
@@ -1386,7 +1385,7 @@ mod tests;
 struct Rustflags(String);
 
 impl Rustflags {
-    fn new(target: &str) -> Rustflags {
+    fn new(target: TargetSelection) -> Rustflags {
         let mut ret = Rustflags(String::new());
 
         // Inherit `RUSTFLAGS` by default ...
@@ -1394,7 +1393,7 @@ impl Rustflags {
 
         // ... and also handle target-specific env RUSTFLAGS if they're
         // configured.
-        let target_specific = format!("CARGO_TARGET_{}_RUSTFLAGS", crate::envify(target));
+        let target_specific = format!("CARGO_TARGET_{}_RUSTFLAGS", crate::envify(&target.triple));
         ret.env(&target_specific);
 
         ret
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 1e75e67af0c9e..69a54bec33b67 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -1,5 +1,5 @@
 use super::*;
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 use std::thread;
 
 use pretty_assertions::assert_eq;
@@ -17,16 +17,16 @@ fn configure(host: &[&str], target: &[&str]) -> Config {
         .join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
     t!(fs::create_dir_all(&dir));
     config.out = dir;
-    config.build = INTERNER.intern_str("A");
+    config.build = TargetSelection::from_user("A");
     config.hosts = vec![config.build]
         .into_iter()
-        .chain(host.iter().map(|s| INTERNER.intern_str(s)))
+        .chain(host.iter().map(|s| TargetSelection::from_user(s)))
         .collect::<Vec<_>>();
     config.targets = config
         .hosts
         .clone()
         .into_iter()
-        .chain(target.iter().map(|s| INTERNER.intern_str(s)))
+        .chain(target.iter().map(|s| TargetSelection::from_user(s)))
         .collect::<Vec<_>>();
     config
 }
@@ -41,7 +41,7 @@ fn dist_baseline() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
+    let a = TargetSelection::from_user("A");
 
     assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
     assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
@@ -67,8 +67,8 @@ fn dist_with_targets() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -98,8 +98,8 @@ fn dist_with_hosts() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -128,8 +128,8 @@ fn dist_with_hosts() {
 
 #[test]
 fn dist_only_cross_host() {
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
     let mut build = Build::new(configure(&["B"], &[]));
     build.config.docs = false;
     build.config.extended = true;
@@ -156,9 +156,9 @@ fn dist_with_targets_and_hosts() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
-    let c = INTERNER.intern_str("C");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
+    let c = TargetSelection::from_user("C");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -194,9 +194,9 @@ fn dist_with_target_flag() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
-    let c = INTERNER.intern_str("C");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
+    let c = TargetSelection::from_user("C");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -224,8 +224,8 @@ fn dist_with_same_targets_and_hosts() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -277,9 +277,9 @@ fn build_default() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
-    let c = INTERNER.intern_str("C");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
+    let c = TargetSelection::from_user("C");
 
     assert_eq!(
         first(builder.cache.all::<compile::Std>()),
@@ -318,9 +318,9 @@ fn build_with_target_flag() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
-    let c = INTERNER.intern_str("C");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
+    let c = TargetSelection::from_user("C");
 
     assert_eq!(
         first(builder.cache.all::<compile::Std>()),
@@ -374,7 +374,7 @@ fn test_with_no_doc_stage0() {
     let build = Build::new(config);
     let mut builder = Builder::new(&build);
 
-    let host = INTERNER.intern_str("A");
+    let host = TargetSelection::from_user("A");
 
     builder
         .run_step_descriptions(&[StepDescription::from::<test::Crate>()], &["src/libstd".into()]);
@@ -428,7 +428,7 @@ fn doc_default() {
     let build = Build::new(config);
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]);
-    let a = INTERNER.intern_str("A");
+    let a = TargetSelection::from_user("A");
 
     // error_index_generator uses stage 1 to share rustdoc artifacts with the
     // rustdoc tool.
@@ -466,7 +466,7 @@ fn test_docs() {
     let build = Build::new(config);
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
-    let a = INTERNER.intern_str("A");
+    let a = TargetSelection::from_user("A");
 
     // error_index_generator uses stage 1 to share rustdoc artifacts with the
     // rustdoc tool.
diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs
index ab16ca3732c1f..7ff00d85dd2f2 100644
--- a/src/bootstrap/cc_detect.rs
+++ b/src/bootstrap/cc_detect.rs
@@ -28,16 +28,15 @@ use std::{env, iter};
 
 use build_helper::output;
 
-use crate::cache::Interned;
-use crate::config::Target;
+use crate::config::{Target, TargetSelection};
 use crate::{Build, GitRepo};
 
 // The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
 // so use some simplified logic here. First we respect the environment variable `AR`, then
 // try to infer the archiver path from the C compiler path.
 // In the future this logic should be replaced by calling into the `cc` crate.
-fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
-    if let Some(ar) = env::var_os(format!("AR_{}", target.replace("-", "_"))) {
+fn cc2ar(cc: &Path, target: TargetSelection) -> Option<PathBuf> {
+    if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace("-", "_"))) {
         Some(PathBuf::from(ar))
     } else if let Some(ar) = env::var_os("AR") {
         Some(PathBuf::from(ar))
@@ -79,8 +78,8 @@ pub fn find(build: &mut Build) {
             .opt_level(2)
             .warnings(false)
             .debug(false)
-            .target(&target)
-            .host(&build.build);
+            .target(&target.triple)
+            .host(&build.build.triple);
         match build.crt_static(target) {
             Some(a) => {
                 cfg.static_crt(a);
@@ -106,10 +105,10 @@ pub fn find(build: &mut Build) {
         let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
             ar
         } else {
-            cc2ar(compiler.path(), &target)
+            cc2ar(compiler.path(), target)
         };
 
-        build.cc.insert(target, compiler);
+        build.cc.insert(target, compiler.clone());
         let cflags = build.cflags(target, GitRepo::Rustc);
 
         // If we use llvm-libunwind, we will need a C++ compiler as well for all targets
@@ -120,8 +119,8 @@ pub fn find(build: &mut Build) {
             .warnings(false)
             .debug(false)
             .cpp(true)
-            .target(&target)
-            .host(&build.build);
+            .target(&target.triple)
+            .host(&build.build.triple);
 
         let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
             cfg.compiler(cxx);
@@ -138,14 +137,14 @@ pub fn find(build: &mut Build) {
             build.cxx.insert(target, compiler);
         }
 
-        build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target)));
-        build.verbose(&format!("CFLAGS_{} = {:?}", &target, cflags));
+        build.verbose(&format!("CC_{} = {:?}", &target.triple, build.cc(target)));
+        build.verbose(&format!("CFLAGS_{} = {:?}", &target.triple, cflags));
         if let Ok(cxx) = build.cxx(target) {
-            build.verbose(&format!("CXX_{} = {:?}", &target, cxx));
-            build.verbose(&format!("CXXFLAGS_{} = {:?}", &target, cflags));
+            build.verbose(&format!("CXX_{} = {:?}", &target.triple, cxx));
+            build.verbose(&format!("CXXFLAGS_{} = {:?}", &target.triple, cflags));
         }
         if let Some(ar) = ar {
-            build.verbose(&format!("AR_{} = {:?}", &target, ar));
+            build.verbose(&format!("AR_{} = {:?}", &target.triple, ar));
             build.ar.insert(target, ar);
         }
     }
@@ -154,17 +153,18 @@ pub fn find(build: &mut Build) {
 fn set_compiler(
     cfg: &mut cc::Build,
     compiler: Language,
-    target: Interned<String>,
+    target: TargetSelection,
     config: Option<&Target>,
     build: &Build,
 ) {
-    match &*target {
+    match &*target.triple {
         // When compiling for android we may have the NDK configured in the
         // config.toml in which case we look there. Otherwise the default
         // compiler already takes into account the triple in question.
         t if t.contains("android") => {
             if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) {
                 let target = target
+                    .triple
                     .replace("armv7neon", "arm")
                     .replace("armv7", "arm")
                     .replace("thumbv7neon", "arm")
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 0d38d2eebe793..9f34bb4e6ccd7 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -1,15 +1,15 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
 use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, std_cargo};
+use crate::config::TargetSelection;
 use crate::tool::{prepare_tool_cargo, SourceType};
 use crate::{Compiler, Mode};
 use std::path::PathBuf;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 fn args(kind: Kind) -> Vec<String> {
@@ -71,7 +71,7 @@ impl Step for Std {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Rustc {
@@ -127,7 +127,7 @@ macro_rules! tool_check_step {
     ($name:ident, $path:expr, $source_type:expr) => {
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
-            pub target: Interned<String>,
+            pub target: TargetSelection,
         }
 
         impl Step for $name {
@@ -163,8 +163,8 @@ macro_rules! tool_check_step {
                 println!(
                     "Checking {} artifacts ({} -> {})",
                     stringify!($name).to_lowercase(),
-                    &compiler.host,
-                    target
+                    &compiler.host.triple,
+                    target.triple
                 );
                 run_cargo(
                     builder,
@@ -184,7 +184,7 @@ macro_rules! tool_check_step {
                 fn stamp(
                     builder: &Builder<'_>,
                     compiler: Compiler,
-                    target: Interned<String>,
+                    target: TargetSelection,
                 ) -> PathBuf {
                     builder
                         .cargo_out(compiler, Mode::ToolRustc, target)
@@ -204,12 +204,12 @@ tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
-fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: Interned<String>) -> PathBuf {
+fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
 }
 
 /// Cargo's output path for librustc in a given stage, compiled by a particular
 /// compiler for the specified target.
-fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: Interned<String>) -> PathBuf {
+fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
 }
diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs
index b4e58c06fdea9..f83dfe8e635e3 100644
--- a/src/bootstrap/clean.rs
+++ b/src/bootstrap/clean.rs
@@ -23,7 +23,7 @@ pub fn clean(build: &Build, all: bool) {
         rm_rf(&build.out.join("dist"));
 
         for host in &build.hosts {
-            let entries = match build.out.join(host).read_dir() {
+            let entries = match build.out.join(host.triple).read_dir() {
                 Ok(iter) => iter,
                 Err(_) => continue,
             };
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 9b4926f28d4ed..f3063489c1854 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -22,6 +22,7 @@ use serde::Deserialize;
 use crate::builder::Cargo;
 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
+use crate::config::TargetSelection;
 use crate::dist;
 use crate::native;
 use crate::tool::SourceType;
@@ -30,7 +31,7 @@ use crate::{Compiler, DependencyType, GitRepo, Mode};
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
     pub compiler: Compiler,
 }
 
@@ -129,7 +130,7 @@ fn copy_and_stamp(
 fn copy_third_party_objects(
     builder: &Builder<'_>,
     compiler: &Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> Vec<(PathBuf, DependencyType)> {
     let mut target_deps = vec![];
 
@@ -157,7 +158,7 @@ fn copy_third_party_objects(
 fn copy_self_contained_objects(
     builder: &Builder<'_>,
     compiler: &Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> Vec<(PathBuf, DependencyType)> {
     // cfg(bootstrap)
     // Remove when upgrading bootstrap compiler.
@@ -212,7 +213,7 @@ fn copy_self_contained_objects(
 
 /// Configure cargo to compile the standard library, adding appropriate env vars
 /// and such.
-pub fn std_cargo(builder: &Builder<'_>, target: Interned<String>, stage: u32, cargo: &mut Cargo) {
+pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) {
     if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
         cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
     }
@@ -307,7 +308,7 @@ pub fn std_cargo(builder: &Builder<'_>, target: Interned<String>, stage: u32, ca
 struct StdLink {
     pub compiler: Compiler,
     pub target_compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for StdLink {
@@ -343,7 +344,7 @@ impl Step for StdLink {
 fn copy_sanitizers(
     builder: &Builder<'_>,
     compiler: &Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> Vec<PathBuf> {
     let runtimes: Vec<native::SanitizerRuntime> = builder.ensure(native::Sanitizers { target });
 
@@ -378,7 +379,7 @@ fn copy_sanitizers(
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct StartupObjects {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for StartupObjects {
@@ -425,7 +426,7 @@ impl Step for StartupObjects {
                         .arg("--cfg")
                         .arg("bootstrap")
                         .arg("--target")
-                        .arg(target)
+                        .arg(target.rustc_target_arg())
                         .arg("--emit=obj")
                         .arg("-o")
                         .arg(dst_file)
@@ -444,7 +445,7 @@ impl Step for StartupObjects {
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
     pub compiler: Compiler,
 }
 
@@ -524,7 +525,7 @@ impl Step for Rustc {
     }
 }
 
-pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
+pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
     cargo
         .arg("--features")
         .arg(builder.rustc_features())
@@ -533,7 +534,7 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<St
     rustc_cargo_env(builder, cargo, target);
 }
 
-pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
+pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
     // Set some configuration variables picked up by build scripts and
     // the compiler alike
     cargo
@@ -614,7 +615,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interne
 struct RustcLink {
     pub compiler: Compiler,
     pub target_compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RustcLink {
@@ -644,11 +645,7 @@ impl Step for RustcLink {
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
-pub fn libstd_stamp(
-    builder: &Builder<'_>,
-    compiler: Compiler,
-    target: Interned<String>,
-) -> PathBuf {
+pub fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
     builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp")
 }
 
@@ -657,7 +654,7 @@ pub fn libstd_stamp(
 pub fn librustc_stamp(
     builder: &Builder<'_>,
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> PathBuf {
     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp")
 }
@@ -665,7 +662,7 @@ pub fn librustc_stamp(
 pub fn compiler_file(
     builder: &Builder<'_>,
     compiler: &Path,
-    target: Interned<String>,
+    target: TargetSelection,
     file: &str,
 ) -> PathBuf {
     let mut cmd = Command::new(compiler);
@@ -696,9 +693,9 @@ impl Step for Sysroot {
     fn run(self, builder: &Builder<'_>) -> Interned<PathBuf> {
         let compiler = self.compiler;
         let sysroot = if compiler.stage == 0 {
-            builder.out.join(&compiler.host).join("stage0-sysroot")
+            builder.out.join(&compiler.host.triple).join("stage0-sysroot")
         } else {
-            builder.out.join(&compiler.host).join(format!("stage{}", compiler.stage))
+            builder.out.join(&compiler.host.triple).join(format!("stage{}", compiler.stage))
         };
         let _ = fs::remove_dir_all(&sysroot);
         t!(fs::create_dir_all(&sysroot));
@@ -812,8 +809,8 @@ impl Step for Assemble {
 
         let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host);
         if let Some(lld_install) = lld_install {
-            let src_exe = exe("lld", &target_compiler.host);
-            let dst_exe = exe("rust-lld", &target_compiler.host);
+            let src_exe = exe("lld", target_compiler.host);
+            let dst_exe = exe("rust-lld", target_compiler.host);
             // we prepend this bin directory to the user PATH when linking Rust binaries. To
             // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`.
             let dst = libdir.parent().unwrap().join("bin");
@@ -828,7 +825,7 @@ impl Step for Assemble {
 
         // Link the compiler binary itself into place
         let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host);
-        let rustc = out_dir.join(exe("rustc_binary", &*host));
+        let rustc = out_dir.join(exe("rustc_binary", host));
         let bindir = sysroot.join("bin");
         t!(fs::create_dir_all(&bindir));
         let compiler = builder.rustc(target_compiler);
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index ff545a6ddcf47..d71f31704209e 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -7,6 +7,7 @@ use std::cmp;
 use std::collections::{HashMap, HashSet};
 use std::env;
 use std::ffi::OsString;
+use std::fmt;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process;
@@ -39,7 +40,7 @@ pub struct Config {
     pub docs: bool,
     pub locked_deps: bool,
     pub vendor: bool,
-    pub target_config: HashMap<Interned<String>, Target>,
+    pub target_config: HashMap<TargetSelection, Target>,
     pub full_bootstrap: bool,
     pub extended: bool,
     pub tools: Option<HashSet<String>>,
@@ -112,9 +113,9 @@ pub struct Config {
     pub rust_thin_lto_import_instr_limit: Option<u32>,
     pub rust_remap_debuginfo: bool,
 
-    pub build: Interned<String>,
-    pub hosts: Vec<Interned<String>>,
-    pub targets: Vec<Interned<String>>,
+    pub build: TargetSelection,
+    pub hosts: Vec<TargetSelection>,
+    pub targets: Vec<TargetSelection>,
     pub local_rebuild: bool,
     pub jemalloc: bool,
     pub control_flow_guard: bool,
@@ -158,6 +159,67 @@ pub struct Config {
     pub out: PathBuf,
 }
 
+#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct TargetSelection {
+    pub triple: Interned<String>,
+    file: Option<Interned<String>>,
+}
+
+impl TargetSelection {
+    pub fn from_user(selection: &str) -> Self {
+        let path = Path::new(selection);
+
+        let (triple, file) = if path.exists() {
+            let triple = path
+                .file_stem()
+                .expect("Target specification file has no file stem")
+                .to_str()
+                .expect("Target specification file stem is not UTF-8");
+
+            (triple, Some(selection))
+        } else {
+            (selection, None)
+        };
+
+        let triple = INTERNER.intern_str(triple);
+        let file = file.map(|f| INTERNER.intern_str(f));
+
+        Self { triple, file }
+    }
+
+    pub fn rustc_target_arg(&self) -> &str {
+        self.file.as_ref().unwrap_or(&self.triple)
+    }
+
+    pub fn contains(&self, needle: &str) -> bool {
+        self.triple.contains(needle)
+    }
+
+    pub fn starts_with(&self, needle: &str) -> bool {
+        self.triple.starts_with(needle)
+    }
+
+    pub fn ends_with(&self, needle: &str) -> bool {
+        self.triple.ends_with(needle)
+    }
+}
+
+impl fmt::Display for TargetSelection {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.triple)?;
+        if let Some(file) = self.file {
+            write!(f, "({})", file)?;
+        }
+        Ok(())
+    }
+}
+
+impl PartialEq<&str> for TargetSelection {
+    fn eq(&self, other: &&str) -> bool {
+        self.triple == *other
+    }
+}
+
 /// Per-target configuration stored in the global configuration structure.
 #[derive(Default)]
 pub struct Target {
@@ -403,7 +465,7 @@ impl Config {
         config.missing_tools = false;
 
         // set by bootstrap.py
-        config.build = INTERNER.intern_str(&env::var("BUILD").expect("'BUILD' to be set"));
+        config.build = TargetSelection::from_user(&env::var("BUILD").expect("'BUILD' to be set"));
         config.src = Config::path_from_python("SRC");
         config.out = Config::path_from_python("BUILD_DIR");
 
@@ -464,14 +526,16 @@ impl Config {
         let build = toml.build.clone().unwrap_or_default();
         // set by bootstrap.py
         config.hosts.push(config.build.clone());
-        for host in build.host.iter() {
-            let host = INTERNER.intern_str(host);
+        for host in build.host.iter().map(|h| TargetSelection::from_user(h)) {
             if !config.hosts.contains(&host) {
                 config.hosts.push(host);
             }
         }
-        for target in
-            config.hosts.iter().cloned().chain(build.target.iter().map(|s| INTERNER.intern_str(s)))
+        for target in config
+            .hosts
+            .iter()
+            .copied()
+            .chain(build.target.iter().map(|h| TargetSelection::from_user(h)))
         {
             if !config.targets.contains(&target) {
                 config.targets.push(target);
@@ -637,7 +701,7 @@ impl Config {
                 target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from);
                 target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from);
 
-                config.target_config.insert(INTERNER.intern_string(triple.clone()), target);
+                config.target_config.insert(TargetSelection::from_user(triple), target);
             }
         }
 
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 5d2fcba7feaba..af30747a9592e 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -20,6 +20,7 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::channel;
 use crate::compile;
+use crate::config::TargetSelection;
 use crate::tool::{self, Tool};
 use crate::util::{exe, is_dylib, timeit};
 use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
@@ -68,7 +69,7 @@ fn missing_tool(tool_name: &str, skip: bool) {
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Docs {
-    pub host: Interned<String>,
+    pub host: TargetSelection,
 }
 
 impl Step for Docs {
@@ -131,7 +132,7 @@ impl Step for Docs {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustcDocs {
-    pub host: Interned<String>,
+    pub host: TargetSelection,
 }
 
 impl Step for RustcDocs {
@@ -210,11 +211,11 @@ fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
 fn make_win_dist(
     rust_root: &Path,
     plat_root: &Path,
-    target_triple: Interned<String>,
+    target: TargetSelection,
     builder: &Builder<'_>,
 ) {
     //Ask gcc where it keeps its stuff
-    let mut cmd = Command::new(builder.cc(target_triple));
+    let mut cmd = Command::new(builder.cc(target));
     cmd.arg("-print-search-dirs");
     let gcc_out = output(&mut cmd);
 
@@ -234,16 +235,16 @@ fn make_win_dist(
         }
     }
 
-    let compiler = if target_triple == "i686-pc-windows-gnu" {
+    let compiler = if target == "i686-pc-windows-gnu" {
         "i686-w64-mingw32-gcc.exe"
-    } else if target_triple == "x86_64-pc-windows-gnu" {
+    } else if target == "x86_64-pc-windows-gnu" {
         "x86_64-w64-mingw32-gcc.exe"
     } else {
         "gcc.exe"
     };
     let target_tools = [compiler, "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
     let mut rustc_dlls = vec!["libwinpthread-1.dll"];
-    if target_triple.starts_with("i686-") {
+    if target.starts_with("i686-") {
         rustc_dlls.push("libgcc_s_dw2-1.dll");
     } else {
         rustc_dlls.push("libgcc_s_seh-1.dll");
@@ -311,7 +312,7 @@ fn make_win_dist(
     let target_bin_dir = plat_root
         .join("lib")
         .join("rustlib")
-        .join(target_triple)
+        .join(target.triple)
         .join("bin")
         .join("self-contained");
     fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
@@ -331,7 +332,7 @@ fn make_win_dist(
     let target_lib_dir = plat_root
         .join("lib")
         .join("rustlib")
-        .join(target_triple)
+        .join(target.triple)
         .join("lib")
         .join("self-contained");
     fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
@@ -342,7 +343,7 @@ fn make_win_dist(
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Mingw {
-    pub host: Interned<String>,
+    pub host: TargetSelection,
 }
 
 impl Step for Mingw {
@@ -530,11 +531,11 @@ impl Step for Rustc {
 
             // Copy over lld if it's there
             if builder.config.lld_enabled {
-                let exe = exe("rust-lld", &compiler.host);
+                let exe = exe("rust-lld", compiler.host);
                 let src =
                     builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin").join(&exe);
                 // for the rationale about this rename check `compile::copy_lld_to_sysroot`
-                let dst = image.join("lib/rustlib").join(&*host).join("bin").join(&exe);
+                let dst = image.join("lib/rustlib").join(&*host.triple).join("bin").join(&exe);
                 t!(fs::create_dir_all(&dst.parent().unwrap()));
                 builder.copy(&src, &dst);
             }
@@ -592,7 +593,7 @@ impl Step for Rustc {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct DebuggerScripts {
     pub sysroot: Interned<PathBuf>,
-    pub host: Interned<String>,
+    pub host: TargetSelection,
 }
 
 impl Step for DebuggerScripts {
@@ -662,8 +663,8 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
 }
 
 /// Copy stamped files into an image's `target/lib` directory.
-fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &Path) {
-    let dst = image.join("lib/rustlib").join(target).join("lib");
+fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path) {
+    let dst = image.join("lib/rustlib").join(target.triple).join("lib");
     let self_contained_dst = dst.join("self-contained");
     t!(fs::create_dir_all(&dst));
     t!(fs::create_dir_all(&self_contained_dst));
@@ -679,7 +680,7 @@ fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &P
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Std {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Std {
@@ -718,7 +719,7 @@ impl Step for Std {
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         let stamp = compile::libstd_stamp(builder, compiler_to_use, target);
-        copy_target_libs(builder, &target, &image, &stamp);
+        copy_target_libs(builder, target, &image, &stamp);
 
         let mut cmd = rust_installer(builder);
         cmd.arg("generate")
@@ -747,7 +748,7 @@ impl Step for Std {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustcDev {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RustcDev {
@@ -787,7 +788,7 @@ impl Step for RustcDev {
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         let stamp = compile::librustc_stamp(builder, compiler_to_use, target);
-        copy_target_libs(builder, &target, &image, &stamp);
+        copy_target_libs(builder, target, &image, &stamp);
 
         let mut cmd = rust_installer(builder);
         cmd.arg("generate")
@@ -818,7 +819,7 @@ impl Step for RustcDev {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Analysis {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Analysis {
@@ -861,12 +862,12 @@ impl Step for Analysis {
 
         let src = builder
             .stage_out(compiler, Mode::Std)
-            .join(target)
+            .join(target.triple)
             .join(builder.cargo_dir())
             .join("deps");
 
         let image_src = src.join("save-analysis");
-        let dst = image.join("lib/rustlib").join(target).join("analysis");
+        let dst = image.join("lib/rustlib").join(target.triple).join("analysis");
         t!(fs::create_dir_all(&dst));
         builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
         builder.cp_r(&image_src, &dst);
@@ -1163,7 +1164,7 @@ pub fn sanitize_sh(path: &Path) -> String {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Cargo {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Cargo {
@@ -1255,7 +1256,7 @@ impl Step for Cargo {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Rls {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Rls {
@@ -1345,7 +1346,7 @@ impl Step for Rls {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustAnalyzer {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RustAnalyzer {
@@ -1432,7 +1433,7 @@ impl Step for RustAnalyzer {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Clippy {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Clippy {
@@ -1523,7 +1524,7 @@ impl Step for Clippy {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Miri {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Miri {
@@ -1620,7 +1621,7 @@ impl Step for Miri {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Rustfmt {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Rustfmt {
@@ -1714,8 +1715,8 @@ impl Step for Rustfmt {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Extended {
     stage: u32,
-    host: Interned<String>,
-    target: Interned<String>,
+    host: TargetSelection,
+    target: TargetSelection,
 }
 
 impl Step for Extended {
@@ -2255,7 +2256,7 @@ impl Step for Extended {
     }
 }
 
-fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: Interned<String>) {
+fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
     let mut parts = channel::CFG_RELEASE_NUM.split('.');
     cmd.env("CFG_RELEASE_INFO", builder.rust_version())
         .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
@@ -2266,7 +2267,7 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: Interned<String>) {
         .env("CFG_VER_BUILD", "0") // just needed to build
         .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
         .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
-        .env("CFG_BUILD", target)
+        .env("CFG_BUILD", target.triple)
         .env("CFG_CHANNEL", &builder.config.channel);
 
     if target.contains("windows-gnu") {
@@ -2348,7 +2349,7 @@ impl Step for HashSign {
 ///
 /// Note: This function does not yet support Windows, but we also don't support
 ///       linking LLVM tools dynamically on Windows yet.
-fn maybe_install_llvm(builder: &Builder<'_>, target: Interned<String>, dst_libdir: &Path) {
+fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) {
     let src_libdir = builder.llvm_out(target).join("lib");
 
     if target.contains("apple-darwin") {
@@ -2373,13 +2374,13 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: Interned<String>, dst_libdi
 }
 
 /// Maybe add libLLVM.so to the target lib-dir for linking.
-pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
-    let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib");
+pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
+    let dst_libdir = sysroot.join("lib/rustlib").join(&*target.triple).join("lib");
     maybe_install_llvm(builder, target, &dst_libdir);
 }
 
 /// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
-pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
+pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
     let dst_libdir =
         sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
     maybe_install_llvm(builder, target, &dst_libdir);
@@ -2387,7 +2388,7 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: Interned<String
 
 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
 pub struct LlvmTools {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for LlvmTools {
@@ -2425,10 +2426,10 @@ impl Step for LlvmTools {
 
         // Prepare the image directory
         let src_bindir = builder.llvm_out(target).join("bin");
-        let dst_bindir = image.join("lib/rustlib").join(&*target).join("bin");
+        let dst_bindir = image.join("lib/rustlib").join(&*target.triple).join("bin");
         t!(fs::create_dir_all(&dst_bindir));
         for tool in LLVM_TOOLS {
-            let exe = src_bindir.join(exe(tool, &target));
+            let exe = src_bindir.join(exe(tool, target));
             builder.install(&exe, &dst_bindir, 0o755);
         }
 
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 582bc9da0e804..054daa3cf4814 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -18,7 +18,7 @@ use build_helper::{t, up_to_date};
 use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::compile;
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 use crate::tool::{self, prepare_tool_cargo, SourceType, Tool};
 use crate::util::symlink_dir;
 
@@ -27,7 +27,7 @@ macro_rules! book {
         $(
             #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
-            target: Interned<String>,
+            target: TargetSelection,
         }
 
         impl Step for $name {
@@ -101,7 +101,7 @@ fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct UnstableBook {
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for UnstableBook {
@@ -129,7 +129,7 @@ impl Step for UnstableBook {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 struct RustbookSrc {
-    target: Interned<String>,
+    target: TargetSelection,
     name: Interned<String>,
     src: Interned<PathBuf>,
 }
@@ -169,7 +169,7 @@ impl Step for RustbookSrc {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct TheBook {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for TheBook {
@@ -241,7 +241,7 @@ impl Step for TheBook {
 fn invoke_rustdoc(
     builder: &Builder<'_>,
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     markdown: &str,
 ) {
     let out = builder.doc_out(target);
@@ -277,7 +277,7 @@ fn invoke_rustdoc(
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Standalone {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for Standalone {
@@ -386,7 +386,7 @@ impl Step for Standalone {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Std {
     pub stage: u32,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Std {
@@ -415,7 +415,7 @@ impl Step for Std {
         let compiler = builder.compiler(stage, builder.config.build);
 
         builder.ensure(compile::Std { compiler, target });
-        let out_dir = builder.stage_out(compiler, Mode::Std).join(target).join("doc");
+        let out_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join("doc");
 
         // Here what we're doing is creating a *symlink* (directory junction on
         // Windows) to the final output location. This is not done as an
@@ -487,7 +487,7 @@ impl Step for Std {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Rustc {
     stage: u32,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for Rustc {
@@ -531,7 +531,7 @@ impl Step for Rustc {
 
         // We do not symlink to the same shared folder that already contains std library
         // documentation from previous steps as we do not want to include that.
-        let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc");
+        let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc");
         t!(symlink_dir_force(&builder.config, &out, &out_dir));
 
         // Build cargo command.
@@ -568,7 +568,7 @@ impl Step for Rustc {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Rustdoc {
     stage: u32,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for Rustdoc {
@@ -613,7 +613,7 @@ impl Step for Rustdoc {
         builder.ensure(tool::Rustdoc { compiler });
 
         // Symlink compiler docs to the output directory of rustdoc documentation.
-        let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc");
+        let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target.triple).join("doc");
         t!(fs::create_dir_all(&out_dir));
         t!(symlink_dir_force(&builder.config, &out, &out_dir));
 
@@ -641,7 +641,7 @@ impl Step for Rustdoc {
 #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct ErrorIndex {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for ErrorIndex {
@@ -681,7 +681,7 @@ impl Step for ErrorIndex {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct UnstableBookGen {
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for UnstableBookGen {
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index f477c75293385..1055689c81e6a 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -10,8 +10,7 @@ use std::process;
 use getopts::Options;
 
 use crate::builder::Builder;
-use crate::cache::{Interned, INTERNER};
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 use crate::{Build, DocTests};
 
 /// Deserialized version of all flags for this compile.
@@ -21,8 +20,8 @@ pub struct Flags {
     pub stage: Option<u32>,
     pub keep_stage: Vec<u32>,
 
-    pub host: Vec<Interned<String>>,
-    pub target: Vec<Interned<String>>,
+    pub host: Vec<TargetSelection>,
+    pub target: Vec<TargetSelection>,
     pub config: Option<PathBuf>,
     pub jobs: Option<u32>,
     pub cmd: Subcommand,
@@ -532,11 +531,11 @@ Arguments:
                 .collect(),
             host: split(&matches.opt_strs("host"))
                 .into_iter()
-                .map(|x| INTERNER.intern_string(x))
+                .map(|x| TargetSelection::from_user(&x))
                 .collect::<Vec<_>>(),
             target: split(&matches.opt_strs("target"))
                 .into_iter()
-                .map(|x| INTERNER.intern_string(x))
+                .map(|x| TargetSelection::from_user(&x))
                 .collect::<Vec<_>>(),
             config: cfg_file,
             jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 7026b25d1b984..7266625ff39f8 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -14,46 +14,47 @@ use crate::dist::{self, pkgname, sanitize_sh, tmpdir};
 use crate::Compiler;
 
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 
-pub fn install_docs(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_docs(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "docs", "rust-docs", stage, Some(host));
 }
 
-pub fn install_std(builder: &Builder<'_>, stage: u32, target: Interned<String>) {
+pub fn install_std(builder: &Builder<'_>, stage: u32, target: TargetSelection) {
     install_sh(builder, "std", "rust-std", stage, Some(target));
 }
 
-pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "cargo", "cargo", stage, Some(host));
 }
 
-pub fn install_rls(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_rls(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "rls", "rls", stage, Some(host));
 }
-pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+
+pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "rust-analyzer", "rust-analyzer", stage, Some(host));
 }
-pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+
+pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "clippy", "clippy", stage, Some(host));
 }
-pub fn install_miri(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_miri(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "miri", "miri", stage, Some(host));
 }
 
-pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
 }
 
-pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
 }
 
 pub fn install_src(builder: &Builder<'_>, stage: u32) {
     install_sh(builder, "src", "rust-src", stage, None);
 }
-pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "rustc", "rustc", stage, Some(host));
 }
 
@@ -62,7 +63,7 @@ fn install_sh(
     package: &str,
     name: &str,
     stage: u32,
-    host: Option<Interned<String>>,
+    host: Option<TargetSelection>,
 ) {
     builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));
 
@@ -150,7 +151,7 @@ macro_rules! install {
             #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
             pub compiler: Compiler,
-            pub target: Interned<String>,
+            pub target: TargetSelection,
         }
 
         impl $name {
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 783a64c3581f9..05c63734b82ae 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -123,6 +123,7 @@ use std::os::windows::fs::symlink_file;
 use build_helper::{mtime, output, run, run_suppressed, t, try_run, try_run_suppressed};
 use filetime::FileTime;
 
+use crate::config::TargetSelection;
 use crate::util::{exe, libdir, CiEnv};
 
 mod builder;
@@ -187,7 +188,7 @@ const LLVM_TOOLS: &[&str] = &[
 #[derive(Eq, PartialOrd, Ord, PartialEq, Clone, Copy, Hash, Debug)]
 pub struct Compiler {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
@@ -236,9 +237,9 @@ pub struct Build {
     verbosity: usize,
 
     // Targets for which to build
-    build: Interned<String>,
-    hosts: Vec<Interned<String>>,
-    targets: Vec<Interned<String>>,
+    build: TargetSelection,
+    hosts: Vec<TargetSelection>,
+    targets: Vec<TargetSelection>,
 
     // Stage 0 (downloaded) compiler, lld and cargo or their local rust equivalents
     initial_rustc: PathBuf,
@@ -248,10 +249,10 @@ pub struct Build {
 
     // Runtime state filled in later on
     // C/C++ compilers and archiver for all targets
-    cc: HashMap<Interned<String>, cc::Tool>,
-    cxx: HashMap<Interned<String>, cc::Tool>,
-    ar: HashMap<Interned<String>, PathBuf>,
-    ranlib: HashMap<Interned<String>, PathBuf>,
+    cc: HashMap<TargetSelection, cc::Tool>,
+    cxx: HashMap<TargetSelection, cc::Tool>,
+    ar: HashMap<TargetSelection, PathBuf>,
+    ranlib: HashMap<TargetSelection, PathBuf>,
     // Miscellaneous
     crates: HashMap<Interned<String>, Crate>,
     is_sudo: bool,
@@ -259,7 +260,7 @@ pub struct Build {
     delayed_failures: RefCell<Vec<String>>,
     prerelease_version: Cell<Option<u32>>,
     tool_artifacts:
-        RefCell<HashMap<Interned<String>, HashMap<String, (&'static str, PathBuf, Vec<String>)>>>,
+        RefCell<HashMap<TargetSelection, HashMap<String, (&'static str, PathBuf, Vec<String>)>>>,
 }
 
 #[derive(Debug)]
@@ -365,7 +366,7 @@ impl Build {
             output(
                 Command::new(&config.initial_rustc)
                     .arg("--target")
-                    .arg(config.build)
+                    .arg(config.build.rustc_target_arg())
                     .arg("--print")
                     .arg("target-libdir"),
             )
@@ -453,7 +454,7 @@ impl Build {
     }
 
     pub fn build_triple(&self) -> &[Interned<String>] {
-        unsafe { slice::from_raw_parts(&self.build, 1) }
+        slice::from_ref(&self.build.triple)
     }
 
     /// Executes the entire build, as configured by the flags and configuration.
@@ -558,7 +559,10 @@ impl Build {
     }
 
     fn tools_dir(&self, compiler: Compiler) -> PathBuf {
-        let out = self.out.join(&*compiler.host).join(format!("stage{}-tools-bin", compiler.stage));
+        let out = self
+            .out
+            .join(&*compiler.host.triple)
+            .join(format!("stage{}-tools-bin", compiler.stage));
         t!(fs::create_dir_all(&out));
         out
     }
@@ -575,54 +579,54 @@ impl Build {
             Mode::ToolBootstrap => "-bootstrap-tools",
             Mode::ToolStd | Mode::ToolRustc => "-tools",
         };
-        self.out.join(&*compiler.host).join(format!("stage{}{}", compiler.stage, suffix))
+        self.out.join(&*compiler.host.triple).join(format!("stage{}{}", compiler.stage, suffix))
     }
 
     /// Returns the root output directory for all Cargo output in a given stage,
     /// running a particular compiler, whether or not we're building the
     /// standard library, and targeting the specified architecture.
-    fn cargo_out(&self, compiler: Compiler, mode: Mode, target: Interned<String>) -> PathBuf {
-        self.stage_out(compiler, mode).join(&*target).join(self.cargo_dir())
+    fn cargo_out(&self, compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf {
+        self.stage_out(compiler, mode).join(&*target.triple).join(self.cargo_dir())
     }
 
     /// Root output directory for LLVM compiled for `target`
     ///
     /// Note that if LLVM is configured externally then the directory returned
     /// will likely be empty.
-    fn llvm_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("llvm")
+    fn llvm_out(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("llvm")
     }
 
-    fn lld_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("lld")
+    fn lld_out(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("lld")
     }
 
     /// Output directory for all documentation for a target
-    fn doc_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("doc")
+    fn doc_out(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("doc")
     }
 
     /// Output directory for all documentation for a target
-    fn compiler_doc_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("compiler-doc")
+    fn compiler_doc_out(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("compiler-doc")
     }
 
     /// Output directory for some generated md crate documentation for a target (temporary)
-    fn md_doc_out(&self, target: Interned<String>) -> Interned<PathBuf> {
-        INTERNER.intern_path(self.out.join(&*target).join("md-doc"))
+    fn md_doc_out(&self, target: TargetSelection) -> Interned<PathBuf> {
+        INTERNER.intern_path(self.out.join(&*target.triple).join("md-doc"))
     }
 
     /// Output directory for all crate documentation for a target (temporary)
     ///
     /// The artifacts here are then copied into `doc_out` above.
-    fn crate_doc_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("crate-docs")
+    fn crate_doc_out(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("crate-docs")
     }
 
     /// Returns `true` if no custom `llvm-config` is set for the specified target.
     ///
     /// If no custom `llvm-config` was specified then Rust's llvm will be used.
-    fn is_rust_llvm(&self, target: Interned<String>) -> bool {
+    fn is_rust_llvm(&self, target: TargetSelection) -> bool {
         match self.config.target_config.get(&target) {
             Some(ref c) => c.llvm_config.is_none(),
             None => true,
@@ -630,13 +634,13 @@ impl Build {
     }
 
     /// Returns the path to `FileCheck` binary for the specified target
-    fn llvm_filecheck(&self, target: Interned<String>) -> PathBuf {
+    fn llvm_filecheck(&self, target: TargetSelection) -> PathBuf {
         let target_config = self.config.target_config.get(&target);
         if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) {
             s.to_path_buf()
         } else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
             let llvm_bindir = output(Command::new(s).arg("--bindir"));
-            let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target));
+            let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", target));
             if filecheck.exists() {
                 filecheck
             } else {
@@ -644,7 +648,7 @@ impl Build {
                 // llvm subdirectory of the libdir.
                 let llvm_libdir = output(Command::new(s).arg("--libdir"));
                 let lib_filecheck =
-                    Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", &*target));
+                    Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", target));
                 if lib_filecheck.exists() {
                     lib_filecheck
                 } else {
@@ -669,18 +673,18 @@ impl Build {
             } else {
                 base
             };
-            base.join("bin").join(exe("FileCheck", &*target))
+            base.join("bin").join(exe("FileCheck", target))
         }
     }
 
     /// Directory for libraries built from C/C++ code and shared between stages.
-    fn native_dir(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("native")
+    fn native_dir(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("native")
     }
 
     /// Root output directory for rust_test_helpers library compiled for
     /// `target`
-    fn test_helpers_out(&self, target: Interned<String>) -> PathBuf {
+    fn test_helpers_out(&self, target: TargetSelection) -> PathBuf {
         self.native_dir(target).join("rust-test-helpers")
     }
 
@@ -693,7 +697,7 @@ impl Build {
 
     /// Returns the libdir of the snapshot compiler.
     fn rustc_snapshot_libdir(&self) -> PathBuf {
-        self.rustc_snapshot_sysroot().join(libdir(&self.config.build))
+        self.rustc_snapshot_sysroot().join(libdir(self.config.build))
     }
 
     /// Returns the sysroot of the snapshot compiler.
@@ -791,13 +795,13 @@ impl Build {
     }
 
     /// Returns the path to the C compiler for the target specified.
-    fn cc(&self, target: Interned<String>) -> &Path {
+    fn cc(&self, target: TargetSelection) -> &Path {
         self.cc[&target].path()
     }
 
     /// Returns a list of flags to pass to the C compiler for the target
     /// specified.
-    fn cflags(&self, target: Interned<String>, which: GitRepo) -> Vec<String> {
+    fn cflags(&self, target: TargetSelection, which: GitRepo) -> Vec<String> {
         // Filter out -O and /O (the optimization flags) that we picked up from
         // cc-rs because the build scripts will determine that for themselves.
         let mut base = self.cc[&target]
@@ -818,7 +822,7 @@ impl Build {
         // Work around an apparently bad MinGW / GCC optimization,
         // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html
         // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78936
-        if &*target == "i686-pc-windows-gnu" {
+        if &*target.triple == "i686-pc-windows-gnu" {
             base.push("-fno-omit-frame-pointer".into());
         }
 
@@ -836,17 +840,17 @@ impl Build {
     }
 
     /// Returns the path to the `ar` archive utility for the target specified.
-    fn ar(&self, target: Interned<String>) -> Option<&Path> {
+    fn ar(&self, target: TargetSelection) -> Option<&Path> {
         self.ar.get(&target).map(|p| &**p)
     }
 
     /// Returns the path to the `ranlib` utility for the target specified.
-    fn ranlib(&self, target: Interned<String>) -> Option<&Path> {
+    fn ranlib(&self, target: TargetSelection) -> Option<&Path> {
         self.ranlib.get(&target).map(|p| &**p)
     }
 
     /// Returns the path to the C++ compiler for the target specified.
-    fn cxx(&self, target: Interned<String>) -> Result<&Path, String> {
+    fn cxx(&self, target: TargetSelection) -> Result<&Path, String> {
         match self.cxx.get(&target) {
             Some(p) => Ok(p.path()),
             None => {
@@ -856,12 +860,12 @@ impl Build {
     }
 
     /// Returns the path to the linker for the given target if it needs to be overridden.
-    fn linker(&self, target: Interned<String>, can_use_lld: bool) -> Option<&Path> {
+    fn linker(&self, target: TargetSelection, can_use_lld: bool) -> Option<&Path> {
         if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref())
         {
             Some(linker)
         } else if target != self.config.build
-            && util::use_host_linker(&target)
+            && util::use_host_linker(target)
             && !target.contains("msvc")
         {
             Some(self.cc(target))
@@ -873,7 +877,7 @@ impl Build {
     }
 
     /// Returns if this target should statically link the C runtime, if specified
-    fn crt_static(&self, target: Interned<String>) -> Option<bool> {
+    fn crt_static(&self, target: TargetSelection) -> Option<bool> {
         if target.contains("pc-windows-msvc") {
             Some(true)
         } else {
@@ -882,7 +886,7 @@ impl Build {
     }
 
     /// Returns the "musl root" for this `target`, if defined
-    fn musl_root(&self, target: Interned<String>) -> Option<&Path> {
+    fn musl_root(&self, target: TargetSelection) -> Option<&Path> {
         self.config
             .target_config
             .get(&target)
@@ -892,7 +896,7 @@ impl Build {
     }
 
     /// Returns the "musl libdir" for this `target`.
-    fn musl_libdir(&self, target: Interned<String>) -> Option<PathBuf> {
+    fn musl_libdir(&self, target: TargetSelection) -> Option<PathBuf> {
         let t = self.config.target_config.get(&target)?;
         if let libdir @ Some(_) = &t.musl_libdir {
             return libdir.clone();
@@ -901,18 +905,18 @@ impl Build {
     }
 
     /// Returns the sysroot for the wasi target, if defined
-    fn wasi_root(&self, target: Interned<String>) -> Option<&Path> {
+    fn wasi_root(&self, target: TargetSelection) -> Option<&Path> {
         self.config.target_config.get(&target).and_then(|t| t.wasi_root.as_ref()).map(|p| &**p)
     }
 
     /// Returns `true` if this is a no-std `target`, if defined
-    fn no_std(&self, target: Interned<String>) -> Option<bool> {
+    fn no_std(&self, target: TargetSelection) -> Option<bool> {
         self.config.target_config.get(&target).map(|t| t.no_std)
     }
 
     /// Returns `true` if the target will be tested using the `remote-test-client`
     /// and `remote-test-server` binaries.
-    fn remote_tested(&self, target: Interned<String>) -> bool {
+    fn remote_tested(&self, target: TargetSelection) -> bool {
         self.qemu_rootfs(target).is_some()
             || target.contains("android")
             || env::var_os("TEST_DEVICE_ADDR").is_some()
@@ -923,7 +927,7 @@ impl Build {
     ///
     /// If `Some` is returned then that means that tests for this target are
     /// emulated with QEMU and binaries will need to be shipped to the emulator.
-    fn qemu_rootfs(&self, target: Interned<String>) -> Option<&Path> {
+    fn qemu_rootfs(&self, target: TargetSelection) -> Option<&Path> {
         self.config.target_config.get(&target).and_then(|t| t.qemu_rootfs.as_ref()).map(|p| &**p)
     }
 
@@ -955,7 +959,7 @@ impl Build {
     ///
     /// When all of these conditions are met the build will lift artifacts from
     /// the previous stage forward.
-    fn force_use_stage1(&self, compiler: Compiler, target: Interned<String>) -> bool {
+    fn force_use_stage1(&self, compiler: Compiler, target: TargetSelection) -> bool {
         !self.config.full_bootstrap
             && compiler.stage >= 2
             && (self.hosts.iter().any(|h| *h == target) || target == self.build)
@@ -1065,7 +1069,7 @@ impl Build {
         self.rust_version()
     }
 
-    fn llvm_link_tools_dynamically(&self, target: Interned<String>) -> bool {
+    fn llvm_link_tools_dynamically(&self, target: TargetSelection) -> bool {
         target.contains("linux-gnu") || target.contains("apple-darwin")
     }
 
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index e8ec575ea3746..bc71242b619db 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -19,8 +19,8 @@ use std::process::Command;
 use build_helper::{output, t};
 
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
 use crate::channel;
+use crate::config::TargetSelection;
 use crate::util::{self, exe};
 use crate::GitRepo;
 use build_helper::up_to_date;
@@ -41,7 +41,7 @@ pub struct Meta {
 // if not).
 pub fn prebuilt_llvm_config(
     builder: &Builder<'_>,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> Result<PathBuf, Meta> {
     // If we're using a custom LLVM bail out here, but we can only use a
     // custom LLVM for the build triple.
@@ -54,13 +54,14 @@ pub fn prebuilt_llvm_config(
 
     let root = "src/llvm-project/llvm";
     let out_dir = builder.llvm_out(target);
+
     let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build);
     if !builder.config.build.contains("msvc") || builder.config.ninja {
         llvm_config_ret_dir.push("build");
     }
     llvm_config_ret_dir.push("bin");
 
-    let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", &*builder.config.build));
+    let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", builder.config.build));
 
     let stamp = out_dir.join("llvm-finished-building");
     let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha());
@@ -93,7 +94,7 @@ pub fn prebuilt_llvm_config(
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Llvm {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Llvm {
@@ -165,8 +166,8 @@ impl Step for Llvm {
             .define("LLVM_ENABLE_BINDINGS", "OFF")
             .define("LLVM_ENABLE_Z3_SOLVER", "OFF")
             .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string())
-            .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
-            .define("LLVM_DEFAULT_TARGET_TRIPLE", target);
+            .define("LLVM_TARGET_ARCH", target.triple.split('-').next().unwrap())
+            .define("LLVM_DEFAULT_TARGET_TRIPLE", target.triple);
 
         if !target.contains("netbsd") {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
@@ -339,7 +340,7 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
 
 fn configure_cmake(
     builder: &Builder<'_>,
-    target: Interned<String>,
+    target: TargetSelection,
     cfg: &mut cmake::Config,
     use_compiler_launcher: bool,
 ) {
@@ -350,7 +351,7 @@ fn configure_cmake(
     if builder.config.ninja {
         cfg.generator("Ninja");
     }
-    cfg.target(&target).host(&builder.config.build);
+    cfg.target(&target.triple).host(&builder.config.build.triple);
 
     let sanitize_cc = |cc: &Path| {
         if target.contains("msvc") {
@@ -380,7 +381,7 @@ fn configure_cmake(
         cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc))
             .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc));
         cfg.env("SCCACHE_PATH", builder.config.ccache.as_ref().unwrap())
-            .env("SCCACHE_TARGET", target)
+            .env("SCCACHE_TARGET", target.triple)
             .env("SCCACHE_CC", &cc)
             .env("SCCACHE_CXX", &cxx);
 
@@ -480,7 +481,7 @@ fn configure_cmake(
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Lld {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Lld {
@@ -553,8 +554,8 @@ impl Step for Lld {
         // brittle and will break over time. If anyone knows better how to
         // cross-compile LLD it would be much appreciated to fix this!
         if target != builder.config.build {
-            cfg.env("LLVM_CONFIG_SHIM_REPLACE", &builder.config.build)
-                .env("LLVM_CONFIG_SHIM_REPLACE_WITH", &target)
+            cfg.env("LLVM_CONFIG_SHIM_REPLACE", &builder.config.build.triple)
+                .env("LLVM_CONFIG_SHIM_REPLACE_WITH", &target.triple)
                 .define(
                     "LLVM_TABLEGEN_EXE",
                     llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION),
@@ -574,7 +575,7 @@ impl Step for Lld {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct TestHelpers {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for TestHelpers {
@@ -621,8 +622,8 @@ impl Step for TestHelpers {
 
         cfg.cargo_metadata(false)
             .out_dir(&dst)
-            .target(&target)
-            .host(&builder.config.build)
+            .target(&target.triple)
+            .host(&builder.config.build.triple)
             .opt_level(0)
             .warnings(false)
             .debug(false)
@@ -633,7 +634,7 @@ impl Step for TestHelpers {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Sanitizers {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Sanitizers {
@@ -684,7 +685,7 @@ impl Step for Sanitizers {
 
         let mut cfg = cmake::Config::new(&compiler_rt_dir);
         cfg.profile("Release");
-        cfg.define("CMAKE_C_COMPILER_TARGET", self.target);
+        cfg.define("CMAKE_C_COMPILER_TARGET", self.target.triple);
         cfg.define("COMPILER_RT_BUILD_BUILTINS", "OFF");
         cfg.define("COMPILER_RT_BUILD_CRT", "OFF");
         cfg.define("COMPILER_RT_BUILD_LIBFUZZER", "OFF");
@@ -727,7 +728,7 @@ pub struct SanitizerRuntime {
 /// Returns sanitizers available on a given target.
 fn supported_sanitizers(
     out_dir: &Path,
-    target: Interned<String>,
+    target: TargetSelection,
     channel: &str,
 ) -> Vec<SanitizerRuntime> {
     let darwin_libs = |os: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
@@ -753,7 +754,7 @@ fn supported_sanitizers(
             .collect()
     };
 
-    match &*target {
+    match &*target.triple {
         "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
         "aarch64-unknown-linux-gnu" => {
             common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"])
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 3301d41cfeefa..f89bef50de982 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -183,7 +183,11 @@ pub fn check(build: &mut Build) {
             panic!("the iOS target is only supported on macOS");
         }
 
-        build.config.target_config.entry(target.clone()).or_insert(Target::from_triple(target));
+        build
+            .config
+            .target_config
+            .entry(target.clone())
+            .or_insert(Target::from_triple(&target.triple));
 
         if target.contains("-none-") || target.contains("nvptx") {
             if build.no_std(*target) == Some(false) {
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 1916d96bed71d..b6641180c92c0 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -16,6 +16,7 @@ use build_helper::{self, output, t};
 use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::compile;
+use crate::config::TargetSelection;
 use crate::dist;
 use crate::flags::Subcommand;
 use crate::native;
@@ -93,7 +94,7 @@ fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Linkcheck {
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Linkcheck {
@@ -115,7 +116,7 @@ impl Step for Linkcheck {
         let _time = util::timeit(&builder);
         try_run(
             builder,
-            builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host).join("doc")),
+            builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host.triple).join("doc")),
         );
     }
 
@@ -132,7 +133,7 @@ impl Step for Linkcheck {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Cargotest {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Cargotest {
@@ -177,7 +178,7 @@ impl Step for Cargotest {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Cargo {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Cargo {
@@ -230,7 +231,7 @@ impl Step for Cargo {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rls {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Rls {
@@ -281,7 +282,7 @@ impl Step for Rls {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rustfmt {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Rustfmt {
@@ -338,7 +339,7 @@ impl Step for Rustfmt {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Miri {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Miri {
@@ -464,7 +465,7 @@ impl Step for Miri {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CompiletestTest {
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for CompiletestTest {
@@ -501,7 +502,7 @@ impl Step for CompiletestTest {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Clippy {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Clippy {
@@ -542,8 +543,10 @@ impl Step for Clippy {
         cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
         cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
         let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
-        let target_libs =
-            builder.stage_out(compiler, Mode::ToolRustc).join(&self.host).join(builder.cargo_dir());
+        let target_libs = builder
+            .stage_out(compiler, Mode::ToolRustc)
+            .join(&self.host.triple)
+            .join(builder.cargo_dir());
         cargo.env("HOST_LIBS", host_libs);
         cargo.env("TARGET_LIBS", target_libs);
         // clippy tests need to find the driver
@@ -607,7 +610,7 @@ impl Step for RustdocTheme {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustdocJSStd {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RustdocJSStd {
@@ -646,8 +649,8 @@ impl Step for RustdocJSStd {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustdocJSNotStd {
-    pub host: Interned<String>,
-    pub target: Interned<String>,
+    pub host: TargetSelection,
+    pub target: TargetSelection,
     pub compiler: Compiler,
 }
 
@@ -683,8 +686,8 @@ impl Step for RustdocJSNotStd {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustdocUi {
-    pub host: Interned<String>,
-    pub target: Interned<String>,
+    pub host: TargetSelection,
+    pub target: TargetSelection,
     pub compiler: Compiler,
 }
 
@@ -785,8 +788,8 @@ impl Step for ExpandYamlAnchors {
     }
 }
 
-fn testdir(builder: &Builder<'_>, host: Interned<String>) -> PathBuf {
-    builder.out.join(host).join("test")
+fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
+    builder.out.join(host.triple).join("test")
 }
 
 macro_rules! default_test {
@@ -855,7 +858,7 @@ macro_rules! test_definitions {
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
             pub compiler: Compiler,
-            pub target: Interned<String>,
+            pub target: TargetSelection,
         }
 
         impl Step for $name {
@@ -943,7 +946,7 @@ default_test!(Assembly { path: "src/test/assembly", mode: "assembly", suite: "as
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 struct Compiletest {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     mode: &'static str,
     suite: &'static str,
     path: &'static str,
@@ -1023,8 +1026,8 @@ impl Step for Compiletest {
         cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
         cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target));
         cmd.arg("--mode").arg(mode);
-        cmd.arg("--target").arg(target);
-        cmd.arg("--host").arg(&*compiler.host);
+        cmd.arg("--target").arg(target.rustc_target_arg());
+        cmd.arg("--host").arg(&*compiler.host.triple);
         cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
 
         if builder.config.cmd.bless() {
@@ -1543,7 +1546,7 @@ impl Step for RustcGuide {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CrateLibrustc {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     test_kind: TestKind,
     krate: Interned<String>,
 }
@@ -1589,7 +1592,7 @@ impl Step for CrateLibrustc {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CrateNotDefault {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     test_kind: TestKind,
     krate: &'static str,
 }
@@ -1638,7 +1641,7 @@ impl Step for CrateNotDefault {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Crate {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
     pub mode: Mode,
     pub test_kind: TestKind,
     pub krate: Interned<String>,
@@ -1750,17 +1753,17 @@ impl Step for Crate {
 
         if target.contains("emscripten") {
             cargo.env(
-                format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
+                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
                 builder.config.nodejs.as_ref().expect("nodejs not configured"),
             );
         } else if target.starts_with("wasm32") {
             let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
             let runner =
                 format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
-            cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner);
+            cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
         } else if builder.remote_tested(target) {
             cargo.env(
-                format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
+                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
                 format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
             );
         }
@@ -1776,7 +1779,7 @@ impl Step for Crate {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CrateRustdoc {
-    host: Interned<String>,
+    host: TargetSelection,
     test_kind: TestKind,
 }
 
@@ -1883,7 +1886,7 @@ impl Step for CrateRustdoc {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct RemoteCopyLibs {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for RemoteCopyLibs {
@@ -1911,7 +1914,7 @@ impl Step for RemoteCopyLibs {
         // Spawn the emulator and wait for it to come online
         let tool = builder.tool_exe(Tool::RemoteTestClient);
         let mut cmd = Command::new(&tool);
-        cmd.arg("spawn-emulator").arg(target).arg(&server).arg(builder.out.join("tmp"));
+        cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.out.join("tmp"));
         if let Some(rootfs) = builder.qemu_rootfs(target) {
             cmd.arg(rootfs);
         }
@@ -1966,7 +1969,9 @@ impl Step for Distcheck {
                 .current_dir(&dir),
         );
         builder.run(
-            Command::new(build_helper::make(&builder.config.build)).arg("check").current_dir(&dir),
+            Command::new(build_helper::make(&builder.config.build.triple))
+                .arg("check")
+                .current_dir(&dir),
         );
 
         // Now make sure that rust-src has all of libstd's dependencies
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 450b534d5dfdb..f66061975d64d 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -7,10 +7,10 @@ use std::process::{exit, Command};
 use build_helper::t;
 
 use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
 use crate::channel;
 use crate::channel::GitInfo;
 use crate::compile;
+use crate::config::TargetSelection;
 use crate::toolstate::ToolState;
 use crate::util::{add_dylib_path, exe};
 use crate::Compiler;
@@ -25,7 +25,7 @@ pub enum SourceType {
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 struct ToolBuild {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     tool: &'static str,
     path: &'static str,
     mode: Mode,
@@ -111,7 +111,7 @@ impl Step for ToolBuild {
                             .and_then(|p| p.file_name())
                             .and_then(|p| p.to_str())
                             .unwrap();
-                        if maybe_target != &*target {
+                        if maybe_target != &*target.triple {
                             continue;
                         }
                     }
@@ -208,8 +208,8 @@ impl Step for ToolBuild {
             }
         } else {
             let cargo_out =
-                builder.cargo_out(compiler, self.mode, target).join(exe(tool, &compiler.host));
-            let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host));
+                builder.cargo_out(compiler, self.mode, target).join(exe(tool, compiler.host));
+            let bin = builder.tools_dir(compiler).join(exe(tool, compiler.host));
             builder.copy(&cargo_out, &bin);
             Some(bin)
         }
@@ -220,7 +220,7 @@ pub fn prepare_tool_cargo(
     builder: &Builder<'_>,
     compiler: Compiler,
     mode: Mode,
-    target: Interned<String>,
+    target: TargetSelection,
     command: &'static str,
     path: &'static str,
     source_type: SourceType,
@@ -303,7 +303,7 @@ macro_rules! bootstrap_tool {
             #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
             pub compiler: Compiler,
-            pub target: Interned<String>,
+            pub target: TargetSelection,
         }
 
         impl Step for $name {
@@ -416,7 +416,7 @@ impl Step for ErrorIndex {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RemoteTestServer {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RemoteTestServer {
@@ -476,7 +476,7 @@ impl Step for Rustdoc {
             if !target_compiler.is_snapshot(builder) {
                 panic!("rustdoc in stage 0 must be snapshot rustdoc");
             }
-            return builder.initial_rustc.with_file_name(exe("rustdoc", &target_compiler.host));
+            return builder.initial_rustc.with_file_name(exe("rustdoc", target_compiler.host));
         }
         let target = target_compiler.host;
         // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
@@ -514,14 +514,14 @@ impl Step for Rustdoc {
         // rustdoc a different name.
         let tool_rustdoc = builder
             .cargo_out(build_compiler, Mode::ToolRustc, target)
-            .join(exe("rustdoc_tool_binary", &target_compiler.host));
+            .join(exe("rustdoc_tool_binary", target_compiler.host));
 
         // don't create a stage0-sysroot/bin directory.
         if target_compiler.stage > 0 {
             let sysroot = builder.sysroot(target_compiler);
             let bindir = sysroot.join("bin");
             t!(fs::create_dir_all(&bindir));
-            let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host));
+            let bin_rustdoc = bindir.join(exe("rustdoc", target_compiler.host));
             let _ = fs::remove_file(&bin_rustdoc);
             builder.copy(&tool_rustdoc, &bin_rustdoc);
             bin_rustdoc
@@ -534,7 +534,7 @@ impl Step for Rustdoc {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Cargo {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Cargo {
@@ -583,7 +583,7 @@ macro_rules! tool_extended {
             #[derive(Debug, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
             pub compiler: Compiler,
-            pub target: Interned<String>,
+            pub target: TargetSelection,
             pub extra_features: Vec<String>,
         }
 
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 2bc6f1939d97b..a307ef39d03a8 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -14,17 +14,16 @@ use std::time::Instant;
 use build_helper::t;
 
 use crate::builder::Builder;
-use crate::cache::Interned;
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 
 /// Returns the `name` as the filename of a static library for `target`.
-pub fn staticlib(name: &str, target: &str) -> String {
+pub fn staticlib(name: &str, target: TargetSelection) -> String {
     if target.contains("windows") { format!("{}.lib", name) } else { format!("lib{}.a", name) }
 }
 
 /// Given an executable called `name`, return the filename for the
 /// executable for a particular target.
-pub fn exe(name: &str, target: &str) -> String {
+pub fn exe(name: &str, target: TargetSelection) -> String {
     if target.contains("windows") { format!("{}.exe", name) } else { name.to_string() }
 }
 
@@ -35,7 +34,7 @@ pub fn is_dylib(name: &str) -> bool {
 
 /// Returns the corresponding relative library directory that the compiler's
 /// dylibs will be found in.
-pub fn libdir(target: &str) -> &'static str {
+pub fn libdir(target: TargetSelection) -> &'static str {
     if target.contains("windows") { "bin" } else { "lib" }
 }
 
@@ -294,7 +293,7 @@ pub fn forcing_clang_based_tests() -> bool {
     }
 }
 
-pub fn use_host_linker(target: &Interned<String>) -> bool {
+pub fn use_host_linker(target: TargetSelection) -> bool {
     // FIXME: this information should be gotten by checking the linker flavor
     // of the rustc target
     !(target.contains("emscripten")

From 9a3a31a153be84b9be33859a25b56be9cab8177d Mon Sep 17 00:00:00 2001
From: Teddy_Wang <wangtheo662@gmail.com>
Date: Sun, 12 Jul 2020 22:38:37 -0400
Subject: [PATCH 62/66] Added tests for volatile and nearbyint intrinsics

---
 src/test/codegen/intrinsics/nearby.rs   | 18 ++++++++
 src/test/codegen/intrinsics/volatile.rs | 55 +++++++++++++++++++++++++
 2 files changed, 73 insertions(+)
 create mode 100644 src/test/codegen/intrinsics/nearby.rs
 create mode 100644 src/test/codegen/intrinsics/volatile.rs

diff --git a/src/test/codegen/intrinsics/nearby.rs b/src/test/codegen/intrinsics/nearby.rs
new file mode 100644
index 0000000000000..520fe2f1886eb
--- /dev/null
+++ b/src/test/codegen/intrinsics/nearby.rs
@@ -0,0 +1,18 @@
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+// CHECK-LABEL: @nearbyintf32
+#[no_mangle]
+pub unsafe fn nearbyintf32(a: f32) -> f32 {
+    // CHECK: llvm.nearbyint.f32
+    intrinsics::nearbyintf32(a)
+}
+
+// CHECK-LABEL: @nearbyintf64
+#[no_mangle]
+pub unsafe fn nearbyintf64(a: f64) -> f64 {
+    // CHECK: llvm.nearbyint.f64
+    intrinsics::nearbyintf64(a)
+}
diff --git a/src/test/codegen/intrinsics/volatile.rs b/src/test/codegen/intrinsics/volatile.rs
new file mode 100644
index 0000000000000..1970517e73262
--- /dev/null
+++ b/src/test/codegen/intrinsics/volatile.rs
@@ -0,0 +1,55 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+// CHECK-LABEL: @volatile_copy_memory
+#[no_mangle]
+pub unsafe fn volatile_copy_memory(a: *mut u8, b: *const u8) {
+    // CHECK: llvm.memmove.p0i8.p0i8.{{\w*(.*true)}}
+    intrinsics::volatile_copy_memory(a, b, 1)
+}
+
+// CHECK-LABEL: @volatile_copy_nonoverlapping_memory
+#[no_mangle]
+pub unsafe fn volatile_copy_nonoverlapping_memory(a: *mut u8, b: *const u8) {
+    // CHECK: llvm.memcpy.p0i8.p0i8.{{\w*(.*true)}}
+    intrinsics::volatile_copy_nonoverlapping_memory(a, b, 1)
+}
+
+// CHECK-LABEL: @volatile_set_memory
+#[no_mangle]
+pub unsafe fn volatile_set_memory(a: *mut u8, b: u8) {
+    // CHECK: llvm.memset.p0i8.{{\w*(.*true)}}
+    intrinsics::volatile_set_memory(a, b, 1)
+}
+
+// CHECK-LABEL: @volatile_load
+#[no_mangle]
+pub unsafe fn volatile_load(a: *const u8) -> u8 {
+    // CHECK: load volatile
+    intrinsics::volatile_load(a)
+}
+
+// CHECK-LABEL: @volatile_store
+#[no_mangle]
+pub unsafe fn volatile_store(a: *mut u8, b: u8) {
+    // CHECK: store volatile
+    intrinsics::volatile_store(a, b)
+}
+
+// CHECK-LABEL: @unaligned_volatile_load
+#[no_mangle]
+pub unsafe fn unaligned_volatile_load(a: *const u8) -> u8 {
+    // CHECK: load volatile
+    intrinsics::unaligned_volatile_load(a)
+}
+
+// CHECK-LABEL: @unaligned_volatile_store
+#[no_mangle]
+pub unsafe fn unaligned_volatile_store(a: *mut u8, b: u8) {
+    // CHECK: store volatile
+    intrinsics::unaligned_volatile_store(a, b)
+}

From 5ff7e1ad2cc438bd1ecb29f6b4414d368115ca31 Mon Sep 17 00:00:00 2001
From: Teddy_Wang <wangtheo662@gmail.com>
Date: Mon, 13 Jul 2020 00:47:09 -0400
Subject: [PATCH 63/66] Added ui tests for volatile and nearby intrinsics

---
 src/test/codegen/intrinsics/volatile_order.rs | 18 ++++++++
 src/test/ui/intrinsics/intrinsic-nearby.rs    | 11 +++++
 src/test/ui/intrinsics/intrinsic-volatile.rs  | 43 +++++++++++++++++++
 3 files changed, 72 insertions(+)
 create mode 100644 src/test/codegen/intrinsics/volatile_order.rs
 create mode 100644 src/test/ui/intrinsics/intrinsic-nearby.rs
 create mode 100644 src/test/ui/intrinsics/intrinsic-volatile.rs

diff --git a/src/test/codegen/intrinsics/volatile_order.rs b/src/test/codegen/intrinsics/volatile_order.rs
new file mode 100644
index 0000000000000..29331219ba6ee
--- /dev/null
+++ b/src/test/codegen/intrinsics/volatile_order.rs
@@ -0,0 +1,18 @@
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::*;
+
+pub unsafe fn test_volatile_order() {
+    let mut a: Box<u8> = Box::new(0);
+    // CHECK: load volatile
+    let x = volatile_load(&*a);
+    // CHECK: load volatile
+    let x = volatile_load(&*a);
+    // CHECK: store volatile
+    volatile_store(&mut *a, 12);
+    // CHECK: store volatile
+    unaligned_volatile_store(&mut *a, 12);
+    // CHECK: llvm.memset.p0i8
+    volatile_set_memory(&mut *a, 12, 1)
+}
diff --git a/src/test/ui/intrinsics/intrinsic-nearby.rs b/src/test/ui/intrinsics/intrinsic-nearby.rs
new file mode 100644
index 0000000000000..7b1d1eeaadbd0
--- /dev/null
+++ b/src/test/ui/intrinsics/intrinsic-nearby.rs
@@ -0,0 +1,11 @@
+// run-pass
+#![feature(core_intrinsics)]
+
+use std::intrinsics::*;
+
+fn main() {
+    unsafe {
+        assert_eq!(nearbyintf32(5.234f32), 5f32);
+        assert_eq!(nearbyintf64(6.777f64), 7f64);
+    }
+}
diff --git a/src/test/ui/intrinsics/intrinsic-volatile.rs b/src/test/ui/intrinsics/intrinsic-volatile.rs
new file mode 100644
index 0000000000000..45bfe5ee3066d
--- /dev/null
+++ b/src/test/ui/intrinsics/intrinsic-volatile.rs
@@ -0,0 +1,43 @@
+// run-pass
+#![feature(core_intrinsics)]
+
+use std::intrinsics::*;
+
+pub fn main() {
+    unsafe {
+        let mut x: Box<u8> = Box::new(0);
+        let mut y: Box<u8> = Box::new(0);
+
+        // test volatile load
+        assert_eq!(volatile_load(&*x), 0);
+        *x = 1;
+        assert_eq!(volatile_load(&*x), 1);
+
+        // test volatile store
+        volatile_store(&mut *x, 2);
+        assert_eq!(*x, 2);
+
+        // test volatile copy memory
+        volatile_copy_memory(&mut *y, &*x, 1);
+        assert_eq!(*y, 2);
+
+        // test volatile copy non-overlapping memory
+        *x = 3;
+        volatile_copy_nonoverlapping_memory(&mut *y, &*x, 1);
+        assert_eq!(*y, 3);
+
+        // test volatile set memory
+        volatile_set_memory(&mut *x, 4, 1);
+        assert_eq!(*x, 4);
+
+        // test unaligned volatile load
+        let arr: [u8; 3] = [1, 2, 3];
+        let ptr = arr[1..].as_ptr() as *const u16;
+        assert_eq!(unaligned_volatile_load(ptr), u16::from_ne_bytes([arr[1], arr[2]]));
+        
+        // test unaligned volatile store
+        let ptr = arr[1..].as_ptr() as *mut u16;
+        unaligned_volatile_store(ptr, 0);
+        assert_eq!(arr, [1, 0, 0]);
+    }
+}

From eac809244e881b9d0437492fb4aeac55fc93e000 Mon Sep 17 00:00:00 2001
From: Teddy_Wang <wangtheo662@gmail.com>
Date: Mon, 13 Jul 2020 01:52:10 -0400
Subject: [PATCH 64/66] Removed trailing whitespace

---
 src/test/ui/intrinsics/intrinsic-volatile.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/ui/intrinsics/intrinsic-volatile.rs b/src/test/ui/intrinsics/intrinsic-volatile.rs
index 45bfe5ee3066d..e509363382f34 100644
--- a/src/test/ui/intrinsics/intrinsic-volatile.rs
+++ b/src/test/ui/intrinsics/intrinsic-volatile.rs
@@ -34,7 +34,7 @@ pub fn main() {
         let arr: [u8; 3] = [1, 2, 3];
         let ptr = arr[1..].as_ptr() as *const u16;
         assert_eq!(unaligned_volatile_load(ptr), u16::from_ne_bytes([arr[1], arr[2]]));
-        
+
         // test unaligned volatile store
         let ptr = arr[1..].as_ptr() as *mut u16;
         unaligned_volatile_store(ptr, 0);

From e3ae4c7345cfd06b06c6996536d7c158ce6970db Mon Sep 17 00:00:00 2001
From: PankajChaudhary5 <pankajchaudhary172@gmail.com>
Date: Mon, 13 Jul 2020 14:05:48 +0530
Subject: [PATCH 65/66] Added proper explanation of ErrorCode-E0688

---
 src/librustc_error_codes/error_codes.rs       |  2 +-
 src/librustc_error_codes/error_codes/E0688.md | 36 +++++++++++++++++++
 src/test/ui/in-band-lifetimes/E0688.stderr    |  1 +
 3 files changed, 38 insertions(+), 1 deletion(-)
 create mode 100644 src/librustc_error_codes/error_codes/E0688.md

diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index 225ede851b4d9..d1cc69b1ab8e2 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -380,6 +380,7 @@ E0668: include_str!("./error_codes/E0668.md"),
 E0669: include_str!("./error_codes/E0669.md"),
 E0670: include_str!("./error_codes/E0670.md"),
 E0671: include_str!("./error_codes/E0671.md"),
+E0688: include_str!("./error_codes/E0688.md"),
 E0689: include_str!("./error_codes/E0689.md"),
 E0690: include_str!("./error_codes/E0690.md"),
 E0691: include_str!("./error_codes/E0691.md"),
@@ -600,7 +601,6 @@ E0751: include_str!("./error_codes/E0751.md"),
 //  E0645, // trait aliases not finished
     E0667, // `impl Trait` in projections
     E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
-    E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
 //  E0694, // an unknown tool name found in scoped attributes
     E0696, // `continue` pointing to a labeled block
 //  E0702, // replaced with a generic attribute input check
diff --git a/src/librustc_error_codes/error_codes/E0688.md b/src/librustc_error_codes/error_codes/E0688.md
new file mode 100644
index 0000000000000..db50f490208f4
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0688.md
@@ -0,0 +1,36 @@
+In-band lifetimes were mixed with explicit lifetime binders.
+
+Erroneous code example:
+
+```compile_fail,E0688
+#![feature(in_band_lifetimes)]
+
+fn foo<'a>(x: &'a u32, y: &'b u32) {}   // error!
+
+struct Foo<'a> { x: &'a u32 }
+
+impl Foo<'a> {
+    fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {}   // error!
+}
+
+impl<'b> Foo<'a> {  // error!
+    fn baz() {}
+}
+```
+
+In-band lifetimes cannot be mixed with explicit lifetime binders.
+For example:
+
+```
+fn foo<'a, 'b>(x: &'a u32, y: &'b u32) {}   // ok!
+
+struct Foo<'a> { x: &'a u32 }
+
+impl<'a> Foo<'a> {
+    fn bar<'b,'c>(x: &'a u32, y: &'b u32, z: &'c u32) {}    // ok!
+}
+
+impl<'a> Foo<'a> {  // ok!
+    fn baz() {}
+}
+```
diff --git a/src/test/ui/in-band-lifetimes/E0688.stderr b/src/test/ui/in-band-lifetimes/E0688.stderr
index 0078cd58001e3..8662110679b5f 100644
--- a/src/test/ui/in-band-lifetimes/E0688.stderr
+++ b/src/test/ui/in-band-lifetimes/E0688.stderr
@@ -24,3 +24,4 @@ LL | impl<'b> Foo<'a> {
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0688`.
\ No newline at end of file

From 8df79fcc76814d0a47d64446eafbbb881f7204ca Mon Sep 17 00:00:00 2001
From: wangtheo <wangtheo662@gmail.com>
Date: Mon, 13 Jul 2020 09:44:48 -0400
Subject: [PATCH 66/66] Remove trailing whitespace

---
 src/test/ui/intrinsics/intrinsic-volatile.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/test/ui/intrinsics/intrinsic-volatile.rs b/src/test/ui/intrinsics/intrinsic-volatile.rs
index e509363382f34..7b2c825a2084b 100644
--- a/src/test/ui/intrinsics/intrinsic-volatile.rs
+++ b/src/test/ui/intrinsics/intrinsic-volatile.rs
@@ -1,4 +1,5 @@
 // run-pass
+
 #![feature(core_intrinsics)]
 
 use std::intrinsics::*;