about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-08-19 18:13:03 +0000
committerbors <bors@rust-lang.org>2020-08-19 18:13:03 +0000
commit9900178cba95369cd5822c8ce579edcc89ffeb76 (patch)
treed3005c84ee82e922dc2d27aa7a2426c9de49571d
parent443e177c7f0f94fc85b0e13e076b21e9eac60189 (diff)
parentad3db41182a6f256fb6d44d4b8e67cd2ab6e7922 (diff)
downloadrust-9900178cba95369cd5822c8ce579edcc89ffeb76.tar.gz
rust-9900178cba95369cd5822c8ce579edcc89ffeb76.zip
Auto merge of #75715 - tmandry:rollup-18atkj4, r=tmandry
Rollup of 7 pull requests

Successful merges:

 - #75069 (move const param structural match checks to wfcheck)
 - #75587 (mir building: fix some comments)
 - #75593 (Adjust installation place for compiler docs)
 - #75648 (Make OnceCell<T> transparent to dropck)
 - #75649 (Fix intra-doc links for inherent impls that are both lang items and not the default impl)
 - #75674 (Move to intra doc links for std::io)
 - #75696 (Remove `#[cfg(miri)]` from OnceCell tests)

Failed merges:

r? @ghost
-rw-r--r--Cargo.lock1
-rw-r--r--library/core/tests/lazy.rs9
-rw-r--r--library/std/src/io/buffered.rs50
-rw-r--r--library/std/src/io/cursor.rs14
-rw-r--r--library/std/src/io/error.rs65
-rw-r--r--library/std/src/io/mod.rs99
-rw-r--r--library/std/src/io/stdio.rs29
-rw-r--r--library/std/src/io/util.rs33
-rw-r--r--library/std/src/lazy.rs42
-rw-r--r--src/bootstrap/dist.rs4
-rw-r--r--src/librustc_mir/transform/mod.rs3
-rw-r--r--src/librustc_typeck/check/wfcheck.rs137
-rw-r--r--src/librustc_typeck/collect/type_of.rs85
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/clean/types.rs83
-rw-r--r--src/librustdoc/clean/utils.rs30
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs57
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs35
-rw-r--r--src/test/mir-opt/issue-41697.rs2
-rw-r--r--src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit (renamed from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.32bit)2
-rw-r--r--src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit (renamed from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.64bit)2
-rw-r--r--src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir (renamed from src/test/mir-opt/loop_test.main.SimplifyCfg-qualify-consts.after.mir)2
-rw-r--r--src/test/mir-opt/loop_test.rs2
-rw-r--r--src/test/rustdoc/intra-link-primitive-non-default-impl.rs32
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr2
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.rs2
-rw-r--r--src/test/ui/const-generics/const-param-elided-lifetime.min.stderr10
-rw-r--r--src/test/ui/const-generics/const-param-elided-lifetime.rs10
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr4
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-const-param.rs4
-rw-r--r--src/test/ui/const-generics/different_byref.min.stderr2
-rw-r--r--src/test/ui/const-generics/different_byref.rs2
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.min.stderr6
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.min.stderr3
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr4
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.rs4
-rw-r--r--src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr2
-rw-r--r--src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-56445.min.stderr11
-rw-r--r--src/test/ui/const-generics/issues/issue-56445.rs1
-rw-r--r--src/test/ui/const-generics/issues/issue-74950.min.stderr47
-rw-r--r--src/test/ui/const-generics/issues/issue-74950.rs25
-rw-r--r--src/test/ui/const-generics/issues/issue-75047.rs15
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-types.rs9
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-types.stderr12
-rw-r--r--src/test/ui/const-generics/nested-type.full.stderr163
-rw-r--r--src/test/ui/const-generics/nested-type.min.stderr171
-rw-r--r--src/test/ui/const-generics/nested-type.rs7
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr6
-rw-r--r--src/test/ui/const-generics/raw-ptr-const-param.min.stderr3
-rw-r--r--src/test/ui/const-generics/slice-const-param-mismatch.min.stderr4
-rw-r--r--src/test/ui/const-generics/slice-const-param.min.stderr4
-rw-r--r--src/test/ui/const-generics/slice-const-param.rs4
54 files changed, 604 insertions, 755 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 985dbb046d0..f8fa2971b49 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4106,6 +4106,7 @@ dependencies = [
  "rustc-rayon",
  "serde",
  "serde_json",
+ "smallvec 1.4.2",
  "tempfile",
 ]
 
diff --git a/library/core/tests/lazy.rs b/library/core/tests/lazy.rs
index 1c0bddb9aef..24f921ca7e4 100644
--- a/library/core/tests/lazy.rs
+++ b/library/core/tests/lazy.rs
@@ -122,3 +122,12 @@ fn reentrant_init() {
     });
     eprintln!("use after free: {:?}", dangling_ref.get().unwrap());
 }
+
+#[test]
+fn dropck() {
+    let cell = OnceCell::new();
+    {
+        let s = String::new();
+        cell.set(&s).unwrap();
+    }
+}
diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered.rs
index b4c91cced43..f3aadf29b2f 100644
--- a/library/std/src/io/buffered.rs
+++ b/library/std/src/io/buffered.rs
@@ -21,17 +21,16 @@ use crate::memchr;
 /// *repeated* read calls to the same file or network socket. It does not
 /// help when reading very large amounts at once, or reading just one or a few
 /// times. It also provides no advantage when reading from a source that is
-/// already in memory, like a `Vec<u8>`.
+/// already in memory, like a [`Vec`]`<u8>`.
 ///
 /// When the `BufReader<R>` is dropped, the contents of its buffer will be
 /// discarded. Creating multiple instances of a `BufReader<R>` on the same
 /// stream can cause data loss. Reading from the underlying reader after
-/// unwrapping the `BufReader<R>` with `BufReader::into_inner` can also cause
+/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause
 /// data loss.
 ///
-/// [`Read`]: ../../std/io/trait.Read.html
-/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
-/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+/// [`TcpStream::read`]: Read::read
+/// [`TcpStream`]: crate::net::TcpStream
 ///
 /// # Examples
 ///
