]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #75692 - JohnTitor:rollup-8gr04ah, r=JohnTitor
authorbors <bors@rust-lang.org>
Wed, 19 Aug 2020 06:59:13 +0000 (06:59 +0000)
committerbors <bors@rust-lang.org>
Wed, 19 Aug 2020 06:59:13 +0000 (06:59 +0000)
Rollup of 9 pull requests

Successful merges:

 - #75038 (See also X-Link mem::{swap, take, replace})
 - #75049 (docs(marker/copy): provide example for `&T` being `Copy`)
 - #75499 (Fix documentation error)
 - #75554 (Fix clashing_extern_declarations stack overflow for recursive types.)
 - #75646 (Move to intra doc links for keyword documentation)
 - #75652 (Resolve true and false as booleans)
 - #75658 (Don't emit "is not a logical operator" error outside of associative expressions)
 - #75665 (Add doc examples coverage)
 - #75685 (Switch to intra-doc links in /src/sys/unix/ext/*.rs)

Failed merges:

r? @ghost

32 files changed:
library/core/src/marker.rs
library/core/src/mem/mod.rs
library/core/src/str/mod.rs
library/std/src/keyword_docs.rs
library/std/src/sys/unix/ext/fs.rs
library/std/src/sys/unix/ext/net.rs
library/std/src/sys/unix/ext/process.rs
library/std/src/sys/unix/ext/thread.rs
src/librustc_lint/builtin.rs
src/librustc_parse/parser/expr.rs
src/librustdoc/html/render/cache.rs
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/doc_test_lints.rs
src/test/rustdoc-ui/coverage/basic.stdout
src/test/rustdoc-ui/coverage/doc-examples.rs [new file with mode: 0644]
src/test/rustdoc-ui/coverage/doc-examples.stdout [new file with mode: 0644]
src/test/rustdoc-ui/coverage/empty.stdout
src/test/rustdoc-ui/coverage/enums.stdout
src/test/rustdoc-ui/coverage/exotic.stdout
src/test/rustdoc-ui/coverage/json.stdout
src/test/rustdoc-ui/coverage/private.stdout
src/test/rustdoc-ui/coverage/statics-consts.stdout
src/test/rustdoc-ui/coverage/traits.stdout
src/test/rustdoc/intra-doc-link-true-false.rs [new file with mode: 0644]
src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs
src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr
src/test/ui/did_you_mean/issue-54109-without-witness.fixed
src/test/ui/did_you_mean/issue-54109-without-witness.rs
src/test/ui/did_you_mean/issue-54109-without-witness.stderr
src/test/ui/issues/issue-75599.rs [new file with mode: 0644]
src/test/ui/lint/clashing-extern-fn-recursion.rs [new file with mode: 0644]

