From 172e67e487f59e58a3ce61886bfec61ec5f21fa5 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 16 Aug 2020 11:38:46 -0400 Subject: [PATCH 01/18] Adjust installation place for compiler docs This avoids conflicts when installing with rustup; rustup does not currently support overlapping installations. --- src/bootstrap/dist.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 98b6be29c073b..01121977f130b 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); From 695d86f584bf2fb1fd49d34b83166b6b28d99d10 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 17 Aug 2020 23:54:41 +0200 Subject: [PATCH 02/18] Make OnceCell transparent to dropck See the failed build in https://github.com/rust-lang/rust/pull/75555#issuecomment-675016718 for an example where we need this in real life --- library/core/tests/lazy.rs | 9 +++++++++ library/std/src/lazy.rs | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/library/core/tests/lazy.rs b/library/core/tests/lazy.rs index 1c0bddb9aef62..24f921ca7e4dc 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/lazy.rs b/library/std/src/lazy.rs index 60eba96bcc015..c1d05213e1147 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -386,9 +386,10 @@ impl SyncOnceCell { } } -impl Drop for SyncOnceCell { +unsafe impl<#[may_dangle] T> Drop for SyncOnceCell { 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() }; } } @@ -845,4 +846,13 @@ mod tests { assert_eq!(msg, MSG); } } + + #[test] + fn dropck() { + let cell = SyncOnceCell::new(); + { + let s = String::new(); + cell.set(&s).unwrap(); + } + } } From 75d13734bf9dcb31c8487493ae7ba9c45bbc6031 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 10:44:53 +0200 Subject: [PATCH 03/18] mir building: fix some comments --- src/librustc_mir/transform/mod.rs | 3 ++- src/test/mir-opt/issue-41697.rs | 2 +- ...}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit} | 2 +- ...}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit} | 2 +- ...mir => loop_test.main.SimplifyCfg-promote-consts.after.mir} | 2 +- src/test/mir-opt/loop_test.rs | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) rename src/test/mir-opt/{issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.32bit => issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit} (96%) rename src/test/mir-opt/{issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.64bit => issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit} (96%) rename src/test/mir-opt/{loop_test.main.SimplifyCfg-qualify-consts.after.mir => loop_test.main.SimplifyCfg-promote-consts.after.mir} (98%) diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 4f26f3bb45973..1c1c54434d619 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/test/mir-opt/issue-41697.rs b/src/test/mir-opt/issue-41697.rs index c90cfc792a978..2c4f7544844d0 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 similarity index 96% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.32bit rename to src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit index 14ece035f34af..1cef88fd1096b 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 `::{{constant}}#0` after SimplifyCfg-qualify-consts +// MIR for `::{{constant}}#0` after SimplifyCfg-promote-consts ::{{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 similarity index 96% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir.64bit rename to src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit index 14ece035f34af..1cef88fd1096b 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 `::{{constant}}#0` after SimplifyCfg-qualify-consts +// MIR for `::{{constant}}#0` after SimplifyCfg-promote-consts ::{{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 similarity index 98% rename from src/test/mir-opt/loop_test.main.SimplifyCfg-qualify-consts.after.mir rename to src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir index 77bd884681272..b95e73854e352 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 5d0c30d44108b..7ded5b5757f55 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) From 5d49c0e55a1ab9757c05df44bee4bf50d9d71f9c Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Tue, 18 Aug 2020 19:36:52 +0200 Subject: [PATCH 04/18] Move to intra doc links for std::io --- library/std/src/io/buffered.rs | 50 ++++++++++----------- library/std/src/io/cursor.rs | 14 +++--- library/std/src/io/error.rs | 65 ++++++++++++++------------- library/std/src/io/mod.rs | 81 ++++++++++++++++++---------------- library/std/src/io/stdio.rs | 29 +++--------- library/std/src/io/util.rs | 33 +++++++------- 6 files changed, 126 insertions(+), 146 deletions(-) diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered.rs index b4c91cced43bf..f3aadf29b2f2b 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`. +/// already in memory, like a [`Vec`]``. /// /// When the `BufReader` is dropped, the contents of its buffer will be /// discarded. Creating multiple instances of a `BufReader` on the same /// stream can cause data loss. Reading from the underlying reader after -/// unwrapping the `BufReader` with `BufReader::into_inner` can also cause +/// unwrapping the `BufReader` 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 BufReader { /// 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 Seek for BufReader { /// 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` 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 { let result: u64; if let SeekFrom::Current(n) = pos { @@ -397,7 +397,7 @@ impl Seek for BufReader { /// *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`. +/// in memory, like a [`Vec`]`. /// /// It is critical to call [`flush`] before `BufWriter` is dropped. Though /// dropping will attempt to flush the contents of the buffer, any errors @@ -441,10 +441,9 @@ impl Seek for BufReader { /// 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 { inner: Option, @@ -455,7 +454,7 @@ pub struct BufWriter { 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 BufWriter { /// /// # 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 Drop for BufWriter { } impl IntoInnerError { - /// 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 fmt::Display for IntoInnerError { /// 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 LineWriter { /// /// # 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 f4db5f8145060..58343f66f3ffd 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 { impl Cursor { /// 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 f7248e7547e27..e6eda2caf758f 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 = result::Result; /// `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 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 e90ee5c285f2f..f1ee3c6986062 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`]: crate::vec::Vec +//! [`Vec`]: 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 @@ -479,11 +479,11 @@ where /// } /// ``` /// -/// [`read()`]: Read::read +/// [`read()`]: Self::read /// [`&str`]: str /// [`std::io`]: self /// [`File`]: crate::fs::File -/// [slice]: ../../std/primitive.slice.html +/// [slice]: crate::slice #[stable(feature = "rust1", since = "1.0.0")] #[doc(spotlight)] pub trait Read { @@ -633,7 +633,7 @@ pub trait Read { /// /// [`File`]s implement `Read`: /// - /// [`read()`]: Read::read + /// [`read()`]: Self::read /// [`Ok(0)`]: Ok /// [`File`]: crate::fs::File /// @@ -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`]: Self::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; @@ -746,7 +746,7 @@ pub trait Read { /// /// [`File`]s implement `Read`: /// - /// [`read`]: Read::read + /// [`read`]: Self::read /// [`File`]: crate::fs::File /// /// ```no_run @@ -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; @@ -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; - /// 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`]: Self::write #[stable(feature = "iovec", since = "1.36.0")] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { 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`]: Self::write_vectored #[unstable(feature = "can_vector", issue = "69941")] fn is_write_vectored(&self) -> bool { false @@ -1399,16 +1404,15 @@ pub trait Write { /// /// # 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. /// /// # 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`]: Self::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 @@ -1775,7 +1777,6 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) -> 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 @@ -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 @@ -1976,7 +1979,7 @@ pub trait BufRead: Read { /// also yielded an error. /// /// [`io::Result`]: self::Result - /// [`Vec`]: crate::vec::Vec + /// [`Vec`]: Vec /// [`read_until`]: Self::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 156f555be02d8..286eb92915e49 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -252,8 +252,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// /// 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>>>, @@ -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 b9d5dc27db006..a093b745b0c13 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 From 70dfe3fa746ac459747da30aca0bac11379088d5 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 2 Aug 2020 21:28:18 +0200 Subject: [PATCH 05/18] move const param structural match checks to wfcheck --- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 116 +++++++++++- src/librustc_typeck/collect/type_of.rs | 85 +-------- .../ui/const-generics/issues/issue-75047.rs | 15 ++ .../ui/const-generics/nested-type.full.stderr | 163 ++--------------- .../ui/const-generics/nested-type.min.stderr | 167 ++---------------- src/test/ui/const-generics/nested-type.rs | 6 +- 7 files changed, 155 insertions(+), 401 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-75047.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 824e81a974ca6..dc4f181ec939b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -729,8 +729,8 @@ impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { } pub fn check_wf_new(tcx: TyCtxt<'_>) { - let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().krate().par_visit_all_item_likes(&visit); + let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); + tcx.hir().krate().visit_all_item_likes(&mut visit.as_deep_visitor()); } fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d47a8273d07ea..740f30f5224d0 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -6,9 +6,11 @@ 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::itemlikevisit::ParItemLikeVisitor; +use rustc_hir::intravisit as hir_visit; +use rustc_hir::intravisit::Visitor; 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 +277,95 @@ 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 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(); + } + } + } + } +} + fn check_associated_item( tcx: TyCtxt<'_>, item_id: hir::HirId, @@ -1292,23 +1383,38 @@ impl CheckTypeWellFormedVisitor<'tcx> { } } -impl ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { - fn visit_item(&self, i: &'tcx hir::Item<'tcx>) { +impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { + type Map = hir_map::Map<'tcx>; + + fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap { + 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); + // No need to walk further here, there is nothing interesting + // inside of generic params we don't already check in `check_param_wf`. } } diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs index f1478c8c952f8..70ed92c5614a1 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 ¶m.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/test/ui/const-generics/issues/issue-75047.rs b/src/test/ui/const-generics/issues/issue-75047.rs new file mode 100644 index 0000000000000..5d068d851c10b --- /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); + +impl Bar { + const fn value() -> usize { + 42 + } +} + +struct Foo::value()]>; + +fn main() {} diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index 012b8fe587b30..a55d43d395c84 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:17:5 | -LL | struct Foo $DIR/nested-type.rs:7:18 - | -LL | struct Foo $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires const-evaluating `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires type-checking `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`... - --> $DIR/nested-type.rs:11:5 - | -LL | struct Foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = 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 $DIR/nested-type.rs:7:18 - | -LL | struct Foo $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires const-evaluating `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires type-checking `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`... - --> $DIR/nested-type.rs:11:5 - | -LL | struct Foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = 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:17: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 ebe818785ac7c..17e2eef7278a0 100644 --- a/src/test/ui/const-generics/nested-type.min.stderr +++ b/src/test/ui/const-generics/nested-type.min.stderr @@ -4,172 +4,29 @@ error: using `[u8; _]` as const generic parameters is forbidden LL | struct Foo; LL | | ... | -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 $DIR/nested-type.rs:7:18 - | -LL | struct Foo $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires const-evaluating `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires type-checking `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`... - --> $DIR/nested-type.rs:11:5 - | -LL | struct Foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = 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[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants + --> $DIR/nested-type.rs:17: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() + | ^^^^^^^^^^^^^^^^^^ -error[E0391]: cycle detected when computing type of `Foo` - --> $DIR/nested-type.rs:7:1 - | -LL | struct Foo $DIR/nested-type.rs:7:18 - | -LL | struct Foo $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires const-evaluating + checking `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::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:17:5 | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires type-checking `Foo::{{constant}}#0`... - --> $DIR/nested-type.rs:7:26 - | -LL | struct Foo::value() -LL | | }]>; - | |_^ -note: ...which requires computing the variances of `Foo::{{constant}}#0::Foo`... - --> $DIR/nested-type.rs:11:5 - | -LL | struct Foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = 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 98a5a0dd3d8fd..70d6ac42e9ff2 100644 --- a/src/test/ui/const-generics/nested-type.rs +++ b/src/test/ui/const-generics/nested-type.rs @@ -5,9 +5,7 @@ #![cfg_attr(min, feature(min_const_generics))] struct Foo; impl Foo { @@ -17,6 +15,8 @@ struct Foo::value() + //~^ ERROR calls in constants are limited to constant functions + //~| ERROR evaluation of constant value failed }]>; fn main() {} From 6ad01e993272132b96e9f1f9c390c85816672ce3 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 13 Aug 2020 22:26:55 +0200 Subject: [PATCH 06/18] run wfcheck in parralel again, add test for 74950 --- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 19 +++++++- .../issues/issue-56445.min.stderr | 11 +---- .../ui/const-generics/issues/issue-56445.rs | 1 - .../issues/issue-74950.min.stderr | 47 +++++++++++++++++++ .../ui/const-generics/issues/issue-74950.rs | 25 ++++++++++ 6 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-74950.min.stderr create mode 100644 src/test/ui/const-generics/issues/issue-74950.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index dc4f181ec939b..824e81a974ca6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -729,8 +729,8 @@ impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { } pub fn check_wf_new(tcx: TyCtxt<'_>) { - let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().krate().visit_all_item_likes(&mut visit.as_deep_visitor()); + let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); + tcx.hir().krate().par_visit_all_item_likes(&visit); } fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 740f30f5224d0..cbf302ad71005 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -8,6 +8,7 @@ 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; @@ -1373,6 +1374,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>, } @@ -1383,6 +1385,20 @@ 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>; @@ -1413,8 +1429,7 @@ impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { check_param_wf(self.tcx, p); - // No need to walk further here, there is nothing interesting - // inside of generic params we don't already check in `check_param_wf`. + hir_visit::walk_generic_param(self, p); } } 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 ca35ee5b2905d..bcb27d8d1e197 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 -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 174eb16abfc5f..0bcde348b05d5 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 0000000000000..e98f1d94a7240 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74950.min.stderr @@ -0,0 +1,47 @@ +error: using `Inner` as const generic parameters is forbidden + --> $DIR/issue-74950.rs:18:23 + | +LL | struct Outer; + | ^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: using `Inner` as const generic parameters is forbidden + --> $DIR/issue-74950.rs:18:23 + | +LL | struct Outer; + | ^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: using `Inner` as const generic parameters is forbidden + --> $DIR/issue-74950.rs:18:23 + | +LL | struct Outer; + | ^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: using `Inner` as const generic parameters is forbidden + --> $DIR/issue-74950.rs:18:23 + | +LL | struct Outer; + | ^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: using `Inner` as const generic parameters is forbidden + --> $DIR/issue-74950.rs:18:23 + | +LL | struct Outer; + | ^^^^^ + | + = 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 0000000000000..bfa0630a93629 --- /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; +//[min]~^ using `Inner` as const generic parameters is forbidden +//[min]~| using `Inner` as const generic parameters is forbidden +//[min]~| using `Inner` as const generic parameters is forbidden +//[min]~| using `Inner` as const generic parameters is forbidden +//[min]~| using `Inner` as const generic parameters is forbidden + +fn main() {} From 7542615c21ad7fef1cbd160252ba1bf4b7b4289c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 18 Aug 2020 22:44:06 +0200 Subject: [PATCH 07/18] change const param ty warning message --- src/librustc_typeck/check/wfcheck.rs | 30 +++++++++++++------ ...ay-size-in-generic-struct-param.min.stderr | 2 +- .../array-size-in-generic-struct-param.rs | 2 +- .../const-param-elided-lifetime.min.stderr | 10 +++---- .../const-param-elided-lifetime.rs | 10 +++---- ...ram-type-depends-on-const-param.min.stderr | 4 +-- ...const-param-type-depends-on-const-param.rs | 4 +-- .../const-generics/different_byref.min.stderr | 2 +- src/test/ui/const-generics/different_byref.rs | 2 +- .../fn-const-param-call.min.stderr | 6 ---- .../fn-const-param-infer.min.stderr | 3 -- ...rbid-non-structural_match-types.min.stderr | 4 +-- .../forbid-non-structural_match-types.rs | 4 +-- ...96-impl-trait-for-str-const-arg.min.stderr | 2 +- ...ssue-66596-impl-trait-for-str-const-arg.rs | 2 +- .../issues/issue-74950.min.stderr | 10 +++---- .../ui/const-generics/issues/issue-74950.rs | 10 +++---- .../min_const_generics/complex-types.rs | 9 +++--- .../min_const_generics/complex-types.stderr | 12 ++++---- .../ui/const-generics/nested-type.full.stderr | 4 +-- .../ui/const-generics/nested-type.min.stderr | 8 ++--- src/test/ui/const-generics/nested-type.rs | 3 +- .../raw-ptr-const-param-deref.min.stderr | 6 ---- .../raw-ptr-const-param.min.stderr | 3 -- .../slice-const-param-mismatch.min.stderr | 4 +-- .../slice-const-param.min.stderr | 4 +-- .../ui/const-generics/slice-const-param.rs | 4 +-- 27 files changed, 78 insertions(+), 86 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index cbf302ad71005..810bf59ea6c35 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -289,12 +289,14 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { 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()) } @@ -307,19 +309,29 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { } }; 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`") + 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() - } else { - err.emit(); } }; + if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty) .is_some() { 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 61d23475c6f79..809514e8a1c9d 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 { 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 aa1a3b9cf2888..8bd3b78725957 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 { - //[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 bdd1da96c7565..81dbaee0ec514 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() {} | ^ 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; @@ -37,7 +37,7 @@ LL | struct A; = 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 A { @@ -46,7 +46,7 @@ LL | impl A { = 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 B for A {} @@ -55,7 +55,7 @@ LL | impl B for A {} = 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() {} @@ -64,7 +64,7 @@ LL | fn bar() {} = 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(&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 814b71d4b741f..633e876f1d7dd 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; //~^ 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 A { //~^ 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(&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 B for A {} //~^ 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() {} //~^ 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 103f4c36faef3..b00a160787629 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; | ^ 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([(); N]); @@ -19,7 +19,7 @@ LL | pub struct Dependent([(); 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; 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 d21a7cec117ee..29371eeb21d1c 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([(); 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; //~^ 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 770491179abb5..050b28abe5088 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 {} diff --git a/src/test/ui/const-generics/different_byref.rs b/src/test/ui/const-generics/different_byref.rs index ec85ed775d4f5..cd3960eeb8e0d 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 {} -//[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 83acd04e4640b..f1bd8def9ff16 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 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 u32> Wrapper { | ^^^^^^^^^^^ - | - = 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 27d1101cbcb05..4bdc9b89af607 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 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 25aa354022304..40d8f44cafc04 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; // ok @@ -7,7 +7,7 @@ LL | struct B; // 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; 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 86540db2d03a0..e7356d485dbff 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; // ok -//[min]~^ ERROR using `A` as const generic parameters is forbidden +//[min]~^ ERROR `A` is forbidden struct C; struct D; //~ 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 3ff17ddb3bcf3..786ded3c2fe42 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 { 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 d458a366fb373..11d4bf4c3e6aa 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 { -//[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-74950.min.stderr b/src/test/ui/const-generics/issues/issue-74950.min.stderr index e98f1d94a7240..f093e6651bc28 100644 --- a/src/test/ui/const-generics/issues/issue-74950.min.stderr +++ b/src/test/ui/const-generics/issues/issue-74950.min.stderr @@ -1,4 +1,4 @@ -error: using `Inner` as const generic parameters is forbidden +error: `Inner` is forbidden as the type of a const generic parameter --> $DIR/issue-74950.rs:18:23 | LL | struct Outer; @@ -7,7 +7,7 @@ LL | struct Outer; = note: the only supported types are integers, `bool` and `char` = note: more complex types are supported with `#[feature(const_generics)]` -error: using `Inner` as const generic parameters is forbidden +error: `Inner` is forbidden as the type of a const generic parameter --> $DIR/issue-74950.rs:18:23 | LL | struct Outer; @@ -16,7 +16,7 @@ LL | struct Outer; = note: the only supported types are integers, `bool` and `char` = note: more complex types are supported with `#[feature(const_generics)]` -error: using `Inner` as const generic parameters is forbidden +error: `Inner` is forbidden as the type of a const generic parameter --> $DIR/issue-74950.rs:18:23 | LL | struct Outer; @@ -25,7 +25,7 @@ LL | struct Outer; = note: the only supported types are integers, `bool` and `char` = note: more complex types are supported with `#[feature(const_generics)]` -error: using `Inner` as const generic parameters is forbidden +error: `Inner` is forbidden as the type of a const generic parameter --> $DIR/issue-74950.rs:18:23 | LL | struct Outer; @@ -34,7 +34,7 @@ LL | struct Outer; = note: the only supported types are integers, `bool` and `char` = note: more complex types are supported with `#[feature(const_generics)]` -error: using `Inner` as const generic parameters is forbidden +error: `Inner` is forbidden as the type of a const generic parameter --> $DIR/issue-74950.rs:18:23 | LL | struct Outer; diff --git a/src/test/ui/const-generics/issues/issue-74950.rs b/src/test/ui/const-generics/issues/issue-74950.rs index bfa0630a93629..39f91f2b83dfb 100644 --- a/src/test/ui/const-generics/issues/issue-74950.rs +++ b/src/test/ui/const-generics/issues/issue-74950.rs @@ -16,10 +16,10 @@ struct Inner; // - impl StructuralEq #[derive(PartialEq, Eq)] struct Outer; -//[min]~^ using `Inner` as const generic parameters is forbidden -//[min]~| using `Inner` as const generic parameters is forbidden -//[min]~| using `Inner` as const generic parameters is forbidden -//[min]~| using `Inner` as const generic parameters is forbidden -//[min]~| using `Inner` as const generic parameters is forbidden +//[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/min_const_generics/complex-types.rs b/src/test/ui/const-generics/min_const_generics/complex-types.rs index a396fa83aa629..98bc99d019421 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; -//~^ ERROR using `[u8; 0]` as const generic parameters is forbidden +//~^ ERROR `[u8; 0]` is forbidden struct Bar; -//~^ ERROR using `()` as const generic parameters is forbidden - +//~^ ERROR `()` is forbidden #[derive(PartialEq, Eq)] struct No; struct Fez; -//~^ ERROR using `No` as const generic parameters is forbidden +//~^ ERROR `No` is forbidden struct Faz; -//~^ 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 835b1f1a3e867..4772aaf1b3e0c 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; @@ -7,7 +7,7 @@ LL | struct Foo; = 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; @@ -16,8 +16,8 @@ LL | struct Bar; = 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; | ^^ @@ -25,8 +25,8 @@ LL | struct Fez; = 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; | ^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index a55d43d395c84..ded6f882caf42 100644 --- a/src/test/ui/const-generics/nested-type.full.stderr +++ b/src/test/ui/const-generics/nested-type.full.stderr @@ -1,11 +1,11 @@ error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> $DIR/nested-type.rs:17:5 + --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() | ^^^^^^^^^^^^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/nested-type.rs:17:5 + --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value` diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr index 17e2eef7278a0..55f6fe7cc16e8 100644 --- a/src/test/ui/const-generics/nested-type.min.stderr +++ b/src/test/ui/const-generics/nested-type.min.stderr @@ -1,11 +1,11 @@ -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; LL | | +LL | | impl Foo { ... | LL | | LL | | }]>; @@ -15,13 +15,13 @@ LL | | }]>; = note: more complex types are supported with `#[feature(const_generics)]` error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> $DIR/nested-type.rs:17:5 + --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() | ^^^^^^^^^^^^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/nested-type.rs:17:5 + --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value` diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs index 70d6ac42e9ff2..8372551fb450b 100644 --- a/src/test/ui/const-generics/nested-type.rs +++ b/src/test/ui/const-generics/nested-type.rs @@ -4,8 +4,7 @@ #![cfg_attr(full, allow(incomplete_features))] #![cfg_attr(min, feature(min_const_generics))] -struct Foo; impl Foo { 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 dc4bb8b0f042a..ffaab51f766d8 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; | ^^^^^^^^^^ - | - = 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