@@ -155,7 +154,9 @@ impl<R> BufReader<R> {
 
     /// Returns a reference to the internally buffered data.
     ///
-    /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
+    /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty.
+    ///
+    /// [`fill_buf`]: BufRead::fill_buf
     ///
     /// # Examples
     ///
@@ -338,27 +339,26 @@ where
 impl<R: Seek> Seek for BufReader<R> {
     /// Seek to an offset, in bytes, in the underlying reader.
     ///
-    /// The position used for seeking with `SeekFrom::Current(_)` is the
+    /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
     /// position the underlying reader would be at if the `BufReader<R>` had no
     /// internal buffer.
     ///
     /// Seeking always discards the internal buffer, even if the seek position
     /// would otherwise fall within it. This guarantees that calling
-    /// `.into_inner()` immediately after a seek yields the underlying reader
+    /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
     /// at the same position.
     ///
     /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
     ///
     /// See [`std::io::Seek`] for more details.
     ///
-    /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)`
+    /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
     /// where `n` minus the internal buffer length overflows an `i64`, two
     /// seeks will be performed instead of one. If the second seek returns
-    /// `Err`, the underlying reader will be left at the same position it would
-    /// have if you called `seek` with `SeekFrom::Current(0)`.
+    /// [`Err`], the underlying reader will be left at the same position it would
+    /// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
     ///
-    /// [`BufReader::seek_relative`]: struct.BufReader.html#method.seek_relative
-    /// [`std::io::Seek`]: trait.Seek.html
+    /// [`std::io::Seek`]: Seek
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         let result: u64;
         if let SeekFrom::Current(n) = pos {
@@ -397,7 +397,7 @@ impl<R: Seek> Seek for BufReader<R> {
 /// *repeated* write calls to the same file or network socket. It does not
 /// help when writing very large amounts at once, or writing just one or a few
 /// times. It also provides no advantage when writing to a destination that is
-/// in memory, like a `Vec<u8>`.
+/// in memory, like a [`Vec`]<u8>`.
 ///
 /// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
 /// dropping will attempt to flush the contents of the buffer, any errors
@@ -441,10 +441,9 @@ impl<R: Seek> Seek for BufReader<R> {
 /// together by the buffer and will all be written out in one system call when
 /// the `stream` is flushed.
 ///
-/// [`Write`]: ../../std/io/trait.Write.html
-/// [`TcpStream::write`]: ../../std/net/struct.TcpStream.html#method.write
-/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
-/// [`flush`]: #method.flush
+/// [`TcpStream::write`]: Write::write
+/// [`TcpStream`]: crate::net::TcpStream
+/// [`flush`]: Write::flush
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
     inner: Option<W>,
@@ -455,7 +454,7 @@ pub struct BufWriter<W: Write> {
     panicked: bool,
 }
 
-/// An error returned by `into_inner` which combines an error that
+/// An error returned by [`BufWriter::into_inner`] which combines an error that
 /// happened while writing out the buffer, and the buffered writer object
 /// which may be used to recover from the condition.
 ///
@@ -629,7 +628,7 @@ impl<W: Write> BufWriter<W> {
     ///
     /// # Errors
     ///
-    /// An `Err` will be returned if an error occurs while flushing the buffer.
+    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
     ///
     /// # Examples
     ///
@@ -725,7 +724,8 @@ impl<W: Write> Drop for BufWriter<W> {
 }
 
 impl<W> IntoInnerError<W> {
-    /// Returns the error which caused the call to `into_inner()` to fail.
+    /// Returns the error which caused the call to [`BufWriter::into_inner()`]
+    /// to fail.
     ///
     /// This error was returned when attempting to write the internal buffer.
     ///
@@ -819,17 +819,15 @@ impl<W> fmt::Display for IntoInnerError<W> {
 /// Wraps a writer and buffers output to it, flushing whenever a newline
 /// (`0x0a`, `'\n'`) is detected.
 ///
-/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output.
+/// The [`BufWriter`] struct wraps a writer and buffers its output.
 /// But it only does this batched write when it goes out of scope, or when the
 /// internal buffer is full. Sometimes, you'd prefer to write each line as it's
 /// completed, rather than the entire buffer at once. Enter `LineWriter`. It
 /// does exactly that.
 ///
-/// Like [`BufWriter`][bufwriter], a `LineWriter`’s buffer will also be flushed when the
+/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
 /// `LineWriter` goes out of scope or when its internal buffer is full.
 ///
-/// [bufwriter]: struct.BufWriter.html
-///
 /// If there's still a partial line in the buffer when the `LineWriter` is
 /// dropped, it will flush those contents.
 ///
@@ -979,7 +977,7 @@ impl<W: Write> LineWriter<W> {
     ///
     /// # Errors
     ///
-    /// An `Err` will be returned if an error occurs while flushing the buffer.
+    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index f4db5f81450..58343f66f3f 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -9,7 +9,7 @@ use core::convert::TryInto;
 /// [`Seek`] implementation.
 ///
 /// `Cursor`s are used with in-memory buffers, anything implementing
-/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
+/// [`AsRef`]`<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
 /// allowing these buffers to be used anywhere you might use a reader or writer
 /// that does actual I/O.
 ///
@@ -23,12 +23,8 @@ use core::convert::TryInto;
 /// code, but use an in-memory buffer in our tests. We can do this with
 /// `Cursor`:
 ///
-/// [`Seek`]: trait.Seek.html
-/// [`Read`]: ../../std/io/trait.Read.html
-/// [`Write`]: ../../std/io/trait.Write.html
-/// [`Vec`]: ../../std/vec/struct.Vec.html
-/// [bytes]: ../../std/primitive.slice.html
-/// [`File`]: ../fs/struct.File.html
+/// [bytes]: crate::slice
+/// [`File`]: crate::fs::File
 ///
 /// ```no_run
 /// use std::io::prelude::*;
@@ -81,8 +77,8 @@ pub struct Cursor<T> {
 impl<T> Cursor<T> {
     /// Creates a new cursor wrapping the provided underlying in-memory buffer.
     ///
-    /// Cursor initial position is `0` even if underlying buffer (e.g., `Vec`)
-    /// is not empty. So writing to cursor starts with overwriting `Vec`
+    /// Cursor initial position is `0` even if underlying buffer (e.g., [`Vec`])
+    /// is not empty. So writing to cursor starts with overwriting [`Vec`]
     /// content, not with appending to it.
     ///
     /// # Examples
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index f7248e7547e..e6eda2caf75 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -4,8 +4,7 @@ use crate::fmt;
 use crate::result;
 use crate::sys;
 
-/// A specialized [`Result`](../result/enum.Result.html) type for I/O
-/// operations.
+/// A specialized [`Result`] type for I/O operations.
 ///
 /// This type is broadly used across [`std::io`] for any operation which may
 /// produce an error.
@@ -16,12 +15,13 @@ use crate::sys;
 /// While usual Rust style is to import types directly, aliases of [`Result`]
 /// often are not, to make it easier to distinguish between them. [`Result`] is
 /// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
-/// will generally use `io::Result` instead of shadowing the prelude's import
+/// will generally use `io::Result` instead of shadowing the [prelude]'s import
 /// of [`std::result::Result`][`Result`].
 ///
-/// [`std::io`]: ../io/index.html
-/// [`io::Error`]: ../io/struct.Error.html
-/// [`Result`]: ../result/enum.Result.html
+/// [`std::io`]: crate::io
+/// [`io::Error`]: Error
+/// [`Result`]: crate::result::Result
+/// [prelude]: crate::prelude
 ///
 /// # Examples
 ///
@@ -48,10 +48,9 @@ pub type Result<T> = result::Result<T, Error>;
 /// `Error` can be created with crafted error messages and a particular value of
 /// [`ErrorKind`].
 ///
-/// [`Read`]: ../io/trait.Read.html
-/// [`Write`]: ../io/trait.Write.html
-/// [`Seek`]: ../io/trait.Seek.html
-/// [`ErrorKind`]: enum.ErrorKind.html
+/// [`Read`]: crate::io::Read
+/// [`Write`]: crate::io::Write
+/// [`Seek`]: crate::io::Seek
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Error {
     repr: Repr,
@@ -83,7 +82,7 @@ struct Custom {
 ///
 /// It is used with the [`io::Error`] type.
 ///
-/// [`io::Error`]: struct.Error.html
+/// [`io::Error`]: Error
 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated)]
@@ -137,7 +136,7 @@ pub enum ErrorKind {
     /// For example, a function that reads a file into a string will error with
     /// `InvalidData` if the file's contents are not valid UTF-8.
     ///
-    /// [`InvalidInput`]: #variant.InvalidInput
+    /// [`InvalidInput`]: ErrorKind::InvalidInput
     #[stable(feature = "io_invalid_data", since = "1.2.0")]
     InvalidData,
     /// The I/O operation's timeout expired, causing it to be canceled.
@@ -150,8 +149,8 @@ pub enum ErrorKind {
     /// particular number of bytes but only a smaller number of bytes could be
     /// written.
     ///
-    /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
-    /// [`Ok(0)`]: ../../std/io/type.Result.html
+    /// [`write`]: crate::io::Write::write
+    /// [`Ok(0)`]: Ok
     #[stable(feature = "rust1", since = "1.0.0")]
     WriteZero,
     /// This operation was interrupted.
@@ -220,9 +219,6 @@ impl From<ErrorKind> for Error {
     /// let error = Error::from(not_found);
     /// assert_eq!("entity not found", format!("{}", error));
     /// ```
-    ///
-    /// [`ErrorKind`]: ../../std/io/enum.ErrorKind.html
-    /// [`Error`]: ../../std/io/struct.Error.html
     #[inline]
     fn from(kind: ErrorKind) -> Error {
         Error { repr: Repr::Simple(kind) }
@@ -235,7 +231,7 @@ impl Error {
     ///
     /// This function is used to generically create I/O errors which do not
     /// originate from the OS itself. The `error` argument is an arbitrary
-    /// payload which will be contained in this `Error`.
+    /// payload which will be contained in this [`Error`].
     ///
     /// # Examples
     ///
@@ -264,7 +260,7 @@ impl Error {
     ///
     /// This function reads the value of `errno` for the target platform (e.g.
     /// `GetLastError` on Windows) and will return a corresponding instance of
-    /// `Error` for the error code.
+    /// [`Error`] for the error code.
     ///
     /// # Examples
     ///
@@ -278,7 +274,7 @@ impl Error {
         Error::from_raw_os_error(sys::os::errno() as i32)
     }
 
-    /// Creates a new instance of an `Error` from a particular OS error code.
+    /// Creates a new instance of an [`Error`] from a particular OS error code.
     ///
     /// # Examples
     ///
@@ -310,9 +306,12 @@ impl Error {
 
     /// Returns the OS error that this error represents (if any).
     ///
-    /// If this `Error` was constructed via `last_os_error` or
-    /// `from_raw_os_error`, then this function will return `Some`, otherwise
-    /// it will return `None`.
+    /// If this [`Error`] was constructed via [`last_os_error`] or
+    /// [`from_raw_os_error`], then this function will return [`Some`], otherwise
+    /// it will return [`None`].
+    ///
+    /// [`last_os_error`]: Error::last_os_error
+    /// [`from_raw_os_error`]: Error::from_raw_os_error
     ///
     /// # Examples
     ///
@@ -345,8 +344,10 @@ impl Error {
 
     /// Returns a reference to the inner error wrapped by this error (if any).
     ///
-    /// If this `Error` was constructed via `new` then this function will
-    /// return `Some`, otherwise it will return `None`.
+    /// If this [`Error`] was constructed via [`new`] then this function will
+    /// return [`Some`], otherwise it will return [`None`].
+    ///
+    /// [`new`]: Error::new
     ///
     /// # Examples
     ///
@@ -380,8 +381,10 @@ impl Error {
     /// Returns a mutable reference to the inner error wrapped by this error
     /// (if any).
     ///
-    /// If this `Error` was constructed via `new` then this function will
-    /// return `Some`, otherwise it will return `None`.
+    /// If this [`Error`] was constructed via [`new`] then this function will
+    /// return [`Some`], otherwise it will return [`None`].
+    ///
+    /// [`new`]: Error::new
     ///
     /// # Examples
     ///
@@ -448,8 +451,10 @@ impl Error {
 
     /// Consumes the `Error`, returning its inner error (if any).
     ///
-    /// If this `Error` was constructed via `new` then this function will
-    /// return `Some`, otherwise it will return `None`.
+    /// If this [`Error`] was constructed via [`new`] then this function will
+    /// return [`Some`], otherwise it will return [`None`].
+    ///
+    /// [`new`]: Error::new
     ///
     /// # Examples
     ///
@@ -480,7 +485,7 @@ impl Error {
         }
     }
 
-    /// Returns the corresponding `ErrorKind` for this error.
+    /// Returns the corresponding [`ErrorKind`] for this error.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index e90ee5c285f..32456294838 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -240,9 +240,9 @@
 //!
 //! [`File`]: crate::fs::File
 //! [`TcpStream`]: crate::net::TcpStream
-//! [`Vec<T>`]: crate::vec::Vec
+//! [`Vec<T>`]: Vec
 //! [`io::stdout`]: stdout
-//! [`io::Result`]: crate::io::Result
+//! [`io::Result`]: self::Result
 //! [`?` operator]: ../../book/appendix-02-operators.html
 //! [`Result`]: crate::result::Result
 //! [`.unwrap()`]: crate::result::Result::unwrap
@@ -671,15 +671,15 @@ pub trait Read {
     /// If the data in this stream is *not* valid UTF-8 then an error is
     /// returned and `buf` is unchanged.
     ///
-    /// See [`read_to_end`][readtoend] for other error semantics.
+    /// See [`read_to_end`] for other error semantics.
     ///
-    /// [readtoend]: Self::read_to_end
+    /// [`read_to_end`]: Read::read_to_end
     ///
     /// # Examples
     ///
-    /// [`File`][file]s implement `Read`:
+    /// [`File`]s implement `Read`:
     ///
-    /// [file]: crate::fs::File
+    /// [`File`]: crate::fs::File
     ///
     /// ```no_run
     /// use std::io;
@@ -790,9 +790,9 @@ pub trait Read {
     ///
     /// # Examples
     ///
-    /// [`File`][file]s implement `Read`:
+    /// [`File`]s implement `Read`:
     ///
-    /// [file]: crate::fs::File
+    /// [`File`]: crate::fs::File
     ///
     /// ```no_run
     /// use std::io;
@@ -834,10 +834,9 @@ pub trait Read {
     ///
     /// # Examples
     ///
-    /// [`File`][file]s implement `Read`:
+    /// [`File`]s implement `Read`:
     ///
-    /// [file]: crate::fs::File
-    /// [`Iterator`]: crate::iter::Iterator
+    /// [`File`]: crate::fs::File
     /// [`Result`]: crate::result::Result
     /// [`io::Error`]: self::Error
     ///
@@ -871,9 +870,9 @@ pub trait Read {
     ///
     /// # Examples
     ///
-    /// [`File`][file]s implement `Read`:
+    /// [`File`]s implement `Read`:
     ///
-    /// [file]: crate::fs::File
+    /// [`File`]: crate::fs::File
     ///
     /// ```no_run
     /// use std::io;
@@ -1210,8 +1209,8 @@ impl Initializer {
 /// throughout [`std::io`] take and provide types which implement the `Write`
 /// trait.
 ///
-/// [`write`]: Self::write
-/// [`flush`]: Self::flush
+/// [`write`]: Write::write
+/// [`flush`]: Write::flush
 /// [`std::io`]: self
 ///
 /// # Examples
@@ -1237,7 +1236,7 @@ impl Initializer {
 /// The trait also provides convenience methods like [`write_all`], which calls
 /// `write` in a loop until its entire input has been written.
 ///
-/// [`write_all`]: Self::write_all
+/// [`write_all`]: Write::write_all
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(spotlight)]
 pub trait Write {
@@ -1283,30 +1282,36 @@ pub trait Write {
     ///     Ok(())
     /// }
     /// ```
+    ///
+    /// [`Ok(n)`]: Ok
     #[stable(feature = "rust1", since = "1.0.0")]
     fn write(&mut self, buf: &[u8]) -> Result<usize>;
 
-    /// Like `write`, except that it writes from a slice of buffers.
+    /// Like [`write`], except that it writes from a slice of buffers.
     ///
     /// Data is copied from each buffer in order, with the final buffer
     /// read from possibly being only partially consumed. This method must
-    /// behave as a call to `write` with the buffers concatenated would.
+    /// behave as a call to [`write`] with the buffers concatenated would.
     ///
-    /// The default implementation calls `write` with either the first nonempty
+    /// The default implementation calls [`write`] with either the first nonempty
     /// buffer provided, or an empty one if none exists.
+    ///
+    /// [`write`]: Write::write
     #[stable(feature = "iovec", since = "1.36.0")]
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
         default_write_vectored(|b| self.write(b), bufs)
     }
 
-    /// Determines if this `Write`er has an efficient `write_vectored`
+    /// Determines if this `Write`er has an efficient [`write_vectored`]
     /// implementation.
     ///
-    /// If a `Write`er does not override the default `write_vectored`
+    /// If a `Write`er does not override the default [`write_vectored`]
     /// implementation, code using it may want to avoid the method all together
     /// and coalesce writes into a single buffer for higher performance.
     ///
     /// The default implementation returns `false`.
+    ///
+    /// [`write_vectored`]: Write::write_vectored
     #[unstable(feature = "can_vector", issue = "69941")]
     fn is_write_vectored(&self) -> bool {
         false
@@ -1354,7 +1359,7 @@ pub trait Write {
     /// This function will return the first error of
     /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns.
     ///
-    /// [`write`]: Self::write
+    /// [`write`]: Write::write
     ///
     /// # Examples
     ///
@@ -1395,22 +1400,21 @@ pub trait Write {
     ///
     /// If the buffer contains no data, this will never call [`write_vectored`].
     ///
-    /// [`write_vectored`]: Self::write_vectored
-    ///
     /// # Notes
     ///
-    ///
-    /// Unlike `io::Write::write_vectored`, this takes a *mutable* reference to
-    /// a slice of `IoSlice`s, not an immutable one. That's because we need to
+    /// Unlike [`write_vectored`], this takes a *mutable* reference to
+    /// a slice of [`IoSlice`]s, not an immutable one. That's because we need to
     /// modify the slice to keep track of the bytes already written.
     ///
     /// Once this function returns, the contents of `bufs` are unspecified, as
-    /// this depends on how many calls to `write_vectored` were necessary. It is
+    /// this depends on how many calls to [`write_vectored`] were necessary. It is
     /// best to understand this function as taking ownership of `bufs` and to
     /// not use `bufs` afterwards. The underlying buffers, to which the
-    /// `IoSlice`s point (but not the `IoSlice`s themselves), are unchanged and
+    /// [`IoSlice`]s point (but not the [`IoSlice`]s themselves), are unchanged and
     /// can be reused.
     ///
+    /// [`write_vectored`]: Write::write_vectored
+    ///
     /// # Examples
     ///
     /// ```
@@ -1458,12 +1462,12 @@ pub trait Write {
     /// explicitly be called. The [`write!()`] macro should be favored to
     /// invoke this method instead.
     ///
-    /// This function internally uses the [`write_all`][writeall] method on
+    /// This function internally uses the [`write_all`] method on
     /// this trait and hence will continuously write data so long as no errors
     /// are received. This also means that partial writes are not indicated in
     /// this signature.
     ///
-    /// [writeall]: Self::write_all
+    /// [`write_all`]: Write::write_all
     ///
     /// # Errors
     ///
@@ -1558,9 +1562,9 @@ pub trait Write {
 ///
 /// # Examples
 ///
-/// [`File`][file]s implement `Seek`:
+/// [`File`]s implement `Seek`:
 ///
-/// [file]: crate::fs::File
+/// [`File`]: crate::fs::File
 ///
 /// ```no_run
 /// use std::io;
@@ -1610,7 +1614,6 @@ pub trait Seek {
     /// data is appended to a file). So calling this method multiple times does
     /// not necessarily return the same length each time.
     ///
-    ///
     /// # Example
     ///
     /// ```no_run
@@ -1646,7 +1649,6 @@ pub trait Seek {
     ///
     /// This is equivalent to `self.seek(SeekFrom::Current(0))`.
     ///
-    ///
     /// # Example
     ///
     /// ```no_run
@@ -1756,8 +1758,8 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> R
 /// [`BufReader`] to the rescue!
 ///
 /// [`File`]: crate::fs::File
-/// [`read_line`]: Self::read_line
-/// [`lines`]: Self::lines
+/// [`read_line`]: BufRead::read_line
+/// [`lines`]: BufRead::lines
 ///
 /// ```no_run
 /// use std::io::{self, BufReader};
@@ -1775,7 +1777,6 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> R
 ///     Ok(())
 /// }
 /// ```
-///
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait BufRead: Read {
     /// Returns the contents of the internal buffer, filling it with more data
@@ -1788,7 +1789,7 @@ pub trait BufRead: Read {
     /// be called with the number of bytes that are consumed from this buffer to
     /// ensure that the bytes are never returned twice.
     ///
-    /// [`consume`]: Self::consume
+    /// [`consume`]: BufRead::consume
     ///
     /// An empty buffer returned indicates that the stream has reached EOF.
     ///
@@ -1838,7 +1839,7 @@ pub trait BufRead: Read {
     /// Since `consume()` is meant to be used with [`fill_buf`],
     /// that method's example includes an example of `consume()`.
     ///
-    /// [`fill_buf`]: Self::fill_buf
+    /// [`fill_buf`]: BufRead::fill_buf
     #[stable(feature = "rust1", since = "1.0.0")]
     fn consume(&mut self, amt: usize);
 
@@ -1862,7 +1863,7 @@ pub trait BufRead: Read {
     /// If an I/O error is encountered then all bytes read so far will be
     /// present in `buf` and its length will have been adjusted appropriately.
     ///
-    /// [`fill_buf`]: Self::fill_buf
+    /// [`fill_buf`]: BufRead::fill_buf
     ///
     /// # Examples
     ///
@@ -1901,22 +1902,24 @@ pub trait BufRead: Read {
         read_until(self, byte, buf)
     }
 
-    /// Read all bytes until a newline (the 0xA byte) is reached, and append
+    /// Read all bytes until a newline (the `0xA` byte) is reached, and append
     /// them to the provided buffer.
     ///
     /// This function will read bytes from the underlying stream until the
-    /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes
+    /// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes
     /// up to, and including, the delimiter (if found) will be appended to
     /// `buf`.
     ///
     /// If successful, this function will return the total number of bytes read.
     ///
-    /// If this function returns `Ok(0)`, the stream has reached EOF.
+    /// If this function returns [`Ok(0)`], the stream has reached EOF.
     ///
     /// This function is blocking and should be used carefully: it is possible for
     /// an attacker to continuously send bytes without ever sending a newline
     /// or EOF.
     ///
+    /// [`Ok(0)`]: Ok
+    ///
     /// # Errors
     ///
     /// This function has the same error semantics as [`read_until`] and will
@@ -1924,7 +1927,7 @@ pub trait BufRead: Read {
     /// error is encountered then `buf` may contain some bytes already read in
     /// the event that all data read so far was valid UTF-8.
     ///
-    /// [`read_until`]: Self::read_until
+    /// [`read_until`]: BufRead::read_until
     ///
     /// # Examples
     ///
@@ -1976,8 +1979,8 @@ pub trait BufRead: Read {
     /// also yielded an error.
     ///
     /// [`io::Result`]: self::Result
-    /// [`Vec<u8>`]: crate::vec::Vec
-    /// [`read_until`]: Self::read_until
+    /// [`Vec<u8>`]: Vec
+    /// [`read_until`]: BufRead::read_until
     ///
     /// # Examples
     ///
@@ -2008,7 +2011,7 @@ pub trait BufRead: Read {
     ///
     /// The iterator returned from this function will yield instances of
     /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline
-    /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end.
+    /// byte (the `0xA` byte) or `CRLF` (`0xD`, `0xA` bytes) at the end.
     ///
     /// [`io::Result`]: self::Result
     ///
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 156f555be02..286eb92915e 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -252,8 +252,7 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
 ///
 /// Created by the [`io::stdin`] method.
 ///
-/// [`io::stdin`]: fn.stdin.html
-/// [`BufRead`]: trait.BufRead.html
+/// [`io::stdin`]: stdin
 ///
 /// ### Note: Windows Portability Consideration
 ///
@@ -283,10 +282,6 @@ pub struct Stdin {
 /// This handle implements both the [`Read`] and [`BufRead`] traits, and
 /// is constructed via the [`Stdin::lock`] method.
 ///
-/// [`Read`]: trait.Read.html
-/// [`BufRead`]: trait.BufRead.html
-/// [`Stdin::lock`]: struct.Stdin.html#method.lock
-///
 /// ### Note: Windows Portability Consideration
 ///
 /// When operating in a console, the Windows implementation of this stream does not support
@@ -319,8 +314,6 @@ pub struct StdinLock<'a> {
 /// is synchronized via a mutex. If you need more explicit control over
 /// locking, see the [`Stdin::lock`] method.
 ///
-/// [`Stdin::lock`]: struct.Stdin.html#method.lock
-///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
@@ -380,9 +373,6 @@ impl Stdin {
     /// returned guard also implements the [`Read`] and [`BufRead`] traits for
     /// accessing the underlying data.
     ///
-    /// [`Read`]: trait.Read.html
-    /// [`BufRead`]: trait.BufRead.html
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -407,8 +397,6 @@ impl Stdin {
     /// For detailed semantics of this method, see the documentation on
     /// [`BufRead::read_line`].
     ///
-    /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -542,8 +530,8 @@ impl fmt::Debug for StdinLock<'_> {
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
 /// an error.
 ///
-/// [`lock`]: #method.lock
-/// [`io::stdout`]: fn.stdout.html
+/// [`lock`]: Stdout::lock
+/// [`io::stdout`]: stdout
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Stdout {
     // FIXME: this should be LineWriter or BufWriter depending on the state of
@@ -561,9 +549,6 @@ pub struct Stdout {
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
 /// an error.
-///
-/// [`Write`]: trait.Write.html
-/// [`Stdout::lock`]: struct.Stdout.html#method.lock
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StdoutLock<'a> {
     inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>,
@@ -575,8 +560,6 @@ pub struct StdoutLock<'a> {
 /// is synchronized via a mutex. If you need more explicit control over
 /// locking, see the [`Stdout::lock`] method.
 ///
-/// [`Stdout::lock`]: struct.Stdout.html#method.lock
-///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
@@ -724,7 +707,7 @@ impl fmt::Debug for StdoutLock<'_> {
 ///
 /// For more information, see the [`io::stderr`] method.
 ///
-/// [`io::stderr`]: fn.stderr.html
+/// [`io::stderr`]: stderr
 ///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
@@ -740,8 +723,6 @@ pub struct Stderr {
 /// This handle implements the `Write` trait and is constructed via
 /// the [`Stderr::lock`] method.
 ///
-/// [`Stderr::lock`]: struct.Stderr.html#method.lock
-///
 /// ### Note: Windows Portability Consideration
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
@@ -819,7 +800,7 @@ impl Stderr {
     /// guard.
     ///
     /// The lock is released when the returned lock goes out of scope. The
-    /// returned guard also implements the `Write` trait for writing data.
+    /// returned guard also implements the [`Write`] trait for writing data.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index b9d5dc27db0..a093b745b0c 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -16,14 +16,17 @@ use crate::mem::MaybeUninit;
 /// If you’re wanting to copy the contents of one file to another and you’re
 /// working with filesystem paths, see the [`fs::copy`] function.
 ///
-/// [`fs::copy`]: ../fs/fn.copy.html
+/// [`fs::copy`]: crate::fs::copy
 ///
 /// # Errors
 ///
-/// This function will return an error immediately if any call to `read` or
-/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
+/// This function will return an error immediately if any call to [`read`] or
+/// [`write`] returns an error. All instances of [`ErrorKind::Interrupted`] are
 /// handled by this function and the underlying operation is retried.
 ///
+/// [`read`]: Read::read
+/// [`write`]: Write::write
+///
 /// # Examples
 ///
 /// ```
@@ -70,10 +73,8 @@ where
 
 /// A reader which is always at EOF.
 ///
-/// This struct is generally created by calling [`empty`]. Please see
-/// the documentation of [`empty()`][`empty`] for more details.
-///
-/// [`empty`]: fn.empty.html
+/// This struct is generally created by calling [`empty()`]. Please see
+/// the documentation of [`empty()`] for more details.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Empty {
     _priv: (),
@@ -83,8 +84,6 @@ pub struct Empty {
 ///
 /// All reads from the returned reader will return [`Ok`]`(0)`.
 ///
-/// [`Ok`]: ../result/enum.Result.html#variant.Ok
-///
 /// # Examples
 ///
 /// A slightly sad example of not reading anything into a buffer:
@@ -132,10 +131,8 @@ impl fmt::Debug for Empty {
 
 /// A reader which yields one byte over and over and over and over and over and...
 ///
-/// This struct is generally created by calling [`repeat`][repeat]. Please
-/// see the documentation of `repeat()` for more details.
-///
-/// [repeat]: fn.repeat.html
+/// This struct is generally created by calling [`repeat()`]. Please
+/// see the documentation of [`repeat()`] for more details.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Repeat {
     byte: u8,
@@ -199,10 +196,8 @@ impl fmt::Debug for Repeat {
 
 /// A writer which will move data into the void.
 ///
-/// This struct is generally created by calling [`sink`][sink]. Please
-/// see the documentation of `sink()` for more details.
-///
-/// [sink]: fn.sink.html
+/// This struct is generally created by calling [`sink`]. Please
+/// see the documentation of [`sink()`] for more details.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Sink {
     _priv: (),
@@ -210,9 +205,11 @@ pub struct Sink {
 
 /// Creates an instance of a writer which will successfully consume all data.
 ///
-/// All calls to `write` on the returned instance will return `Ok(buf.len())`
+/// All calls to [`write`] on the returned instance will return `Ok(buf.len())`
 /// and the contents of the buffer will not be inspected.
 ///
+/// [`write`]: Write::write
+///
 /// # Examples
 ///
 /// ```rust
diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs
index 60eba96bcc0..f0548582d2f 100644
--- a/library/std/src/lazy.rs
+++ b/library/std/src/lazy.rs
@@ -386,9 +386,10 @@ impl<T> SyncOnceCell<T> {
     }
 }
 
-impl<T> Drop for SyncOnceCell<T> {
+unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
     fn drop(&mut self) {
-        // Safety: The cell is being dropped, so it can't be accessed again
+        // Safety: The cell is being dropped, so it can't be accessed again.
+        // We also don't touch the `T`, which validates our usage of #[may_dangle].
         unsafe { self.take_inner() };
     }
 }
@@ -516,6 +517,7 @@ mod tests {
             mpsc::channel,
             Mutex,
         },
+        thread,
     };
 
     #[test]
@@ -552,26 +554,8 @@ mod tests {
         }
     }
 
-    // miri doesn't support threads
-    #[cfg(not(miri))]
     fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
-        crate::thread::spawn(f).join().unwrap()
-    }
-
-    #[cfg(not(miri))]
-    fn spawn(f: impl FnOnce() + Send + 'static) {
-        let _ = crate::thread::spawn(f);
-    }
-
-    // "stub threads" for Miri
-    #[cfg(miri)]
-    fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
-        f(())
-    }
-
-    #[cfg(miri)]
-    fn spawn(f: impl FnOnce() + Send + 'static) {
-        f(())
+        thread::spawn(f).join().unwrap()
     }
 
     #[test]
@@ -734,7 +718,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(miri, ignore)] // leaks memory
     fn static_sync_lazy() {
         static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
             let mut xs = Vec::new();
@@ -752,7 +735,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(miri, ignore)] // leaks memory
     fn static_sync_lazy_via_fn() {
         fn xs() -> &'static Vec<i32> {
             static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
@@ -811,7 +793,6 @@ mod tests {
     }
 
     #[test]
-    #[cfg_attr(miri, ignore)] // deadlocks without real threads
     fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
         static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
 
@@ -823,7 +804,7 @@ mod tests {
 
         for _ in 0..n_readers {
             let tx = tx.clone();
-            spawn(move || {
+            thread::spawn(move || {
                 loop {
                     if let Some(msg) = ONCE_CELL.get() {
                         tx.send(msg).unwrap();
@@ -835,7 +816,7 @@ mod tests {
             });
         }
         for _ in 0..n_writers {
-            spawn(move || {
+            thread::spawn(move || {
                 let _ = ONCE_CELL.set(MSG.to_owned());
             });
         }
@@ -845,4 +826,13 @@ mod tests {
             assert_eq!(msg, MSG);
         }
     }
+
+    #[test]
+    fn dropck() {
+        let cell = SyncOnceCell::new();
+        {
+            let s = String::new();
+            cell.set(&s).unwrap();
+        }
+    }
 }
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 98b6be29c07..01121977f13 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -162,7 +162,7 @@ impl Step for RustcDocs {
         let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
         let _ = fs::remove_dir_all(&image);
 
-        let dst = image.join("share/doc/rust/html");
+        let dst = image.join("share/doc/rust/html/rustc");
         t!(fs::create_dir_all(&dst));
         let src = builder.compiler_doc_out(host);
         builder.cp_r(&src, &dst);
@@ -181,7 +181,7 @@ impl Step for RustcDocs {
             .arg(format!("--package-name={}-{}", name, host.triple))
             .arg("--component-name=rustc-docs")
             .arg("--legacy-manifest-dirs=rustlib,cargo")
-            .arg("--bulk-dirs=share/doc/rust/html");
+            .arg("--bulk-dirs=share/doc/rust/html/rustc");
 
         builder.info(&format!("Dist compiler docs ({})", host));
         let _time = timeit(builder);
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 4f26f3bb459..1c1c54434d6 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -321,6 +321,7 @@ fn mir_validated(
 
     // Ensure that we compute the `mir_const_qualif` for constants at
     // this point, before we steal the mir-const result.
+    // Also this means promotion can rely on all const checks having been done.
     let _ = tcx.mir_const_qualif_opt_const_arg(def);
 
     let mut body = tcx.mir_const(def).steal();
@@ -336,7 +337,7 @@ fn mir_validated(
     let promote: &[&dyn MirPass<'tcx>] = &[
         // What we need to run borrowck etc.
         &promote_pass,
-        &simplify::SimplifyCfg::new("qualify-consts"),
+        &simplify::SimplifyCfg::new("promote-consts"),
     ];
 
     let opt_coverage: &[&dyn MirPass<'tcx>] = if tcx.sess.opts.debugging_opts.instrument_coverage {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index d47a8273d07..810bf59ea6c 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -6,9 +6,12 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit as hir_visit;
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::itemlikevisit::ParItemLikeVisitor;
 use rustc_hir::lang_items;
 use rustc_hir::ItemKind;
+use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
@@ -275,6 +278,107 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
 }
 
+fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
+    match param.kind {
+        // We currently only check wf of const params here.
+        hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
+
+        // Const parameters are well formed if their
+        // type is structural match.
+        hir::GenericParamKind::Const { ty: hir_ty } => {
+            let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
+
+            let err_ty_str;
+            let mut is_ptr = true;
+            let err = if tcx.features().min_const_generics {
+                match ty.kind {
+                    ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
+                    ty::FnPtr(_) => Some("function pointers"),
+                    ty::RawPtr(_) => Some("raw pointers"),
+                    _ => {
+                        is_ptr = false;
+                        err_ty_str = format!("`{}`", ty);
+                        Some(err_ty_str.as_str())
+                    }
+                }
+            } else {
+                match ty.peel_refs().kind {
+                    ty::FnPtr(_) => Some("function pointers"),
+                    ty::RawPtr(_) => Some("raw pointers"),
+                    _ => None,
+                }
+            };
+            if let Some(unsupported_type) = err {
+                if is_ptr {
+                    tcx.sess.span_err(
+                        hir_ty.span,
+                        &format!(
+                            "using {} as const generic parameters is forbidden",
+                            unsupported_type
+                        ),
+                    )
+                } else {
+                    tcx.sess
+                        .struct_span_err(
+                            hir_ty.span,
+                            &format!(
+                                "{} is forbidden as the type of a const generic parameter",
+                                unsupported_type
+                            ),
+                        )
+                        .note("the only supported types are integers, `bool` and `char`")
+                        .note("more complex types are supported with `#[feature(const_generics)]`")
+                        .emit()
+                }
+            };
+
+            if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
+                .is_some()
+            {
+                // We use the same error code in both branches, because this is really the same
+                // issue: we just special-case the message for type parameters to make it
+                // clearer.
+                if let ty::Param(_) = ty.peel_refs().kind {
+                    // Const parameters may not have type parameters as their types,
+                    // because we cannot be sure that the type parameter derives `PartialEq`
+                    // and `Eq` (just implementing them is not enough for `structural_match`).
+                    struct_span_err!(
+                        tcx.sess,
+                        hir_ty.span,
+                        E0741,
+                        "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
+                            used as the type of a const parameter",
+                        ty,
+                    )
+                    .span_label(
+                        hir_ty.span,
+                        format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
+                    )
+                    .note(
+                        "it is not currently possible to use a type parameter as the type of a \
+                            const parameter",
+                    )
+                    .emit();
+                } else {
+                    struct_span_err!(
+                        tcx.sess,
+                        hir_ty.span,
+                        E0741,
+                        "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
+                            the type of a const parameter",
+                        ty,
+                    )
+                    .span_label(
+                        hir_ty.span,
+                        format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
+                    )
+                    .emit();
+                }
+            }
+        }
+    }
+}
+
 fn check_associated_item(
     tcx: TyCtxt<'_>,
     item_id: hir::HirId,
@@ -1282,6 +1386,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) {
     fcx.select_all_obligations_or_error();
 }
 
+#[derive(Clone, Copy)]
 pub struct CheckTypeWellFormedVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
 }
@@ -1294,21 +1399,49 @@ impl CheckTypeWellFormedVisitor<'tcx> {
 
 impl ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
     fn visit_item(&self, i: &'tcx hir::Item<'tcx>) {
+        Visitor::visit_item(&mut self.clone(), i);
+    }
+
+    fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem<'tcx>) {
+        Visitor::visit_trait_item(&mut self.clone(), trait_item);
+    }
+
+    fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) {
+        Visitor::visit_impl_item(&mut self.clone(), impl_item);
+    }
+}
+
+impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
+    type Map = hir_map::Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
+        hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    }
+
+    fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
         debug!("visit_item: {:?}", i);
         let def_id = self.tcx.hir().local_def_id(i.hir_id);
         self.tcx.ensure().check_item_well_formed(def_id);
+        hir_visit::walk_item(self, i);
     }
 
-    fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem<'tcx>) {
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         debug!("visit_trait_item: {:?}", trait_item);
         let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
         self.tcx.ensure().check_trait_item_well_formed(def_id);
+        hir_visit::walk_trait_item(self, trait_item);
     }
 
-    fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) {
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         debug!("visit_impl_item: {:?}", impl_item);
         let def_id = self.tcx.hir().local_def_id(impl_item.hir_id);
         self.tcx.ensure().check_impl_item_well_formed(def_id);
+        hir_visit::walk_impl_item(self, impl_item);
+    }
+
+    fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
+        check_param_wf(self.tcx, p);
+        hir_visit::walk_generic_param(self, p);
     }
 }
 
diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs
index f1478c8c952..70ed92c5614 100644
--- a/src/librustc_typeck/collect/type_of.rs
+++ b/src/librustc_typeck/collect/type_of.rs
@@ -12,7 +12,6 @@ use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
-use rustc_trait_selection::traits;
 
 use super::ItemCtxt;
 use super::{bad_placeholder_type, is_suggestable_infer_ty};
@@ -323,88 +322,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
         }
 
         Node::GenericParam(param) => match &param.kind {
-            GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
-            GenericParamKind::Const { ty: ref hir_ty, .. } => {
-                let ty = icx.to_ty(hir_ty);
-                let err_ty_str;
-                let err = if tcx.features().min_const_generics {
-                    match ty.kind {
-                        ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
-                        ty::FnPtr(_) => Some("function pointers"),
-                        ty::RawPtr(_) => Some("raw pointers"),
-                        _ => {
-                            err_ty_str = format!("`{}`", ty);
-                            Some(err_ty_str.as_str())
-                        }
-                    }
-                } else {
-                    match ty.peel_refs().kind {
-                        ty::FnPtr(_) => Some("function pointers"),
-                        ty::RawPtr(_) => Some("raw pointers"),
-                        _ => None,
-                    }
-                };
-                if let Some(unsupported_type) = err {
-                    let mut err = tcx.sess.struct_span_err(
-                        hir_ty.span,
-                        &format!(
-                            "using {} as const generic parameters is forbidden",
-                            unsupported_type
-                        ),
-                    );
-
-                    if tcx.features().min_const_generics {
-                        err.note("the only supported types are integers, `bool` and `char`")
-                        .note("more complex types are supported with `#[feature(const_generics)]`").emit()
-                    } else {
-                        err.emit();
-                    }
-                };
-                if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
-                    .is_some()
-                {
-                    // We use the same error code in both branches, because this is really the same
-                    // issue: we just special-case the message for type parameters to make it
-                    // clearer.
-                    if let ty::Param(_) = ty.peel_refs().kind {
-                        // Const parameters may not have type parameters as their types,
-                        // because we cannot be sure that the type parameter derives `PartialEq`
-                        // and `Eq` (just implementing them is not enough for `structural_match`).
-                        struct_span_err!(
-                            tcx.sess,
-                            hir_ty.span,
-                            E0741,
-                            "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
-                             used as the type of a const parameter",
-                            ty,
-                        )
-                        .span_label(
-                            hir_ty.span,
-                            format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
-                        )
-                        .note(
-                            "it is not currently possible to use a type parameter as the type of a \
-                             const parameter",
-                        )
-                        .emit();
-                    } else {
-                        struct_span_err!(
-                            tcx.sess,
-                            hir_ty.span,
-                            E0741,
-                            "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
-                             the type of a const parameter",
-                            ty,
-                        )
-                        .span_label(
-                            hir_ty.span,
-                            format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
-                        )
-                        .emit();
-                    }
-                }
-                ty
-            }
+            GenericParamKind::Type { default: Some(ty), .. }
+            | GenericParamKind::Const { ty, .. } => icx.to_ty(ty),
             x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
         },
 
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 4af13e4cd58..1354ef5cbde 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -14,5 +14,6 @@ minifier = "0.0.33"
 rayon = { version = "0.3.0", package = "rustc-rayon" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+smallvec = "1.0"
 tempfile = "3"
 itertools = "0.8"
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 914dc2e1b88..3eac5bbda00 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -3,6 +3,7 @@ use std::default::Default;
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
+use std::lazy::SyncOnceCell as OnceCell;
 use std::num::NonZeroU32;
 use std::rc::Rc;
 use std::sync::Arc;
@@ -19,12 +20,14 @@ use rustc_hir::lang_items;
 use rustc_hir::Mutability;
 use rustc_index::vec::IndexVec;
 use rustc_middle::middle::stability;
+use rustc_middle::ty::TyCtxt;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{self, FileName};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
+use smallvec::{smallvec, SmallVec};
 
 use crate::clean::cfg::Cfg;
 use crate::clean::external_path;
@@ -1264,6 +1267,86 @@ impl PrimitiveType {
         }
     }
 
+    pub fn impls(&self, tcx: TyCtxt<'_>) -> &'static SmallVec<[DefId; 4]> {
+        Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
+    }
+
+    pub fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>> {
+        static CELL: OnceCell<FxHashMap<PrimitiveType, SmallVec<[DefId; 4]>>> = OnceCell::new();
+
+        CELL.get_or_init(move || {
+            use self::PrimitiveType::*;
+
+            /// A macro to create a FxHashMap.
+            ///
+            /// Example:
+            ///
+            /// ```
+            /// let letters = map!{"a" => "b", "c" => "d"};
+            /// ```
+            ///
+            /// Trailing commas are allowed.
+            /// Commas between elements are required (even if the expression is a block).
+            macro_rules! map {
+                ($( $key: expr => $val: expr ),* $(,)*) => {{
+                    let mut map = ::rustc_data_structures::fx::FxHashMap::default();
+                    $( map.insert($key, $val); )*
+                    map
+                }}
+            }
+
+            let single = |a: Option<DefId>| a.into_iter().collect();
+            let both = |a: Option<DefId>, b: Option<DefId>| -> SmallVec<_> {
+                a.into_iter().chain(b).collect()
+            };
+
+            let lang_items = tcx.lang_items();
+            map! {
+                Isize => single(lang_items.isize_impl()),
+                I8 => single(lang_items.i8_impl()),
+                I16 => single(lang_items.i16_impl()),
+                I32 => single(lang_items.i32_impl()),
+                I64 => single(lang_items.i64_impl()),
+                I128 => single(lang_items.i128_impl()),
+                Usize => single(lang_items.usize_impl()),
+                U8 => single(lang_items.u8_impl()),
+                U16 => single(lang_items.u16_impl()),
+                U32 => single(lang_items.u32_impl()),
+                U64 => single(lang_items.u64_impl()),
+                U128 => single(lang_items.u128_impl()),
+                F32 => both(lang_items.f32_impl(), lang_items.f32_runtime_impl()),
+                F64 => both(lang_items.f64_impl(), lang_items.f64_runtime_impl()),
+                Char => single(lang_items.char_impl()),
+                Bool => single(lang_items.bool_impl()),
+                Str => both(lang_items.str_impl(), lang_items.str_alloc_impl()),
+                Slice => {
+                    lang_items
+                        .slice_impl()
+                        .into_iter()
+                        .chain(lang_items.slice_u8_impl())
+                        .chain(lang_items.slice_alloc_impl())
+                        .chain(lang_items.slice_u8_alloc_impl())
+                        .collect()
+                },
+                Array => single(lang_items.array_impl()),
+                Tuple => smallvec![],
+                Unit => smallvec![],
+                RawPointer => {
+                    lang_items
+                        .const_ptr_impl()
+                        .into_iter()
+                        .chain(lang_items.mut_ptr_impl())
+                        .chain(lang_items.const_slice_ptr_impl())
+                        .chain(lang_items.mut_slice_ptr_impl())
+                        .collect()
+                },
+                Reference => smallvec![],
+                Fn => smallvec![],
+                Never => smallvec![],
+            }
+        })
+    }
+
     pub fn to_url_str(&self) -> &'static str {
         self.as_str()
     }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index a502a27948e..75fdcd5ec1c 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -351,7 +351,6 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String {
 }
 
 pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec<Item>) {
-    use self::PrimitiveType::*;
     let tcx = cx.tcx;
 
     for item in items {
@@ -370,34 +369,7 @@ pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut V
                 None => continue,
             },
         };
-        let did = match primitive {
-            Isize => tcx.lang_items().isize_impl(),
-            I8 => tcx.lang_items().i8_impl(),
-            I16 => tcx.lang_items().i16_impl(),
-            I32 => tcx.lang_items().i32_impl(),
-            I64 => tcx.lang_items().i64_impl(),
-            I128 => tcx.lang_items().i128_impl(),
-            Usize => tcx.lang_items().usize_impl(),
-            U8 => tcx.lang_items().u8_impl(),
-            U16 => tcx.lang_items().u16_impl(),
-            U32 => tcx.lang_items().u32_impl(),
-            U64 => tcx.lang_items().u64_impl(),
-            U128 => tcx.lang_items().u128_impl(),
-            F32 => tcx.lang_items().f32_impl(),
-            F64 => tcx.lang_items().f64_impl(),
-            Char => tcx.lang_items().char_impl(),
-            Bool => tcx.lang_items().bool_impl(),
-            Str => tcx.lang_items().str_impl(),
-            Slice => tcx.lang_items().slice_impl(),
-            Array => tcx.lang_items().array_impl(),
-            Tuple => None,
-            Unit => None,
-            RawPointer => tcx.lang_items().const_ptr_impl(),
-            Reference => None,
-            Fn => None,
-            Never => None,
-        };
-        if let Some(did) = did {
+        for &did in primitive.impls(tcx) {
             if !did.is_local() {
                 inline::build_impl(cx, did, None, ret);
             }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index d5f7ddcbdfb..3dfa7b529e3 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -12,6 +12,7 @@
 #![feature(ptr_offset_from)]
 #![feature(crate_visibility_modifier)]
 #![feature(never_type)]
+#![feature(once_cell)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index edfe8c05c6d..97b9fcce05b 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -16,6 +16,7 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::Ident;
 use rustc_span::symbol::Symbol;
 use rustc_span::DUMMY_SP;
+use smallvec::SmallVec;
 
 use std::cell::Cell;
 use std::ops::Range;
@@ -270,18 +271,26 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 .ok_or(ErrorKind::ResolutionFailure)?;
 
             if let Some((path, prim)) = is_primitive(&path, TypeNS) {
-                let did = primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)?;
-                return cx
-                    .tcx
-                    .associated_items(did)
-                    .filter_by_name_unhygienic(item_name)
-                    .next()
-                    .and_then(|item| match item.kind {
-                        ty::AssocKind::Fn => Some("method"),
-                        _ => None,
-                    })
-                    .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))))
-                    .ok_or(ErrorKind::ResolutionFailure);
+                for &impl_ in primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)? {
+                    let link = cx
+                        .tcx
+                        .associated_items(impl_)
+                        .find_by_name_and_namespace(
+                            cx.tcx,
+                            Ident::with_dummy_span(item_name),
+                            ns,
+                            impl_,
+                        )
+                        .and_then(|item| match item.kind {
+                            ty::AssocKind::Fn => Some("method"),
+                            _ => None,
+                        })
+                        .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))));
+                    if let Some(link) = link {
+                        return Ok(link);
+                    }
+                }
+                return Err(ErrorKind::ResolutionFailure);
             }
 
             let (_, ty_res) = cx
@@ -1238,26 +1247,6 @@ fn is_primitive(path_str: &str, ns: Namespace) -> Option<(&'static str, Res)> {
     }
 }
 
-fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<DefId> {
-    let tcx = cx.tcx;
-    match path_str {
-        "u8" => tcx.lang_items().u8_impl(),
-        "u16" => tcx.lang_items().u16_impl(),
-        "u32" => tcx.lang_items().u32_impl(),
-        "u64" => tcx.lang_items().u64_impl(),
-        "u128" => tcx.lang_items().u128_impl(),
-        "usize" => tcx.lang_items().usize_impl(),
-        "i8" => tcx.lang_items().i8_impl(),
-        "i16" => tcx.lang_items().i16_impl(),
-        "i32" => tcx.lang_items().i32_impl(),
-        "i64" => tcx.lang_items().i64_impl(),
-        "i128" => tcx.lang_items().i128_impl(),
-        "isize" => tcx.lang_items().isize_impl(),
-        "f32" => tcx.lang_items().f32_impl(),
-        "f64" => tcx.lang_items().f64_impl(),
-        "str" => tcx.lang_items().str_impl(),
-        "bool" => tcx.lang_items().bool_impl(),
-        "char" => tcx.lang_items().char_impl(),
-        _ => None,
-    }
+fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<&'static SmallVec<[DefId; 4]>> {
+    Some(PrimitiveType::from_symbol(Symbol::intern(path_str))?.impls(cx.tcx))
 }
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index a40b45f9a7e..24baff46dcf 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -34,40 +34,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
     }
 
     // Also try to inline primitive impls from other crates.
-    let lang_items = cx.tcx.lang_items();
-    let primitive_impls = [
-        lang_items.isize_impl(),
-        lang_items.i8_impl(),
-        lang_items.i16_impl(),
-        lang_items.i32_impl(),
-        lang_items.i64_impl(),
-        lang_items.i128_impl(),
-        lang_items.usize_impl(),
-        lang_items.u8_impl(),
-        lang_items.u16_impl(),
-        lang_items.u32_impl(),
-        lang_items.u64_impl(),
-        lang_items.u128_impl(),
-        lang_items.f32_impl(),
-        lang_items.f64_impl(),
-        lang_items.f32_runtime_impl(),
-        lang_items.f64_runtime_impl(),
-        lang_items.bool_impl(),
-        lang_items.char_impl(),
-        lang_items.str_impl(),
-        lang_items.array_impl(),
-        lang_items.slice_impl(),
-        lang_items.slice_u8_impl(),
-        lang_items.str_alloc_impl(),
-        lang_items.slice_alloc_impl(),
-        lang_items.slice_u8_alloc_impl(),
-        lang_items.const_ptr_impl(),
-        lang_items.mut_ptr_impl(),
-        lang_items.const_slice_ptr_impl(),
-        lang_items.mut_slice_ptr_impl(),
-    ];
-
-    for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
+    for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
         if !def_id.is_local() {
             inline::build_impl(cx, def_id, None, &mut new_items);
 
diff --git a/src/test/mir-opt/issue-41697.rs b/src/test/mir-opt/issue-41697.rs
index c90cfc792a9..2c4f7544844 100644
--- a/src/test/mir-opt/issue-41697.rs
+++ b/src/test/mir-opt/issue-41697.rs
@@ -14,7 +14,7 @@ trait Foo {
 }
 
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
-// EMIT_MIR issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir
+// EMIT_MIR issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir
 impl Foo for [u8; 1+1] {
     fn get(&self) -> [u8; 2] {
         *self
diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.32bit b/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit
index 14ece035f34..1cef88fd109 100644
--- a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.32bit
+++ b/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit
@@ -1,4 +1,4 @@
-// MIR for `<impl at $DIR/issue-41697.rs:18:1: 22:2>::{{constant}}#0` after SimplifyCfg-qualify-consts
+// MIR for `<impl at $DIR/issue-41697.rs:18:1: 22:2>::{{constant}}#0` after SimplifyCfg-promote-consts
 
 <impl at $DIR/issue-41697.rs:18:1: 22:2>::{{constant}}#0: usize = {
     let mut _0: usize;                   // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22
diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.64bit b/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit
index 14ece035f34..1cef88fd109 100644
--- a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.64bit
+++ b/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit
@@ -1,4 +1,4 @@
-// MIR for `<impl at $DIR/issue-41697.rs:18:1: 22:2>::{{constant}}#0` after SimplifyCfg-qualify-consts
+// MIR for `<impl at $DIR/issue-41697.rs:18:1: 22:2>::{{constant}}#0` after SimplifyCfg-promote-consts
 
 <impl at $DIR/issue-41697.rs:18:1: 22:2>::{{constant}}#0: usize = {
     let mut _0: usize;                   // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22
diff --git a/src/test/mir-opt/loop_test.main.SimplifyCfg-qualify-consts.after.mir b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
index 77bd8846812..b95e73854e3 100644
--- a/src/test/mir-opt/loop_test.main.SimplifyCfg-qualify-consts.after.mir
+++ b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
@@ -1,4 +1,4 @@
-// MIR for `main` after SimplifyCfg-qualify-consts
+// MIR for `main` after SimplifyCfg-promote-consts
 
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/loop_test.rs:6:11: 6:11
diff --git a/src/test/mir-opt/loop_test.rs b/src/test/mir-opt/loop_test.rs
index 5d0c30d4410..7ded5b5757f 100644
--- a/src/test/mir-opt/loop_test.rs
+++ b/src/test/mir-opt/loop_test.rs
@@ -2,7 +2,7 @@
 
 // Tests to make sure we correctly generate falseUnwind edges in loops
 
-// EMIT_MIR loop_test.main.SimplifyCfg-qualify-consts.after.mir
+// EMIT_MIR loop_test.main.SimplifyCfg-promote-consts.after.mir
 fn main() {
     // Exit early at runtime. Since only care about the generated MIR
     // and not the runtime behavior (which is exercised by other tests)
diff --git a/src/test/rustdoc/intra-link-primitive-non-default-impl.rs b/src/test/rustdoc/intra-link-primitive-non-default-impl.rs
new file mode 100644
index 00000000000..160b18a967b
--- /dev/null
+++ b/src/test/rustdoc/intra-link-primitive-non-default-impl.rs
@@ -0,0 +1,32 @@
+#![deny(broken_intra_doc_links)]
+
+// ignore-tidy-linelength
+
+// @has intra_link_primitive_non_default_impl/fn.str_methods.html
+/// [`str::trim`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim"]' 'str::trim'
+/// [`str::to_lowercase`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
+/// [`str::into_boxed_bytes`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
+/// [`str::replace`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.replace"]' 'str::replace'
+pub fn str_methods() {}
+
+// @has intra_link_primitive_non_default_impl/fn.f32_methods.html
+/// [f32::powi]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.powi"]' 'f32::powi'
+/// [f32::sqrt]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
+/// [f32::mul_add]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
+pub fn f32_methods() {}
+
+// @has intra_link_primitive_non_default_impl/fn.f64_methods.html
+/// [`f64::powi`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.powi"]' 'f64::powi'
+/// [`f64::sqrt`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
+/// [`f64::mul_add`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
+pub fn f64_methods() {}
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
index 61d23475c6f..809514e8a1c 100644
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
@@ -14,7 +14,7 @@ LL |     arr: [u8; CFG.arr_size],
    |
    = help: it is currently only allowed to use either `CFG` or `{ CFG }` as generic constants
 
-error: using `Config` as const generic parameters is forbidden
+error: `Config` is forbidden as the type of a const generic parameter
   --> $DIR/array-size-in-generic-struct-param.rs:18:21
    |
 LL | struct B<const CFG: Config> {
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
index aa1a3b9cf28..8bd3b787259 100644
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
@@ -16,7 +16,7 @@ struct Config {
 }
 
 struct B<const CFG: Config> {
-    //[min]~^ ERROR using `Config` as const generic parameters is forbidden
+    //[min]~^ ERROR `Config` is forbidden
     arr: [u8; CFG.arr_size],
     //[full]~^ ERROR constant expression depends on a generic parameter
     //[min]~^^ ERROR generic parameters must not be used inside of non trivial
diff --git a/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr b/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr
index bdd1da96c75..81dbaee0ec5 100644
--- a/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr
+++ b/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr
@@ -28,7 +28,7 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
 
-error: using `&'static u8` as const generic parameters is forbidden
+error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:11:19
    |
 LL | struct A<const N: &u8>;
@@ -37,7 +37,7 @@ LL | struct A<const N: &u8>;
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `&'static u8` as const generic parameters is forbidden
+error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:16:15
    |
 LL | impl<const N: &u8> A<N> {
@@ -46,7 +46,7 @@ LL | impl<const N: &u8> A<N> {
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `&'static u8` as const generic parameters is forbidden
+error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:24:15
    |
 LL | impl<const N: &u8> B for A<N> {}
@@ -55,7 +55,7 @@ LL | impl<const N: &u8> B for A<N> {}
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `&'static u8` as const generic parameters is forbidden
+error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:28:17
    |
 LL | fn bar<const N: &u8>() {}
@@ -64,7 +64,7 @@ LL | fn bar<const N: &u8>() {}
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `&'static u8` as const generic parameters is forbidden
+error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:19:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
diff --git a/src/test/ui/const-generics/const-param-elided-lifetime.rs b/src/test/ui/const-generics/const-param-elided-lifetime.rs
index 814b71d4b74..633e876f1d7 100644
--- a/src/test/ui/const-generics/const-param-elided-lifetime.rs
+++ b/src/test/ui/const-generics/const-param-elided-lifetime.rs
@@ -10,23 +10,23 @@
 
 struct A<const N: &u8>;
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
+//[min]~^^ ERROR `&'static u8` is forbidden
 trait B {}
 
 impl<const N: &u8> A<N> {
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
+//[min]~^^ ERROR `&'static u8` is forbidden
     fn foo<const M: &u8>(&self) {}
     //~^ ERROR `&` without an explicit lifetime name cannot be used here
-    //[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
+    //[min]~^^ ERROR `&'static u8` is forbidden
 }
 
 impl<const N: &u8> B for A<N> {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
+//[min]~^^ ERROR `&'static u8` is forbidden
 
 fn bar<const N: &u8>() {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
+//[min]~^^ ERROR `&'static u8` is forbidden
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
index 103f4c36fae..b00a1607876 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
@@ -10,7 +10,7 @@ error[E0770]: the type of const parameters must not depend on other generic para
 LL | pub struct SelfDependent<const N: [u8; N]>;
    |                                        ^ the type must not depend on the parameter `N`
 
-error: using `[u8; _]` as const generic parameters is forbidden
+error: `[u8; _]` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-type-depends-on-const-param.rs:12:47
    |
 LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
@@ -19,7 +19,7 @@ LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `[u8; _]` as const generic parameters is forbidden
+error: `[u8; _]` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-type-depends-on-const-param.rs:16:35
    |
 LL | pub struct SelfDependent<const N: [u8; N]>;
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs
index d21a7cec117..29371eeb21d 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs
+++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs
@@ -11,10 +11,10 @@
 
 pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
 //~^ ERROR: the type of const parameters must not depend on other generic parameters
-//[min]~^^ ERROR using `[u8; _]` as const generic parameters is forbidden
+//[min]~^^ ERROR `[u8; _]` is forbidden
 
 pub struct SelfDependent<const N: [u8; N]>;
 //~^ ERROR: the type of const parameters must not depend on other generic parameters
-//[min]~^^ ERROR using `[u8; _]` as const generic parameters is forbidden
+//[min]~^^ ERROR `[u8; _]` is forbidden
 
 fn main() {}
diff --git a/src/test/ui/const-generics/different_byref.min.stderr b/src/test/ui/const-generics/different_byref.min.stderr
index 770491179ab..050b28abe50 100644
--- a/src/test/ui/const-generics/different_byref.min.stderr
+++ b/src/test/ui/const-generics/different_byref.min.stderr
@@ -1,4 +1,4 @@
-error: using `[usize; 1]` as const generic parameters is forbidden
+error: `[usize; 1]` is forbidden as the type of a const generic parameter
   --> $DIR/different_byref.rs:8:23
    |
 LL | struct Const<const V: [usize; 1]> {}
diff --git a/src/test/ui/const-generics/different_byref.rs b/src/test/ui/const-generics/different_byref.rs
index ec85ed775d4..cd3960eeb8e 100644
--- a/src/test/ui/const-generics/different_byref.rs
+++ b/src/test/ui/const-generics/different_byref.rs
@@ -6,7 +6,7 @@
 #![cfg_attr(min, feature(min_const_generics))]
 
 struct Const<const V: [usize; 1]> {}
-//[min]~^ using `[usize; 1]` as const generic parameters is forbidden
+//[min]~^ ERROR `[usize; 1]` is forbidden
 
 fn main() {
     let mut x = Const::<{ [3] }> {};
diff --git a/src/test/ui/const-generics/fn-const-param-call.min.stderr b/src/test/ui/const-generics/fn-const-param-call.min.stderr
index 83acd04e464..f1bd8def9ff 100644
--- a/src/test/ui/const-generics/fn-const-param-call.min.stderr
+++ b/src/test/ui/const-generics/fn-const-param-call.min.stderr
@@ -3,18 +3,12 @@ error: using function pointers as const generic parameters is forbidden
    |
 LL | struct Wrapper<const F: fn() -> u32>;
    |                         ^^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/fn-const-param-call.rs:14:15
    |
 LL | impl<const F: fn() -> u32> Wrapper<F> {
    |               ^^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/fn-const-param-infer.min.stderr b/src/test/ui/const-generics/fn-const-param-infer.min.stderr
index 27d1101cbcb..4bdc9b89af6 100644
--- a/src/test/ui/const-generics/fn-const-param-infer.min.stderr
+++ b/src/test/ui/const-generics/fn-const-param-infer.min.stderr
@@ -3,9 +3,6 @@ error: using function pointers as const generic parameters is forbidden
    |
 LL | struct Checked<const F: fn(usize) -> bool>;
    |                         ^^^^^^^^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr b/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr
index 25aa3540223..40d8f44cafc 100644
--- a/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr
@@ -1,4 +1,4 @@
-error: using `A` as const generic parameters is forbidden
+error: `A` is forbidden as the type of a const generic parameter
   --> $DIR/forbid-non-structural_match-types.rs:10:19
    |
 LL | struct B<const X: A>; // ok
@@ -7,7 +7,7 @@ LL | struct B<const X: A>; // ok
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `C` as const generic parameters is forbidden
+error: `C` is forbidden as the type of a const generic parameter
   --> $DIR/forbid-non-structural_match-types.rs:15:19
    |
 LL | struct D<const X: C>;
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.rs b/src/test/ui/const-generics/forbid-non-structural_match-types.rs
index 86540db2d03..e7356d485db 100644
--- a/src/test/ui/const-generics/forbid-non-structural_match-types.rs
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.rs
@@ -8,11 +8,11 @@
 struct A;
 
 struct B<const X: A>; // ok
-//[min]~^ ERROR using `A` as const generic parameters is forbidden
+//[min]~^ ERROR `A` is forbidden
 
 struct C;
 
 struct D<const X: C>; //~ ERROR `C` must be annotated with `#[derive(PartialEq, Eq)]`
-//[min]~^ ERROR using `C` as const generic parameters is forbidden
+//[min]~^ ERROR `C` is forbidden
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr
index 3ff17ddb3bc..786ded3c2fe 100644
--- a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr
+++ b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr
@@ -1,4 +1,4 @@
-error: using `&'static str` as const generic parameters is forbidden
+error: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/issue-66596-impl-trait-for-str-const-arg.rs:9:25
    |
 LL | trait Trait<const NAME: &'static str> {
diff --git a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs
index d458a366fb3..11d4bf4c3e6 100644
--- a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs
+++ b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.rs
@@ -7,7 +7,7 @@
 
 
 trait Trait<const NAME: &'static str> {
-//[min]~^ ERROR using `&'static str` as const generic parameters is forbidden
+//[min]~^ ERROR `&'static str` is forbidden
     type Assoc;
 }
 
diff --git a/src/test/ui/const-generics/issues/issue-56445.min.stderr b/src/test/ui/const-generics/issues/issue-56445.min.stderr
index ca35ee5b290..bcb27d8d1e1 100644
--- a/src/test/ui/const-generics/issues/issue-56445.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-56445.min.stderr
@@ -6,15 +6,6 @@ LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
    |
    = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
 
-error: using `&'static str` as const generic parameters is forbidden
-  --> $DIR/issue-56445.rs:9:25
-   |
-LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
-   |                         ^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0771`.
diff --git a/src/test/ui/const-generics/issues/issue-56445.rs b/src/test/ui/const-generics/issues/issue-56445.rs
index 174eb16abfc..0bcde348b05 100644
--- a/src/test/ui/const-generics/issues/issue-56445.rs
+++ b/src/test/ui/const-generics/issues/issue-56445.rs
@@ -8,6 +8,5 @@ use std::marker::PhantomData;
 
 struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
 //~^ ERROR: use of non-static lifetime `'a` in const generic
-//[min]~| ERROR: using `&'static str` as const
 
 impl Bug<'_, ""> {}
diff --git a/src/test/ui/const-generics/issues/issue-74950.min.stderr b/src/test/ui/const-generics/issues/issue-74950.min.stderr
new file mode 100644
index 00000000000..f093e6651bc
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-74950.min.stderr
@@ -0,0 +1,47 @@
+error: `Inner` is forbidden as the type of a const generic parameter
+  --> $DIR/issue-74950.rs:18:23
+   |
+LL | struct Outer<const I: Inner>;
+   |                       ^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: `Inner` is forbidden as the type of a const generic parameter
+  --> $DIR/issue-74950.rs:18:23
+   |
+LL | struct Outer<const I: Inner>;
+   |                       ^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: `Inner` is forbidden as the type of a const generic parameter
+  --> $DIR/issue-74950.rs:18:23
+   |
+LL | struct Outer<const I: Inner>;
+   |                       ^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: `Inner` is forbidden as the type of a const generic parameter
+  --> $DIR/issue-74950.rs:18:23
+   |
+LL | struct Outer<const I: Inner>;
+   |                       ^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: `Inner` is forbidden as the type of a const generic parameter
+  --> $DIR/issue-74950.rs:18:23
+   |
+LL | struct Outer<const I: Inner>;
+   |                       ^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/const-generics/issues/issue-74950.rs b/src/test/ui/const-generics/issues/issue-74950.rs
new file mode 100644
index 00000000000..39f91f2b83d
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-74950.rs
@@ -0,0 +1,25 @@
+// [full] build-pass
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+
+#[derive(PartialEq, Eq)]
+struct Inner;
+
+// Note: We emit the error 5 times if we don't deduplicate:
+// - struct definition
+// - impl PartialEq
+// - impl Eq
+// - impl StructuralPartialEq
+// - impl StructuralEq
+#[derive(PartialEq, Eq)]
+struct Outer<const I: Inner>;
+//[min]~^ `Inner` is forbidden
+//[min]~| `Inner` is forbidden
+//[min]~| `Inner` is forbidden
+//[min]~| `Inner` is forbidden
+//[min]~| `Inner` is forbidden
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-75047.rs b/src/test/ui/const-generics/issues/issue-75047.rs
new file mode 100644
index 00000000000..5d068d851c1
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-75047.rs
@@ -0,0 +1,15 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Bar<T>(T);
+
+impl<T> Bar<T> {
+    const fn value() -> usize {
+        42
+    }
+}
+
+struct Foo<const N: [u8; Bar::<u32>::value()]>;
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.rs b/src/test/ui/const-generics/min_const_generics/complex-types.rs
index a396fa83aa6..98bc99d0194 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-types.rs
+++ b/src/test/ui/const-generics/min_const_generics/complex-types.rs
@@ -1,18 +1,17 @@
 #![feature(min_const_generics)]
 
 struct Foo<const N: [u8; 0]>;
-//~^ ERROR using `[u8; 0]` as const generic parameters is forbidden
+//~^ ERROR `[u8; 0]` is forbidden
 
 struct Bar<const N: ()>;
-//~^ ERROR using `()` as const generic parameters is forbidden
-
+//~^ ERROR `()` is forbidden
 #[derive(PartialEq, Eq)]
 struct No;
 
 struct Fez<const N: No>;
-//~^ ERROR using `No` as const generic parameters is forbidden
+//~^ ERROR `No` is forbidden
 
 struct Faz<const N: &'static u8>;
-//~^ ERROR using `&'static u8` as const generic parameters is forbidden
+//~^ ERROR `&'static u8` is forbidden
 
 fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.stderr b/src/test/ui/const-generics/min_const_generics/complex-types.stderr
index 835b1f1a3e8..4772aaf1b3e 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-types.stderr
+++ b/src/test/ui/const-generics/min_const_generics/complex-types.stderr
@@ -1,4 +1,4 @@
-error: using `[u8; 0]` as const generic parameters is forbidden
+error: `[u8; 0]` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:3:21
    |
 LL | struct Foo<const N: [u8; 0]>;
@@ -7,7 +7,7 @@ LL | struct Foo<const N: [u8; 0]>;
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `()` as const generic parameters is forbidden
+error: `()` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:6:21
    |
 LL | struct Bar<const N: ()>;
@@ -16,8 +16,8 @@ LL | struct Bar<const N: ()>;
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `No` as const generic parameters is forbidden
-  --> $DIR/complex-types.rs:12:21
+error: `No` is forbidden as the type of a const generic parameter
+  --> $DIR/complex-types.rs:11:21
    |
 LL | struct Fez<const N: No>;
    |                     ^^
@@ -25,8 +25,8 @@ LL | struct Fez<const N: No>;
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `&'static u8` as const generic parameters is forbidden
-  --> $DIR/complex-types.rs:15:21
+error: `&'static u8` is forbidden as the type of a const generic parameter
+  --> $DIR/complex-types.rs:14:21
    |
 LL | struct Faz<const N: &'static u8>;
    |                     ^^^^^^^^^^^
diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr
index 012b8fe587b..ded6f882caf 100644
--- a/src/test/ui/const-generics/nested-type.full.stderr
+++ b/src/test/ui/const-generics/nested-type.full.stderr
@@ -1,159 +1,16 @@
-error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:7:1
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/nested-type.rs:16:5
    |
-LL | struct Foo<const N: [u8; {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:7:18
-   |
-LL | struct Foo<const N: [u8; {
-   |                  ^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:11:5
-   |
-LL |     struct Foo<const N: usize>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing the variances for items in this crate...
-   = note: ...which again requires computing type of `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:3:1
-   |
-LL | / #![cfg_attr(full, feature(const_generics))]
-LL | | #![cfg_attr(full, allow(incomplete_features))]
-LL | | #![cfg_attr(min, feature(min_const_generics))]
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+LL |     Foo::<17>::value()
+   |     ^^^^^^^^^^^^^^^^^^
 
-error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:7:1
-   |
-LL | struct Foo<const N: [u8; {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:7:18
-   |
-LL | struct Foo<const N: [u8; {
-   |                  ^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:11:5
-   |
-LL |     struct Foo<const N: usize>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing the variances for items in this crate...
-   = note: ...which again requires computing type of `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:3:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/nested-type.rs:16:5
    |
-LL | / #![cfg_attr(full, feature(const_generics))]
-LL | | #![cfg_attr(full, allow(incomplete_features))]
-LL | | #![cfg_attr(min, feature(min_const_generics))]
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+LL |     Foo::<17>::value()
+   |     ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0015, E0080.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr
index ebe818785ac..55f6fe7cc16 100644
--- a/src/test/ui/const-generics/nested-type.min.stderr
+++ b/src/test/ui/const-generics/nested-type.min.stderr
@@ -1,175 +1,32 @@
-error: using `[u8; _]` as const generic parameters is forbidden
+error: `[u8; _]` is forbidden as the type of a const generic parameter
   --> $DIR/nested-type.rs:7:21
    |
 LL |   struct Foo<const N: [u8; {
    |  _____________________^
+LL | |     struct Foo<const N: usize>;
 LL | |
-LL | |
-LL | |
+LL | |     impl<const N: usize> Foo<N> {
 ...  |
-LL | |     Foo::<17>::value()
+LL | |
 LL | | }]>;
    | |__^
    |
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:7:1
-   |
-LL | struct Foo<const N: [u8; {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:7:18
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/nested-type.rs:16:5
    |
-LL | struct Foo<const N: [u8; {
-   |                  ^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:11:5
-   |
-LL |     struct Foo<const N: usize>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing the variances for items in this crate...
-   = note: ...which again requires computing type of `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:3:1
-   |
-LL | / #![cfg_attr(full, feature(const_generics))]
-LL | | #![cfg_attr(full, allow(incomplete_features))]
-LL | | #![cfg_attr(min, feature(min_const_generics))]
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+LL |     Foo::<17>::value()
+   |     ^^^^^^^^^^^^^^^^^^
 
-error[E0391]: cycle detected when computing type of `Foo`
-  --> $DIR/nested-type.rs:7:1
-   |
-LL | struct Foo<const N: [u8; {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires computing type of `Foo::N`...
-  --> $DIR/nested-type.rs:7:18
-   |
-LL | struct Foo<const N: [u8; {
-   |                  ^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires const-evaluating `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
+error[E0080]: evaluation of constant value failed
+  --> $DIR/nested-type.rs:16:5
    |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires type-checking `Foo::{{constant}}#0`...
-  --> $DIR/nested-type.rs:7:26
-   |
-LL |   struct Foo<const N: [u8; {
-   |  __________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     Foo::<17>::value()
-LL | | }]>;
-   | |_^
-note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`...
-  --> $DIR/nested-type.rs:11:5
-   |
-LL |     struct Foo<const N: usize>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing the variances for items in this crate...
-   = note: ...which again requires computing type of `Foo`, completing the cycle
-note: cycle used when collecting item types in top-level module
-  --> $DIR/nested-type.rs:3:1
-   |
-LL | / #![cfg_attr(full, feature(const_generics))]
-LL | | #![cfg_attr(full, allow(incomplete_features))]
-LL | | #![cfg_attr(min, feature(min_const_generics))]
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
+LL |     Foo::<17>::value()
+   |     ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value`
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0015, E0080.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs
index 98a5a0dd3d8..8372551fb45 100644
--- a/src/test/ui/const-generics/nested-type.rs
+++ b/src/test/ui/const-generics/nested-type.rs
@@ -4,10 +4,7 @@
 #![cfg_attr(full, allow(incomplete_features))]
 #![cfg_attr(min, feature(min_const_generics))]
 
-struct Foo<const N: [u8; {
-//~^ ERROR cycle detected
-//~| ERROR cycle detected
-//[min]~| ERROR using `[u8; _]` as const generic
+struct Foo<const N: [u8; { //[min]~ ERROR `[u8; _]` is forbidden
     struct Foo<const N: usize>;
 
     impl<const N: usize> Foo<N> {
@@ -17,6 +14,8 @@ struct Foo<const N: [u8; {
     }
 
     Foo::<17>::value()
+    //~^ ERROR calls in constants are limited to constant functions
+    //~| ERROR evaluation of constant value failed
 }]>;
 
 fn main() {}
diff --git a/src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr b/src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr
index dc4bb8b0f04..ffaab51f766 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr
+++ b/src/test/ui/const-generics/raw-ptr-const-param-deref.min.stderr
@@ -3,18 +3,12 @@ error: using raw pointers as const generic parameters is forbidden
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
 
 error: using raw pointers as const generic parameters is forbidden
   --> $DIR/raw-ptr-const-param-deref.rs:12:15
    |
 LL | impl<const P: *const u32> Const<P> {
    |               ^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/raw-ptr-const-param.min.stderr b/src/test/ui/const-generics/raw-ptr-const-param.min.stderr
index f387974a21a..d317aa0f585 100644
--- a/src/test/ui/const-generics/raw-ptr-const-param.min.stderr
+++ b/src/test/ui/const-generics/raw-ptr-const-param.min.stderr
@@ -3,9 +3,6 @@ error: using raw pointers as const generic parameters is forbidden
    |
 LL | struct Const<const P: *const u32>;
    |                       ^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr b/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr
index e86f885b9bb..1f711bef4aa 100644
--- a/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr
+++ b/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr
@@ -1,4 +1,4 @@
-error: using `&'static str` as const generic parameters is forbidden
+error: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/slice-const-param-mismatch.rs:8:29
    |
 LL | struct ConstString<const T: &'static str>;
@@ -7,7 +7,7 @@ LL | struct ConstString<const T: &'static str>;
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `&'static [u8]` as const generic parameters is forbidden
+error: `&'static [u8]` is forbidden as the type of a const generic parameter
   --> $DIR/slice-const-param-mismatch.rs:10:28
    |
 LL | struct ConstBytes<const T: &'static [u8]>;
diff --git a/src/test/ui/const-generics/slice-const-param.min.stderr b/src/test/ui/const-generics/slice-const-param.min.stderr
index e2ffc67c357..2a49619e661 100644
--- a/src/test/ui/const-generics/slice-const-param.min.stderr
+++ b/src/test/ui/const-generics/slice-const-param.min.stderr
@@ -1,4 +1,4 @@
-error: using `&'static str` as const generic parameters is forbidden
+error: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/slice-const-param.rs:8:40
    |
 LL | pub fn function_with_str<const STRING: &'static str>() -> &'static str {
@@ -7,7 +7,7 @@ LL | pub fn function_with_str<const STRING: &'static str>() -> &'static str {
    = note: the only supported types are integers, `bool` and `char`
    = note: more complex types are supported with `#[feature(const_generics)]`
 
-error: using `&'static [u8]` as const generic parameters is forbidden
+error: `&'static [u8]` is forbidden as the type of a const generic parameter
   --> $DIR/slice-const-param.rs:13:41
    |
 LL | pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
diff --git a/src/test/ui/const-generics/slice-const-param.rs b/src/test/ui/const-generics/slice-const-param.rs
index 1b6d2f6216c..f76e948c4af 100644
--- a/src/test/ui/const-generics/slice-const-param.rs
+++ b/src/test/ui/const-generics/slice-const-param.rs
@@ -6,12 +6,12 @@
 #![cfg_attr(min, feature(min_const_generics))]
 
 pub fn function_with_str<const STRING: &'static str>() -> &'static str {
-    //[min]~^ ERROR using `&'static str` as const
+    //[min]~^ ERROR `&'static str` is forbidden
     STRING
 }
 
 pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
-    //[min]~^ ERROR using `&'static [u8]` as const
+    //[min]~^ ERROR `&'static [u8]` is forbidden
     BYTES
 }