index 56dddee7b7799f00fd01a608f11b20a74f4f22f9..9326aaf56847c577f59e2e86b299f9c67bf6082f 100644 (file)
@@ -291,6 +291,7 @@ pub trait StructuralEq {
 ///
 /// ```
 /// # #[allow(dead_code)]
+/// #[derive(Copy, Clone)]
 /// struct Point {
 ///    x: i32,
 ///    y: i32,
@@ -315,6 +316,20 @@ pub trait StructuralEq {
 /// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy`
 /// ```
 ///
+/// Shared references (`&T`) are also `Copy`, so a type can be `Copy`, even when it holds
+/// shared references of types `T` that are *not* `Copy`. Consider the following struct,
+/// which can implement `Copy`, because it only holds a *shared reference* to our non-`Copy`
+/// type `PointList` from above:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// # struct PointList;
+/// #[derive(Copy, Clone)]
+/// struct PointListWrapper<'a> {
+///     point_list_ref: &'a PointList,
+/// }
+/// ```
+///
 /// ## When *can't* my type be `Copy`?
 ///
 /// Some types can't be copied safely. For example, copying `&mut T` would create an aliased
index 4e58e118562ef92a082299d74dba4ad92b4b4101..9107c570a897097bf542773ae5c58c402a020805 100644 (file)
@@ -670,6 +670,9 @@ pub unsafe fn uninitialized<T>() -> T {
 
 /// Swaps the values at two mutable locations, without deinitializing either one.
 ///
+/// * If you want to swap with a default or dummy value, see [`take`].
+/// * If you want to swap with a passed value, returning the old value, see [`replace`].
+///
 /// # Examples
 ///
 /// ```
@@ -683,6 +686,9 @@ pub unsafe fn uninitialized<T>() -> T {
 /// assert_eq!(42, x);
 /// assert_eq!(5, y);
 /// ```
+///
+/// [`replace`]: fn.replace.html
+/// [`take`]: fn.take.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn swap<T>(x: &mut T, y: &mut T) {
@@ -695,6 +701,9 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
 
 /// Replaces `dest` with the default value of `T`, returning the previous `dest` value.
 ///
+/// * If you want to replace the values of two variables, see [`swap`].
+/// * If you want to replace with a passed value instead of the default value, see [`replace`].
+///
 /// # Examples
 ///
 /// A simple example:
@@ -747,6 +756,8 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
 /// ```
 ///
 /// [`Clone`]: ../../std/clone/trait.Clone.html
+/// [`replace`]: fn.replace.html
+/// [`swap`]: fn.swap.html
 #[inline]
 #[stable(feature = "mem_take", since = "1.40.0")]
 pub fn take<T: Default>(dest: &mut T) -> T {
@@ -757,6 +768,9 @@ pub fn take<T: Default>(dest: &mut T) -> T {
 ///
 /// Neither value is dropped.
 ///
+/// * If you want to replace the values of two variables, see [`swap`].
+/// * If you want to replace with a default value, see [`take`].
+///
 /// # Examples
 ///
 /// A simple example:
@@ -810,6 +824,8 @@ pub fn take<T: Default>(dest: &mut T) -> T {
 /// ```
 ///
 /// [`Clone`]: ../../std/clone/trait.Clone.html
+/// [`swap`]: fn.swap.html
+/// [`take`]: fn.take.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[must_use = "if you don't need the old value, you can just assign the new value directly"]
index 934f581f3faeb7575aa8f99726e22c69f51b50a2..4705c984bd426ffa2f6421cc19640eede2816b87 100644 (file)
@@ -2031,7 +2031,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
     /// # Panics
     ///
     /// Panics if `begin` does not point to the starting byte offset of
-    /// a character (as defined by `is_char_boundary`), or if `begin >= len`.
+    /// a character (as defined by `is_char_boundary`), or if `begin > len`.
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
         type Output = str;
index c39989a60c92b5c62d4615de8c46192064f45963..af25c39fccfd0264a488a96303368019458e88b3 100644 (file)
@@ -98,7 +98,6 @@ mod as_keyword {}
 /// [Reference on "break expression"]: ../reference/expressions/loop-expr.html#break-expressions
 /// [Reference on "break and loop values"]:
 /// ../reference/expressions/loop-expr.html#break-and-loop-values
-///
 mod break_keyword {}
 
 #[doc(keyword = "const")]
@@ -336,7 +335,6 @@ mod else_keyword {}
 /// For more information, take a look at the [Rust Book] or the [Reference]
 ///
 /// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type
-/// [`Option`]: option/enum.Option.html
 /// [Rust Book]: ../book/ch06-01-defining-an-enum.html
 /// [Reference]: ../reference/items/enumerations.html
 mod enum_keyword {}
@@ -534,7 +532,6 @@ mod fn_keyword {}
 /// [`in`]: keyword.in.html
 /// [`impl`]: keyword.impl.html
 /// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds
-/// [`IntoIterator`]: iter/trait.IntoIterator.html
 /// [Rust book]:
 /// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for
 /// [Reference]: ../reference/expressions/loop-expr.html#iterator-loops
@@ -993,7 +990,6 @@ mod mod_keyword {}
 /// For more information on the `move` keyword, see the [closure]'s section
 /// of the Rust book or the [threads] section
 ///
-/// [`Fn` trait]: ../std/ops/trait.Fn.html
 /// [closure]: ../book/ch13-01-closures.html
 /// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads
 mod move_keyword {}
@@ -1413,9 +1409,7 @@ mod self_upper_keyword {}
 /// [`extern`]: keyword.extern.html
 /// [`mut`]: keyword.mut.html
 /// [`unsafe`]: keyword.unsafe.html
-/// [`drop`]: mem/fn.drop.html
-/// [`Sync`]: marker/trait.Sync.html
-/// [`RefCell`]: cell/struct.RefCell.html
+/// [`RefCell`]: cell::RefCell
 /// [Reference]: ../reference/items/static-items.html
 mod static_keyword {}
 
@@ -1522,7 +1516,7 @@ mod static_keyword {}
 /// For more information on structs, take a look at the [Rust Book][book] or the
 /// [Reference][reference].
 ///
-/// [`PhantomData`]: marker/struct.PhantomData.html
+/// [`PhantomData`]: marker::PhantomData
 /// [book]: ../book/ch05-01-defining-structs.html
 /// [reference]: ../reference/items/structs.html
 mod struct_keyword {}
@@ -1733,8 +1727,6 @@ mod super_keyword {}
 /// [`for`]: keyword.for.html
 /// [`impl`]: keyword.impl.html
 /// [`unsafe`]: keyword.unsafe.html
-/// [`Send`]: marker/trait.Send.html
-/// [`Sync`]: marker/trait.Sync.html
 /// [Ref-Traits]: ../reference/items/traits.html
 /// [Ref-Trait-Objects]: ../reference/types/trait-object.html
 mod trait_keyword {}
@@ -1764,7 +1756,6 @@ mod trait_keyword {}
 /// [`while`]: keyword.while.html
 /// [`match`]: ../reference/expressions/match-expr.html#match-guards
 /// [`false`]: keyword.false.html
-/// [`bool`]: primitive.bool.html
 mod true_keyword {}
 
 #[doc(keyword = "type")]
@@ -1986,9 +1977,6 @@ mod type_keyword {}
 /// [`static`]: keyword.static.html
 /// [`union`]: keyword.union.html
 /// [`impl`]: keyword.impl.html
-/// [Send]: marker/trait.Send.html
-/// [Sync]: marker/trait.Sync.html
-/// [`Vec::set_len`]: vec/struct.Vec.html#method.set_len
 /// [raw pointers]: ../reference/types/pointer.html
 /// [memory safety]: ../book/ch19-01-unsafe-rust.html
 /// [Rustnomicon]: ../nomicon/index.html
@@ -2178,7 +2166,7 @@ mod where_keyword {}
 ///
 /// It is available for use in stable rust from version 1.39 onwards.
 ///
-/// [`Future`]: ./future/trait.Future.html
+/// [`Future`]: future::Future
 /// [async book]: https://rust-lang.github.io/async-book/
 mod async_keyword {}
 
@@ -2197,7 +2185,7 @@ mod async_keyword {}
 ///
 /// It is available for use in stable rust from version 1.39 onwards.
 ///
-/// [`Future`]: ./future/trait.Future.html
+/// [`Future`]: future::Future
 /// [async book]: https://rust-lang.github.io/async-book/
 mod await_keyword {}
 
index f174a59b49a6ba51b01a1bc50f720ee2a6e4dd37..b590a0280d1382e2888358c503cd01a76f2f95d8 100644 (file)
@@ -9,9 +9,7 @@
 use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
 
-/// Unix-specific extensions to [`File`].
-///
-/// [`File`]: ../../../../std/fs/struct.File.html
+/// Unix-specific extensions to [`fs::File`].
 #[stable(feature = "file_offset", since = "1.15.0")]
 pub trait FileExt {
     /// Reads a number of bytes starting from a given offset.
@@ -55,19 +53,18 @@ pub trait FileExt {
     ///
     /// The current file cursor is not affected by this function.
     ///
-    /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
+    /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
     ///
-    /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
-    /// [`read_at`]: #tymethod.read_at
+    /// [`read_at`]: FileExt::read_at
     ///
     /// # Errors
     ///
     /// If this function encounters an error of the kind
-    /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
     /// will continue.
     ///
     /// If this function encounters an "end of file" before completely filling
-    /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+    /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
     /// The contents of `buf` are unspecified in this case.
     ///
     /// If any other read error is encountered then this function immediately
@@ -77,9 +74,6 @@ pub trait FileExt {
     /// has read, but it will never read more than would be necessary to
     /// completely fill the buffer.
     ///
-    /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
-    /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -161,19 +155,18 @@ fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
     /// The current file cursor is not affected by this function.
     ///
     /// This method will continuously call [`write_at`] until there is no more data
-    /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+    /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
     /// returned. This method will not return until the entire buffer has been
     /// successfully written or such an error occurs. The first error that is
-    /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+    /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
     /// returned.
     ///
     /// # Errors
     ///
     /// This function will return the first error of
-    /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
+    /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
     ///
-    /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
-    /// [`write_at`]: #tymethod.write_at
+    /// [`write_at`]: FileExt::write_at
     ///
     /// # Examples
     ///
@@ -223,8 +216,6 @@ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
 }
 
 /// Unix-specific extensions to [`fs::Permissions`].
-///
-/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
 #[stable(feature = "fs_ext", since = "1.1.0")]
 pub trait PermissionsExt {
     /// Returns the underlying raw `st_mode` bits that contain the standard
@@ -302,8 +293,6 @@ fn from_mode(mode: u32) -> Permissions {
 }
 
 /// Unix-specific extensions to [`fs::OpenOptions`].
-///
-/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
 #[stable(feature = "fs_ext", since = "1.1.0")]
 pub trait OpenOptionsExt {
     /// Sets the mode bits that a new file will be created with.
@@ -372,8 +361,6 @@ fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
 }
 
 /// Unix-specific extensions to [`fs::Metadata`].
-///
-/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
 #[stable(feature = "metadata_ext", since = "1.1.0")]
 pub trait MetadataExt {
     /// Returns the ID of the device containing the file.
@@ -535,7 +522,7 @@ pub trait MetadataExt {
     fn atime(&self) -> i64;
     /// Returns the last access time of the file, in nanoseconds since [`atime`].
     ///
-    /// [`atime`]: #tymethod.atime
+    /// [`atime`]: MetadataExt::atime
     ///
     /// # Examples
     ///
@@ -571,7 +558,7 @@ pub trait MetadataExt {
     fn mtime(&self) -> i64;
     /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
     ///
-    /// [`mtime`]: #tymethod.mtime
+    /// [`mtime`]: MetadataExt::mtime
     ///
     /// # Examples
     ///
@@ -607,7 +594,7 @@ pub trait MetadataExt {
     fn ctime(&self) -> i64;
     /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
     ///
-    /// [`ctime`]: #tymethod.ctime
+    /// [`ctime`]: MetadataExt::ctime
     ///
     /// # Examples
     ///
@@ -714,12 +701,10 @@ fn blocks(&self) -> u64 {
     }
 }
 
-/// Unix-specific extensions for [`FileType`].
+/// Unix-specific extensions for [`fs::FileType`].
 ///
 /// Adds support for special Unix file types such as block/character devices,
 /// pipes, and sockets.
-///
-/// [`FileType`]: ../../../../std/fs/struct.FileType.html
 #[stable(feature = "file_type_ext", since = "1.5.0")]
 pub trait FileTypeExt {
     /// Returns `true` if this file type is a block device.
@@ -813,8 +798,6 @@ fn is_socket(&self) -> bool {
 }
 
 /// Unix-specific extension methods for [`fs::DirEntry`].
-///
-/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
 pub trait DirEntryExt {
     /// Returns the underlying `d_ino` field in the contained `dirent`
@@ -875,8 +858,6 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
 }
 
 /// Unix-specific extensions to [`fs::DirBuilder`].
-///
-/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
 #[stable(feature = "dir_builder", since = "1.6.0")]
 pub trait DirBuilderExt {
     /// Sets the mode to create new directories with. This option defaults to
index ada8eaa1c9745e61fe2810eb3d99575008574ecc..55803ddfc43232209238a246ac65cafd5eb5313f 100644 (file)
@@ -408,10 +408,7 @@ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
     /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
     /// method.
     ///
-    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
-    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
-    /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
-    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    /// [`read`]: io::Read::read
     ///
     /// # Examples
     ///
@@ -453,10 +450,7 @@ pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
     /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
     /// passed to this method.
     ///
-    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
-    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
-    /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
-    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    /// [`read`]: io::Read::read
     ///
     /// # Examples
     ///
@@ -581,8 +575,6 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
     /// specified portions to immediately return with an appropriate value
     /// (see the documentation of [`Shutdown`]).
     ///
-    /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -852,7 +844,7 @@ fn inner(path: &Path) -> io::Result<UnixListener> {
     /// is established. When established, the corresponding [`UnixStream`] and
     /// the remote peer's address will be returned.
     ///
-    /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
+    /// [`UnixStream`]: crate::os::unix::net::UnixStream
     ///
     /// # Examples
     ///
@@ -937,8 +929,6 @@ pub fn local_addr(&self) -> io::Result<SocketAddr> {
     ///     Ok(())
     /// }
     /// ```
-    ///
-    /// [`io::ErrorKind::WouldBlock`]: ../../../io/enum.ErrorKind.html#variant.WouldBlock
     #[stable(feature = "unix_socket", since = "1.10.0")]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         self.0.set_nonblocking(nonblocking)
@@ -973,9 +963,6 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
     /// The iterator will never return [`None`] and will also not yield the
     /// peer's [`SocketAddr`] structure.
     ///
-    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
-    /// [`SocketAddr`]: struct.SocketAddr.html
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -1043,9 +1030,6 @@ fn into_iter(self) -> Incoming<'a> {
 ///
 /// It will never return [`None`].
 ///
-/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
-/// [`UnixListener`]: struct.UnixListener.html
-///
 /// # Examples
 ///
 /// ```no_run
@@ -1205,9 +1189,9 @@ pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
     /// The [`send`] method may be used to send data to the specified address.
     /// [`recv`] and [`recv_from`] will only receive data from that address.
     ///
-    /// [`send`]: #method.send
-    /// [`recv`]: #method.recv
-    /// [`recv_from`]: #method.recv_from
+    /// [`send`]: UnixDatagram::send
+    /// [`recv`]: UnixDatagram::recv
+    /// [`recv_from`]: UnixDatagram::recv_from
     ///
     /// # Examples
     ///
@@ -1284,7 +1268,7 @@ pub fn local_addr(&self) -> io::Result<SocketAddr> {
     ///
     /// The [`connect`] method will connect the socket to a peer.
     ///
-    /// [`connect`]: #method.connect
+    /// [`connect`]: UnixDatagram::connect
     ///
     /// # Examples
     ///
@@ -1432,11 +1416,8 @@ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
     /// block indefinitely. An [`Err`] is returned if the zero [`Duration`]
     /// is passed to this method.
     ///
-    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
-    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
-    /// [`recv`]: #method.recv
-    /// [`recv_from`]: #method.recv_from
-    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    /// [`recv`]: UnixDatagram::recv
+    /// [`recv_from`]: UnixDatagram::recv_from
     ///
     /// # Examples
     ///
@@ -1479,10 +1460,8 @@ pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
     /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
     /// method.
     ///
-    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
-    /// [`send`]: #method.send
-    /// [`send_to`]: #method.send_to
-    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    /// [`send`]: UnixDatagram::send
+    /// [`send_to`]: UnixDatagram::send_to
     ///
     /// # Examples
     ///
@@ -1605,8 +1584,6 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
     /// specified portions to immediately return with an appropriate value
     /// (see the documentation of [`Shutdown`]).
     ///
-    /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
-    ///
     /// ```no_run
     /// use std::os::unix::net::UnixDatagram;
     /// use std::net::Shutdown;
index 048ce24d6ba889a8559297b84054c3526dc5aab4..82527c40e91382f8c6a7c2add76801fd1c46a20c 100644 (file)
@@ -10,8 +10,6 @@
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
 /// Unix-specific extensions to the [`process::Command`] builder.
-///
-/// [`process::Command`]: ../../../../std/process/struct.Command.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait CommandExt {
     /// Sets the child process's user ID. This translates to a
@@ -65,7 +63,7 @@ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
     /// This method is stable and usable, but it should be unsafe. To fix
     /// that, it got deprecated in favor of the unsafe [`pre_exec`].
     ///
-    /// [`pre_exec`]: #tymethod.pre_exec
+    /// [`pre_exec`]: CommandExt::pre_exec
     #[stable(feature = "process_exec", since = "1.15.0")]
     #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
     fn before_exec<F>(&mut self, f: F) -> &mut process::Command
@@ -94,8 +92,6 @@ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
     /// a new child. Like spawn, however, the default behavior for the stdio
     /// descriptors will be to inherited from the current process.
     ///
-    /// [`process::exit`]: ../../../process/fn.exit.html
-    ///
     /// # Notes
     ///
     /// The process may be in a "broken state" if this function returns in
@@ -151,8 +147,6 @@ fn arg0<S>(&mut self, arg: S) -> &mut process::Command
 }
 
 /// Unix-specific extensions to [`process::ExitStatus`].
-///
-/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ExitStatusExt {
     /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
index 759ef6236e80459f272ca07f71aa33fa1ba0527a..7221da1a9a7bbc998b891b43bb8d7fbe82ed37f0 100644 (file)
@@ -11,9 +11,7 @@
 #[allow(deprecated)]
 pub type RawPthread = pthread_t;
 
-/// Unix-specific extensions to [`thread::JoinHandle`].
-///
-/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
+/// Unix-specific extensions to [`JoinHandle`].
 #[stable(feature = "thread_extensions", since = "1.9.0")]
 pub trait JoinHandleExt {
     /// Extracts the raw pthread_t without taking ownership
index 36eb272cdfc8dcaa9534316c682a052a620105db..b337bf0a3f9226f7fecb3ccdfc4375a4791fd1b3 100644 (file)
@@ -29,6 +29,7 @@
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust::{self, expr_to_string};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
 use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
 use rustc_feature::{GateIssue, Stability};
@@ -2153,44 +2154,58 @@ fn structurally_same_type<'tcx>(
         b: Ty<'tcx>,
         ckind: CItemKind,
     ) -> bool {
-        debug!("structurally_same_type(cx, a = {:?}, b = {:?})", a, b);
-        let tcx = cx.tcx;
-        if a == b || rustc_middle::ty::TyS::same_type(a, b) {
-            // All nominally-same types are structurally same, too.
-            true
-        } else {
-            // Do a full, depth-first comparison between the two.
-            use rustc_middle::ty::TyKind::*;
-            let a_kind = &a.kind;
-            let b_kind = &b.kind;
-
-            let compare_layouts = |a, b| -> bool {
-                let a_layout = &cx.layout_of(a).unwrap().layout.abi;
-                let b_layout = &cx.layout_of(b).unwrap().layout.abi;
-                debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout);
-                a_layout == b_layout
-            };
+        fn structurally_same_type_impl<'tcx>(
+            seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
+            cx: &LateContext<'tcx>,
+            a: Ty<'tcx>,
+            b: Ty<'tcx>,
+            ckind: CItemKind,
+        ) -> bool {
+            debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
+            if !seen_types.insert((a, b)) {
+                // We've encountered a cycle. There's no point going any further -- the types are
+                // structurally the same.
+                return true;
+            }
+            let tcx = cx.tcx;
+            if a == b || rustc_middle::ty::TyS::same_type(a, b) {
+                // All nominally-same types are structurally same, too.
+                true
+            } else {
+                // Do a full, depth-first comparison between the two.
+                use rustc_middle::ty::TyKind::*;
+                let a_kind = &a.kind;
+                let b_kind = &b.kind;
+
+                let compare_layouts = |a, b| -> bool {
+                    let a_layout = &cx.layout_of(a).unwrap().layout.abi;
+                    let b_layout = &cx.layout_of(b).unwrap().layout.abi;
+                    debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout);
+                    a_layout == b_layout
+                };
+
+                #[allow(rustc::usage_of_ty_tykind)]
+                let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| {
+                    kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..))
+                };
 
-            #[allow(rustc::usage_of_ty_tykind)]
-            let is_primitive_or_pointer =
-                |kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..));
-
-            match (a_kind, b_kind) {
-                (Adt(_, a_substs), Adt(_, b_substs)) => {
-                    let a = a.subst(cx.tcx, a_substs);
-                    let b = b.subst(cx.tcx, b_substs);
-                    debug!("Comparing {:?} and {:?}", a, b);
-
-                    if let (Adt(a_def, ..), Adt(b_def, ..)) = (&a.kind, &b.kind) {
-                        // Grab a flattened representation of all fields.
-                        let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
-                        let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
-                        compare_layouts(a, b)
+                ensure_sufficient_stack(|| {
+                    match (a_kind, b_kind) {
+                        (Adt(a_def, a_substs), Adt(b_def, b_substs)) => {
+                            let a = a.subst(cx.tcx, a_substs);
+                            let b = b.subst(cx.tcx, b_substs);
+                            debug!("Comparing {:?} and {:?}", a, b);
+
+                            // Grab a flattened representation of all fields.
+                            let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
+                            let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
+                            compare_layouts(a, b)
                             && a_fields.eq_by(
                                 b_fields,
                                 |&ty::FieldDef { did: a_did, .. },
                                  &ty::FieldDef { did: b_did, .. }| {
-                                    Self::structurally_same_type(
+                                    structurally_same_type_impl(
+                                        seen_types,
                                         cx,
                                         tcx.type_of(a_did),
                                         tcx.type_of(b_did),
@@ -2198,78 +2213,93 @@ fn structurally_same_type<'tcx>(
                                     )
                                 },
                             )
-                    } else {
-                        unreachable!()
-                    }
-                }
-                (Array(a_ty, a_const), Array(b_ty, b_const)) => {
-                    // For arrays, we also check the constness of the type.
-                    a_const.val == b_const.val
-                        && Self::structurally_same_type(cx, a_const.ty, b_const.ty, ckind)
-                        && Self::structurally_same_type(cx, a_ty, b_ty, ckind)
-                }
-                (Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty, ckind),
-                (RawPtr(a_tymut), RawPtr(b_tymut)) => {
-                    a_tymut.mutbl == b_tymut.mutbl
-                        && Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty, ckind)
-                }
-                (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
-                    // For structural sameness, we don't need the region to be same.
-                    a_mut == b_mut && Self::structurally_same_type(cx, a_ty, b_ty, ckind)
-                }
-                (FnDef(..), FnDef(..)) => {
-                    let a_poly_sig = a.fn_sig(tcx);
-                    let b_poly_sig = b.fn_sig(tcx);
-
-                    // As we don't compare regions, skip_binder is fine.
-                    let a_sig = a_poly_sig.skip_binder();
-                    let b_sig = b_poly_sig.skip_binder();
-
-                    (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
-                        == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
-                        && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
-                            Self::structurally_same_type(cx, a, b, ckind)
-                        })
-                        && Self::structurally_same_type(cx, a_sig.output(), b_sig.output(), ckind)
-                }
-                (Tuple(a_substs), Tuple(b_substs)) => {
-                    a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
-                        Self::structurally_same_type(cx, a_ty, b_ty, ckind)
-                    })
-                }
-                // For these, it's not quite as easy to define structural-sameness quite so easily.
-                // For the purposes of this lint, take the conservative approach and mark them as
-                // not structurally same.
-                (Dynamic(..), Dynamic(..))
-                | (Error(..), Error(..))
-                | (Closure(..), Closure(..))
-                | (Generator(..), Generator(..))
-                | (GeneratorWitness(..), GeneratorWitness(..))
-                | (Projection(..), Projection(..))
-                | (Opaque(..), Opaque(..)) => false,
-
-                // These definitely should have been caught above.
-                (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
-
-                // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a
-                // non-null field.
-                (Adt(..), other_kind) | (other_kind, Adt(..))
-                    if is_primitive_or_pointer(other_kind) =>
-                {
-                    let (primitive, adt) =
-                        if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) };
-                    if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
-                        ty == primitive
-                    } else {
-                        compare_layouts(a, b)
+                        }
+                        (Array(a_ty, a_const), Array(b_ty, b_const)) => {
+                            // For arrays, we also check the constness of the type.
+                            a_const.val == b_const.val
+                                && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+                        }
+                        (Slice(a_ty), Slice(b_ty)) => {
+                            structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+                        }
+                        (RawPtr(a_tymut), RawPtr(b_tymut)) => {
+                            a_tymut.mutbl == b_tymut.mutbl
+                                && structurally_same_type_impl(
+                                    seen_types,
+                                    cx,
+                                    &a_tymut.ty,
+                                    &b_tymut.ty,
+                                    ckind,
+                                )
+                        }
+                        (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
+                            // For structural sameness, we don't need the region to be same.
+                            a_mut == b_mut
+                                && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+                        }
+                        (FnDef(..), FnDef(..)) => {
+                            let a_poly_sig = a.fn_sig(tcx);
+                            let b_poly_sig = b.fn_sig(tcx);
+
+                            // As we don't compare regions, skip_binder is fine.
+                            let a_sig = a_poly_sig.skip_binder();
+                            let b_sig = b_poly_sig.skip_binder();
+
+                            (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
+                                == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
+                                && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
+                                    structurally_same_type_impl(seen_types, cx, a, b, ckind)
+                                })
+                                && structurally_same_type_impl(
+                                    seen_types,
+                                    cx,
+                                    a_sig.output(),
+                                    b_sig.output(),
+                                    ckind,
+                                )
+                        }
+                        (Tuple(a_substs), Tuple(b_substs)) => {
+                            a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
+                                structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+                            })
+                        }
+                        // For these, it's not quite as easy to define structural-sameness quite so easily.
+                        // For the purposes of this lint, take the conservative approach and mark them as
+                        // not structurally same.
+                        (Dynamic(..), Dynamic(..))
+                        | (Error(..), Error(..))
+                        | (Closure(..), Closure(..))
+                        | (Generator(..), Generator(..))
+                        | (GeneratorWitness(..), GeneratorWitness(..))
+                        | (Projection(..), Projection(..))
+                        | (Opaque(..), Opaque(..)) => false,
+
+                        // These definitely should have been caught above.
+                        (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
+
+                        // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
+                        // enum layout optimisation is being applied.
+                        (Adt(..), other_kind) | (other_kind, Adt(..))
+                            if is_primitive_or_pointer(other_kind) =>
+                        {
+                            let (primitive, adt) =
+                                if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) };
+                            if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
+                                ty == primitive
+                            } else {
+                                compare_layouts(a, b)
+                            }
+                        }
+                        // Otherwise, just compare the layouts. This may fail to lint for some
+                        // incompatible types, but at the very least, will stop reads into
+                        // uninitialised memory.
+                        _ => compare_layouts(a, b),
                     }
-                }
-                // Otherwise, just compare the layouts. This may fail to lint for some
-                // incompatible types, but at the very least, will stop reads into
-                // uninitialised memory.
-                _ => compare_layouts(a, b),
+                })
             }
         }
+        let mut seen_types = FxHashSet::default();
+        structurally_same_type_impl(&mut seen_types, cx, a, b, ckind)
     }
 }
 
index e5c28f225c611f3f5a15559076207e63bf546865..62aec66a255d5f2d5973983e6b5b7de6370b99f7 100644 (file)
@@ -308,7 +308,7 @@ pub(super) fn parse_assoc_expr_with(
     }
 
     fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
-        match (self.expr_is_complete(lhs), self.check_assoc_op().map(|op| op.node)) {
+        match (self.expr_is_complete(lhs), AssocOp::from_token(&self.token)) {
             // Semi-statement forms are odd:
             // See https://github.com/rust-lang/rust/issues/29071
             (true, None) => false,
index 5a9e9dda6771ecb7854a6346768bb3c841f0f6b0..ccc07645620a9c8ffe536a071e3c3958e48a2140 100644 (file)
@@ -200,10 +200,12 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
     match *clean_type {
         clean::ResolvedPath { ref path, .. } => {
             let segments = &path.segments;
-            let path_segment = segments.iter().last().unwrap_or_else(|| panic!(
+            let path_segment = segments.iter().last().unwrap_or_else(|| {
+                panic!(
                 "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path",
                 clean_type, accept_generic
-            ));
+            )
+            });
             Some(path_segment.name.clone())
         }
         clean::Generic(ref s) if accept_generic => Some(s.clone()),
index b722cfc8f7521f9bb3d46912cba0b8f145a40e15..0a836f46c0eb85bc96bc861e94f3af109e58eb1c 100644 (file)
@@ -2,8 +2,9 @@
 use crate::config::OutputFormat;
 use crate::core::DocContext;
 use crate::fold::{self, DocFolder};
+use crate::html::markdown::{find_testable_code, ErrorCodes};
+use crate::passes::doc_test_lints::Tests;
 use crate::passes::Pass;
-
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use serde::Serialize;
@@ -30,15 +31,19 @@ fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::C
 struct ItemCount {
     total: u64,
     with_docs: u64,
+    with_examples: u64,
 }
 
 impl ItemCount {
-    fn count_item(&mut self, has_docs: bool) {
+    fn count_item(&mut self, has_docs: bool, has_doc_example: bool) {
         self.total += 1;
 
         if has_docs {
             self.with_docs += 1;
         }
+        if has_doc_example {
+            self.with_examples += 1;
+        }
     }
 
     fn percentage(&self) -> Option<f64> {
@@ -48,13 +53,25 @@ fn percentage(&self) -> Option<f64> {
             None
         }
     }
+
+    fn examples_percentage(&self) -> Option<f64> {
+        if self.total > 0 {
+            Some((self.with_examples as f64 * 100.0) / self.total as f64)
+        } else {
+            None
+        }
+    }
 }
 
 impl ops::Sub for ItemCount {
     type Output = Self;
 
     fn sub(self, rhs: Self) -> Self {
-        ItemCount { total: self.total - rhs.total, with_docs: self.with_docs - rhs.with_docs }
+        ItemCount {
+            total: self.total - rhs.total,
+            with_docs: self.with_docs - rhs.with_docs,
+            with_examples: self.with_examples - rhs.with_examples,
+        }
     }
 }
 
@@ -62,6 +79,7 @@ impl ops::AddAssign for ItemCount {
     fn add_assign(&mut self, rhs: Self) {
         self.total += rhs.total;
         self.with_docs += rhs.with_docs;
+        self.with_examples += rhs.with_examples;
     }
 }
 
@@ -103,33 +121,55 @@ fn print_results(&self, output_format: Option<OutputFormat>) {
         let mut total = ItemCount::default();
 
         fn print_table_line() {
-            println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", "");
+            println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", "");
         }
 
-        fn print_table_record(name: &str, count: ItemCount, percentage: f64) {
+        fn print_table_record(
+            name: &str,
+            count: ItemCount,
+            percentage: f64,
+            examples_percentage: f64,
+        ) {
             println!(
-                "| {:<35} | {:>10} | {:>10} | {:>9.1}% |",
-                name, count.with_docs, count.total, percentage
+                "| {:<35} | {:>10} | {:>10} | {:>9.1}% | {:>10} | {:>9.1}% |",
+                name,
+                count.with_docs,
+                count.total,
+                percentage,
+                count.with_examples,
+                examples_percentage,
             );
         }
 
         print_table_line();
         println!(
-            "| {:<35} | {:>10} | {:>10} | {:>10} |",
-            "File", "Documented", "Total", "Percentage"
+            "| {:<35} | {:>10} | {:>10} | {:>10} | {:>10} | {:>10} |",
+            "File", "Documented", "Total", "Percentage", "Examples", "Percentage",
         );
         print_table_line();
 
         for (file, &count) in &self.items {
-            if let Some(percentage) = count.percentage() {
-                print_table_record(&limit_filename_len(file.to_string()), count, percentage);
+            if let (Some(percentage), Some(examples_percentage)) =
+                (count.percentage(), count.examples_percentage())
+            {
+                print_table_record(
+                    &limit_filename_len(file.to_string()),
+                    count,
+                    percentage,
+                    examples_percentage,
+                );
 
                 total += count;
             }
         }
 
         print_table_line();
-        print_table_record("Total", total, total.percentage().unwrap_or(0.0));
+        print_table_record(
+            "Total",
+            total,
+            total.percentage().unwrap_or(0.0),
+            total.examples_percentage().unwrap_or(0.0),
+        );
         print_table_line();
     }
 }
@@ -137,6 +177,17 @@ fn print_table_record(name: &str, count: ItemCount, percentage: f64) {
 impl fold::DocFolder for CoverageCalculator {
     fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
         let has_docs = !i.attrs.doc_strings.is_empty();
+        let mut tests = Tests { found_tests: 0 };
+
+        find_testable_code(
+            &i.attrs.doc_strings.iter().map(|d| d.as_str()).collect::<Vec<_>>().join("\n"),
+            &mut tests,
+            ErrorCodes::No,
+            false,
+            None,
+        );
+
+        let has_doc_example = tests.found_tests != 0;
 
         match i.inner {
             _ if !i.def_id.is_local() => {
@@ -187,7 +238,10 @@ fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
             }
             _ => {
                 debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename);
-                self.items.entry(i.source.filename.clone()).or_default().count_item(has_docs);
+                self.items
+                    .entry(i.source.filename.clone())
+                    .or_default()
+                    .count_item(has_docs, has_doc_example);
             }
         }
 
index d4d6a8119c316d7055fb83b8d4358de5b210d852..edfe8c05c6db987b796ec4a86c077f067c4e23cf 100644 (file)
@@ -222,11 +222,11 @@ fn resolve(
                             disambiguator,
                             None | Some(Disambiguator::Namespace(Namespace::TypeNS))
                         ) {
-                            if let Some(prim) = is_primitive(path_str, ns) {
+                            if let Some((path, prim)) = is_primitive(path_str, ns) {
                                 if extra_fragment.is_some() {
                                     return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
                                 }
-                                return Ok((prim, Some(path_str.to_owned())));
+                                return Ok((prim, Some(path.to_owned())));
                             }
                         }
                         return Ok((res, extra_fragment.clone()));
@@ -239,11 +239,11 @@ fn resolve(
                 if value != (ns == ValueNS) {
                     return Err(ErrorKind::ResolutionFailure);
                 }
-            } else if let Some(prim) = is_primitive(path_str, ns) {
+            } else if let Some((path, prim)) = is_primitive(path_str, ns) {
                 if extra_fragment.is_some() {
                     return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
                 }
-                return Ok((prim, Some(path_str.to_owned())));
+                return Ok((prim, Some(path.to_owned())));
             } else {
                 // If resolution failed, it may still be a method
                 // because methods are not handled by the resolver
@@ -269,7 +269,7 @@ fn resolve(
                 })
                 .ok_or(ErrorKind::ResolutionFailure)?;
 
-            if let Some(prim) = is_primitive(&path, TypeNS) {
+            if let Some((path, prim)) = is_primitive(&path, TypeNS) {
                 let did = primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)?;
                 return cx
                     .tcx
@@ -1220,11 +1220,22 @@ fn handle_variant(
     ("f64", Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))),
     ("str", Res::PrimTy(hir::PrimTy::Str)),
     ("bool", Res::PrimTy(hir::PrimTy::Bool)),
+    ("true", Res::PrimTy(hir::PrimTy::Bool)),
+    ("false", Res::PrimTy(hir::PrimTy::Bool)),
     ("char", Res::PrimTy(hir::PrimTy::Char)),
 ];
 
-fn is_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
-    if ns == TypeNS { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) } else { None }
+fn is_primitive(path_str: &str, ns: Namespace) -> Option<(&'static str, Res)> {
+    if ns == TypeNS {
+        PRIMITIVES
+            .iter()
+            .filter(|x| x.0 == path_str)
+            .copied()
+            .map(|x| if x.0 == "true" || x.0 == "false" { ("bool", x.1) } else { x })
+            .next()
+    } else {
+        None
+    }
 }
 
 fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<DefId> {
index aced7d55281adccb6db96f0883bbcf6d535d3ac1..1fdc4ee247adfc6a34b39c0f14051d59b9fae37d 100644 (file)
@@ -43,6 +43,22 @@ fn fold_item(&mut self, item: Item) -> Option<Item> {
     }
 }
 
+pub(crate) struct Tests {
+    pub(crate) found_tests: usize,
+}
+
+impl Tests {
+    pub(crate) fn new() -> Tests {
+        Tests { found_tests: 0 }
+    }
+}
+
+impl crate::test::Tester for Tests {
+    fn add_test(&mut self, _: String, _: LangString, _: usize) {
+        self.found_tests += 1;
+    }
+}
+
 pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
     let hir_id = match cx.as_local_hir_id(item.def_id) {
         Some(hir_id) => hir_id,
@@ -52,17 +68,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
         }
     };
 
-    struct Tests {
-        found_tests: usize,
-    }
-
-    impl crate::test::Tester for Tests {
-        fn add_test(&mut self, _: String, _: LangString, _: usize) {
-            self.found_tests += 1;
-        }
-    }
-
-    let mut tests = Tests { found_tests: 0 };
+    let mut tests = Tests::new();
 
     find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
 
index 3e916606316260bcb727f53bf3cb7b98a957d6ce..7e795acc575bccd51debfbea00fdd055b534cf23 100644 (file)
@@ -1,7 +1,7 @@
-+-------------------------------------+------------+------------+------------+
-| File                                | Documented |      Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...est/rustdoc-ui/coverage/basic.rs |          7 |         14 |      50.0% |
-+-------------------------------------+------------+------------+------------+
-| Total                               |          7 |         14 |      50.0% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File                                | Documented |      Total | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...est/rustdoc-ui/coverage/basic.rs |          7 |         14 |      50.0% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total                               |          7 |         14 |      50.0% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/coverage/doc-examples.rs b/src/test/rustdoc-ui/coverage/doc-examples.rs
new file mode 100644 (file)
index 0000000..cd718f8
--- /dev/null
@@ -0,0 +1,27 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+//! This test ensure that only rust code examples are counted.
+
+/// Doc
+///
+/// ```
+/// let x = 2;
+/// ```
+pub struct Foo;
+
+/// Doc
+///
+/// ```text
+/// yolo
+/// ```
+pub trait Bar {}
+
+/// Doc
+///
+/// ```ignore (just for the sake of this test)
+/// let x = 2;
+/// ```
+pub fn foo<T: Bar, D: ::std::fmt::Debug>(a: Foo, b: u32, c: T, d: D) -> u32 {
+    0
+}
diff --git a/src/test/rustdoc-ui/coverage/doc-examples.stdout b/src/test/rustdoc-ui/coverage/doc-examples.stdout
new file mode 100644 (file)
index 0000000..f25cf79
--- /dev/null
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+------------+
+| File                                | Documented |      Total | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...tdoc-ui/coverage/doc-examples.rs |          4 |          4 |     100.0% |          2 |      50.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total                               |          4 |          4 |     100.0% |          2 |      50.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
index 11b514fbfeaef524c8df4601a81f5b765b1238db..2a6a2231e5b5727e009ce2751fcee1431298d250 100644 (file)
@@ -1,7 +1,7 @@
-+-------------------------------------+------------+------------+------------+
-| File                                | Documented |      Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...est/rustdoc-ui/coverage/empty.rs |          0 |          1 |       0.0% |
-+-------------------------------------+------------+------------+------------+
-| Total                               |          0 |          1 |       0.0% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File                                | Documented |      Total | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...est/rustdoc-ui/coverage/empty.rs |          0 |          1 |       0.0% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total                               |          0 |          1 |       0.0% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
index 87e2ad9f20df68ed54b97aeecb32cbe19acfadce..dd86f61f8d5014f31b286581d0cc76cc4f1c508b 100644 (file)
@@ -1,7 +1,7 @@
-+-------------------------------------+------------+------------+------------+
-| File                                | Documented |      Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...est/rustdoc-ui/coverage/enums.rs |          6 |          8 |      75.0% |
-+-------------------------------------+------------+------------+------------+
-| Total                               |          6 |          8 |      75.0% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File                                | Documented |      Total | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...est/rustdoc-ui/coverage/enums.rs |          6 |          8 |      75.0% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total                               |          6 |          8 |      75.0% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
index 2bacfcfcecabe497df43805f3fc59e44dabcb39f..f920a3abd36bb6dbcee91e32d4a98856bac68480 100644 (file)
@@ -1,8 +1,8 @@
-+-------------------------------------+------------+------------+------------+
-| File                                | Documented |      Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...st/rustdoc-ui/coverage/exotic.rs |          1 |          1 |     100.0% |
-| <anon>                              |          2 |          2 |     100.0% |
-+-------------------------------------+------------+------------+------------+
-| Total                               |          3 |          3 |     100.0% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File                                | Documented |      Total | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...st/rustdoc-ui/coverage/exotic.rs |          1 |          1 |     100.0% |          0 |       0.0% |
+| <anon>                              |          2 |          2 |     100.0% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total                               |          3 |          3 |     100.0% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
index 63b22a7d94b00f5073577418ceb03fe85b51a8b6..7b5b083e1584c01a1e6fde7688feec686921acb7 100644 (file)
@@ -1 +1 @@
-{"$DIR/json.rs":{"total":13,"with_docs":7}}
+{"$DIR/json.rs":{"total":13,"with_docs":7,"with_examples":0}}
index 0d4c7c68fd05e0b8eb93702a70fc04324e855c05..bca3d51da59d066bc3eff24336d57c2fc405fbe9 100644 (file)
@@ -1,7 +1,7 @@
-+-------------------------------------+------------+------------+------------+
-| File                                | Documented |      Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...t/rustdoc-ui/coverage/private.rs |          4 |          7 |      57.1% |
-+-------------------------------------+------------+------------+------------+
-| Total                               |          4 |          7 |      57.1% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File                                | Documented |      Total | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...t/rustdoc-ui/coverage/private.rs |          4 |          7 |      57.1% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total                               |          4 |          7 |      57.1% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
index 8459f90ae7b31674cda8c58603f4b2bd4aa58b8b..31b48cc602a76246763bf371fa0ac6935abeaf5a 100644 (file)
@@ -1,7 +1,7 @@
-+-------------------------------------+------------+------------+------------+
-| File                                | Documented |      Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...oc-ui/coverage/statics-consts.rs |          6 |          7 |      85.7% |
-+-------------------------------------+------------+------------+------------+
-| Total                               |          6 |          7 |      85.7% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File                                | Documented |      Total | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...oc-ui/coverage/statics-consts.rs |          6 |          7 |      85.7% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total                               |          6 |          7 |      85.7% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
index e347a4da0b97829bad77162765ad7e08952f61e1..ac63b65023d0b302449627c4a4699ddf71374d6a 100644 (file)
@@ -1,7 +1,7 @@
-+-------------------------------------+------------+------------+------------+
-| File                                | Documented |      Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...st/rustdoc-ui/coverage/traits.rs |          6 |          7 |      85.7% |
-+-------------------------------------+------------+------------+------------+
-| Total                               |          6 |          7 |      85.7% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File                                | Documented |      Total | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...st/rustdoc-ui/coverage/traits.rs |          6 |          7 |      85.7% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total                               |          6 |          7 |      85.7% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc/intra-doc-link-true-false.rs b/src/test/rustdoc/intra-doc-link-true-false.rs
new file mode 100644 (file)
index 0000000..7b21e93
--- /dev/null
@@ -0,0 +1,10 @@
+#![deny(broken_intra_doc_links)]
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+// @has foo/index.html
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'false'
+
+//! A `bool` is either [`true`] or [`false`].
index 467daef63f6a660b015b84006e342902e2e07e38..44421b077fa26eb2c0e75f664c07be4d45cbd76f 100644 (file)
@@ -5,10 +5,8 @@ fn test_and() {
     let b = false;
 
     let _ = a and b; //~ ERROR `and` is not a logical operator
-                     //~| ERROR `and` is not a logical operator
 
     if a and b { //~ ERROR `and` is not a logical operator
-                 //~| ERROR `and` is not a logical operator
         println!("both");
     }
 
@@ -20,10 +18,8 @@ fn test_or() {
     let b = false;
 
     let _ = a or b; //~ ERROR `or` is not a logical operator
-                    //~| ERROR `or` is not a logical operator
 
     if a or b { //~ ERROR `or` is not a logical operator
-                //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
@@ -32,7 +28,6 @@ fn test_and_par() {
     let a = true;
     let b = false;
     if (a and b) {  //~ ERROR `and` is not a logical operator
-                    //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -41,7 +36,6 @@ fn test_or_par() {
     let a = true;
     let b = false;
     if (a or b) {  //~ ERROR `or` is not a logical operator
-                   //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
@@ -50,7 +44,6 @@ fn test_while_and() {
     let a = true;
     let b = false;
     while a and b {  //~ ERROR `and` is not a logical operator
-                     //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -59,7 +52,6 @@ fn test_while_or() {
     let a = true;
     let b = false;
     while a or b { //~ ERROR `or` is not a logical operator
-                   //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
index e8731cf238ec40b56bd74a0328d39d7b87e986cc..528c62f501e0d1bf65bcad255050b235f1255559 100644 (file)
@@ -7,23 +7,7 @@ LL |     let _ = a and b;
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:7:15
-   |
-LL |     let _ = a and b;
-   |               ^^^ help: use `&&` to perform logical conjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:10:10
-   |
-LL |     if a and b {
-   |          ^^^ help: use `&&` to perform logical conjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:10:10
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:9:10
    |
 LL |     if a and b {
    |          ^^^ help: use `&&` to perform logical conjunction
@@ -31,7 +15,7 @@ LL |     if a and b {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:15
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:20:15
    |
 LL |     let _ = a or b;
    |               ^^ help: use `||` to perform logical disjunction
@@ -39,23 +23,7 @@ LL |     let _ = a or b;
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:15
-   |
-LL |     let _ = a or b;
-   |               ^^ help: use `||` to perform logical disjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:25:10
-   |
-LL |     if a or b {
-   |          ^^ help: use `||` to perform logical disjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:25:10
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:10
    |
 LL |     if a or b {
    |          ^^ help: use `||` to perform logical disjunction
@@ -63,31 +31,15 @@ LL |     if a or b {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:34:11
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:30:11
    |
 LL |     if (a and b) {
    |           ^^^ help: use `&&` to perform logical conjunction
    |
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
-error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:34:11
-   |
-LL |     if (a and b) {
-   |           ^^^ help: use `&&` to perform logical conjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:43:11
-   |
-LL |     if (a or b) {
-   |           ^^ help: use `||` to perform logical disjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:43:11
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:38:11
    |
 LL |     if (a or b) {
    |           ^^ help: use `||` to perform logical disjunction
@@ -95,31 +47,15 @@ LL |     if (a or b) {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:52:13
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:46:13
    |
 LL |     while a and b {
    |             ^^^ help: use `&&` to perform logical conjunction
    |
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
-error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:52:13
-   |
-LL |     while a and b {
-   |             ^^^ help: use `&&` to perform logical conjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:61:13
-   |
-LL |     while a or b {
-   |             ^^ help: use `||` to perform logical disjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:61:13
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:54:13
    |
 LL |     while a or b {
    |             ^^ help: use `||` to perform logical disjunction
@@ -127,13 +63,13 @@ LL |     while a or b {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:15:33
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:13:33
    |
 LL |     let _recovery_witness: () = 0;
    |                            --   ^ expected `()`, found integer
    |                            |
    |                            expected due to this
 
-error: aborting due to 17 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index 21471d75c821550449a18c25d83336fb6091e324..5079a37f4da7f9821ec4d390ece765a06ea69d45 100644 (file)
@@ -11,10 +11,8 @@ fn test_and() {
     let b = false;
 
     let _ = a && b; //~ ERROR `and` is not a logical operator
-                     //~| ERROR `and` is not a logical operator
 
     if a && b { //~ ERROR `and` is not a logical operator
-                 //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -24,10 +22,8 @@ fn test_or() {
     let b = false;
 
     let _ = a || b; //~ ERROR `or` is not a logical operator
-                    //~| ERROR `or` is not a logical operator
 
     if a || b { //~ ERROR `or` is not a logical operator
-                //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
@@ -36,7 +32,6 @@ fn test_and_par() {
     let a = true;
     let b = false;
     if (a && b) {  //~ ERROR `and` is not a logical operator
-                    //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -45,7 +40,6 @@ fn test_or_par() {
     let a = true;
     let b = false;
     if (a || b) {  //~ ERROR `or` is not a logical operator
-                   //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
@@ -54,7 +48,6 @@ fn test_while_and() {
     let a = true;
     let b = false;
     while a && b {  //~ ERROR `and` is not a logical operator
-                     //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -63,7 +56,6 @@ fn test_while_or() {
     let a = true;
     let b = false;
     while a || b { //~ ERROR `or` is not a logical operator
-                   //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
index bb9a3a195962e58a91b3da4111e9d47ed8e68cd0..00660a938d5d625b6e7be016d3f5d6c359698532 100644 (file)
@@ -11,10 +11,8 @@ fn test_and() {
     let b = false;
 
     let _ = a and b; //~ ERROR `and` is not a logical operator
-                     //~| ERROR `and` is not a logical operator
 
     if a and b { //~ ERROR `and` is not a logical operator
-                 //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -24,10 +22,8 @@ fn test_or() {
     let b = false;
 
     let _ = a or b; //~ ERROR `or` is not a logical operator
-                    //~| ERROR `or` is not a logical operator
 
     if a or b { //~ ERROR `or` is not a logical operator
-                //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
@@ -36,7 +32,6 @@ fn test_and_par() {
     let a = true;
     let b = false;
     if (a and b) {  //~ ERROR `and` is not a logical operator
-                    //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -45,7 +40,6 @@ fn test_or_par() {
     let a = true;
     let b = false;
     if (a or b) {  //~ ERROR `or` is not a logical operator
-                   //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
@@ -54,7 +48,6 @@ fn test_while_and() {
     let a = true;
     let b = false;
     while a and b {  //~ ERROR `and` is not a logical operator
-                     //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -63,7 +56,6 @@ fn test_while_or() {
     let a = true;
     let b = false;
     while a or b { //~ ERROR `or` is not a logical operator
-                   //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
index fe48af592db9137873028764506f500dbaa25eeb..0350890c1fde0ca0129a6b42e29301ba0a03ee53 100644 (file)
@@ -7,23 +7,7 @@ LL |     let _ = a and b;
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `and` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:13:15
-   |
-LL |     let _ = a and b;
-   |               ^^^ help: use `&&` to perform logical conjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `and` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:16:10
-   |
-LL |     if a and b {
-   |          ^^^ help: use `&&` to perform logical conjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `and` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:16:10
+  --> $DIR/issue-54109-without-witness.rs:15:10
    |
 LL |     if a and b {
    |          ^^^ help: use `&&` to perform logical conjunction
@@ -31,7 +15,7 @@ LL |     if a and b {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:26:15
+  --> $DIR/issue-54109-without-witness.rs:24:15
    |
 LL |     let _ = a or b;
    |               ^^ help: use `||` to perform logical disjunction
@@ -39,23 +23,7 @@ LL |     let _ = a or b;
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:26:15
-   |
-LL |     let _ = a or b;
-   |               ^^ help: use `||` to perform logical disjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:29:10
-   |
-LL |     if a or b {
-   |          ^^ help: use `||` to perform logical disjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:29:10
+  --> $DIR/issue-54109-without-witness.rs:26:10
    |
 LL |     if a or b {
    |          ^^ help: use `||` to perform logical disjunction
@@ -63,31 +31,15 @@ LL |     if a or b {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `and` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:38:11
+  --> $DIR/issue-54109-without-witness.rs:34:11
    |
 LL |     if (a and b) {
    |           ^^^ help: use `&&` to perform logical conjunction
    |
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
-error: `and` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:38:11
-   |
-LL |     if (a and b) {
-   |           ^^^ help: use `&&` to perform logical conjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:47:11
-   |
-LL |     if (a or b) {
-   |           ^^ help: use `||` to perform logical disjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:47:11
+  --> $DIR/issue-54109-without-witness.rs:42:11
    |
 LL |     if (a or b) {
    |           ^^ help: use `||` to perform logical disjunction
@@ -95,36 +47,20 @@ LL |     if (a or b) {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `and` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:56:13
+  --> $DIR/issue-54109-without-witness.rs:50:13
    |
 LL |     while a and b {
    |             ^^^ help: use `&&` to perform logical conjunction
    |
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
-error: `and` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:56:13
-   |
-LL |     while a and b {
-   |             ^^^ help: use `&&` to perform logical conjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:65:13
-   |
-LL |     while a or b {
-   |             ^^ help: use `||` to perform logical disjunction
-   |
-   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-without-witness.rs:65:13
+  --> $DIR/issue-54109-without-witness.rs:58:13
    |
 LL |     while a or b {
    |             ^^ help: use `||` to perform logical disjunction
    |
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
-error: aborting due to 16 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/issues/issue-75599.rs b/src/test/ui/issues/issue-75599.rs
new file mode 100644 (file)
index 0000000..0857676
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+#![allow(non_upper_case_globals)]
+
+const or: usize = 1;
+const and: usize = 2;
+
+mod or {
+    pub const X: usize = 3;
+}
+
+mod and {
+    pub const X: usize = 4;
+}
+
+fn main() {
+    match 0 {
+        0 => {}
+        or => {}
+        and => {}
+        or::X => {}
+        and::X => {}
+        _ => {}
+    }
+}
diff --git a/src/test/ui/lint/clashing-extern-fn-recursion.rs b/src/test/ui/lint/clashing-extern-fn-recursion.rs
new file mode 100644 (file)
index 0000000..ab0fd0a
--- /dev/null
@@ -0,0 +1,119 @@
+// check-pass
+//
+// This tests checks that clashing_extern_declarations handles types that are recursive through a
+// pointer or ref argument. See #75512.
+
+#![crate_type = "lib"]
+
+mod raw_ptr_recursion {
+    mod a {
+        #[repr(C)]
+        struct Pointy {
+            pointy: *const Pointy,
+        }
+
+        extern "C" {
+            fn run_pointy(pointy: Pointy);
+        }
+    }
+    mod b {
+        #[repr(C)]
+        struct Pointy {
+            pointy: *const Pointy,
+        }
+
+        extern "C" {
+            fn run_pointy(pointy: Pointy);
+        }
+    }
+}
+
+mod raw_ptr_recursion_once_removed {
+    mod a {
+        #[repr(C)]
+        struct Pointy1 {
+            pointy_two: *const Pointy2,
+        }
+
+        #[repr(C)]
+        struct Pointy2 {
+            pointy_one: *const Pointy1,
+        }
+
+        extern "C" {
+            fn run_pointy2(pointy: Pointy2);
+        }
+    }
+
+    mod b {
+        #[repr(C)]
+        struct Pointy1 {
+            pointy_two: *const Pointy2,
+        }
+
+        #[repr(C)]
+        struct Pointy2 {
+            pointy_one: *const Pointy1,
+        }
+
+        extern "C" {
+            fn run_pointy2(pointy: Pointy2);
+        }
+    }
+}
+
+mod ref_recursion {
+    mod a {
+        #[repr(C)]
+        struct Reffy<'a> {
+            reffy: &'a Reffy<'a>,
+        }
+
+        extern "C" {
+            fn reffy_recursion(reffy: Reffy);
+        }
+    }
+    mod b {
+        #[repr(C)]
+        struct Reffy<'a> {
+            reffy: &'a Reffy<'a>,
+        }
+
+        extern "C" {
+            fn reffy_recursion(reffy: Reffy);
+        }
+    }
+}
+
+mod ref_recursion_once_removed {
+    mod a {
+        #[repr(C)]
+        struct Reffy1<'a> {
+            reffy: &'a Reffy2<'a>,
+        }
+
+        struct Reffy2<'a> {
+            reffy: &'a Reffy1<'a>,
+        }
+
+        extern "C" {
+            #[allow(improper_ctypes)]
+            fn reffy_once_removed(reffy: Reffy1);
+        }
+    }
+    mod b {
+        #[repr(C)]
+        struct Reffy1<'a> {
+            reffy: &'a Reffy2<'a>,
+        }
+
+        struct Reffy2<'a> {
+            reffy: &'a Reffy1<'a>,
+        }
+
+        extern "C" {
+            #[allow(improper_ctypes)]
+            fn reffy_once_removed(reffy: Reffy1);
+        }
+    }
+}