{ | ^^^^^^^^^^ - | - = 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 f387974a21aca..d317aa0f585cf 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; | ^^^^^^^^^^ - | - = 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 e86f885b9bbad..1f711bef4aa63 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; @@ -7,7 +7,7 @@ LL | struct ConstString; = 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; 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 e2ffc67c3579c..2a49619e6614a 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() -> &'static str { @@ -7,7 +7,7 @@ LL | pub fn function_with_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() -> &'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 1b6d2f6216c44..f76e948c4af2b 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() -> &'static str { - //[min]~^ ERROR using `&'static str` as const + //[min]~^ ERROR `&'static str` is forbidden STRING } pub fn function_with_bytes() -> &'static [u8] { - //[min]~^ ERROR using `&'static [u8]` as const + //[min]~^ ERROR `&'static [u8]` is forbidden BYTES } From 34e7eac1ca2d9c66f2ad3f723f18ecf4c5db934b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 19 Aug 2020 10:28:22 +0200 Subject: [PATCH 08/18] Remove `#[cfg(miri)]` from OnceCell tests They were carried over from once_cell crate, but they are not entirely correct (as miri now supports more things), and we don't run miri tests for std, so let's just remove them. Maybe one day we'll run miri in std, but then we can just re-install these attributes. --- library/std/src/lazy.rs | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index 60eba96bcc015..bf801b3c8c704 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -516,6 +516,7 @@ mod tests { mpsc::channel, Mutex, }, + thread, }; #[test] @@ -552,26 +553,8 @@ mod tests { } } - // miri doesn't support threads - #[cfg(not(miri))] fn spawn_and_wait(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(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 +717,6 @@ mod tests { } #[test] - #[cfg_attr(miri, ignore)] // leaks memory fn static_sync_lazy() { static XS: SyncLazy> = SyncLazy::new(|| { let mut xs = Vec::new(); @@ -752,7 +734,6 @@ mod tests { } #[test] - #[cfg_attr(miri, ignore)] // leaks memory fn static_sync_lazy_via_fn() { fn xs() -> &'static Vec { static XS: SyncOnceCell> = SyncOnceCell::new(); @@ -811,7 +792,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 = SyncOnceCell::new(); @@ -823,7 +803,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 +815,7 @@ mod tests { }); } for _ in 0..n_writers { - spawn(move || { + thread::spawn(move || { let _ = ONCE_CELL.set(MSG.to_owned()); }); } From 967ec1f62360c1e9666568aaddfaf4535718d6df Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 17 Aug 2020 18:03:38 -0400 Subject: [PATCH 09/18] Refactor `impl_for_type` into a separate function --- src/librustdoc/clean/utils.rs | 63 +++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index a502a27948e29..65dfc7b2481ad 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -15,7 +15,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::mir::interpret::{sign_extend, ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, DefIdTree, Ty}; +use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; @@ -350,8 +350,39 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String { s } -pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec) { +pub fn impl_for_type(tcx: TyCtxt<'_>, primitive: PrimitiveType) -> Option { use self::PrimitiveType::*; + + 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, + } +} + +pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec) { let tcx = cx.tcx; for item in items { @@ -370,33 +401,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, - }; + let did = impl_for_type(tcx, primitive); if let Some(did) = did { if !did.is_local() { inline::build_impl(cx, did, None, ret); From 8a0aa7bd9d65dcc9a052fbbcc95ef40100744092 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 17 Aug 2020 18:06:46 -0400 Subject: [PATCH 10/18] Say `tcx.lang_items()` less --- src/librustdoc/clean/utils.rs | 41 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 65dfc7b2481ad..7ab2196585fab 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -353,29 +353,30 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String { pub fn impl_for_type(tcx: TyCtxt<'_>, primitive: PrimitiveType) -> Option { use self::PrimitiveType::*; + let lang_items = tcx.lang_items(); 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(), + Isize => lang_items.isize_impl(), + I8 => lang_items.i8_impl(), + I16 => lang_items.i16_impl(), + I32 => lang_items.i32_impl(), + I64 => lang_items.i64_impl(), + I128 => lang_items.i128_impl(), + Usize => lang_items.usize_impl(), + U8 => lang_items.u8_impl(), + U16 => lang_items.u16_impl(), + U32 => lang_items.u32_impl(), + U64 => lang_items.u64_impl(), + U128 => lang_items.u128_impl(), + F32 => lang_items.f32_impl(), + F64 => lang_items.f64_impl(), + Char => lang_items.char_impl(), + Bool => lang_items.bool_impl(), + Str => lang_items.str_impl(), + Slice => lang_items.slice_impl(), + Array => lang_items.array_impl(), Tuple => None, Unit => None, - RawPointer => tcx.lang_items().const_ptr_impl(), + RawPointer => lang_items.const_ptr_impl(), Reference => None, Fn => None, Never => None, From 3ddd8b233c95853dd281493f4c646520354461b5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 17 Aug 2020 18:21:31 -0400 Subject: [PATCH 11/18] Return all impls, not just the primary one --- Cargo.lock | 1 + src/librustdoc/Cargo.toml | 1 + src/librustdoc/clean/utils.rs | 41 ++++++++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 985dbb046d0c6..fc4e72138e7a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4106,6 +4106,7 @@ dependencies = [ "rustc-rayon", "serde", "serde_json", + "smallvec 1.4.0", "tempfile", ] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 4af13e4cd587a..1354ef5cbdeb4 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/utils.rs b/src/librustdoc/clean/utils.rs index 7ab2196585fab..969098122bfca 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -17,6 +17,7 @@ use rustc_middle::mir::interpret::{sign_extend, ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; +use smallvec::SmallVec; use std::mem; pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { @@ -350,11 +351,14 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String { s } -pub fn impl_for_type(tcx: TyCtxt<'_>, primitive: PrimitiveType) -> Option { +pub fn impl_for_type(tcx: TyCtxt<'_>, primitive: PrimitiveType) -> SmallVec<[DefId; 4]> { use self::PrimitiveType::*; + let both = + |a: Option, b: Option| -> SmallVec<_> { a.into_iter().chain(b).collect() }; + let lang_items = tcx.lang_items(); - match primitive { + let primary_impl = match primitive { Isize => lang_items.isize_impl(), I8 => lang_items.i8_impl(), I16 => lang_items.i16_impl(), @@ -367,20 +371,38 @@ pub fn impl_for_type(tcx: TyCtxt<'_>, primitive: PrimitiveType) -> Option U32 => lang_items.u32_impl(), U64 => lang_items.u64_impl(), U128 => lang_items.u128_impl(), - F32 => lang_items.f32_impl(), - F64 => lang_items.f64_impl(), + F32 => return both(lang_items.f32_impl(), lang_items.f32_runtime_impl()), + F64 => return both(lang_items.f64_impl(), lang_items.f64_runtime_impl()), Char => lang_items.char_impl(), Bool => lang_items.bool_impl(), - Str => lang_items.str_impl(), - Slice => lang_items.slice_impl(), + Str => return both(lang_items.str_impl(), lang_items.str_alloc_impl()), + Slice => { + return 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 => lang_items.array_impl(), Tuple => None, Unit => None, - RawPointer => lang_items.const_ptr_impl(), + RawPointer => { + return 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 => None, Fn => None, Never => None, - } + }; + + primary_impl.into_iter().collect() } pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec) { @@ -402,8 +424,7 @@ pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut V None => continue, }, }; - let did = impl_for_type(tcx, primitive); - if let Some(did) = did { + for did in impl_for_type(tcx, primitive) { if !did.is_local() { inline::build_impl(cx, did, None, ret); } From 06d6d3dff5f95c7ef24954cc3c6c1b8010705378 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 17 Aug 2020 18:26:10 -0400 Subject: [PATCH 12/18] impl_for_type -> PrimitiveType::impls --- src/librustdoc/clean/types.rs | 57 +++++++++++++++++++++++++++++++++ src/librustdoc/clean/utils.rs | 59 ++--------------------------------- 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 914dc2e1b8847..5b9f4830261e2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -19,12 +19,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; use crate::clean::cfg::Cfg; use crate::clean::external_path; @@ -1264,6 +1266,61 @@ impl PrimitiveType { } } + pub fn impls(&self, tcx: TyCtxt<'_>) -> SmallVec<[DefId; 4]> { + use self::PrimitiveType::*; + + let both = + |a: Option, b: Option| -> SmallVec<_> { a.into_iter().chain(b).collect() }; + + let lang_items = tcx.lang_items(); + let primary_impl = match self { + Isize => lang_items.isize_impl(), + I8 => lang_items.i8_impl(), + I16 => lang_items.i16_impl(), + I32 => lang_items.i32_impl(), + I64 => lang_items.i64_impl(), + I128 => lang_items.i128_impl(), + Usize => lang_items.usize_impl(), + U8 => lang_items.u8_impl(), + U16 => lang_items.u16_impl(), + U32 => lang_items.u32_impl(), + U64 => lang_items.u64_impl(), + U128 => lang_items.u128_impl(), + F32 => return both(lang_items.f32_impl(), lang_items.f32_runtime_impl()), + F64 => return both(lang_items.f64_impl(), lang_items.f64_runtime_impl()), + Char => lang_items.char_impl(), + Bool => lang_items.bool_impl(), + Str => return both(lang_items.str_impl(), lang_items.str_alloc_impl()), + Slice => { + return 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 => lang_items.array_impl(), + Tuple => None, + Unit => None, + RawPointer => { + return 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 => None, + Fn => None, + Never => None, + }; + + primary_impl.into_iter().collect() + } + + 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 969098122bfca..b80ac0384fddb 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -15,9 +15,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::mir::interpret::{sign_extend, ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, Ty}; use rustc_span::symbol::{kw, sym, Symbol}; -use smallvec::SmallVec; use std::mem; pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { @@ -351,60 +350,6 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String { s } -pub fn impl_for_type(tcx: TyCtxt<'_>, primitive: PrimitiveType) -> SmallVec<[DefId; 4]> { - use self::PrimitiveType::*; - - let both = - |a: Option, b: Option| -> SmallVec<_> { a.into_iter().chain(b).collect() }; - - let lang_items = tcx.lang_items(); - let primary_impl = match primitive { - Isize => lang_items.isize_impl(), - I8 => lang_items.i8_impl(), - I16 => lang_items.i16_impl(), - I32 => lang_items.i32_impl(), - I64 => lang_items.i64_impl(), - I128 => lang_items.i128_impl(), - Usize => lang_items.usize_impl(), - U8 => lang_items.u8_impl(), - U16 => lang_items.u16_impl(), - U32 => lang_items.u32_impl(), - U64 => lang_items.u64_impl(), - U128 => lang_items.u128_impl(), - F32 => return both(lang_items.f32_impl(), lang_items.f32_runtime_impl()), - F64 => return both(lang_items.f64_impl(), lang_items.f64_runtime_impl()), - Char => lang_items.char_impl(), - Bool => lang_items.bool_impl(), - Str => return both(lang_items.str_impl(), lang_items.str_alloc_impl()), - Slice => { - return 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 => lang_items.array_impl(), - Tuple => None, - Unit => None, - RawPointer => { - return 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 => None, - Fn => None, - Never => None, - }; - - primary_impl.into_iter().collect() -} - pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec) { let tcx = cx.tcx; @@ -424,7 +369,7 @@ pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut V None => continue, }, }; - for did in impl_for_type(tcx, primitive) { + for did in primitive.impls(tcx) { if !did.is_local() { inline::build_impl(cx, did, None, ret); } From 9cf2fa84e8dfbbeb01d4d06fabd921300c58ade0 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 17 Aug 2020 18:45:18 -0400 Subject: [PATCH 13/18] Allow reusing the code in `collect_trait_impls` --- src/librustdoc/clean/types.rs | 129 +++++++++++-------- src/librustdoc/clean/utils.rs | 2 +- src/librustdoc/lib.rs | 1 + src/librustdoc/passes/collect_trait_impls.rs | 35 +---- 4 files changed, 80 insertions(+), 87 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5b9f4830261e2..62f71514fcf60 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -7,6 +7,7 @@ use std::num::NonZeroU32; use std::rc::Rc; use std::sync::Arc; use std::{slice, vec}; +use std::lazy::SyncOnceCell as OnceCell; use rustc_ast::attr; use rustc_ast::util::comments::beautify_doc_string; @@ -26,7 +27,7 @@ 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; +use smallvec::{SmallVec, smallvec}; use crate::clean::cfg::Cfg; use crate::clean::external_path; @@ -1266,61 +1267,85 @@ impl PrimitiveType { } } - pub fn impls(&self, tcx: TyCtxt<'_>) -> SmallVec<[DefId; 4]> { - use self::PrimitiveType::*; - - let both = - |a: Option, b: Option| -> SmallVec<_> { a.into_iter().chain(b).collect() }; - - let lang_items = tcx.lang_items(); - let primary_impl = match self { - Isize => lang_items.isize_impl(), - I8 => lang_items.i8_impl(), - I16 => lang_items.i16_impl(), - I32 => lang_items.i32_impl(), - I64 => lang_items.i64_impl(), - I128 => lang_items.i128_impl(), - Usize => lang_items.usize_impl(), - U8 => lang_items.u8_impl(), - U16 => lang_items.u16_impl(), - U32 => lang_items.u32_impl(), - U64 => lang_items.u64_impl(), - U128 => lang_items.u128_impl(), - F32 => return both(lang_items.f32_impl(), lang_items.f32_runtime_impl()), - F64 => return both(lang_items.f64_impl(), lang_items.f64_runtime_impl()), - Char => lang_items.char_impl(), - Bool => lang_items.bool_impl(), - Str => return both(lang_items.str_impl(), lang_items.str_alloc_impl()), - Slice => { - return 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(); + pub fn impls(&self, tcx: TyCtxt<'_>) -> &SmallVec<[DefId; 4]> { + Self::all_impls(tcx).get(self).expect("missing impl for primitive type") + } + + pub fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap> { + static CELL: OnceCell>> = 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 + }} } - Array => lang_items.array_impl(), - Tuple => None, - Unit => None, - RawPointer => { - return 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 => None, - Fn => None, - Never => None, - }; - primary_impl.into_iter().collect() + let single = |a: Option| a.into_iter().collect(); + let both = + |a: Option, b: Option| -> 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 b80ac0384fddb..75fdcd5ec1c9c 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -369,7 +369,7 @@ pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut V None => continue, }, }; - for did in primitive.impls(tcx) { + 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 d5f7ddcbdfbde..3dfa7b529e34c 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_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index a40b45f9a7e2c..24baff46dcfa5 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); From 219e93d91e417f76e0071e42c78edc00f7f2cd4b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 17 Aug 2020 18:54:29 -0400 Subject: [PATCH 14/18] Use `impls` for intra doc links as well --- Cargo.lock | 2 +- src/librustdoc/clean/types.rs | 2 +- .../passes/collect_intra_doc_links.rs | 52 +++++++------------ 3 files changed, 20 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc4e72138e7a5..f8fa2971b49d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4106,7 +4106,7 @@ dependencies = [ "rustc-rayon", "serde", "serde_json", - "smallvec 1.4.0", + "smallvec 1.4.2", "tempfile", ] diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 62f71514fcf60..344d5603d7637 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1267,7 +1267,7 @@ impl PrimitiveType { } } - pub fn impls(&self, tcx: TyCtxt<'_>) -> &SmallVec<[DefId; 4]> { + pub fn impls(&self, tcx: TyCtxt<'_>) -> &'static SmallVec<[DefId; 4]> { Self::all_impls(tcx).get(self).expect("missing impl for primitive type") } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index edfe8c05c6db9..60b212c0243ec 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,21 @@ 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 +1242,6 @@ fn is_primitive(path_str: &str, ns: Namespace) -> Option<(&'static str, Res)> { } } -fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option { - 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)) } From 121974e37df723d86ea4fe94dacf5300b83c49ab Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 17 Aug 2020 19:36:29 -0400 Subject: [PATCH 15/18] xpy fmt --- src/librustdoc/clean/types.rs | 9 +++++---- src/librustdoc/passes/collect_intra_doc_links.rs | 7 ++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 344d5603d7637..3eac5bbda0078 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -3,11 +3,11 @@ 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; use std::{slice, vec}; -use std::lazy::SyncOnceCell as OnceCell; use rustc_ast::attr; use rustc_ast::util::comments::beautify_doc_string; @@ -27,7 +27,7 @@ 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 smallvec::{smallvec, SmallVec}; use crate::clean::cfg::Cfg; use crate::clean::external_path; @@ -1296,8 +1296,9 @@ impl PrimitiveType { } let single = |a: Option| a.into_iter().collect(); - let both = - |a: Option, b: Option| -> SmallVec<_> { a.into_iter().chain(b).collect() }; + let both = |a: Option, b: Option| -> SmallVec<_> { + a.into_iter().chain(b).collect() + }; let lang_items = tcx.lang_items(); map! { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 60b212c0243ec..97b9fcce05b36 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -275,7 +275,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let link = cx .tcx .associated_items(impl_) - .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, 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, From 570b0d9eceaa630b0fc2399ae9975aeaca777b9b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 17 Aug 2020 19:42:39 -0400 Subject: [PATCH 16/18] Add a test --- .../intra-link-primitive-non-default-impl.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/rustdoc/intra-link-primitive-non-default-impl.rs 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 0000000000000..427cd2124a926 --- /dev/null +++ b/src/test/rustdoc/intra-link-primitive-non-default-impl.rs @@ -0,0 +1,14 @@ +#![deny(broken_intra_doc_links)] + +// ignore-tidy-linelength + +// @has intra_link_primitive_non_default_impl/fn.f.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 f() {} From dad8e11e9fcbd76c0a2dc47211dcd654effed010 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Wed, 19 Aug 2020 16:26:17 +0200 Subject: [PATCH 17/18] Fix nits in intra-doc links for std io --- library/std/src/io/mod.rs | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index f1ee3c6986062..3245629483828 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -479,11 +479,11 @@ where /// } /// ``` /// -/// [`read()`]: Self::read +/// [`read()`]: Read::read /// [`&str`]: str /// [`std::io`]: self /// [`File`]: crate::fs::File -/// [slice]: crate::slice +/// [slice]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] #[doc(spotlight)] pub trait Read { @@ -633,7 +633,7 @@ pub trait Read { /// /// [`File`]s implement `Read`: /// - /// [`read()`]: Self::read + /// [`read()`]: Read::read /// [`Ok(0)`]: Ok /// [`File`]: crate::fs::File /// @@ -673,7 +673,7 @@ pub trait Read { /// /// See [`read_to_end`] for other error semantics. /// - /// [`read_to_end`]: Self::read_to_end + /// [`read_to_end`]: Read::read_to_end /// /// # Examples /// @@ -746,7 +746,7 @@ pub trait Read { /// /// [`File`]s implement `Read`: /// - /// [`read`]: Self::read + /// [`read`]: Read::read /// [`File`]: crate::fs::File /// /// ```no_run @@ -1209,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 @@ -1236,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 { @@ -1296,7 +1296,7 @@ pub trait Write { /// The default implementation calls [`write`] with either the first nonempty /// buffer provided, or an empty one if none exists. /// - /// [`write`]: Self::write + /// [`write`]: Write::write #[stable(feature = "iovec", since = "1.36.0")] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { default_write_vectored(|b| self.write(b), bufs) @@ -1311,7 +1311,7 @@ pub trait Write { /// /// The default implementation returns `false`. /// - /// [`write_vectored`]: Self::write_vectored + /// [`write_vectored`]: Write::write_vectored #[unstable(feature = "can_vector", issue = "69941")] fn is_write_vectored(&self) -> bool { false @@ -1359,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 /// @@ -1400,8 +1400,6 @@ pub trait Write { /// /// If the buffer contains no data, this will never call [`write_vectored`]. /// - /// [`write_vectored`]: Self::write_vectored - /// /// # Notes /// /// Unlike [`write_vectored`], this takes a *mutable* reference to @@ -1415,6 +1413,8 @@ pub trait Write { /// [`IoSlice`]s point (but not the [`IoSlice`]s themselves), are unchanged and /// can be reused. /// + /// [`write_vectored`]: Write::write_vectored + /// /// # Examples /// /// ``` @@ -1467,7 +1467,7 @@ pub trait Write { /// are received. This also means that partial writes are not indicated in /// this signature. /// - /// [`write_all`]: Self::write_all + /// [`write_all`]: Write::write_all /// /// # Errors /// @@ -1758,8 +1758,8 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) -> 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}; @@ -1789,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. /// @@ -1839,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); @@ -1863,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 /// @@ -1927,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 /// @@ -1980,7 +1980,7 @@ pub trait BufRead: Read { /// /// [`io::Result`]: self::Result /// [`Vec`]: Vec - /// [`read_until`]: Self::read_until + /// [`read_until`]: BufRead::read_until /// /// # Examples /// @@ -2011,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 /// From aff01f8de915d201b588a0dcff502f7adde7194d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 19 Aug 2020 10:35:56 -0400 Subject: [PATCH 18/18] Add test for f32 and f64 methods --- .../intra-link-primitive-non-default-impl.rs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/intra-link-primitive-non-default-impl.rs b/src/test/rustdoc/intra-link-primitive-non-default-impl.rs index 427cd2124a926..160b18a967b20 100644 --- a/src/test/rustdoc/intra-link-primitive-non-default-impl.rs +++ b/src/test/rustdoc/intra-link-primitive-non-default-impl.rs @@ -2,7 +2,7 @@ // ignore-tidy-linelength -// @has intra_link_primitive_non_default_impl/fn.f.html +// @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`] @@ -11,4 +11,22 @@ // @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 f() {} +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() {}