From 0b3c9d84656a86cb3c57b20fff6bef5f8f2aeabb Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 21 Aug 2020 14:52:10 +0200 Subject: [PATCH 001/274] unix: Extend UnixStream and UnixDatagram to send and receive file descriptors Add the functions `recv_vectored_fds` and `send_vectored_fds` to send and receive file descriptors, by using `recvmsg` and `sendmsg` system call. --- library/std/src/sys/unix/ext/net.rs | 867 ++++++++++++++++++++++ library/std/src/sys/unix/ext/net/tests.rs | 152 ++++ library/std/src/sys/unix/net.rs | 92 +++ 3 files changed, 1111 insertions(+) diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index 3d2366554b5..c72800b5d57 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -25,7 +25,10 @@ use crate::net::{self, Shutdown}; use crate::os::unix::ffi::OsStrExt; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::Path; +use crate::ptr::null_mut; +use crate::slice::from_raw_parts; use crate::sys::net::Socket; +use crate::sys::unix::net::{add_to_ancillary_data, AncillaryDataIter}; use crate::sys::{self, cvt}; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; use crate::time::Duration; @@ -114,6 +117,62 @@ unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::sockl Ok((addr, len as libc::socklen_t)) } +fn recv_vectored_with_ancillary_from( + socket: &Socket, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result<(usize, bool, io::Result)> { + unsafe { + let mut msg_name: libc::sockaddr_un = mem::zeroed(); + + let mut msg = libc::msghdr { + msg_name: &mut msg_name as *mut _ as *mut _, + msg_namelen: mem::size_of::() as libc::socklen_t, + msg_iov: bufs.as_mut_ptr().cast(), + msg_iovlen: bufs.len(), + msg_control: ancillary.buffer.as_mut_ptr().cast(), + msg_controllen: ancillary.buffer.len(), + msg_flags: 0, + }; + + let count = socket.recv_msg(&mut msg)?; + + ancillary.length = msg.msg_controllen; + ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC; + + let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC; + let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen); + + Ok((count, truncated, addr)) + } +} + +fn send_vectored_with_ancillary_to( + socket: &Socket, + path: Option<&Path>, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result { + unsafe { + let (mut msg_name, msg_namelen) = + if let Some(path) = path { sockaddr_un(path)? } else { (mem::zeroed(), 0) }; + + let mut msg = libc::msghdr { + msg_name: &mut msg_name as *mut _ as *mut _, + msg_namelen, + msg_iov: bufs.as_mut_ptr().cast(), + msg_iovlen: bufs.len(), + msg_control: ancillary.buffer.as_mut_ptr().cast(), + msg_controllen: ancillary.length, + msg_flags: 0, + }; + + ancillary.truncated = false; + + socket.send_msg(&mut msg) + } +} + enum AddressKind<'a> { Unnamed, Pathname(&'a Path), @@ -269,6 +328,556 @@ impl fmt::Debug for SocketAddr { } } +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +impl<'a> Iterator for ScmRights<'a> { + type Item = RawFd; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +#[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); + +#[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +impl<'a> Iterator for ScmCredentials<'a> { + type Item = libc::ucred; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub enum AncillaryData<'a> { + ScmRights(ScmRights<'a>), + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + ScmCredentials(ScmCredentials<'a>), +} + +impl<'a> AncillaryData<'a> { + #[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + fn as_rights(data: &'a [u8]) -> Self { + let ancillary_data_iter = AncillaryDataIter::new(data); + let scm_rights = ScmRights(ancillary_data_iter); + AncillaryData::ScmRights(scm_rights) + } + + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + fn as_credentials(data: &'a [u8]) -> Self { + let ancillary_data_iter = AncillaryDataIter::new(data); + let scm_credentials = ScmCredentials(ancillary_data_iter); + AncillaryData::ScmCredentials(scm_credentials) + } +} + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +impl<'a> AncillaryData<'a> { + fn from(cmsg: &'a libc::cmsghdr) -> Self { + unsafe { + let cmsg_len_zero = libc::CMSG_LEN(0) as usize; + let data_len = (*cmsg).cmsg_len - cmsg_len_zero; + let data = libc::CMSG_DATA(cmsg).cast(); + let data = from_raw_parts(data, data_len); + + if (*cmsg).cmsg_level == libc::SOL_SOCKET { + match (*cmsg).cmsg_type { + libc::SCM_RIGHTS => AncillaryData::as_rights(data), + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + libc::SCM_CREDENTIALS => AncillaryData::as_credentials(data), + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + ))] + libc::SCM_CREDS => AncillaryData::as_credentials(data), + _ => panic!("Unknown cmsg type"), + } + } else { + panic!("Unknown cmsg level"); + } + } + } +} + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub struct Messages<'a> { + buffer: &'a [u8], + current: Option<&'a libc::cmsghdr>, +} + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +impl<'a> Iterator for Messages<'a> { + type Item = AncillaryData<'a>; + + fn next(&mut self) -> Option> { + unsafe { + let msg = libc::msghdr { + msg_name: null_mut(), + msg_namelen: 0, + msg_iov: null_mut(), + msg_iovlen: 0, + msg_control: self.buffer.as_ptr() as *mut _, + msg_controllen: self.buffer.len(), + msg_flags: 0, + }; + + let cmsg = if let Some(current) = self.current { + libc::CMSG_NXTHDR(&msg, current) + } else { + libc::CMSG_FIRSTHDR(&msg) + }; + + let cmsg = cmsg.as_ref()?; + self.current = Some(cmsg); + let ancillary_data = AncillaryData::from(cmsg); + Some(ancillary_data) + } + } +} + +/// A Unix socket Ancillary data struct. +/// +/// # Example +/// ```no_run +/// #![feature(unix_socket_ancillary_data)] +/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; +/// use std::io::IoSliceMut; +/// +/// fn main() -> std::io::Result<()> { +/// let sock = UnixStream::connect("/tmp/sock")?; +/// +/// let mut fds = [0; 8]; +/// let mut ancillary_buffer = [0; 128]; +/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); +/// +/// let mut buf = [1; 8]; +/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; +/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; +/// +/// for ancillary_data in ancillary.messages() { +/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { +/// for fd in scm_rights { +/// println!("receive file descriptor: {}", fd); +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[derive(Debug)] +pub struct SocketAncillary<'a> { + buffer: &'a mut [u8], + length: usize, + truncated: bool, +} + +impl<'a> SocketAncillary<'a> { + /// Create an ancillary data with the given buffer. + /// + /// # Example + /// + /// ```no_run + /// # #![allow(unused_mut)] + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::SocketAncillary; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn new(buffer: &'a mut [u8]) -> Self { + SocketAncillary { buffer, length: 0, truncated: false } + } + + /// Returns the capacity of the buffer. + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn capacity(&self) -> usize { + self.buffer.len() + } + + /// Returns the number of used bytes. + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn len(&self) -> usize { + self.length + } + + #[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn messages(&'a self) -> Messages<'a> { + Messages { buffer: &self.buffer[..self.length], current: None } + } + + /// Is `true` if during a recv operation the ancillary was truncated. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// + /// println!("Is truncated: {}", ancillary.truncated()); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn truncated(&self) -> bool { + self.truncated + } + + /// Add file descriptors to the ancillary data. + /// + /// The function returns `true` if there was enough space in the buffer. + /// If there was not enough space then no file descriptors was appended. + /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` + /// and type `SCM_RIGHTS`. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::os::unix::io::AsRawFd; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&[sock.as_raw_fd()][..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?; + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn add_fds(&mut self, fds: &[RawFd]) -> bool { + self.truncated = false; + add_to_ancillary_data( + &mut self.buffer, + &mut self.length, + fds, + libc::SOL_SOCKET, + libc::SCM_RIGHTS, + ) + } + + /// Add credentials to the ancillary data. + /// + /// The function returns `true` if there was enough space in the buffer. + /// If there was not enough space then no credentials was appended. + /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` + /// and type `SCM_CREDENTIALS`. + /// + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn add_creds(&mut self, creds: &[libc::ucred]) -> bool { + self.truncated = false; + add_to_ancillary_data( + &mut self.buffer, + &mut self.length, + creds, + libc::SOL_SOCKET, + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + libc::SCM_CREDENTIALS, + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + ))] + libc::SCM_CREDS, + ) + } + + /// Clears the ancillary data, removing all values. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut fds1 = [0; 8]; + /// let mut fds2 = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// + /// ancillary.clear(); + /// + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn clear(&mut self) { + self.length = 0; + self.truncated = false; + } +} + struct AsciiEscaped<'a>(&'a [u8]); impl<'a> fmt::Display for AsciiEscaped<'a> { @@ -646,6 +1255,91 @@ impl UnixStream { self.0.shutdown(how) } + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn recv_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + + Ok(count) + } + + /// Sends data and ancillary data on the socket. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn send_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) + } + /// Receives data on the socket from the remote address to which it is /// connected, without removing that data from the queue. On success, /// returns the number of bytes peeked. @@ -1439,6 +2133,102 @@ impl UnixDatagram { self.0.read(buf) } + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn recv_vectored_with_ancillary_from( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result<(usize, bool, SocketAddr)> { + let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + let addr = addr?; + + Ok((count, truncated, addr)) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read and if the data was truncated. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn recv_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result<(usize, bool)> { + let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + addr?; + + Ok((count, truncated)) + } + /// Sends data on the socket to the specified address. /// /// On success, returns the number of bytes written. @@ -1498,6 +2288,83 @@ impl UnixDatagram { self.0.write(buf) } + /// Sends data and ancillary data on the socket to the specified address. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn send_vectored_with_ancillary_to>( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + path: P, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary) + } + + /// Sends data and ancillary data on the socket. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn send_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) + } + /// Sets the read timeout for the socket. /// /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index ee73a6ed538..a4ca81c1c22 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -452,3 +452,155 @@ fn test_unix_datagram_peek_from() { assert_eq!(size, 11); assert_eq!(msg, &buf[..]); } + +#[test] +fn test_send_vectored_fds_unix_stream() { + let (s1, s2) = or_panic!(UnixStream::pair()); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..])); + + let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); + assert_eq!(usize, 8); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() { + let fd_vec = Vec::from_iter(scm_rights); + assert_eq!(fd_vec.len(), 1); + unsafe { + libc::close(fd_vec[0]); + } + } else { + assert!(false); + } +} + +#[test] +fn test_send_vectored_with_ancillary_to_unix_datagram() { + fn getpid() -> libc::pid_t { + unsafe { libc::getpid() } + } + + fn getuid() -> libc::uid_t { + unsafe { libc::getuid() } + } + + fn getgid() -> libc::gid_t { + unsafe { libc::getgid() } + } + + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + + unsafe { + let optval: libc::c_int = 1; + libc::setsockopt( + bsock2.as_raw_fd(), + libc::SOL_SOCKET, + libc::SO_PASSCRED, + &optval as *const _ as *const _, + mem::size_of::() as u32, + ); + } + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + let cred1 = libc::ucred { pid: getpid(), uid: getuid(), gid: getgid() }; + assert!(ancillary1.add_creds(&[cred1][..])); + + let usize = + or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let (usize, truncated, _addr) = + or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2)); + assert_eq!(ancillary2.truncated(), false); + assert_eq!(usize, 8); + assert_eq!(truncated, false); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmCredentials(scm_credentials) = ancillary_data_vec.pop().unwrap() { + let cred_vec = Vec::from_iter(scm_credentials); + assert_eq!(cred_vec.len(), 1); + assert_eq!(cred1.pid, cred_vec[0].pid); + assert_eq!(cred1.uid, cred_vec[0].uid); + assert_eq!(cred1.gid, cred_vec[0].gid); + } else { + assert!(false); + } +} + +#[test] +fn test_send_vectored_with_ancillary_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..])); + + or_panic!(bsock1.connect(&path2)); + let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let (usize, truncated) = + or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); + assert_eq!(usize, 8); + assert_eq!(truncated, false); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() { + let fd_vec = Vec::from_iter(scm_rights); + assert_eq!(fd_vec.len(), 1); + unsafe { + libc::close(fd_vec[0]); + } + } else { + assert!(false); + } +} diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 011325fddc5..e067edd3774 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -1,8 +1,10 @@ use crate::cmp; use crate::ffi::CStr; use crate::io::{self, IoSlice, IoSliceMut}; +use crate::marker::PhantomData; use crate::mem; use crate::net::{Shutdown, SocketAddr}; +use crate::ptr::null_mut; use crate::str; use crate::sys::fd::FileDesc; use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; @@ -18,6 +20,86 @@ pub extern crate libc as netc; pub type wrlen_t = size_t; +pub struct AncillaryDataIter<'a, T> { + data: &'a [u8], + phantom: crate::marker::PhantomData, +} + +impl<'a, T> AncillaryDataIter<'a, T> { + pub fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> { + AncillaryDataIter { data, phantom: PhantomData } + } +} + +impl<'a, T> Iterator for AncillaryDataIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + unsafe { + let mut unit = mem::zeroed(); + if mem::size_of::() <= self.data.len() { + let unit_ptr: *mut T = &mut unit; + libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), mem::size_of::()); + self.data = &self.data[mem::size_of::()..]; + Some(unit) + } else { + None + } + } + } +} + +pub fn add_to_ancillary_data( + buffer: &mut [u8], + length: &mut usize, + source: &[T], + cmsg_level: libc::c_int, + cmsg_type: libc::c_int, +) -> bool { + let len = (source.len() * mem::size_of::()) as u32; + + unsafe { + let additional_space = libc::CMSG_SPACE(len) as usize; + if *length + additional_space > buffer.len() { + return false; + } + + libc::memset(buffer[*length..].as_mut_ptr().cast(), 0, additional_space); + + *length += additional_space; + + let msg = libc::msghdr { + msg_name: null_mut(), + msg_namelen: 0, + msg_iov: null_mut(), + msg_iovlen: 0, + msg_control: buffer.as_mut_ptr().cast(), + msg_controllen: *length, + msg_flags: 0, + }; + + let mut cmsg = libc::CMSG_FIRSTHDR(&msg); + let mut previous_cmsg = cmsg; + while !cmsg.is_null() { + previous_cmsg = cmsg; + cmsg = libc::CMSG_NXTHDR(&msg, cmsg); + } + + if previous_cmsg.is_null() { + return false; + } + + (*previous_cmsg).cmsg_level = cmsg_level; + (*previous_cmsg).cmsg_type = cmsg_type; + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(len) as usize; + + let data = libc::CMSG_DATA(previous_cmsg).cast(); + + libc::memcpy(data, source.as_ptr().cast(), len as usize); + } + true +} + pub struct Socket(FileDesc); pub fn init() {} @@ -237,6 +319,11 @@ impl Socket { self.recv_from_with_flags(buf, 0) } + pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result { + let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?; + Ok(n as usize) + } + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { self.recv_from_with_flags(buf, MSG_PEEK) } @@ -254,6 +341,11 @@ impl Socket { self.0.is_write_vectored() } + pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result { + let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?; + Ok(n as usize) + } + pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { From 6fa7c3f79ed3775912c9ec5db8a824dee646e4dd Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 22 Aug 2020 17:27:43 +0200 Subject: [PATCH 002/274] Split net.rs into multiple files --- library/std/src/sys/unix/ext/net.rs | 2635 ----------------- library/std/src/sys/unix/ext/net/addr.rs | 226 ++ library/std/src/sys/unix/ext/net/ancillary.rs | 614 ++++ library/std/src/sys/unix/ext/net/datagram.rs | 819 +++++ library/std/src/sys/unix/ext/net/listener.rs | 323 ++ library/std/src/sys/unix/ext/net/mod.rs | 25 + library/std/src/sys/unix/ext/net/raw_fd.rs | 67 + library/std/src/sys/unix/ext/net/stream.rs | 615 ++++ library/std/src/sys/unix/ext/net/test.rs | 608 ++++ 9 files changed, 3297 insertions(+), 2635 deletions(-) delete mode 100644 library/std/src/sys/unix/ext/net.rs create mode 100644 library/std/src/sys/unix/ext/net/addr.rs create mode 100644 library/std/src/sys/unix/ext/net/ancillary.rs create mode 100644 library/std/src/sys/unix/ext/net/datagram.rs create mode 100644 library/std/src/sys/unix/ext/net/listener.rs create mode 100644 library/std/src/sys/unix/ext/net/mod.rs create mode 100644 library/std/src/sys/unix/ext/net/raw_fd.rs create mode 100644 library/std/src/sys/unix/ext/net/stream.rs create mode 100644 library/std/src/sys/unix/ext/net/test.rs diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs deleted file mode 100644 index c72800b5d57..00000000000 --- a/library/std/src/sys/unix/ext/net.rs +++ /dev/null @@ -1,2635 +0,0 @@ -//! Unix-specific networking functionality. - -#![stable(feature = "unix_socket", since = "1.10.0")] - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests; - -// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(not(unix))] -#[allow(non_camel_case_types)] -mod libc { - pub use libc::c_int; - pub type socklen_t = u32; - pub struct sockaddr; - #[derive(Clone)] - pub struct sockaddr_un; -} - -use crate::ascii; -use crate::ffi::OsStr; -use crate::fmt; -use crate::io::{self, Initializer, IoSlice, IoSliceMut}; -use crate::mem; -use crate::net::{self, Shutdown}; -use crate::os::unix::ffi::OsStrExt; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::path::Path; -use crate::ptr::null_mut; -use crate::slice::from_raw_parts; -use crate::sys::net::Socket; -use crate::sys::unix::net::{add_to_ancillary_data, AncillaryDataIter}; -use crate::sys::{self, cvt}; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; -use crate::time::Duration; - -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -use crate::os::unix::ucred; - -#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -pub use ucred::UCred; - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -))] -use libc::MSG_NOSIGNAL; -#[cfg(not(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -)))] -const MSG_NOSIGNAL: libc::c_int = 0x0; - -fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { - // Work with an actual instance of the type since using a null pointer is UB - let base = addr as *const _ as usize; - let path = &addr.sun_path as *const _ as usize; - path - base -} - -unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { - let mut addr: libc::sockaddr_un = mem::zeroed(); - addr.sun_family = libc::AF_UNIX as libc::sa_family_t; - - let bytes = path.as_os_str().as_bytes(); - - if bytes.contains(&0) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "paths may not contain interior null bytes", - )); - } - - if bytes.len() >= addr.sun_path.len() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "path must be shorter than SUN_LEN", - )); - } - for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { - *dst = *src as libc::c_char; - } - // null byte for pathname addresses is already there because we zeroed the - // struct - - let mut len = sun_path_offset(&addr) + bytes.len(); - match bytes.get(0) { - Some(&0) | None => {} - Some(_) => len += 1, - } - Ok((addr, len as libc::socklen_t)) -} - -fn recv_vectored_with_ancillary_from( - socket: &Socket, - bufs: &mut [IoSliceMut<'_>], - ancillary: &mut SocketAncillary<'_>, -) -> io::Result<(usize, bool, io::Result)> { - unsafe { - let mut msg_name: libc::sockaddr_un = mem::zeroed(); - - let mut msg = libc::msghdr { - msg_name: &mut msg_name as *mut _ as *mut _, - msg_namelen: mem::size_of::() as libc::socklen_t, - msg_iov: bufs.as_mut_ptr().cast(), - msg_iovlen: bufs.len(), - msg_control: ancillary.buffer.as_mut_ptr().cast(), - msg_controllen: ancillary.buffer.len(), - msg_flags: 0, - }; - - let count = socket.recv_msg(&mut msg)?; - - ancillary.length = msg.msg_controllen; - ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC; - - let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC; - let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen); - - Ok((count, truncated, addr)) - } -} - -fn send_vectored_with_ancillary_to( - socket: &Socket, - path: Option<&Path>, - bufs: &mut [IoSliceMut<'_>], - ancillary: &mut SocketAncillary<'_>, -) -> io::Result { - unsafe { - let (mut msg_name, msg_namelen) = - if let Some(path) = path { sockaddr_un(path)? } else { (mem::zeroed(), 0) }; - - let mut msg = libc::msghdr { - msg_name: &mut msg_name as *mut _ as *mut _, - msg_namelen, - msg_iov: bufs.as_mut_ptr().cast(), - msg_iovlen: bufs.len(), - msg_control: ancillary.buffer.as_mut_ptr().cast(), - msg_controllen: ancillary.length, - msg_flags: 0, - }; - - ancillary.truncated = false; - - socket.send_msg(&mut msg) - } -} - -enum AddressKind<'a> { - Unnamed, - Pathname(&'a Path), - Abstract(&'a [u8]), -} - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[derive(Clone)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, -} - -impl SocketAddr { - fn new(f: F) -> io::Result - where - F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, - { - unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; - SocketAddr::from_parts(addr, len) - } - } - - fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { - if len == 0 { - // When there is a datagram from unnamed unix socket - // linux returns zero bytes of address - len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address - } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "file descriptor did not correspond to a Unix socket", - )); - } - - Ok(SocketAddr { addr, len }) - } - - /// Returns `true` if the address is unnamed. - /// - /// # Examples - /// - /// A named address: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), false); - /// Ok(()) - /// } - /// ``` - /// - /// An unnamed address: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), true); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - if let AddressKind::Unnamed = self.address() { true } else { false } - } - - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// Ok(()) - /// } - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } - } - - fn address(&self) -> AddressKind<'_> { - let len = self.len as usize - sun_path_offset(&self.addr); - let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - - // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 - || (cfg!(not(any(target_os = "linux", target_os = "android"))) - && self.addr.sun_path[0] == 0) - { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) - } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) - } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.address() { - AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), - AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), - } - } -} - -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); - -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -impl<'a> Iterator for ScmRights<'a> { - type Item = RawFd; - - fn next(&mut self) -> Option { - self.0.next() - } -} - -#[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); - -#[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -impl<'a> Iterator for ScmCredentials<'a> { - type Item = libc::ucred; - - fn next(&mut self) -> Option { - self.0.next() - } -} - -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -pub enum AncillaryData<'a> { - ScmRights(ScmRights<'a>), - #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] - ScmCredentials(ScmCredentials<'a>), -} - -impl<'a> AncillaryData<'a> { - #[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] - fn as_rights(data: &'a [u8]) -> Self { - let ancillary_data_iter = AncillaryDataIter::new(data); - let scm_rights = ScmRights(ancillary_data_iter); - AncillaryData::ScmRights(scm_rights) - } - - #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] - fn as_credentials(data: &'a [u8]) -> Self { - let ancillary_data_iter = AncillaryDataIter::new(data); - let scm_credentials = ScmCredentials(ancillary_data_iter); - AncillaryData::ScmCredentials(scm_credentials) - } -} - -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -impl<'a> AncillaryData<'a> { - fn from(cmsg: &'a libc::cmsghdr) -> Self { - unsafe { - let cmsg_len_zero = libc::CMSG_LEN(0) as usize; - let data_len = (*cmsg).cmsg_len - cmsg_len_zero; - let data = libc::CMSG_DATA(cmsg).cast(); - let data = from_raw_parts(data, data_len); - - if (*cmsg).cmsg_level == libc::SOL_SOCKET { - match (*cmsg).cmsg_type { - libc::SCM_RIGHTS => AncillaryData::as_rights(data), - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] - libc::SCM_CREDENTIALS => AncillaryData::as_credentials(data), - #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - ))] - libc::SCM_CREDS => AncillaryData::as_credentials(data), - _ => panic!("Unknown cmsg type"), - } - } else { - panic!("Unknown cmsg level"); - } - } - } -} - -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -pub struct Messages<'a> { - buffer: &'a [u8], - current: Option<&'a libc::cmsghdr>, -} - -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -impl<'a> Iterator for Messages<'a> { - type Item = AncillaryData<'a>; - - fn next(&mut self) -> Option> { - unsafe { - let msg = libc::msghdr { - msg_name: null_mut(), - msg_namelen: 0, - msg_iov: null_mut(), - msg_iovlen: 0, - msg_control: self.buffer.as_ptr() as *mut _, - msg_controllen: self.buffer.len(), - msg_flags: 0, - }; - - let cmsg = if let Some(current) = self.current { - libc::CMSG_NXTHDR(&msg, current) - } else { - libc::CMSG_FIRSTHDR(&msg) - }; - - let cmsg = cmsg.as_ref()?; - self.current = Some(cmsg); - let ancillary_data = AncillaryData::from(cmsg); - Some(ancillary_data) - } - } -} - -/// A Unix socket Ancillary data struct. -/// -/// # Example -/// ```no_run -/// #![feature(unix_socket_ancillary_data)] -/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; -/// use std::io::IoSliceMut; -/// -/// fn main() -> std::io::Result<()> { -/// let sock = UnixStream::connect("/tmp/sock")?; -/// -/// let mut fds = [0; 8]; -/// let mut ancillary_buffer = [0; 128]; -/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); -/// -/// let mut buf = [1; 8]; -/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; -/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; -/// -/// for ancillary_data in ancillary.messages() { -/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { -/// for fd in scm_rights { -/// println!("receive file descriptor: {}", fd); -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -#[derive(Debug)] -pub struct SocketAncillary<'a> { - buffer: &'a mut [u8], - length: usize, - truncated: bool, -} - -impl<'a> SocketAncillary<'a> { - /// Create an ancillary data with the given buffer. - /// - /// # Example - /// - /// ```no_run - /// # #![allow(unused_mut)] - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::SocketAncillary; - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn new(buffer: &'a mut [u8]) -> Self { - SocketAncillary { buffer, length: 0, truncated: false } - } - - /// Returns the capacity of the buffer. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn capacity(&self) -> usize { - self.buffer.len() - } - - /// Returns the number of used bytes. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn len(&self) -> usize { - self.length - } - - #[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn messages(&'a self) -> Messages<'a> { - Messages { buffer: &self.buffer[..self.length], current: None } - } - - /// Is `true` if during a recv operation the ancillary was truncated. - /// - /// # Example - /// - /// ```no_run - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::{UnixStream, SocketAncillary}; - /// use std::io::IoSliceMut; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixStream::connect("/tmp/sock")?; - /// - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// - /// let mut buf = [1; 8]; - /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; - /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; - /// - /// println!("Is truncated: {}", ancillary.truncated()); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn truncated(&self) -> bool { - self.truncated - } - - /// Add file descriptors to the ancillary data. - /// - /// The function returns `true` if there was enough space in the buffer. - /// If there was not enough space then no file descriptors was appended. - /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` - /// and type `SCM_RIGHTS`. - /// - /// # Example - /// - /// ```no_run - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::{UnixStream, SocketAncillary}; - /// use std::os::unix::io::AsRawFd; - /// use std::io::IoSliceMut; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixStream::connect("/tmp/sock")?; - /// - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// ancillary.add_fds(&[sock.as_raw_fd()][..]); - /// - /// let mut buf = [1; 8]; - /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; - /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?; - /// Ok(()) - /// } - /// ``` - #[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn add_fds(&mut self, fds: &[RawFd]) -> bool { - self.truncated = false; - add_to_ancillary_data( - &mut self.buffer, - &mut self.length, - fds, - libc::SOL_SOCKET, - libc::SCM_RIGHTS, - ) - } - - /// Add credentials to the ancillary data. - /// - /// The function returns `true` if there was enough space in the buffer. - /// If there was not enough space then no credentials was appended. - /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` - /// and type `SCM_CREDENTIALS`. - /// - #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn add_creds(&mut self, creds: &[libc::ucred]) -> bool { - self.truncated = false; - add_to_ancillary_data( - &mut self.buffer, - &mut self.length, - creds, - libc::SOL_SOCKET, - #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] - libc::SCM_CREDENTIALS, - #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - ))] - libc::SCM_CREDS, - ) - } - - /// Clears the ancillary data, removing all values. - /// - /// # Example - /// - /// ```no_run - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; - /// use std::io::IoSliceMut; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixStream::connect("/tmp/sock")?; - /// - /// let mut fds1 = [0; 8]; - /// let mut fds2 = [0; 8]; - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// - /// let mut buf = [1; 8]; - /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; - /// - /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { - /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); - /// } - /// } - /// } - /// - /// ancillary.clear(); - /// - /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { - /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); - /// } - /// } - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn clear(&mut self) { - self.length = 0; - self.truncated = false; - } -} - -struct AsciiEscaped<'a>(&'a [u8]); - -impl<'a> fmt::Display for AsciiEscaped<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "\"")?; - for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { - write!(fmt, "{}", byte as char)?; - } - write!(fmt, "\"") - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let mut stream = UnixStream::connect("/path/to/my/socket")?; -/// stream.write_all(b"hello world")?; -/// let mut response = String::new(); -/// stream.read_to_string(&mut response)?; -/// println!("{}", response); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } - } - inner(path.as_ref()) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; - Ok((UnixStream(i1), UnixStream(i2))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - /// Gets the peer credentials for this Unix domain socket. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(peer_credentials_unix_socket)] - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" - ))] - pub fn peer_cred(&self) -> io::Result { - ucred::peer_cred(self) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UdpSocket::bind("127.0.0.1:34254")?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// Receives data and ancillary data from socket. - /// - /// On success, returns the number of bytes read. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; - /// use std::io::IoSliceMut; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), - /// ][..]; - /// let mut fds = [0; 8]; - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?; - /// println!("received {}", size); - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { - /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); - /// } - /// } - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn recv_vectored_with_ancillary( - &self, - bufs: &mut [IoSliceMut<'_>], - ancillary: &mut SocketAncillary<'_>, - ) -> io::Result { - let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; - - Ok(count) - } - - /// Sends data and ancillary data on the socket. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::{UnixStream, SocketAncillary}; - /// use std::io::IoSliceMut; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), - /// ][..]; - /// let fds = [0, 1, 2]; - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// ancillary.add_fds(&fds[..]); - /// socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn send_vectored_with_ancillary( - &self, - bufs: &mut [IoSliceMut<'_>], - ancillary: &mut SocketAncillary<'_>, - ) -> io::Result { - send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) - } - - /// Receives data on the socket from the remote address to which it is - /// connected, without removing that data from the queue. On success, - /// returns the number of bytes peeked. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &*self, buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - io::Read::read_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - io::Read::is_read_vectored(&&*self) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &*self, buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - io::Write::write_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - io::Write::is_write_vectored(&&*self) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &*self) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} - -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; - - Ok(UnixListener(inner)) - } - } - inner(path.as_ref()) - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: crate::os::unix::net::UnixStream - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; - let addr = SocketAddr::from_parts(storage, len)?; - Ok((UnixStream(sock), addr)) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// This will result in the `accept` operation becoming nonblocking, - /// i.e., immediately returning from their calls. If the IO operation is - /// successful, `Ok` is returned and no further action is required. If the - /// IO operation could not be completed and needs to be retried, an error - /// with kind [`io::ErrorKind::WouldBlock`] is returned. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/tmp/sock")?; - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn incoming(&self) -> Incoming<'_> { - Incoming { listener: self } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[derive(Debug)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -/// A Unix datagram socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixDatagram; -/// -/// fn main() -> std::io::Result<()> { -/// let socket = UnixDatagram::bind("/path/to/my/socket")?; -/// socket.send_to(b"hello world", "/path/to/other/socket")?; -/// let mut buf = [0; 100]; -/// let (count, address) = socket.recv_from(&mut buf)?; -/// println!("socket {:?} sent {:?}", address, &buf[..count]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixDatagram(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixDatagram { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixDatagram"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixDatagram { - /// Creates a Unix datagram socket bound to the given path. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't bind: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let socket = UnixDatagram::unbound()?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; - - Ok(socket) - } - } - inner(path.as_ref()) - } - - /// Creates a Unix Datagram socket which is not bound to any address. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::unbound() { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn unbound() -> io::Result { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok(UnixDatagram(inner)) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixDatagrams`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let (sock1, sock2) = match UnixDatagram::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok((UnixDatagram(i1), UnixDatagram(i2))) - } - - /// Connects the socket to the specified address. - /// - /// 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`]: UnixDatagram::send - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// match sock.connect("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return Err(e) - /// } - /// }; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(&self, path: P) -> io::Result<()> { - fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; - - Ok(()) - } - } - inner(self, path.as_ref()) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixDatagram` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one side will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let sock_copy = sock.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixDatagram) - } - - /// Returns the address of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let addr = sock.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the address of this socket's peer. - /// - /// The [`connect`] method will connect the socket to a peer. - /// - /// [`connect`]: UnixDatagram::connect - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/path/to/the/socket")?; - /// - /// let addr = sock.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - fn recv_from_flags( - &self, - buf: &mut [u8], - flags: libc::c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut count = 0; - let addr = SocketAddr::new(|addr, len| unsafe { - count = libc::recvfrom( - *self.0.as_inner(), - buf.as_mut_ptr() as *mut _, - buf.len(), - flags, - addr, - len, - ); - if count > 0 { - 1 - } else if count == 0 { - 0 - } else { - -1 - } - })?; - - Ok((count as usize, addr)) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read and the address from - /// whence the data came. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// let mut buf = vec![0; 10]; - /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; - /// println!("received {} bytes from {:?}", size, sender); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, 0) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let mut buf = vec![0; 10]; - /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - /// Receives data and ancillary data from socket. - /// - /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; - /// use std::io::IoSliceMut; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), - /// ][..]; - /// let mut fds = [0; 8]; - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?; - /// println!("received {}", size); - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { - /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); - /// } - /// } - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn recv_vectored_with_ancillary_from( - &self, - bufs: &mut [IoSliceMut<'_>], - ancillary: &mut SocketAncillary<'_>, - ) -> io::Result<(usize, bool, SocketAddr)> { - let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; - let addr = addr?; - - Ok((count, truncated, addr)) - } - - /// Receives data and ancillary data from socket. - /// - /// On success, returns the number of bytes read and if the data was truncated. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; - /// use std::io::IoSliceMut; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), - /// ][..]; - /// let mut fds = [0; 8]; - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; - /// println!("received {}", size); - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { - /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); - /// } - /// } - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn recv_vectored_with_ancillary( - &self, - bufs: &mut [IoSliceMut<'_>], - ancillary: &mut SocketAncillary<'_>, - ) -> io::Result<(usize, bool)> { - let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; - addr?; - - Ok((count, truncated)) - } - - /// Sends data on the socket to the specified address. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { - fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - let count = cvt(libc::sendto( - *d.0.as_inner(), - buf.as_ptr() as *const _, - buf.len(), - MSG_NOSIGNAL, - &addr as *const _ as *const _, - len, - ))?; - Ok(count as usize) - } - } - inner(self, buf, path.as_ref()) - } - - /// Sends data on the socket to the socket's peer. - /// - /// The peer address may be set by the `connect` method, and this method - /// will return an error if the socket has not already been connected. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/some/sock").expect("Couldn't connect"); - /// sock.send(b"omelette au fromage").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - /// Sends data and ancillary data on the socket to the specified address. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; - /// use std::io::IoSliceMut; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), - /// ][..]; - /// let fds = [0, 1, 2]; - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// ancillary.add_fds(&fds[..]); - /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn send_vectored_with_ancillary_to>( - &self, - bufs: &mut [IoSliceMut<'_>], - ancillary: &mut SocketAncillary<'_>, - path: P, - ) -> io::Result { - send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary) - } - - /// Sends data and ancillary data on the socket. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_ancillary_data)] - /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; - /// use std::io::IoSliceMut; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// let mut buf1 = [1; 8]; - /// let mut buf2 = [2; 16]; - /// let mut buf3 = [3; 8]; - /// let mut bufs = &mut [ - /// IoSliceMut::new(&mut buf1), - /// IoSliceMut::new(&mut buf2), - /// IoSliceMut::new(&mut buf3), - /// ][..]; - /// let fds = [0, 1, 2]; - /// let mut ancillary_buffer = [0; 128]; - /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); - /// ancillary.add_fds(&fds[..]); - /// sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn send_vectored_with_ancillary( - &self, - bufs: &mut [IoSliceMut<'_>], - ancillary: &mut SocketAncillary<'_>, - ) -> io::Result { - send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] - /// is passed to this method. - /// - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`send`]: UnixDatagram::send - /// [`send_to`]: UnixDatagram::send_to - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// if let Ok(Some(err)) = sock.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shut down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// Receives data on the socket from the remote address to which it is - /// connected, without removing that data from the queue. On success, - /// returns the number of bytes peeked. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } - - /// Receives a single datagram message on the socket, without removing it from the - /// queue. On success, returns the number of bytes read and the origin. - /// - /// The function must be called with valid byte array `buf` of sufficient size to - /// hold the message bytes. If a message is too long to fit in the supplied buffer, - /// excess bytes may be discarded. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. - /// - /// Do not use this function to implement busy waiting, instead use `libc::poll` to - /// synchronize IO events on one or more sockets. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, libc::MSG_PEEK) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixDatagram { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixDatagram { - unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { - UnixDatagram(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixDatagram { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} diff --git a/library/std/src/sys/unix/ext/net/addr.rs b/library/std/src/sys/unix/ext/net/addr.rs new file mode 100644 index 00000000000..15fc5bb5b4e --- /dev/null +++ b/library/std/src/sys/unix/ext/net/addr.rs @@ -0,0 +1,226 @@ +use crate::ffi::OsStr; +use crate::os::unix::ffi::OsStrExt; +use crate::path::Path; +use crate::sys::unix::cvt; +use crate::{ascii, fmt, io, mem}; + +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(not(unix))] +#[allow(non_camel_case_types)] +mod libc { + pub use libc::c_int; + pub type socklen_t = u32; + pub struct sockaddr; + #[derive(Clone)] + pub struct sockaddr_un; +} + +fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { + // Work with an actual instance of the type since using a null pointer is UB + let base = addr as *const _ as usize; + let path = &addr.sun_path as *const _ as usize; + path - base +} + +pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { + let mut addr: libc::sockaddr_un = mem::zeroed(); + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + let bytes = path.as_os_str().as_bytes(); + + if bytes.contains(&0) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "paths may not contain interior null bytes", + )); + } + + if bytes.len() >= addr.sun_path.len() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path must be shorter than SUN_LEN", + )); + } + for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { + *dst = *src as libc::c_char; + } + // null byte for pathname addresses is already there because we zeroed the + // struct + + let mut len = sun_path_offset(&addr) + bytes.len(); + match bytes.get(0) { + Some(&0) | None => {} + Some(_) => len += 1, + } + Ok((addr, len as libc::socklen_t)) +} + +enum AddressKind<'a> { + Unnamed, + Pathname(&'a Path), + Abstract(&'a [u8]), +} + +struct AsciiEscaped<'a>(&'a [u8]); + +impl<'a> fmt::Display for AsciiEscaped<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "\"")?; + for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { + write!(fmt, "{}", byte as char)?; + } + write!(fmt, "\"") + } +} + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[derive(Clone)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct SocketAddr { + addr: libc::sockaddr_un, + len: libc::socklen_t, +} + +impl SocketAddr { + pub(super) fn new(f: F) -> io::Result + where + F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, + { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + let mut len = mem::size_of::() as libc::socklen_t; + cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; + SocketAddr::from_parts(addr, len) + } + } + + pub(super) fn from_parts( + addr: libc::sockaddr_un, + mut len: libc::socklen_t, + ) -> io::Result { + if len == 0 { + // When there is a datagram from unnamed unix socket + // linux returns zero bytes of address + len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address + } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "file descriptor did not correspond to a Unix socket", + )); + } + + Ok(SocketAddr { addr, len }) + } + + /// Returns `true` if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// Ok(()) + /// } + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn is_unnamed(&self) -> bool { + if let AddressKind::Unnamed = self.address() { true } else { false } + } + + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// Ok(()) + /// } + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { + if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } + } + + fn address(&self) -> AddressKind<'_> { + let len = self.len as usize - sun_path_offset(&self.addr); + let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; + + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { + AddressKind::Unnamed + } else if self.addr.sun_path[0] == 0 { + AddressKind::Abstract(&path[1..len]) + } else { + AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.address() { + AddressKind::Unnamed => write!(fmt, "(unnamed)"), + AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), + AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), + } + } +} diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs new file mode 100644 index 00000000000..4e584cb143f --- /dev/null +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -0,0 +1,614 @@ +use crate::io::{self, IoSliceMut}; +use crate::mem; +use crate::os::unix::io::RawFd; +use crate::path::Path; +use crate::ptr::null_mut; +use crate::slice::from_raw_parts; +use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use crate::sys::unix::net::{add_to_ancillary_data, AncillaryDataIter, Socket}; + +pub(super) fn recv_vectored_with_ancillary_from( + socket: &Socket, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result<(usize, bool, io::Result)> { + unsafe { + let mut msg_name: libc::sockaddr_un = mem::zeroed(); + + let mut msg = libc::msghdr { + msg_name: &mut msg_name as *mut _ as *mut _, + msg_namelen: mem::size_of::() as libc::socklen_t, + msg_iov: bufs.as_mut_ptr().cast(), + msg_iovlen: bufs.len(), + msg_control: ancillary.buffer.as_mut_ptr().cast(), + msg_controllen: ancillary.buffer.len(), + msg_flags: 0, + }; + + let count = socket.recv_msg(&mut msg)?; + + ancillary.length = msg.msg_controllen; + ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC; + + let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC; + let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen); + + Ok((count, truncated, addr)) + } +} + +pub(super) fn send_vectored_with_ancillary_to( + socket: &Socket, + path: Option<&Path>, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, +) -> io::Result { + unsafe { + let (mut msg_name, msg_namelen) = + if let Some(path) = path { sockaddr_un(path)? } else { (mem::zeroed(), 0) }; + + let mut msg = libc::msghdr { + msg_name: &mut msg_name as *mut _ as *mut _, + msg_namelen, + msg_iov: bufs.as_mut_ptr().cast(), + msg_iovlen: bufs.len(), + msg_control: ancillary.buffer.as_mut_ptr().cast(), + msg_controllen: ancillary.length, + msg_flags: 0, + }; + + ancillary.truncated = false; + + socket.send_msg(&mut msg) + } +} + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +impl<'a> Iterator for ScmRights<'a> { + type Item = RawFd; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +#[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); + +#[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +impl<'a> Iterator for ScmCredentials<'a> { + type Item = libc::ucred; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub enum AncillaryData<'a> { + ScmRights(ScmRights<'a>), + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + ScmCredentials(ScmCredentials<'a>), +} + +impl<'a> AncillaryData<'a> { + #[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + fn as_rights(data: &'a [u8]) -> Self { + let ancillary_data_iter = AncillaryDataIter::new(data); + let scm_rights = ScmRights(ancillary_data_iter); + AncillaryData::ScmRights(scm_rights) + } + + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + fn as_credentials(data: &'a [u8]) -> Self { + let ancillary_data_iter = AncillaryDataIter::new(data); + let scm_credentials = ScmCredentials(ancillary_data_iter); + AncillaryData::ScmCredentials(scm_credentials) + } +} + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +impl<'a> AncillaryData<'a> { + fn from(cmsg: &'a libc::cmsghdr) -> Self { + unsafe { + let cmsg_len_zero = libc::CMSG_LEN(0) as usize; + let data_len = (*cmsg).cmsg_len - cmsg_len_zero; + let data = libc::CMSG_DATA(cmsg).cast(); + let data = from_raw_parts(data, data_len); + + if (*cmsg).cmsg_level == libc::SOL_SOCKET { + match (*cmsg).cmsg_type { + libc::SCM_RIGHTS => AncillaryData::as_rights(data), + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + libc::SCM_CREDENTIALS => AncillaryData::as_credentials(data), + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + ))] + libc::SCM_CREDS => AncillaryData::as_credentials(data), + _ => panic!("Unknown cmsg type"), + } + } else { + panic!("Unknown cmsg level"); + } + } + } +} + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub struct Messages<'a> { + buffer: &'a [u8], + current: Option<&'a libc::cmsghdr>, +} + +#[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", +))] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +impl<'a> Iterator for Messages<'a> { + type Item = AncillaryData<'a>; + + fn next(&mut self) -> Option> { + unsafe { + let msg = libc::msghdr { + msg_name: null_mut(), + msg_namelen: 0, + msg_iov: null_mut(), + msg_iovlen: 0, + msg_control: self.buffer.as_ptr() as *mut _, + msg_controllen: self.buffer.len(), + msg_flags: 0, + }; + + let cmsg = if let Some(current) = self.current { + libc::CMSG_NXTHDR(&msg, current) + } else { + libc::CMSG_FIRSTHDR(&msg) + }; + + let cmsg = cmsg.as_ref()?; + self.current = Some(cmsg); + let ancillary_data = AncillaryData::from(cmsg); + Some(ancillary_data) + } + } +} + +/// A Unix socket Ancillary data struct. +/// +/// # Example +/// ```no_run +/// #![feature(unix_socket_ancillary_data)] +/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; +/// use std::io::IoSliceMut; +/// +/// fn main() -> std::io::Result<()> { +/// let sock = UnixStream::connect("/tmp/sock")?; +/// +/// let mut fds = [0; 8]; +/// let mut ancillary_buffer = [0; 128]; +/// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); +/// +/// let mut buf = [1; 8]; +/// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; +/// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; +/// +/// for ancillary_data in ancillary.messages() { +/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { +/// for fd in scm_rights { +/// println!("receive file descriptor: {}", fd); +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[derive(Debug)] +pub struct SocketAncillary<'a> { + buffer: &'a mut [u8], + length: usize, + truncated: bool, +} + +impl<'a> SocketAncillary<'a> { + /// Create an ancillary data with the given buffer. + /// + /// # Example + /// + /// ```no_run + /// # #![allow(unused_mut)] + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::SocketAncillary; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn new(buffer: &'a mut [u8]) -> Self { + SocketAncillary { buffer, length: 0, truncated: false } + } + + /// Returns the capacity of the buffer. + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn capacity(&self) -> usize { + self.buffer.len() + } + + /// Returns the number of used bytes. + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn len(&self) -> usize { + self.length + } + + #[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn messages(&'a self) -> Messages<'a> { + Messages { buffer: &self.buffer[..self.length], current: None } + } + + /// Is `true` if during a recv operation the ancillary was truncated. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// + /// println!("Is truncated: {}", ancillary.truncated()); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn truncated(&self) -> bool { + self.truncated + } + + /// Add file descriptors to the ancillary data. + /// + /// The function returns `true` if there was enough space in the buffer. + /// If there was not enough space then no file descriptors was appended. + /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` + /// and type `SCM_RIGHTS`. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::os::unix::io::AsRawFd; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&[sock.as_raw_fd()][..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary)?; + /// Ok(()) + /// } + /// ``` + #[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn add_fds(&mut self, fds: &[RawFd]) -> bool { + self.truncated = false; + add_to_ancillary_data( + &mut self.buffer, + &mut self.length, + fds, + libc::SOL_SOCKET, + libc::SCM_RIGHTS, + ) + } + + /// Add credentials to the ancillary data. + /// + /// The function returns `true` if there was enough space in the buffer. + /// If there was not enough space then no credentials was appended. + /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` + /// and type `SCM_CREDENTIALS`. + /// + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn add_creds(&mut self, creds: &[libc::ucred]) -> bool { + self.truncated = false; + add_to_ancillary_data( + &mut self.buffer, + &mut self.length, + creds, + libc::SOL_SOCKET, + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + libc::SCM_CREDENTIALS, + #[cfg(any( + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + ))] + libc::SCM_CREDS, + ) + } + + /// Clears the ancillary data, removing all values. + /// + /// # Example + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixStream::connect("/tmp/sock")?; + /// + /// let mut fds1 = [0; 8]; + /// let mut fds2 = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// + /// let mut buf = [1; 8]; + /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; + /// + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// + /// ancillary.clear(); + /// + /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn clear(&mut self) { + self.length = 0; + self.truncated = false; + } +} diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs new file mode 100644 index 00000000000..e5630127ccb --- /dev/null +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -0,0 +1,819 @@ +use crate::io::IoSliceMut; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::unix::cvt; +use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use crate::sys::unix::ext::net::ancillary::{ + recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, +}; +use crate::sys::unix::net::Socket; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::Duration; +use crate::{fmt, io}; + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +))] +use libc::MSG_NOSIGNAL; +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +)))] +const MSG_NOSIGNAL: libc::c_int = 0x0; + +/// A Unix datagram socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixDatagram; +/// +/// fn main() -> std::io::Result<()> { +/// let socket = UnixDatagram::bind("/path/to/my/socket")?; +/// socket.send_to(b"hello world", "/path/to/other/socket")?; +/// let mut buf = [0; 100]; +/// let (count, address) = socket.recv_from(&mut buf)?; +/// println!("socket {:?} sent {:?}", address, &buf[..count]); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixDatagram(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixDatagram { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixDatagram"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixDatagram { + /// Creates a Unix datagram socket bound to the given path. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't bind: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let socket = UnixDatagram::unbound()?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; + + Ok(socket) + } + } + inner(path.as_ref()) + } + + /// Creates a Unix Datagram socket which is not bound to any address. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::unbound() { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn unbound() -> io::Result { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok(UnixDatagram(inner)) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixDatagrams`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let (sock1, sock2) = match UnixDatagram::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok((UnixDatagram(i1), UnixDatagram(i2))) + } + + /// Connects the socket to the specified address. + /// + /// 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`]: UnixDatagram::send + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// match sock.connect("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(&self, path: P) -> io::Result<()> { + fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { + unsafe { + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; + + Ok(()) + } + } + inner(self, path.as_ref()) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixDatagram` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one side will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let sock_copy = sock.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixDatagram) + } + + /// Returns the address of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let addr = sock.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the address of this socket's peer. + /// + /// The [`connect`] method will connect the socket to a peer. + /// + /// [`connect`]: UnixDatagram::connect + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/path/to/the/socket")?; + /// + /// let addr = sock.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + fn recv_from_flags( + &self, + buf: &mut [u8], + flags: libc::c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut count = 0; + let addr = SocketAddr::new(|addr, len| unsafe { + count = libc::recvfrom( + *self.0.as_inner(), + buf.as_mut_ptr() as *mut _, + buf.len(), + flags, + addr, + len, + ); + if count > 0 { + 1 + } else if count == 0 { + 0 + } else { + -1 + } + })?; + + Ok((count as usize, addr)) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read and the address from + /// whence the data came. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf = vec![0; 10]; + /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; + /// println!("received {} bytes from {:?}", size, sender); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, 0) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let mut buf = vec![0; 10]; + /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn recv_vectored_with_ancillary_from( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result<(usize, bool, SocketAddr)> { + let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + let addr = addr?; + + Ok((count, truncated, addr)) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read and if the data was truncated. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn recv_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result<(usize, bool)> { + let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + addr?; + + Ok((count, truncated)) + } + + /// Sends data on the socket to the specified address. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { + fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { + unsafe { + let (addr, len) = sockaddr_un(path)?; + + let count = cvt(libc::sendto( + *d.0.as_inner(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &addr as *const _ as *const _, + len, + ))?; + Ok(count as usize) + } + } + inner(self, buf, path.as_ref()) + } + + /// Sends data on the socket to the socket's peer. + /// + /// The peer address may be set by the `connect` method, and this method + /// will return an error if the socket has not already been connected. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/some/sock").expect("Couldn't connect"); + /// sock.send(b"omelette au fromage").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + /// Sends data and ancillary data on the socket to the specified address. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock").expect("send_vectored_with_ancillary_to function failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn send_vectored_with_ancillary_to>( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + path: P, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary) + } + + /// Sends data and ancillary data on the socket. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// sock.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn send_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] + /// is passed to this method. + /// + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`send`]: UnixDatagram::send + /// [`send_to`]: UnixDatagram::send_to + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// if let Ok(Some(err)) = sock.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shut down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives a single datagram message on the socket, without removing it from the + /// queue. On success, returns the number of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, libc::MSG_PEEK) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixDatagram { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixDatagram { + unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { + UnixDatagram(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixDatagram { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs new file mode 100644 index 00000000000..84386ea6381 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/listener.rs @@ -0,0 +1,323 @@ +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::net::Socket; +use crate::sys::unix::cvt; +use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use crate::sys::unix::ext::net::stream::UnixStream; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::{fmt, io, mem}; + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixListener(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(*inner.as_inner(), 128))?; + + Ok(UnixListener(inner)) + } + } + inner(path.as_ref()) + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: crate::os::unix::net::UnixStream + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let addr = SocketAddr::from_parts(storage, len)?; + Ok((UnixStream(sock), addr)) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// This will result in the `accept` operation becoming nonblocking, + /// i.e., immediately returning from their calls. If the IO operation is + /// successful, `Ok` is returned and no further action is required. If the + /// IO operation could not be completed and needs to be retried, an error + /// with kind [`io::ErrorKind::WouldBlock`] is returned. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/tmp/sock")?; + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn incoming(&self) -> Incoming<'_> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[derive(Debug)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs new file mode 100644 index 00000000000..93b72df520a --- /dev/null +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -0,0 +1,25 @@ +//! Unix-specific networking functionality + +#![stable(feature = "unix_socket", since = "1.10.0")] + +mod addr; +mod ancillary; +mod datagram; +mod listener; +mod raw_fd; +mod stream; +#[cfg(all(test, not(target_os = "emscripten")))] +mod test; + +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::addr::*; +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub use self::ancillary::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::datagram::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::listener::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::raw_fd::*; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use self::stream::*; diff --git a/library/std/src/sys/unix/ext/net/raw_fd.rs b/library/std/src/sys/unix/ext/net/raw_fd.rs new file mode 100644 index 00000000000..059c0fec06f --- /dev/null +++ b/library/std/src/sys/unix/ext/net/raw_fd.rs @@ -0,0 +1,67 @@ +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; +use crate::{net, sys}; + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::UdpSocket { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for net::TcpStream { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + let socket = sys::net::Socket::from_inner(fd); + net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for net::TcpListener { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + let socket = sys::net::Socket::from_inner(fd); + net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for net::UdpSocket { + unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { + let socket = sys::net::Socket::from_inner(fd); + net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for net::TcpStream { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for net::TcpListener { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for net::UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs new file mode 100644 index 00000000000..75b91902668 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -0,0 +1,615 @@ +use crate::fmt; +use crate::io::{self, Initializer, IoSlice, IoSliceMut}; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +use crate::os::unix::ucred; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; +use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use crate::sys::unix::ext::net::ancillary::{ + recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, +}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::Duration; + +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use ucred::UCred; + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// fn main() -> std::io::Result<()> { +/// let mut stream = UnixStream::connect("/path/to/my/socket")?; +/// stream.write_all(b"hello world")?; +/// let mut response = String::new(); +/// stream.read_to_string(&mut response)?; +/// println!("{}", response); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixStream(pub(super) Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) + } + } + inner(path.as_ref()) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; + Ok((UnixStream(i1), UnixStream(i2))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + /// Gets the peer credentials for this Unix domain socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peer_credentials_unix_socket)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" + ))] + pub fn peer_cred(&self) -> io::Result { + ucred::peer_cred(self) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UdpSocket::bind("127.0.0.1:34254")?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives data and ancillary data from socket. + /// + /// On success, returns the number of bytes read. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let mut fds = [0; 8]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?; + /// println!("received {}", size); + /// for ancillary_data in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for fd in scm_rights { + /// println!("receive file descriptor: {}", fd); + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn recv_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?; + + Ok(count) + } + + /// Sends data and ancillary data on the socket. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::{UnixStream, SocketAncillary}; + /// use std::io::IoSliceMut; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf1 = [1; 8]; + /// let mut buf2 = [2; 16]; + /// let mut buf3 = [3; 8]; + /// let mut bufs = &mut [ + /// IoSliceMut::new(&mut buf1), + /// IoSliceMut::new(&mut buf2), + /// IoSliceMut::new(&mut buf3), + /// ][..]; + /// let fds = [0, 1, 2]; + /// let mut ancillary_buffer = [0; 128]; + /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); + /// ancillary.add_fds(&fds[..]); + /// socket.send_vectored_with_ancillary(bufs, &mut ancillary).expect("send_vectored_with_ancillary function failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn send_vectored_with_ancillary( + &self, + bufs: &mut [IoSliceMut<'_>], + ancillary: &mut SocketAncillary<'_>, + ) -> io::Result { + send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + io::Read::read_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + io::Read::is_read_vectored(&&*self) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + io::Write::write_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/library/std/src/sys/unix/ext/net/test.rs b/library/std/src/sys/unix/ext/net/test.rs new file mode 100644 index 00000000000..724d73c9b1e --- /dev/null +++ b/library/std/src/sys/unix/ext/net/test.rs @@ -0,0 +1,608 @@ +use super::*; +use crate::io::prelude::*; +use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +use crate::iter::FromIterator; +use crate::mem; +use crate::sys::unix::ext::io::AsRawFd; +use crate::sys_common::io::test::tmpdir; +use crate::thread; +use crate::time::Duration; + +macro_rules! or_panic { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{}", e), + } + }; +} + +#[test] +fn basic() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + let msg1 = b"hello"; + let msg2 = b"world!"; + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream.write_all(msg2)); + }); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname()); + or_panic!(stream.write_all(msg1)); + let mut buf = vec![]; + or_panic!(stream.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(stream); + + thread.join().unwrap(); +} + +#[test] +fn vectored() { + let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + + let len = or_panic!(s1.write_vectored(&[ + IoSlice::new(b"hello"), + IoSlice::new(b" "), + IoSlice::new(b"world!") + ],)); + assert_eq!(len, 12); + + let mut buf1 = [0; 6]; + let mut buf2 = [0; 7]; + let len = + or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)); + assert_eq!(len, 12); + assert_eq!(&buf1, b"hello "); + assert_eq!(&buf2, b"world!\0"); +} + +#[test] +fn pair() { + let msg1 = b"hello"; + let msg2 = b"world!"; + + let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + let thread = thread::spawn(move || { + // s1 must be moved in or the test will hang! + let mut buf = [0; 5]; + or_panic!(s1.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(s1.write_all(msg2)); + }); + + or_panic!(s2.write_all(msg1)); + let mut buf = vec![]; + or_panic!(s2.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(s2); + + thread.join().unwrap(); +} + +#[test] +fn try_clone() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + let msg1 = b"hello"; + let msg2 = b"world"; + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + or_panic!(stream.write_all(msg1)); + or_panic!(stream.write_all(msg2)); + }); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + let mut stream2 = or_panic!(stream.try_clone()); + + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream2.read(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + + thread.join().unwrap(); +} + +#[test] +fn iter() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + for stream in listener.incoming().take(2) { + let mut stream = or_panic!(stream); + let mut buf = [0]; + or_panic!(stream.read(&mut buf)); + } + }); + + for _ in 0..2 { + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.write_all(&[0])); + } + + thread.join().unwrap(); +} + +#[test] +fn long_path() { + let dir = tmpdir(); + let socket_path = dir.path().join( + "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ + sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf", + ); + match UnixStream::connect(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } + + match UnixListener::bind(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } + + match UnixDatagram::bind(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } +} + +#[test] +fn timeouts() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let stream = or_panic!(UnixStream::connect(&socket_path)); + let dur = Duration::new(15410, 0); + + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.read_timeout())); + + assert_eq!(None, or_panic!(stream.write_timeout())); + + or_panic!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.write_timeout())); + + or_panic!(stream.set_read_timeout(None)); + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_write_timeout(None)); + assert_eq!(None, or_panic!(stream.write_timeout())); +} + +#[test] +fn test_read_timeout() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); +} + +#[test] +fn test_read_with_timeout() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut other_end = or_panic!(listener.accept()).0; + or_panic!(other_end.write_all(b"hello world")); + + let mut buf = [0; 11]; + or_panic!(stream.read(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_unix_stream_timeout_zero_duration() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let stream = or_panic!(UnixStream::connect(&socket_path)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); +} + +#[test] +fn test_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::bind(&path2)); + + let msg = b"hello world"; + or_panic!(sock1.send_to(msg, &path2)); + let mut buf = [0; 11]; + or_panic!(sock2.recv_from(&mut buf)); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_unnamed_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + + let msg = b"hello world"; + or_panic!(sock2.send_to(msg, &path1)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert!(addr.is_unnamed()); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_connect_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + let sock = or_panic!(UnixDatagram::unbound()); + or_panic!(sock.connect(&path1)); + + // Check send() + let msg = b"hello there"; + or_panic!(sock.send(msg)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert!(addr.is_unnamed()); + assert_eq!(msg, &buf[..]); + + // Changing default socket works too + or_panic!(sock.connect(&path2)); + or_panic!(sock.send(msg)); + or_panic!(bsock2.recv_from(&mut buf)); +} + +#[test] +fn test_unix_datagram_recv() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn datagram_pair() { + let msg1 = b"hello"; + let msg2 = b"world!"; + + let (s1, s2) = or_panic!(UnixDatagram::pair()); + let thread = thread::spawn(move || { + // s1 must be moved in or the test will hang! + let mut buf = [0; 5]; + or_panic!(s1.recv(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(s1.send(msg2)); + }); + + or_panic!(s2.send(msg1)); + let mut buf = [0; 6]; + or_panic!(s2.recv(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(s2); + + thread.join().unwrap(); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_unix_datagram_timeout_zero_duration() { + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let datagram = or_panic!(UnixDatagram::bind(&path)); + + let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); +} + +#[test] +fn abstract_namespace_not_allowed() { + assert!(UnixStream::connect("\0asdf").is_err()); +} + +#[test] +fn test_unix_stream_peek() { + let (txdone, rxdone) = crate::sync::mpsc::channel(); + + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + or_panic!(stream.write_all(&[1, 3, 3, 7])); + or_panic!(rxdone.recv()); + }); + + let mut stream = or_panic!(UnixStream::connect(&path)); + let mut buf = [0; 10]; + for _ in 0..2 { + assert_eq!(or_panic!(stream.peek(&mut buf)), 4); + } + assert_eq!(or_panic!(stream.read(&mut buf)), 4); + + or_panic!(stream.set_nonblocking(true)); + match stream.peek(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error: {}", e), + } + + or_panic!(txdone.send(())); + thread.join().unwrap(); +} + +#[test] +fn test_unix_datagram_peek() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let size = or_panic!(sock1.peek(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_unix_datagram_peek_from() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let (size, _) = or_panic!(sock1.peek_from(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_send_vectored_fds_unix_stream() { + let (s1, s2) = or_panic!(UnixStream::pair()); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..])); + + let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); + assert_eq!(usize, 8); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() { + let fd_vec = Vec::from_iter(scm_rights); + assert_eq!(fd_vec.len(), 1); + unsafe { + libc::close(fd_vec[0]); + } + } else { + assert!(false); + } +} + +#[test] +fn test_send_vectored_with_ancillary_to_unix_datagram() { + fn getpid() -> libc::pid_t { + unsafe { libc::getpid() } + } + + fn getuid() -> libc::uid_t { + unsafe { libc::getuid() } + } + + fn getgid() -> libc::gid_t { + unsafe { libc::getgid() } + } + + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + + unsafe { + let optval: libc::c_int = 1; + libc::setsockopt( + bsock2.as_raw_fd(), + libc::SOL_SOCKET, + libc::SO_PASSCRED, + &optval as *const _ as *const _, + mem::size_of::() as u32, + ); + } + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + let cred1 = libc::ucred { pid: getpid(), uid: getuid(), gid: getgid() }; + assert!(ancillary1.add_creds(&[cred1][..])); + + let usize = + or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let (usize, truncated, _addr) = + or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2)); + assert_eq!(ancillary2.truncated(), false); + assert_eq!(usize, 8); + assert_eq!(truncated, false); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmCredentials(scm_credentials) = ancillary_data_vec.pop().unwrap() { + let cred_vec = Vec::from_iter(scm_credentials); + assert_eq!(cred_vec.len(), 1); + assert_eq!(cred1.pid, cred_vec[0].pid); + assert_eq!(cred1.uid, cred_vec[0].uid); + assert_eq!(cred1.gid, cred_vec[0].gid); + } else { + assert!(false); + } +} + +#[test] +fn test_send_vectored_with_ancillary_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + + let mut buf1 = [1; 8]; + let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; + + let mut ancillary1_buffer = [0; 128]; + let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); + assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..])); + + or_panic!(bsock1.connect(&path2)); + let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); + assert_eq!(usize, 8); + + let mut buf2 = [0; 8]; + let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; + + let mut ancillary2_buffer = [0; 128]; + let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); + + let (usize, truncated) = + or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); + assert_eq!(usize, 8); + assert_eq!(truncated, false); + assert_eq!(buf1, buf2); + + let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); + assert_eq!(ancillary_data_vec.len(), 1); + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() { + let fd_vec = Vec::from_iter(scm_rights); + assert_eq!(fd_vec.len(), 1); + unsafe { + libc::close(fd_vec[0]); + } + } else { + assert!(false); + } +} From 6f82ddf18e3c13a79e3188591a2c386fc052aed1 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 22 Aug 2020 20:25:43 +0200 Subject: [PATCH 003/274] Add AncillaryError --- library/std/src/sys/unix/ext/net/ancillary.rs | 53 ++++++++++++------- library/std/src/sys/unix/ext/net/datagram.rs | 8 +-- library/std/src/sys/unix/ext/net/stream.rs | 4 +- library/std/src/sys/unix/ext/net/test.rs | 8 +-- 4 files changed, 44 insertions(+), 29 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 4e584cb143f..77214801e3e 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -1,3 +1,4 @@ +use crate::convert::TryFrom; use crate::io::{self, IoSliceMut}; use crate::mem; use crate::os::unix::io::RawFd; @@ -145,6 +146,13 @@ impl<'a> Iterator for ScmCredentials<'a> { } } +#[non_exhaustive] +#[derive(Debug)] +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +pub enum AncillaryError { + Unknown { cmsg_level: i32, cmsg_type: i32 }, +} + #[cfg(any( target_os = "haiku", target_os = "solaris", @@ -240,17 +248,19 @@ impl<'a> AncillaryData<'a> { target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -impl<'a> AncillaryData<'a> { - fn from(cmsg: &'a libc::cmsghdr) -> Self { +impl<'a> TryFrom<&'a libc::cmsghdr> for AncillaryData<'a> { + type Error = AncillaryError; + + fn try_from(cmsg: &'a libc::cmsghdr) -> Result { unsafe { let cmsg_len_zero = libc::CMSG_LEN(0) as usize; let data_len = (*cmsg).cmsg_len - cmsg_len_zero; let data = libc::CMSG_DATA(cmsg).cast(); let data = from_raw_parts(data, data_len); - if (*cmsg).cmsg_level == libc::SOL_SOCKET { - match (*cmsg).cmsg_type { - libc::SCM_RIGHTS => AncillaryData::as_rights(data), + match (*cmsg).cmsg_level { + libc::SOL_SOCKET => match (*cmsg).cmsg_type { + libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)), #[cfg(any( target_os = "linux", target_os = "android", @@ -258,7 +268,7 @@ impl<'a> AncillaryData<'a> { target_os = "fuchsia", target_env = "uclibc", ))] - libc::SCM_CREDENTIALS => AncillaryData::as_credentials(data), + libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), #[cfg(any( target_os = "netbsd", target_os = "openbsd", @@ -267,11 +277,14 @@ impl<'a> AncillaryData<'a> { target_os = "macos", target_os = "ios", ))] - libc::SCM_CREDS => AncillaryData::as_credentials(data), - _ => panic!("Unknown cmsg type"), + libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)), + cmsg_type => { + Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type }) + } + }, + cmsg_level => { + Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type }) } - } else { - panic!("Unknown cmsg level"); } } } @@ -317,9 +330,9 @@ pub struct Messages<'a> { ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for Messages<'a> { - type Item = AncillaryData<'a>; + type Item = Result, AncillaryError>; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option { unsafe { let msg = libc::msghdr { msg_name: null_mut(), @@ -339,8 +352,8 @@ impl<'a> Iterator for Messages<'a> { let cmsg = cmsg.as_ref()?; self.current = Some(cmsg); - let ancillary_data = AncillaryData::from(cmsg); - Some(ancillary_data) + let ancillary_result = AncillaryData::try_from(cmsg); + Some(ancillary_result) } } } @@ -364,8 +377,8 @@ impl<'a> Iterator for Messages<'a> { /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; /// -/// for ancillary_data in ancillary.messages() { -/// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { +/// for ancillary_result in ancillary.messages() { +/// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } @@ -585,8 +598,8 @@ impl<'a> SocketAncillary<'a> { /// let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..]; /// /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } @@ -596,8 +609,8 @@ impl<'a> SocketAncillary<'a> { /// ancillary.clear(); /// /// sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index e5630127ccb..e2fa65572e1 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -343,8 +343,8 @@ impl UnixDatagram { /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?; /// println!("received {}", size); - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } @@ -391,8 +391,8 @@ impl UnixDatagram { /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; /// println!("received {}", size); - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 75b91902668..d144c41de3c 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -451,8 +451,8 @@ impl UnixStream { /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?; /// println!("received {}", size); - /// for ancillary_data in ancillary.messages() { - /// if let AncillaryData::ScmRights(scm_rights) = ancillary_data { + /// for ancillary_result in ancillary.messages() { + /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { /// println!("receive file descriptor: {}", fd); /// } diff --git a/library/std/src/sys/unix/ext/net/test.rs b/library/std/src/sys/unix/ext/net/test.rs index 724d73c9b1e..3be9bb48583 100644 --- a/library/std/src/sys/unix/ext/net/test.rs +++ b/library/std/src/sys/unix/ext/net/test.rs @@ -481,7 +481,7 @@ fn test_send_vectored_fds_unix_stream() { let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); assert_eq!(ancillary_data_vec.len(), 1); - if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { let fd_vec = Vec::from_iter(scm_rights); assert_eq!(fd_vec.len(), 1); unsafe { @@ -551,7 +551,9 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); assert_eq!(ancillary_data_vec.len(), 1); - if let AncillaryData::ScmCredentials(scm_credentials) = ancillary_data_vec.pop().unwrap() { + if let AncillaryData::ScmCredentials(scm_credentials) = + ancillary_data_vec.pop().unwrap().unwrap() + { let cred_vec = Vec::from_iter(scm_credentials); assert_eq!(cred_vec.len(), 1); assert_eq!(cred1.pid, cred_vec[0].pid); @@ -596,7 +598,7 @@ fn test_send_vectored_with_ancillary_unix_datagram() { let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); assert_eq!(ancillary_data_vec.len(), 1); - if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { let fd_vec = Vec::from_iter(scm_rights); assert_eq!(fd_vec.len(), 1); unsafe { From e6984eee6f04a63dea3441dd1aec7d2f81e98e6d Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 23 Aug 2020 14:34:12 +0200 Subject: [PATCH 004/274] Add UCred struct --- library/std/src/sys/unix/ext/net/ancillary.rs | 49 +++++++++++++++++-- library/std/src/sys/unix/ext/net/test.rs | 13 +++-- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 77214801e3e..7d0f43ab87f 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -64,6 +64,47 @@ pub(super) fn send_vectored_with_ancillary_to( } } +#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[derive(Clone)] +pub struct UCred(libc::ucred); + +impl UCred { + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn new() -> UCred { + UCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_pid(&mut self, pid: i32) { + self.0.pid = pid; + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn get_pid(&self) -> i32 { + self.0.pid + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_uid(&mut self, uid: u32) { + self.0.uid = uid; + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn get_uid(&self) -> u32 { + self.0.uid + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_gid(&mut self, gid: u32) { + self.0.gid = gid; + } + + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn get_gid(&self) -> u32 { + self.0.gid + } +} + #[cfg(any( target_os = "haiku", target_os = "solaris", @@ -139,10 +180,10 @@ pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for ScmCredentials<'a> { - type Item = libc::ucred; + type Item = UCred; - fn next(&mut self) -> Option { - self.0.next() + fn next(&mut self) -> Option { + Some(UCred(self.0.next()?)) } } @@ -550,7 +591,7 @@ impl<'a> SocketAncillary<'a> { target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn add_creds(&mut self, creds: &[libc::ucred]) -> bool { + pub fn add_creds(&mut self, creds: &[UCred]) -> bool { self.truncated = false; add_to_ancillary_data( &mut self.buffer, diff --git a/library/std/src/sys/unix/ext/net/test.rs b/library/std/src/sys/unix/ext/net/test.rs index 3be9bb48583..a39b97f2c31 100644 --- a/library/std/src/sys/unix/ext/net/test.rs +++ b/library/std/src/sys/unix/ext/net/test.rs @@ -529,8 +529,11 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); - let cred1 = libc::ucred { pid: getpid(), uid: getuid(), gid: getgid() }; - assert!(ancillary1.add_creds(&[cred1][..])); + let mut cred1 = UCred::new(); + cred1.set_pid(getpid()); + cred1.set_uid(getuid()); + cred1.set_gid(getgid()); + assert!(ancillary1.add_creds(&[cred1.clone()][..])); let usize = or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); @@ -556,9 +559,9 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { { let cred_vec = Vec::from_iter(scm_credentials); assert_eq!(cred_vec.len(), 1); - assert_eq!(cred1.pid, cred_vec[0].pid); - assert_eq!(cred1.uid, cred_vec[0].uid); - assert_eq!(cred1.gid, cred_vec[0].gid); + assert_eq!(cred1.get_pid(), cred_vec[0].get_pid()); + assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); + assert_eq!(cred1.get_gid(), cred_vec[0].get_gid()); } else { assert!(false); } From 8783b06bd2c5165cbb356d06bbaf943fae6937a2 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 23 Aug 2020 14:50:54 +0200 Subject: [PATCH 005/274] Move `add_to_ancillary_data` and `AncillaryDataIter` to ancillary.rs --- library/std/src/sys/unix/ext/net/ancillary.rs | 91 ++++++++++++++++++- library/std/src/sys/unix/net.rs | 82 ----------------- 2 files changed, 86 insertions(+), 87 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 7d0f43ab87f..03fd288b870 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -1,12 +1,13 @@ use crate::convert::TryFrom; use crate::io::{self, IoSliceMut}; -use crate::mem; +use crate::marker::PhantomData; +use crate::mem::{size_of, zeroed}; use crate::os::unix::io::RawFd; use crate::path::Path; use crate::ptr::null_mut; use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; -use crate::sys::unix::net::{add_to_ancillary_data, AncillaryDataIter, Socket}; +use crate::sys::unix::net::Socket; pub(super) fn recv_vectored_with_ancillary_from( socket: &Socket, @@ -14,11 +15,11 @@ pub(super) fn recv_vectored_with_ancillary_from( ancillary: &mut SocketAncillary<'_>, ) -> io::Result<(usize, bool, io::Result)> { unsafe { - let mut msg_name: libc::sockaddr_un = mem::zeroed(); + let mut msg_name: libc::sockaddr_un = zeroed(); let mut msg = libc::msghdr { msg_name: &mut msg_name as *mut _ as *mut _, - msg_namelen: mem::size_of::() as libc::socklen_t, + msg_namelen: size_of::() as libc::socklen_t, msg_iov: bufs.as_mut_ptr().cast(), msg_iovlen: bufs.len(), msg_control: ancillary.buffer.as_mut_ptr().cast(), @@ -46,7 +47,7 @@ pub(super) fn send_vectored_with_ancillary_to( ) -> io::Result { unsafe { let (mut msg_name, msg_namelen) = - if let Some(path) = path { sockaddr_un(path)? } else { (mem::zeroed(), 0) }; + if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) }; let mut msg = libc::msghdr { msg_name: &mut msg_name as *mut _ as *mut _, @@ -64,6 +65,86 @@ pub(super) fn send_vectored_with_ancillary_to( } } +fn add_to_ancillary_data( + buffer: &mut [u8], + length: &mut usize, + source: &[T], + cmsg_level: libc::c_int, + cmsg_type: libc::c_int, +) -> bool { + let len = (source.len() * size_of::()) as u32; + + unsafe { + let additional_space = libc::CMSG_SPACE(len) as usize; + if *length + additional_space > buffer.len() { + return false; + } + + libc::memset(buffer[*length..].as_mut_ptr().cast(), 0, additional_space); + + *length += additional_space; + + let msg = libc::msghdr { + msg_name: null_mut(), + msg_namelen: 0, + msg_iov: null_mut(), + msg_iovlen: 0, + msg_control: buffer.as_mut_ptr().cast(), + msg_controllen: *length, + msg_flags: 0, + }; + + let mut cmsg = libc::CMSG_FIRSTHDR(&msg); + let mut previous_cmsg = cmsg; + while !cmsg.is_null() { + previous_cmsg = cmsg; + cmsg = libc::CMSG_NXTHDR(&msg, cmsg); + } + + if previous_cmsg.is_null() { + return false; + } + + (*previous_cmsg).cmsg_level = cmsg_level; + (*previous_cmsg).cmsg_type = cmsg_type; + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(len) as usize; + + let data = libc::CMSG_DATA(previous_cmsg).cast(); + + libc::memcpy(data, source.as_ptr().cast(), len as usize); + } + true +} + +struct AncillaryDataIter<'a, T> { + data: &'a [u8], + phantom: crate::marker::PhantomData, +} + +impl<'a, T> AncillaryDataIter<'a, T> { + pub fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> { + AncillaryDataIter { data, phantom: PhantomData } + } +} + +impl<'a, T> Iterator for AncillaryDataIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + unsafe { + let mut unit = zeroed(); + if size_of::() <= self.data.len() { + let unit_ptr: *mut T = &mut unit; + libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), size_of::()); + self.data = &self.data[size_of::()..]; + Some(unit) + } else { + None + } + } + } +} + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] #[derive(Clone)] pub struct UCred(libc::ucred); diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index e067edd3774..1a514ed0238 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -1,10 +1,8 @@ use crate::cmp; use crate::ffi::CStr; use crate::io::{self, IoSlice, IoSliceMut}; -use crate::marker::PhantomData; use crate::mem; use crate::net::{Shutdown, SocketAddr}; -use crate::ptr::null_mut; use crate::str; use crate::sys::fd::FileDesc; use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; @@ -20,86 +18,6 @@ pub extern crate libc as netc; pub type wrlen_t = size_t; -pub struct AncillaryDataIter<'a, T> { - data: &'a [u8], - phantom: crate::marker::PhantomData, -} - -impl<'a, T> AncillaryDataIter<'a, T> { - pub fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> { - AncillaryDataIter { data, phantom: PhantomData } - } -} - -impl<'a, T> Iterator for AncillaryDataIter<'a, T> { - type Item = T; - - fn next(&mut self) -> Option { - unsafe { - let mut unit = mem::zeroed(); - if mem::size_of::() <= self.data.len() { - let unit_ptr: *mut T = &mut unit; - libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), mem::size_of::()); - self.data = &self.data[mem::size_of::()..]; - Some(unit) - } else { - None - } - } - } -} - -pub fn add_to_ancillary_data( - buffer: &mut [u8], - length: &mut usize, - source: &[T], - cmsg_level: libc::c_int, - cmsg_type: libc::c_int, -) -> bool { - let len = (source.len() * mem::size_of::()) as u32; - - unsafe { - let additional_space = libc::CMSG_SPACE(len) as usize; - if *length + additional_space > buffer.len() { - return false; - } - - libc::memset(buffer[*length..].as_mut_ptr().cast(), 0, additional_space); - - *length += additional_space; - - let msg = libc::msghdr { - msg_name: null_mut(), - msg_namelen: 0, - msg_iov: null_mut(), - msg_iovlen: 0, - msg_control: buffer.as_mut_ptr().cast(), - msg_controllen: *length, - msg_flags: 0, - }; - - let mut cmsg = libc::CMSG_FIRSTHDR(&msg); - let mut previous_cmsg = cmsg; - while !cmsg.is_null() { - previous_cmsg = cmsg; - cmsg = libc::CMSG_NXTHDR(&msg, cmsg); - } - - if previous_cmsg.is_null() { - return false; - } - - (*previous_cmsg).cmsg_level = cmsg_level; - (*previous_cmsg).cmsg_type = cmsg_type; - (*previous_cmsg).cmsg_len = libc::CMSG_LEN(len) as usize; - - let data = libc::CMSG_DATA(previous_cmsg).cast(); - - libc::memcpy(data, source.as_ptr().cast(), len as usize); - } - true -} - pub struct Socket(FileDesc); pub fn init() {} From 8784ffbb4e45c6081369805fccd34b77f3ef8ec1 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:09:35 +0200 Subject: [PATCH 006/274] Using `read_unaligned` instead of `memcpy`. --- library/std/src/sys/unix/ext/net/ancillary.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 03fd288b870..039cdd8ff91 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -4,7 +4,7 @@ use crate::marker::PhantomData; use crate::mem::{size_of, zeroed}; use crate::os::unix::io::RawFd; use crate::path::Path; -use crate::ptr::null_mut; +use crate::ptr::{null_mut, read_unaligned}; use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; @@ -131,16 +131,14 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { type Item = T; fn next(&mut self) -> Option { - unsafe { - let mut unit = zeroed(); - if size_of::() <= self.data.len() { - let unit_ptr: *mut T = &mut unit; - libc::memcpy(unit_ptr.cast(), self.data.as_ptr().cast(), size_of::()); + if size_of::() <= self.data.len() { + unsafe { + let unit = read_unaligned(self.data.as_ptr().cast()); self.data = &self.data[size_of::()..]; Some(unit) - } else { - None } + } else { + None } } } From e1084052a7f6d65a5c5e9656ba507ba42c4caacb Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:14:10 +0200 Subject: [PATCH 007/274] Replace `TryFrom` of `AncillaryData` with a private method. --- library/std/src/sys/unix/ext/net/ancillary.rs | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 039cdd8ff91..142526f3a41 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -349,29 +349,24 @@ impl<'a> AncillaryData<'a> { let scm_credentials = ScmCredentials(ancillary_data_iter); AncillaryData::ScmCredentials(scm_credentials) } -} -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] -impl<'a> TryFrom<&'a libc::cmsghdr> for AncillaryData<'a> { - type Error = AncillaryError; - - fn try_from(cmsg: &'a libc::cmsghdr) -> Result { + #[cfg(any( + target_os = "haiku", + target_os = "solaris", + target_os = "illumos", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + target_env = "uclibc", + ))] + fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { unsafe { let cmsg_len_zero = libc::CMSG_LEN(0) as usize; let data_len = (*cmsg).cmsg_len - cmsg_len_zero; @@ -472,7 +467,7 @@ impl<'a> Iterator for Messages<'a> { let cmsg = cmsg.as_ref()?; self.current = Some(cmsg); - let ancillary_result = AncillaryData::try_from(cmsg); + let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg); Some(ancillary_result) } } From 3dfab6fb6443983d22fa075920a3d66dd54817c7 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:38:25 +0200 Subject: [PATCH 008/274] Add integer overflow check --- library/std/src/sys/unix/ext/net/ancillary.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 142526f3a41..8ba389762fb 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -72,7 +72,15 @@ fn add_to_ancillary_data( cmsg_level: libc::c_int, cmsg_type: libc::c_int, ) -> bool { - let len = (source.len() * size_of::()) as u32; + let len = if let Some(len) = source.len().checked_mul(size_of::()) { + if let Ok(len) = u32::try_from(len) { + len + } else { + return false; + } + } else { + return false; + }; unsafe { let additional_space = libc::CMSG_SPACE(len) as usize; From b82f29d780ae884bc0658a45241d4dde25a6c989 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:43:41 +0200 Subject: [PATCH 009/274] Remove `Clone` trait bound in `add_to_ancillary_data` --- library/std/src/sys/unix/ext/net/ancillary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 8ba389762fb..6175c0ae343 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -65,7 +65,7 @@ pub(super) fn send_vectored_with_ancillary_to( } } -fn add_to_ancillary_data( +fn add_to_ancillary_data( buffer: &mut [u8], length: &mut usize, source: &[T], From 4c929a00ee6f4a8c4904f567d73e1cf6c333617c Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 18:48:27 +0200 Subject: [PATCH 010/274] Remove lifetime annotation in `messages` function --- library/std/src/sys/unix/ext/net/ancillary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 6175c0ae343..8c61c8dec54 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -564,7 +564,7 @@ impl<'a> SocketAncillary<'a> { target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn messages(&'a self) -> Messages<'a> { + pub fn messages(&self) -> Messages<'_> { Messages { buffer: &self.buffer[..self.length], current: None } } From 1f3195a5df18d8a7a886fca17371612f5f6847a3 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 25 Aug 2020 19:33:33 +0200 Subject: [PATCH 011/274] Remove inner function in `bind`, `connect` and `send_to` --- library/std/src/sys/unix/ext/net/datagram.rs | 52 ++++++++------------ library/std/src/sys/unix/ext/net/listener.rs | 15 +++--- library/std/src/sys/unix/ext/net/stream.rs | 15 +++--- 3 files changed, 33 insertions(+), 49 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index e2fa65572e1..7225b3e5f66 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -85,17 +85,14 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let socket = UnixDatagram::unbound()?; - let (addr, len) = sockaddr_un(path)?; + unsafe { + let socket = UnixDatagram::unbound()?; + let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; - Ok(socket) - } + Ok(socket) } - inner(path.as_ref()) } /// Creates a Unix Datagram socket which is not bound to any address. @@ -170,16 +167,12 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn connect>(&self, path: P) -> io::Result<()> { - fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; + unsafe { + let (addr, len) = sockaddr_un(path.as_ref())?; - Ok(()) - } + cvt(libc::connect(*self.0.as_inner(), &addr as *const _ as *const _, len))?; } - inner(self, path.as_ref()) + Ok(()) } /// Creates a new independently owned handle to the underlying socket. @@ -430,22 +423,19 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { - fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - let count = cvt(libc::sendto( - *d.0.as_inner(), - buf.as_ptr() as *const _, - buf.len(), - MSG_NOSIGNAL, - &addr as *const _ as *const _, - len, - ))?; - Ok(count as usize) - } + unsafe { + let (addr, len) = sockaddr_un(path.as_ref())?; + + let count = cvt(libc::sendto( + *self.0.as_inner(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &addr as *const _ as *const _, + len, + ))?; + Ok(count as usize) } - inner(self, buf, path.as_ref()) } /// Sends data on the socket to the socket's peer. diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs index 84386ea6381..2bedfb74dcb 100644 --- a/library/std/src/sys/unix/ext/net/listener.rs +++ b/library/std/src/sys/unix/ext/net/listener.rs @@ -71,18 +71,15 @@ impl UnixListener { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(*inner.as_inner(), 128))?; - Ok(UnixListener(inner)) - } + Ok(UnixListener(inner)) } - inner(path.as_ref()) } /// Accepts a new incoming connection to this listener. diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index d144c41de3c..091026d6cfc 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -87,16 +87,13 @@ impl UnixStream { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn connect>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path.as_ref())?; + + cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) } - inner(path.as_ref()) } /// Creates an unnamed pair of connected sockets. From 6ed9bface6f86cc6ddf50aae9f94389695f84184 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Thu, 27 Aug 2020 16:03:41 +0200 Subject: [PATCH 012/274] Use `fill` instead of `memset` --- library/std/src/lib.rs | 1 + library/std/src/sys/unix/ext/net/ancillary.rs | 25 ++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index d4cc2cd239b..42397de2b63 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -299,6 +299,7 @@ #![feature(rustc_private)] #![feature(shrink_to)] #![feature(slice_concat_ext)] +#![feature(slice_fill)] #![feature(slice_internals)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 8c61c8dec54..4f821a12e12 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -72,9 +72,9 @@ fn add_to_ancillary_data( cmsg_level: libc::c_int, cmsg_type: libc::c_int, ) -> bool { - let len = if let Some(len) = source.len().checked_mul(size_of::()) { - if let Ok(len) = u32::try_from(len) { - len + let source_len = if let Some(source_len) = source.len().checked_mul(size_of::()) { + if let Ok(source_len) = u32::try_from(source_len) { + source_len } else { return false; } @@ -83,14 +83,21 @@ fn add_to_ancillary_data( }; unsafe { - let additional_space = libc::CMSG_SPACE(len) as usize; - if *length + additional_space > buffer.len() { + let additional_space = libc::CMSG_SPACE(source_len) as usize; + + let new_length = if let Some(new_length) = additional_space.checked_add(*length) { + new_length + } else { + return false; + }; + + if new_length > buffer.len() { return false; } - libc::memset(buffer[*length..].as_mut_ptr().cast(), 0, additional_space); + buffer[*length..new_length].fill(0); - *length += additional_space; + *length = new_length; let msg = libc::msghdr { msg_name: null_mut(), @@ -115,11 +122,11 @@ fn add_to_ancillary_data( (*previous_cmsg).cmsg_level = cmsg_level; (*previous_cmsg).cmsg_type = cmsg_type; - (*previous_cmsg).cmsg_len = libc::CMSG_LEN(len) as usize; + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as usize; let data = libc::CMSG_DATA(previous_cmsg).cast(); - libc::memcpy(data, source.as_ptr().cast(), len as usize); + libc::memcpy(data, source.as_ptr().cast(), source_len as usize); } true } From 07ed6afc6de728c6ea8d021156af318172b1dbbc Mon Sep 17 00:00:00 2001 From: LinkTed Date: Thu, 27 Aug 2020 16:09:57 +0200 Subject: [PATCH 013/274] Remove unnecessary path --- library/std/src/sys/unix/ext/net/ancillary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 4f821a12e12..84a73ef8afd 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -133,7 +133,7 @@ fn add_to_ancillary_data( struct AncillaryDataIter<'a, T> { data: &'a [u8], - phantom: crate::marker::PhantomData, + phantom: PhantomData, } impl<'a, T> AncillaryDataIter<'a, T> { From 53791b3ff4322aec2a82a84952be91d1be4058b5 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 28 Aug 2020 18:41:48 +0200 Subject: [PATCH 014/274] Move conditional compilation to the upper module and sort the target OS list alphabetically --- library/std/src/sys/unix/ext/net/ancillary.rs | 260 +++++------------- library/std/src/sys/unix/ext/net/datagram.rs | 48 ++++ library/std/src/sys/unix/ext/net/mod.rs | 32 +++ library/std/src/sys/unix/ext/net/stream.rs | 48 ++++ 4 files changed, 199 insertions(+), 189 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 84a73ef8afd..1da3370b07d 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -158,10 +158,36 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } } +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", +))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] #[derive(Clone)] pub struct UCred(libc::ucred); +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", +))] impl UCred { #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn new() -> UCred { @@ -199,41 +225,9 @@ impl UCred { } } -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for ScmRights<'a> { type Item = RawFd; @@ -244,32 +238,32 @@ impl<'a> Iterator for ScmRights<'a> { } #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] @@ -288,58 +282,26 @@ pub enum AncillaryError { Unknown { cmsg_level: i32, cmsg_type: i32 }, } -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", target_env = "uclibc", ))] ScmCredentials(ScmCredentials<'a>), } impl<'a> AncillaryData<'a> { - #[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] fn as_rights(data: &'a [u8]) -> Self { let ancillary_data_iter = AncillaryDataIter::new(data); let scm_rights = ScmRights(ancillary_data_iter); @@ -347,16 +309,16 @@ impl<'a> AncillaryData<'a> { } #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", target_env = "uclibc", ))] fn as_credentials(data: &'a [u8]) -> Self { @@ -365,22 +327,6 @@ impl<'a> AncillaryData<'a> { AncillaryData::ScmCredentials(scm_credentials) } - #[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { unsafe { let cmsg_len_zero = libc::CMSG_LEN(0) as usize; @@ -392,20 +338,20 @@ impl<'a> AncillaryData<'a> { libc::SOL_SOCKET => match (*cmsg).cmsg_type { libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)), #[cfg(any( - target_os = "linux", target_os = "android", target_os = "emscripten", target_os = "fuchsia", + target_os = "linux", target_env = "uclibc", ))] libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", target_os = "dragonfly", - target_os = "macos", + target_os = "freebsd", target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", ))] libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)), cmsg_type => { @@ -420,44 +366,12 @@ impl<'a> AncillaryData<'a> { } } -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub struct Messages<'a> { buffer: &'a [u8], current: Option<&'a libc::cmsghdr>, } -#[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", -))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for Messages<'a> { type Item = Result, AncillaryError>; @@ -554,22 +468,6 @@ impl<'a> SocketAncillary<'a> { self.length } - #[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn messages(&self) -> Messages<'_> { Messages { buffer: &self.buffer[..self.length], current: None } @@ -631,22 +529,6 @@ impl<'a> SocketAncillary<'a> { /// Ok(()) /// } /// ``` - #[cfg(any( - target_os = "haiku", - target_os = "solaris", - target_os = "illumos", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_env = "uclibc", - ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn add_fds(&mut self, fds: &[RawFd]) -> bool { self.truncated = false; @@ -667,16 +549,16 @@ impl<'a> SocketAncillary<'a> { /// and type `SCM_CREDENTIALS`. /// #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios", - target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", + target_os = "freebsd", target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] @@ -688,20 +570,20 @@ impl<'a> SocketAncillary<'a> { creds, libc::SOL_SOCKET, #[cfg(any( - target_os = "linux", target_os = "android", target_os = "emscripten", target_os = "fuchsia", + target_os = "linux", target_env = "uclibc", ))] libc::SCM_CREDENTIALS, #[cfg(any( - target_os = "netbsd", - target_os = "openbsd", - target_os = "freebsd", target_os = "dragonfly", - target_os = "macos", + target_os = "freebsd", target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", ))] libc::SCM_CREDS, ) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 7225b3e5f66..5df45e6465b 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -4,6 +4,22 @@ use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::Path; use crate::sys::unix::cvt; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +))] use crate::sys::unix::ext::net::ancillary::{ recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, }; @@ -346,6 +362,22 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn recv_vectored_with_ancillary_from( &self, @@ -394,6 +426,22 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn recv_vectored_with_ancillary( &self, diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index 93b72df520a..125432b2b71 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -3,6 +3,22 @@ #![stable(feature = "unix_socket", since = "1.10.0")] mod addr; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +))] mod ancillary; mod datagram; mod listener; @@ -13,6 +29,22 @@ mod test; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::addr::*; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub use self::ancillary::*; #[stable(feature = "unix_socket", since = "1.10.0")] diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 091026d6cfc..907832399d8 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -16,6 +16,22 @@ use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +))] use crate::sys::unix::ext::net::ancillary::{ recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, }; @@ -458,6 +474,22 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn recv_vectored_with_ancillary( &self, @@ -498,6 +530,22 @@ impl UnixStream { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn send_vectored_with_ancillary( &self, From 1869141e5444c8f53e7ef625e1b3f26002fff43c Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 28 Aug 2020 19:15:53 +0200 Subject: [PATCH 015/274] Reduce impl trait by using macro in `raw_fd.rs` --- library/std/src/sys/unix/ext/net/raw_fd.rs | 95 ++++++++-------------- 1 file changed, 34 insertions(+), 61 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/raw_fd.rs b/library/std/src/sys/unix/ext/net/raw_fd.rs index 059c0fec06f..c42fee4c73b 100644 --- a/library/std/src/sys/unix/ext/net/raw_fd.rs +++ b/library/std/src/sys/unix/ext/net/raw_fd.rs @@ -2,66 +2,39 @@ use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; use crate::{net, sys}; -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} +macro_rules! impl_as_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl AsRawFd for net::$t { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } + } + )*}; +} +impl_as_raw_fd! { TcpStream TcpListener UdpSocket } -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} +macro_rules! impl_from_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "from_raw_os", since = "1.1.0")] + impl FromRawFd for net::$t { + unsafe fn from_raw_fd(fd: RawFd) -> net::$t { + let socket = sys::net::Socket::from_inner(fd); + net::$t::from_inner(sys_common::net::$t::from_inner(socket)) + } + } + )*}; +} +impl_from_raw_fd! { TcpStream TcpListener UdpSocket } -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} +macro_rules! impl_into_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "into_raw_os", since = "1.4.0")] + impl IntoRawFd for net::$t { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } + } + )*}; +} +impl_into_raw_fd! { TcpStream TcpListener UdpSocket } From 46764d48bb556c0e3c66fe99cf63d536e22c9a0d Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 29 Aug 2020 19:22:03 +0200 Subject: [PATCH 016/274] Add doc(cfg(...)) --- library/std/src/sys/unix/ext/net/ancillary.rs | 7 +++++++ library/std/src/sys/unix/ext/net/mod.rs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 1da3370b07d..eba884ad8b4 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -159,6 +159,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -176,6 +177,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { pub struct UCred(libc::ucred); #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -238,6 +240,7 @@ impl<'a> Iterator for ScmRights<'a> { } #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -254,6 +257,7 @@ impl<'a> Iterator for ScmRights<'a> { pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -286,6 +290,7 @@ pub enum AncillaryError { pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -309,6 +314,7 @@ impl<'a> AncillaryData<'a> { } #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", @@ -549,6 +555,7 @@ impl<'a> SocketAncillary<'a> { /// and type `SCM_CREDENTIALS`. /// #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index 125432b2b71..d1c943b4f2f 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -3,7 +3,24 @@ #![stable(feature = "unix_socket", since = "1.10.0")] mod addr; +#[doc(cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_env = "uclibc", +)))] #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", From a91fd7328c5742360d0c50e3516e173e61bf7b78 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 29 Aug 2020 20:03:18 +0200 Subject: [PATCH 017/274] Add doc comments --- library/std/src/sys/unix/ext/net/ancillary.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index eba884ad8b4..bfca7ae4a9b 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -158,6 +158,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } } +/// Unix credential. #[cfg(any( doc, target_os = "android", @@ -191,42 +192,54 @@ pub struct UCred(libc::ucred); target_env = "uclibc", ))] impl UCred { + /// Create a Unix credential struct. + /// + /// PID, UID and GID is set to 0. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn new() -> UCred { UCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) } + /// Set the PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn set_pid(&mut self, pid: i32) { self.0.pid = pid; } + /// Get the current PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn get_pid(&self) -> i32 { self.0.pid } + /// Set the UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn set_uid(&mut self, uid: u32) { self.0.uid = uid; } + /// Get the current UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn get_uid(&self) -> u32 { self.0.uid } + /// Set the GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn set_gid(&mut self, gid: u32) { self.0.gid = gid; } + /// Get the current GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn get_gid(&self) -> u32 { self.0.gid } } +/// This control message contains file descriptors. +/// +/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); @@ -239,6 +252,9 @@ impl<'a> Iterator for ScmRights<'a> { } } +/// This control message contains unix credentials. +/// +/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. #[cfg(any( doc, target_os = "android", @@ -279,6 +295,7 @@ impl<'a> Iterator for ScmCredentials<'a> { } } +/// The error type which is returned from parsing the type a control message. #[non_exhaustive] #[derive(Debug)] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] @@ -286,6 +303,7 @@ pub enum AncillaryError { Unknown { cmsg_level: i32, cmsg_type: i32 }, } +/// This enum represent one control message of variable type. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), @@ -372,6 +390,7 @@ impl<'a> AncillaryData<'a> { } } +/// This struct is used to iterate through the control messages. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub struct Messages<'a> { buffer: &'a [u8], @@ -474,6 +493,7 @@ impl<'a> SocketAncillary<'a> { self.length } + /// Returns the iterator of the control messages. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn messages(&self) -> Messages<'_> { Messages { buffer: &self.buffer[..self.length], current: None } @@ -552,7 +572,7 @@ impl<'a> SocketAncillary<'a> { /// The function returns `true` if there was enough space in the buffer. /// If there was not enough space then no credentials was appended. /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` - /// and type `SCM_CREDENTIALS`. + /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. /// #[cfg(any( doc, From 19c5fdda7c76d57b07d85054400ca14bf3849023 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 1 Sep 2020 16:32:13 +0200 Subject: [PATCH 018/274] Rename `test.rs` to `tests.rs` --- library/std/src/sys/unix/ext/net/mod.rs | 2 +- library/std/src/sys/unix/ext/net/test.rs | 613 ---------------------- library/std/src/sys/unix/ext/net/tests.rs | 29 +- 3 files changed, 19 insertions(+), 625 deletions(-) delete mode 100644 library/std/src/sys/unix/ext/net/test.rs diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index d1c943b4f2f..c37e856e5bc 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -42,7 +42,7 @@ mod listener; mod raw_fd; mod stream; #[cfg(all(test, not(target_os = "emscripten")))] -mod test; +mod tests; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::addr::*; diff --git a/library/std/src/sys/unix/ext/net/test.rs b/library/std/src/sys/unix/ext/net/test.rs deleted file mode 100644 index a39b97f2c31..00000000000 --- a/library/std/src/sys/unix/ext/net/test.rs +++ /dev/null @@ -1,613 +0,0 @@ -use super::*; -use crate::io::prelude::*; -use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; -use crate::iter::FromIterator; -use crate::mem; -use crate::sys::unix::ext::io::AsRawFd; -use crate::sys_common::io::test::tmpdir; -use crate::thread; -use crate::time::Duration; - -macro_rules! or_panic { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{}", e), - } - }; -} - -#[test] -fn basic() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world!"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - let mut buf = [0; 5]; - or_panic!(stream.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(stream.write_all(msg2)); - }); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname()); - or_panic!(stream.write_all(msg1)); - let mut buf = vec![]; - or_panic!(stream.read_to_end(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(stream); - - thread.join().unwrap(); -} - -#[test] -fn vectored() { - let (mut s1, mut s2) = or_panic!(UnixStream::pair()); - - let len = or_panic!(s1.write_vectored(&[ - IoSlice::new(b"hello"), - IoSlice::new(b" "), - IoSlice::new(b"world!") - ],)); - assert_eq!(len, 12); - - let mut buf1 = [0; 6]; - let mut buf2 = [0; 7]; - let len = - or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)); - assert_eq!(len, 12); - assert_eq!(&buf1, b"hello "); - assert_eq!(&buf2, b"world!\0"); -} - -#[test] -fn pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (mut s1, mut s2) = or_panic!(UnixStream::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.write_all(msg2)); - }); - - or_panic!(s2.write_all(msg1)); - let mut buf = vec![]; - or_panic!(s2.read_to_end(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); -} - -#[test] -fn try_clone() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - or_panic!(stream.write_all(msg1)); - or_panic!(stream.write_all(msg2)); - }); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - let mut stream2 = or_panic!(stream.try_clone()); - - let mut buf = [0; 5]; - or_panic!(stream.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(stream2.read(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - - thread.join().unwrap(); -} - -#[test] -fn iter() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - for stream in listener.incoming().take(2) { - let mut stream = or_panic!(stream); - let mut buf = [0]; - or_panic!(stream.read(&mut buf)); - } - }); - - for _ in 0..2 { - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.write_all(&[0])); - } - - thread.join().unwrap(); -} - -#[test] -fn long_path() { - let dir = tmpdir(); - let socket_path = dir.path().join( - "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ - sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf", - ); - match UnixStream::connect(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixListener::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixDatagram::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } -} - -#[test] -fn timeouts() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let stream = or_panic!(UnixStream::connect(&socket_path)); - let dur = Duration::new(15410, 0); - - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.read_timeout())); - - assert_eq!(None, or_panic!(stream.write_timeout())); - - or_panic!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.write_timeout())); - - or_panic!(stream.set_read_timeout(None)); - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_write_timeout(None)); - assert_eq!(None, or_panic!(stream.write_timeout())); -} - -#[test] -fn test_read_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); -} - -#[test] -fn test_read_with_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut other_end = or_panic!(listener.accept()).0; - or_panic!(other_end.write_all(b"hello world")); - - let mut buf = [0; 11]; - or_panic!(stream.read(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); -} - -// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors -// when passed zero Durations -#[test] -fn test_unix_stream_timeout_zero_duration() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let stream = or_panic!(UnixStream::connect(&socket_path)); - - let result = stream.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = stream.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - drop(listener); -} - -#[test] -fn test_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::bind(&path2)); - - let msg = b"hello world"; - or_panic!(sock1.send_to(msg, &path2)); - let mut buf = [0; 11]; - or_panic!(sock2.recv_from(&mut buf)); - assert_eq!(msg, &buf[..]); -} - -#[test] -fn test_unnamed_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - - let msg = b"hello world"; - or_panic!(sock2.send_to(msg, &path1)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); -} - -#[test] -fn test_connect_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let bsock1 = or_panic!(UnixDatagram::bind(&path1)); - let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - let sock = or_panic!(UnixDatagram::unbound()); - or_panic!(sock.connect(&path1)); - - // Check send() - let msg = b"hello there"; - or_panic!(sock.send(msg)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); - - // Changing default socket works too - or_panic!(sock.connect(&path2)); - or_panic!(sock.send(msg)); - or_panic!(bsock2.recv_from(&mut buf)); -} - -#[test] -fn test_unix_datagram_recv() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - or_panic!(sock2.connect(&path1)); - - let msg = b"hello world"; - or_panic!(sock2.send(msg)); - let mut buf = [0; 11]; - let size = or_panic!(sock1.recv(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); -} - -#[test] -fn datagram_pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (s1, s2) = or_panic!(UnixDatagram::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.recv(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.send(msg2)); - }); - - or_panic!(s2.send(msg1)); - let mut buf = [0; 6]; - or_panic!(s2.recv(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); -} - -// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors -// when passed zero Durations -#[test] -fn test_unix_datagram_timeout_zero_duration() { - let dir = tmpdir(); - let path = dir.path().join("sock"); - - let datagram = or_panic!(UnixDatagram::bind(&path)); - - let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); -} - -#[test] -fn abstract_namespace_not_allowed() { - assert!(UnixStream::connect("\0asdf").is_err()); -} - -#[test] -fn test_unix_stream_peek() { - let (txdone, rxdone) = crate::sync::mpsc::channel(); - - let dir = tmpdir(); - let path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - or_panic!(stream.write_all(&[1, 3, 3, 7])); - or_panic!(rxdone.recv()); - }); - - let mut stream = or_panic!(UnixStream::connect(&path)); - let mut buf = [0; 10]; - for _ in 0..2 { - assert_eq!(or_panic!(stream.peek(&mut buf)), 4); - } - assert_eq!(or_panic!(stream.read(&mut buf)), 4); - - or_panic!(stream.set_nonblocking(true)); - match stream.peek(&mut buf) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error: {}", e), - } - - or_panic!(txdone.send(())); - thread.join().unwrap(); -} - -#[test] -fn test_unix_datagram_peek() { - let dir = tmpdir(); - let path1 = dir.path().join("sock"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - or_panic!(sock2.connect(&path1)); - - let msg = b"hello world"; - or_panic!(sock2.send(msg)); - for _ in 0..2 { - let mut buf = [0; 11]; - let size = or_panic!(sock1.peek(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); - } - - let mut buf = [0; 11]; - let size = or_panic!(sock1.recv(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); -} - -#[test] -fn test_unix_datagram_peek_from() { - let dir = tmpdir(); - let path1 = dir.path().join("sock"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - or_panic!(sock2.connect(&path1)); - - let msg = b"hello world"; - or_panic!(sock2.send(msg)); - for _ in 0..2 { - let mut buf = [0; 11]; - let (size, _) = or_panic!(sock1.peek_from(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); - } - - let mut buf = [0; 11]; - let size = or_panic!(sock1.recv(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); -} - -#[test] -fn test_send_vectored_fds_unix_stream() { - let (s1, s2) = or_panic!(UnixStream::pair()); - - let mut buf1 = [1; 8]; - let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; - - let mut ancillary1_buffer = [0; 128]; - let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); - assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..])); - - let usize = or_panic!(s1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); - assert_eq!(usize, 8); - - let mut buf2 = [0; 8]; - let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; - - let mut ancillary2_buffer = [0; 128]; - let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); - - let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); - assert_eq!(usize, 8); - assert_eq!(buf1, buf2); - - let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); - assert_eq!(ancillary_data_vec.len(), 1); - if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { - let fd_vec = Vec::from_iter(scm_rights); - assert_eq!(fd_vec.len(), 1); - unsafe { - libc::close(fd_vec[0]); - } - } else { - assert!(false); - } -} - -#[test] -fn test_send_vectored_with_ancillary_to_unix_datagram() { - fn getpid() -> libc::pid_t { - unsafe { libc::getpid() } - } - - fn getuid() -> libc::uid_t { - unsafe { libc::getuid() } - } - - fn getgid() -> libc::gid_t { - unsafe { libc::getgid() } - } - - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let bsock1 = or_panic!(UnixDatagram::bind(&path1)); - let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - - unsafe { - let optval: libc::c_int = 1; - libc::setsockopt( - bsock2.as_raw_fd(), - libc::SOL_SOCKET, - libc::SO_PASSCRED, - &optval as *const _ as *const _, - mem::size_of::() as u32, - ); - } - - let mut buf1 = [1; 8]; - let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; - - let mut ancillary1_buffer = [0; 128]; - let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); - let mut cred1 = UCred::new(); - cred1.set_pid(getpid()); - cred1.set_uid(getuid()); - cred1.set_gid(getgid()); - assert!(ancillary1.add_creds(&[cred1.clone()][..])); - - let usize = - or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); - assert_eq!(usize, 8); - - let mut buf2 = [0; 8]; - let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; - - let mut ancillary2_buffer = [0; 128]; - let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); - - let (usize, truncated, _addr) = - or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2)); - assert_eq!(ancillary2.truncated(), false); - assert_eq!(usize, 8); - assert_eq!(truncated, false); - assert_eq!(buf1, buf2); - - let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); - assert_eq!(ancillary_data_vec.len(), 1); - if let AncillaryData::ScmCredentials(scm_credentials) = - ancillary_data_vec.pop().unwrap().unwrap() - { - let cred_vec = Vec::from_iter(scm_credentials); - assert_eq!(cred_vec.len(), 1); - assert_eq!(cred1.get_pid(), cred_vec[0].get_pid()); - assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); - assert_eq!(cred1.get_gid(), cred_vec[0].get_gid()); - } else { - assert!(false); - } -} - -#[test] -fn test_send_vectored_with_ancillary_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let bsock1 = or_panic!(UnixDatagram::bind(&path1)); - let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - - let mut buf1 = [1; 8]; - let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; - - let mut ancillary1_buffer = [0; 128]; - let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); - assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..])); - - or_panic!(bsock1.connect(&path2)); - let usize = or_panic!(bsock1.send_vectored_with_ancillary(&mut bufs_send, &mut ancillary1)); - assert_eq!(usize, 8); - - let mut buf2 = [0; 8]; - let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..]; - - let mut ancillary2_buffer = [0; 128]; - let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]); - - let (usize, truncated) = - or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2)); - assert_eq!(usize, 8); - assert_eq!(truncated, false); - assert_eq!(buf1, buf2); - - let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); - assert_eq!(ancillary_data_vec.len(), 1); - if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { - let fd_vec = Vec::from_iter(scm_rights); - assert_eq!(fd_vec.len(), 1); - unsafe { - libc::close(fd_vec[0]); - } - } else { - assert!(false); - } -} diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index a4ca81c1c22..a39b97f2c31 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -1,11 +1,13 @@ +use super::*; use crate::io::prelude::*; -use crate::io::{self, ErrorKind}; +use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +use crate::iter::FromIterator; +use crate::mem; +use crate::sys::unix::ext::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; use crate::time::Duration; -use super::*; - macro_rules! or_panic { ($e:expr) => { match $e { @@ -479,7 +481,7 @@ fn test_send_vectored_fds_unix_stream() { let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); assert_eq!(ancillary_data_vec.len(), 1); - if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { let fd_vec = Vec::from_iter(scm_rights); assert_eq!(fd_vec.len(), 1); unsafe { @@ -527,8 +529,11 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); - let cred1 = libc::ucred { pid: getpid(), uid: getuid(), gid: getgid() }; - assert!(ancillary1.add_creds(&[cred1][..])); + let mut cred1 = UCred::new(); + cred1.set_pid(getpid()); + cred1.set_uid(getuid()); + cred1.set_gid(getgid()); + assert!(ancillary1.add_creds(&[cred1.clone()][..])); let usize = or_panic!(bsock1.send_vectored_with_ancillary_to(&mut bufs_send, &mut ancillary1, &path2)); @@ -549,12 +554,14 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); assert_eq!(ancillary_data_vec.len(), 1); - if let AncillaryData::ScmCredentials(scm_credentials) = ancillary_data_vec.pop().unwrap() { + if let AncillaryData::ScmCredentials(scm_credentials) = + ancillary_data_vec.pop().unwrap().unwrap() + { let cred_vec = Vec::from_iter(scm_credentials); assert_eq!(cred_vec.len(), 1); - assert_eq!(cred1.pid, cred_vec[0].pid); - assert_eq!(cred1.uid, cred_vec[0].uid); - assert_eq!(cred1.gid, cred_vec[0].gid); + assert_eq!(cred1.get_pid(), cred_vec[0].get_pid()); + assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); + assert_eq!(cred1.get_gid(), cred_vec[0].get_gid()); } else { assert!(false); } @@ -594,7 +601,7 @@ fn test_send_vectored_with_ancillary_unix_datagram() { let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages()); assert_eq!(ancillary_data_vec.len(), 1); - if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() { let fd_vec = Vec::from_iter(scm_rights); assert_eq!(fd_vec.len(), 1); unsafe { From 686964f0f5c5f620b5cd91772048d75235437df7 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Mon, 7 Sep 2020 18:00:01 +0200 Subject: [PATCH 019/274] Add `set_passcred` and `passcred` methods to `UnixStream` and `UnixDatagram` --- library/std/src/sys/unix/ext/net/datagram.rs | 60 ++++++++++++++++++++ library/std/src/sys/unix/ext/net/stream.rs | 60 ++++++++++++++++++++ library/std/src/sys/unix/ext/net/tests.rs | 12 +--- library/std/src/sys/unix/net.rs | 10 ++++ 4 files changed, 131 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 5df45e6465b..e5309e54e79 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -735,6 +735,66 @@ impl UnixDatagram { self.0.set_nonblocking(nonblocking) } + /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`]. + /// + /// Set the socket option `SO_PASSCRED`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_passcred(true).expect("set_passcred function failed"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + self.0.set_passcred(passcred) + } + + /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`]. + /// This value can be change by [`set_passcred`]. + /// + /// Get the socket option `SO_PASSCRED`. + /// + /// [`set_passcred`]: UnixDatagram::set_passcred + #[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn passcred(&self) -> io::Result { + self.0.passcred() + } + /// Returns the value of the `SO_ERROR` option. /// /// # Examples diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 907832399d8..68e8429dd3b 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -366,6 +366,66 @@ impl UnixStream { self.0.set_nonblocking(nonblocking) } + /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`]. + /// + /// Set the socket option `SO_PASSCRED`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_ancillary_data)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_passcred(true).expect("Couldn't set passcred"); + /// Ok(()) + /// } + /// ``` + #[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + self.0.set_passcred(passcred) + } + + /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`]. + /// This value can be change by [`set_passcred`]. + /// + /// Get the socket option `SO_PASSCRED`. + /// + /// [`set_passcred`]: UnixStream::set_passcred + #[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] + #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + pub fn passcred(&self) -> io::Result { + self.0.passcred() + } + /// Returns the value of the `SO_ERROR` option. /// /// # Examples diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index a39b97f2c31..db6a972e7d2 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -2,7 +2,6 @@ use super::*; use crate::io::prelude::*; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; use crate::iter::FromIterator; -use crate::mem; use crate::sys::unix::ext::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; @@ -513,16 +512,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { let bsock1 = or_panic!(UnixDatagram::bind(&path1)); let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - unsafe { - let optval: libc::c_int = 1; - libc::setsockopt( - bsock2.as_raw_fd(), - libc::SOL_SOCKET, - libc::SO_PASSCRED, - &optval as *const _ as *const _, - mem::size_of::() as u32, - ); - } + or_panic!(bsock2.set_passcred(true)); let mut buf1 = [1; 8]; let mut bufs_send = &mut [IoSliceMut::new(&mut buf1[..])][..]; diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 1a514ed0238..c01d2fa5f23 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -323,6 +323,16 @@ impl Socket { Ok(raw != 0) } + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + let boolean: libc::c_int = if passcred { 1 } else { 0 }; + setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, boolean) + } + + pub fn passcred(&self) -> io::Result { + let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; + Ok(passcred != 0) + } + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as libc::c_int; From eeea5c23b494782bf6a864005684d3405f5c062b Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 12 Sep 2020 15:37:02 +0200 Subject: [PATCH 020/274] Change API to unsafe and add doc comments --- library/std/src/sys/unix/ext/net/ancillary.rs | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index bfca7ae4a9b..d41984a532b 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -137,7 +137,12 @@ struct AncillaryDataIter<'a, T> { } impl<'a, T> AncillaryDataIter<'a, T> { - pub fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> { + /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message. + /// + /// # Safety + /// + /// `data` must contain a valid control message. + unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> { AncillaryDataIter { data, phantom: PhantomData } } } @@ -325,12 +330,24 @@ pub enum AncillaryData<'a> { } impl<'a> AncillaryData<'a> { - fn as_rights(data: &'a [u8]) -> Self { + /// Create a `AncillaryData::ScmRights` variant. + /// + /// # Safety + /// + /// `data` must contain a valid control message and the control message must be type of + /// `SOL_SOCKET` and level of `SCM_RIGHTS`. + unsafe fn as_rights(data: &'a [u8]) -> Self { let ancillary_data_iter = AncillaryDataIter::new(data); let scm_rights = ScmRights(ancillary_data_iter); AncillaryData::ScmRights(scm_rights) } + /// Create a `AncillaryData::ScmCredentials` variant. + /// + /// # Safety + /// + /// `data` must contain a valid control message and the control message must be type of + /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`. #[cfg(any( doc, target_os = "android", @@ -345,7 +362,7 @@ impl<'a> AncillaryData<'a> { target_os = "openbsd", target_env = "uclibc", ))] - fn as_credentials(data: &'a [u8]) -> Self { + unsafe fn as_credentials(data: &'a [u8]) -> Self { let ancillary_data_iter = AncillaryDataIter::new(data); let scm_credentials = ScmCredentials(ancillary_data_iter); AncillaryData::ScmCredentials(scm_credentials) From 1902711f3867753cb2682043c283ffa4a70a317c Mon Sep 17 00:00:00 2001 From: LinkTed Date: Wed, 16 Sep 2020 20:30:59 +0200 Subject: [PATCH 021/274] Change name of struct to SocketCred --- library/std/src/sys/unix/ext/net/ancillary.rs | 16 ++++++++-------- library/std/src/sys/unix/ext/net/tests.rs | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index d41984a532b..8dc74062fdf 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -180,7 +180,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] #[derive(Clone)] -pub struct UCred(libc::ucred); +pub struct SocketCred(libc::ucred); #[cfg(any( doc, @@ -196,13 +196,13 @@ pub struct UCred(libc::ucred); target_os = "openbsd", target_env = "uclibc", ))] -impl UCred { +impl SocketCred { /// Create a Unix credential struct. /// /// PID, UID and GID is set to 0. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn new() -> UCred { - UCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) + pub fn new() -> SocketCred { + SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) } /// Set the PID. @@ -293,10 +293,10 @@ pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for ScmCredentials<'a> { - type Item = UCred; + type Item = SocketCred; - fn next(&mut self) -> Option { - Some(UCred(self.0.next()?)) + fn next(&mut self) -> Option { + Some(SocketCred(self.0.next()?)) } } @@ -606,7 +606,7 @@ impl<'a> SocketAncillary<'a> { target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn add_creds(&mut self, creds: &[UCred]) -> bool { + pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { self.truncated = false; add_to_ancillary_data( &mut self.buffer, diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index db6a972e7d2..16915a4cc1e 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -519,7 +519,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { let mut ancillary1_buffer = [0; 128]; let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]); - let mut cred1 = UCred::new(); + let mut cred1 = SocketCred::new(); cred1.set_pid(getpid()); cred1.set_uid(getuid()); cred1.set_gid(getgid()); From 5964d599ac748ef807594f3dcfc8e69a88449204 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Wed, 16 Sep 2020 20:37:47 +0200 Subject: [PATCH 022/274] Change standard types to libc types --- library/std/src/sys/unix/ext/net/ancillary.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 8dc74062fdf..d8c2939cd8b 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -9,6 +9,8 @@ use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; +use libc::{gid_t, pid_t, uid_t}; + pub(super) fn recv_vectored_with_ancillary_from( socket: &Socket, bufs: &mut [IoSliceMut<'_>], @@ -207,37 +209,37 @@ impl SocketCred { /// Set the PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn set_pid(&mut self, pid: i32) { + pub fn set_pid(&mut self, pid: pid_t) { self.0.pid = pid; } /// Get the current PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn get_pid(&self) -> i32 { + pub fn get_pid(&self) -> pid_t { self.0.pid } /// Set the UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn set_uid(&mut self, uid: u32) { + pub fn set_uid(&mut self, uid: uid_t) { self.0.uid = uid; } /// Get the current UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn get_uid(&self) -> u32 { + pub fn get_uid(&self) -> uid_t { self.0.uid } /// Set the GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn set_gid(&mut self, gid: u32) { + pub fn set_gid(&mut self, gid: gid_t) { self.0.gid = gid; } /// Get the current GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] - pub fn get_gid(&self) -> u32 { + pub fn get_gid(&self) -> gid_t { self.0.gid } } From d0b133cdc60cf843c5806d90ced710589ba95528 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Thu, 17 Sep 2020 11:25:51 +0200 Subject: [PATCH 023/274] Remove unsupported target_os for SocketCred --- library/std/src/sys/unix/ext/net/ancillary.rs | 132 +----------------- 1 file changed, 7 insertions(+), 125 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index d8c2939cd8b..cfe1e328e2c 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -166,38 +166,12 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } /// Unix credential. -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", -))] +#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] #[derive(Clone)] pub struct SocketCred(libc::ucred); -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", -))] +#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] impl SocketCred { /// Create a Unix credential struct. /// @@ -262,37 +236,11 @@ impl<'a> Iterator for ScmRights<'a> { /// This control message contains unix credentials. /// /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", -))] +#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", -))] +#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] impl<'a> Iterator for ScmCredentials<'a> { type Item = SocketCred; @@ -314,20 +262,7 @@ pub enum AncillaryError { #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] ScmCredentials(ScmCredentials<'a>), } @@ -350,20 +285,7 @@ impl<'a> AncillaryData<'a> { /// /// `data` must contain a valid control message and the control message must be type of /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`. - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] unsafe fn as_credentials(data: &'a [u8]) -> Self { let ancillary_data_iter = AncillaryDataIter::new(data); let scm_credentials = ScmCredentials(ancillary_data_iter); @@ -383,20 +305,9 @@ impl<'a> AncillaryData<'a> { #[cfg(any( target_os = "android", target_os = "emscripten", - target_os = "fuchsia", target_os = "linux", - target_env = "uclibc", ))] libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)), cmsg_type => { Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type }) } @@ -593,20 +504,7 @@ impl<'a> SocketAncillary<'a> { /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. /// - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { self.truncated = false; @@ -615,23 +513,7 @@ impl<'a> SocketAncillary<'a> { &mut self.length, creds, libc::SOL_SOCKET, - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "linux", - target_env = "uclibc", - ))] libc::SCM_CREDENTIALS, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - ))] - libc::SCM_CREDS, ) } From e61148f98a21231d5bb3dea0140e3ff2f4d946e2 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Thu, 17 Sep 2020 11:32:20 +0200 Subject: [PATCH 024/274] Cast boolean into int directly in function set_passcred --- library/std/src/sys/unix/net.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index c01d2fa5f23..2bd6b84d671 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -324,8 +324,7 @@ impl Socket { } pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { - let boolean: libc::c_int = if passcred { 1 } else { 0 }; - setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, boolean) + setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) } pub fn passcred(&self) -> io::Result { From cc085e917078ebd5ff4c7c784d8cb04da85143c7 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 18 Sep 2020 14:08:31 +0200 Subject: [PATCH 025/274] Replace `assert` with `unreachable` --- library/std/src/sys/unix/ext/net/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 16915a4cc1e..6cb2e729143 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -487,7 +487,7 @@ fn test_send_vectored_fds_unix_stream() { libc::close(fd_vec[0]); } } else { - assert!(false); + unreachable!("must be ScmRights"); } } @@ -553,7 +553,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { assert_eq!(cred1.get_uid(), cred_vec[0].get_uid()); assert_eq!(cred1.get_gid(), cred_vec[0].get_gid()); } else { - assert!(false); + unreachable!("must be ScmCredentials"); } } @@ -598,6 +598,6 @@ fn test_send_vectored_with_ancillary_unix_datagram() { libc::close(fd_vec[0]); } } else { - assert!(false); + unreachable!("must be ScmRights"); } } From db902bca3a2dfeb449fc42149575d476c85d7fed Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 19 Sep 2020 13:09:18 +0200 Subject: [PATCH 026/274] Add the code of the tracking issue --- library/std/src/sys/unix/ext/net/ancillary.rs | 50 +++++++++---------- library/std/src/sys/unix/ext/net/datagram.rs | 12 ++--- library/std/src/sys/unix/ext/net/mod.rs | 2 +- library/std/src/sys/unix/ext/net/stream.rs | 8 +-- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index cfe1e328e2c..4473c4e5da8 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -167,7 +167,7 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { /// Unix credential. #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] #[derive(Clone)] pub struct SocketCred(libc::ucred); @@ -176,43 +176,43 @@ impl SocketCred { /// Create a Unix credential struct. /// /// PID, UID and GID is set to 0. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn new() -> SocketCred { SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 }) } /// Set the PID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_pid(&mut self, pid: pid_t) { self.0.pid = pid; } /// Get the current PID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_pid(&self) -> pid_t { self.0.pid } /// Set the UID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_uid(&mut self, uid: uid_t) { self.0.uid = uid; } /// Get the current UID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_uid(&self) -> uid_t { self.0.uid } /// Set the GID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_gid(&mut self, gid: gid_t) { self.0.gid = gid; } /// Get the current GID. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn get_gid(&self) -> gid_t { self.0.gid } @@ -221,10 +221,10 @@ impl SocketCred { /// This control message contains file descriptors. /// /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`. -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>); -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl<'a> Iterator for ScmRights<'a> { type Item = RawFd; @@ -237,11 +237,11 @@ impl<'a> Iterator for ScmRights<'a> { /// /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl<'a> Iterator for ScmCredentials<'a> { type Item = SocketCred; @@ -253,13 +253,13 @@ impl<'a> Iterator for ScmCredentials<'a> { /// The error type which is returned from parsing the type a control message. #[non_exhaustive] #[derive(Debug)] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub enum AncillaryError { Unknown { cmsg_level: i32, cmsg_type: i32 }, } /// This enum represent one control message of variable type. -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] @@ -321,13 +321,13 @@ impl<'a> AncillaryData<'a> { } /// This struct is used to iterate through the control messages. -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct Messages<'a> { buffer: &'a [u8], current: Option<&'a libc::cmsghdr>, } -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl<'a> Iterator for Messages<'a> { type Item = Result, AncillaryError>; @@ -386,7 +386,7 @@ impl<'a> Iterator for Messages<'a> { /// Ok(()) /// } /// ``` -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] #[derive(Debug)] pub struct SocketAncillary<'a> { buffer: &'a mut [u8], @@ -406,25 +406,25 @@ impl<'a> SocketAncillary<'a> { /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn new(buffer: &'a mut [u8]) -> Self { SocketAncillary { buffer, length: 0, truncated: false } } /// Returns the capacity of the buffer. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn capacity(&self) -> usize { self.buffer.len() } /// Returns the number of used bytes. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn len(&self) -> usize { self.length } /// Returns the iterator of the control messages. - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn messages(&self) -> Messages<'_> { Messages { buffer: &self.buffer[..self.length], current: None } } @@ -452,7 +452,7 @@ impl<'a> SocketAncillary<'a> { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn truncated(&self) -> bool { self.truncated } @@ -485,7 +485,7 @@ impl<'a> SocketAncillary<'a> { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn add_fds(&mut self, fds: &[RawFd]) -> bool { self.truncated = false; add_to_ancillary_data( @@ -505,7 +505,7 @@ impl<'a> SocketAncillary<'a> { /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. /// #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { self.truncated = false; add_to_ancillary_data( @@ -559,7 +559,7 @@ impl<'a> SocketAncillary<'a> { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn clear(&mut self) { self.length = 0; self.truncated = false; diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index e5309e54e79..5b813ac6481 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -378,7 +378,7 @@ impl UnixDatagram { target_os = "solaris", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary_from( &self, bufs: &mut [IoSliceMut<'_>], @@ -442,7 +442,7 @@ impl UnixDatagram { target_os = "solaris", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( &self, bufs: &mut [IoSliceMut<'_>], @@ -539,7 +539,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary_to>( &self, bufs: &mut [IoSliceMut<'_>], @@ -578,7 +578,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, bufs: &mut [IoSliceMut<'_>], @@ -765,7 +765,7 @@ impl UnixDatagram { target_os = "openbsd", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) } @@ -790,7 +790,7 @@ impl UnixDatagram { target_os = "openbsd", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() } diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index c37e856e5bc..1c792b251b6 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -62,7 +62,7 @@ pub use self::addr::*; target_os = "solaris", target_env = "uclibc", ))] -#[unstable(feature = "unix_socket_ancillary_data", issue = "none")] +#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub use self::ancillary::*; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::datagram::*; diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 68e8429dd3b..49f16861afc 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -396,7 +396,7 @@ impl UnixStream { target_os = "openbsd", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) } @@ -421,7 +421,7 @@ impl UnixStream { target_os = "openbsd", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() } @@ -550,7 +550,7 @@ impl UnixStream { target_os = "solaris", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( &self, bufs: &mut [IoSliceMut<'_>], @@ -606,7 +606,7 @@ impl UnixStream { target_os = "solaris", target_env = "uclibc", ))] - #[unstable(feature = "unix_socket_ancillary_data", issue = "none")] + #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, bufs: &mut [IoSliceMut<'_>], From 7b476d87fbdd678f0a580f90193938e787d0ce99 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 14:44:03 +0200 Subject: [PATCH 027/274] Remove `target_os`, which does not have `MSG_CMSG_CLOEXEC` constant in `libc` --- library/std/src/sys/unix/ext/net/datagram.rs | 38 ++++++++++---------- library/std/src/sys/unix/ext/net/mod.rs | 18 ---------- library/std/src/sys/unix/ext/net/stream.rs | 18 ---------- library/std/src/sys/unix/ext/net/tests.rs | 11 ++++++ 4 files changed, 31 insertions(+), 54 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 5b813ac6481..116375ad48b 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -9,15 +9,9 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] use crate::sys::unix::ext::net::ancillary::{ @@ -367,15 +361,9 @@ impl UnixDatagram { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -431,15 +419,9 @@ impl UnixDatagram { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -539,6 +521,16 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary_to>( &self, @@ -578,6 +570,16 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", + ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index 1c792b251b6..366ee7edf2a 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -8,15 +8,9 @@ mod addr; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", )))] #[cfg(any( @@ -25,15 +19,9 @@ mod addr; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] mod ancillary; @@ -51,15 +39,9 @@ pub use self::addr::*; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 49f16861afc..671639949cb 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -21,15 +21,9 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] use crate::sys::unix::ext::net::ancillary::{ @@ -539,15 +533,9 @@ impl UnixStream { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -595,15 +583,9 @@ impl UnixStream { target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", - target_os = "fuchsia", - target_os = "haiku", - target_os = "illumos", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris", target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 6cb2e729143..7690590b68b 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -557,6 +557,17 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { } } +#[cfg(any( + doc, + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_env = "uclibc", +))] #[test] fn test_send_vectored_with_ancillary_unix_datagram() { let dir = tmpdir(); From 1f6d7dcc0a917617eb135a39b4687c3a4a4e3e0b Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 14:53:21 +0200 Subject: [PATCH 028/274] Remove `target_os`, which does not have `cmsghdr` struct in `libc` --- library/std/src/sys/unix/ext/net/datagram.rs | 5 ----- library/std/src/sys/unix/ext/net/mod.rs | 3 --- library/std/src/sys/unix/ext/net/stream.rs | 3 --- library/std/src/sys/unix/ext/net/tests.rs | 1 - 4 files changed, 12 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 116375ad48b..52cb3c0d904 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -12,7 +12,6 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] use crate::sys::unix::ext::net::ancillary::{ recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, @@ -364,7 +363,6 @@ impl UnixDatagram { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary_from( @@ -422,7 +420,6 @@ impl UnixDatagram { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( @@ -529,7 +526,6 @@ impl UnixDatagram { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary_to>( @@ -578,7 +574,6 @@ impl UnixDatagram { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index 366ee7edf2a..d2799bbcaf8 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -11,7 +11,6 @@ mod addr; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", )))] #[cfg(any( doc, @@ -22,7 +21,6 @@ mod addr; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] mod ancillary; mod datagram; @@ -42,7 +40,6 @@ pub use self::addr::*; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub use self::ancillary::*; diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 671639949cb..21b13a083a0 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -24,7 +24,6 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] use crate::sys::unix::ext::net::ancillary::{ recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, @@ -536,7 +535,6 @@ impl UnixStream { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( @@ -586,7 +584,6 @@ impl UnixStream { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 7690590b68b..9f34059d011 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -566,7 +566,6 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { target_os = "linux", target_os = "netbsd", target_os = "openbsd", - target_env = "uclibc", ))] #[test] fn test_send_vectored_with_ancillary_unix_datagram() { From d30508f95c7a6cf371db5413b04322508d848c0e Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 15:04:09 +0200 Subject: [PATCH 029/274] Remove `target_os`, which does not have `SO_PASSCRED` constant in `libc` --- library/std/src/sys/unix/ext/net/datagram.rs | 30 ++------------------ library/std/src/sys/unix/ext/net/stream.rs | 30 ++------------------ library/std/src/sys/unix/ext/net/tests.rs | 1 + 3 files changed, 5 insertions(+), 56 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 52cb3c0d904..46061200be7 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -748,20 +748,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) @@ -773,20 +760,7 @@ impl UnixDatagram { /// Get the socket option `SO_PASSCRED`. /// /// [`set_passcred`]: UnixDatagram::set_passcred - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 21b13a083a0..783a50e09b2 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -375,20 +375,7 @@ impl UnixStream { /// Ok(()) /// } /// ``` - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) @@ -400,20 +387,7 @@ impl UnixStream { /// Get the socket option `SO_PASSCRED`. /// /// [`set_passcred`]: UnixStream::set_passcred - #[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_env = "uclibc", - ))] + #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index 9f34059d011..abf45ad2d1b 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -491,6 +491,7 @@ fn test_send_vectored_fds_unix_stream() { } } +#[cfg(any(test, target_os = "android", target_os = "emscripten", target_os = "linux",))] #[test] fn test_send_vectored_with_ancillary_to_unix_datagram() { fn getpid() -> libc::pid_t { From e0cedba63e47f172db69669ba499d9e2638f482c Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 15:06:41 +0200 Subject: [PATCH 030/274] Fix cfg condition for test --- library/std/src/sys/unix/ext/net/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index abf45ad2d1b..cb04de18828 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -559,7 +559,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { } #[cfg(any( - doc, + test, target_os = "android", target_os = "dragonfly", target_os = "emscripten", From c2a1b50140642f50b86ee7191b02737ba60848a7 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 20 Sep 2020 15:22:28 +0200 Subject: [PATCH 031/274] Add conditional compilation for import --- library/std/src/sys/unix/ext/net/ancillary.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 4473c4e5da8..0266df46098 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -9,6 +9,7 @@ use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] use libc::{gid_t, pid_t, uid_t}; pub(super) fn recv_vectored_with_ancillary_from( From b01ce2cfd0e0182384cffe7db0c0b94c3414c610 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 22 Sep 2020 13:17:12 +0200 Subject: [PATCH 032/274] Fix `MSG_CMSG_CLOEXEC` for macos --- library/std/src/sys/unix/net.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 2bd6b84d671..8f28c75641f 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -237,6 +237,15 @@ impl Socket { self.recv_from_with_flags(buf, 0) } + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result { let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?; Ok(n as usize) @@ -259,6 +268,15 @@ impl Socket { self.0.is_write_vectored() } + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ))] pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result { let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?; Ok(n as usize) From 31e6e3896d45c82cf1c80aadc87cebe387340ad4 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 22 Sep 2020 13:18:06 +0200 Subject: [PATCH 033/274] Fix `SO_PASSCRED` for macos --- library/std/src/sys/unix/net.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 8f28c75641f..f27786dbf79 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -341,10 +341,12 @@ impl Socket { Ok(raw != 0) } + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) } + #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] pub fn passcred(&self) -> io::Result { let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; Ok(passcred != 0) From 0fcb83483240a274016aa2552952a42a97168c31 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 22 Sep 2020 13:18:56 +0200 Subject: [PATCH 034/274] Fix unused import for `IoSliceMut` for macos --- library/std/src/sys/unix/ext/net/datagram.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 46061200be7..99d90da3820 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -1,3 +1,12 @@ +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] use crate::io::IoSliceMut; use crate::net::Shutdown; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; From 889c9272cb670891ed3b2dca4aef4f333110fee7 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 22 Sep 2020 22:21:27 +0200 Subject: [PATCH 035/274] Remove `SocketCred` for `emscripten` --- library/std/src/sys/unix/ext/net/ancillary.rs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 0266df46098..112d72dc29b 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -9,7 +9,7 @@ use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; -#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(target_os = "android", target_os = "linux",))] use libc::{gid_t, pid_t, uid_t}; pub(super) fn recv_vectored_with_ancillary_from( @@ -167,12 +167,12 @@ impl<'a, T> Iterator for AncillaryDataIter<'a, T> { } /// Unix credential. -#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] #[derive(Clone)] pub struct SocketCred(libc::ucred); -#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(doc, target_os = "android", target_os = "linux",))] impl SocketCred { /// Create a Unix credential struct. /// @@ -237,11 +237,11 @@ impl<'a> Iterator for ScmRights<'a> { /// This control message contains unix credentials. /// /// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`. -#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>); -#[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] impl<'a> Iterator for ScmCredentials<'a> { type Item = SocketCred; @@ -263,7 +263,7 @@ pub enum AncillaryError { #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub enum AncillaryData<'a> { ScmRights(ScmRights<'a>), - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] ScmCredentials(ScmCredentials<'a>), } @@ -286,7 +286,7 @@ impl<'a> AncillaryData<'a> { /// /// `data` must contain a valid control message and the control message must be type of /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`. - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] unsafe fn as_credentials(data: &'a [u8]) -> Self { let ancillary_data_iter = AncillaryDataIter::new(data); let scm_credentials = ScmCredentials(ancillary_data_iter); @@ -303,11 +303,7 @@ impl<'a> AncillaryData<'a> { match (*cmsg).cmsg_level { libc::SOL_SOCKET => match (*cmsg).cmsg_type { libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)), - #[cfg(any( - target_os = "android", - target_os = "emscripten", - target_os = "linux", - ))] + #[cfg(any(target_os = "android", target_os = "linux",))] libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)), cmsg_type => { Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type }) @@ -505,7 +501,7 @@ impl<'a> SocketAncillary<'a> { /// Technically, that means this operation adds a control message with the level `SOL_SOCKET` /// and type `SCM_CREDENTIALS` or `SCM_CREDS`. /// - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool { self.truncated = false; From ce167f8be7cad4140628771f7d37cde59d76936f Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 25 Sep 2020 20:19:02 +0200 Subject: [PATCH 036/274] Fix type mismatching for different OSes. --- library/std/src/sys/unix/ext/net/ancillary.rs | 146 +++++++++++++----- 1 file changed, 105 insertions(+), 41 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 112d72dc29b..c53b213e0f9 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -4,7 +4,7 @@ use crate::marker::PhantomData; use crate::mem::{size_of, zeroed}; use crate::os::unix::io::RawFd; use crate::path::Path; -use crate::ptr::{null_mut, read_unaligned}; +use crate::ptr::read_unaligned; use crate::slice::from_raw_parts; use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; use crate::sys::unix::net::Socket; @@ -20,19 +20,31 @@ pub(super) fn recv_vectored_with_ancillary_from( unsafe { let mut msg_name: libc::sockaddr_un = zeroed(); - let mut msg = libc::msghdr { - msg_name: &mut msg_name as *mut _ as *mut _, - msg_namelen: size_of::() as libc::socklen_t, - msg_iov: bufs.as_mut_ptr().cast(), - msg_iovlen: bufs.len(), - msg_control: ancillary.buffer.as_mut_ptr().cast(), - msg_controllen: ancillary.buffer.len(), - msg_flags: 0, - }; + let mut msg: libc::msghdr = zeroed(); + msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_namelen = size_of::() as libc::socklen_t; + msg.msg_iov = bufs.as_mut_ptr().cast(); + msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_iovlen = bufs.len() as libc::size_t; + msg.msg_controllen = ancillary.buffer.len() as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_iovlen = bufs.len() as libc::c_int; + msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t; + } + } let count = socket.recv_msg(&mut msg)?; - ancillary.length = msg.msg_controllen; + ancillary.length = msg.msg_controllen as usize; ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC; let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC; @@ -52,15 +64,27 @@ pub(super) fn send_vectored_with_ancillary_to( let (mut msg_name, msg_namelen) = if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) }; - let mut msg = libc::msghdr { - msg_name: &mut msg_name as *mut _ as *mut _, - msg_namelen, - msg_iov: bufs.as_mut_ptr().cast(), - msg_iovlen: bufs.len(), - msg_control: ancillary.buffer.as_mut_ptr().cast(), - msg_controllen: ancillary.length, - msg_flags: 0, - }; + let mut msg: libc::msghdr = zeroed(); + msg.msg_name = &mut msg_name as *mut _ as *mut _; + msg.msg_namelen = msg_namelen; + msg.msg_iov = bufs.as_mut_ptr().cast(); + msg.msg_control = ancillary.buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_iovlen = bufs.len() as libc::size_t; + msg.msg_controllen = ancillary.length as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_iovlen = bufs.len() as libc::c_int; + msg.msg_controllen = ancillary.length as libc::socklen_t; + } + } ancillary.truncated = false; @@ -102,15 +126,22 @@ fn add_to_ancillary_data( *length = new_length; - let msg = libc::msghdr { - msg_name: null_mut(), - msg_namelen: 0, - msg_iov: null_mut(), - msg_iovlen: 0, - msg_control: buffer.as_mut_ptr().cast(), - msg_controllen: *length, - msg_flags: 0, - }; + let mut msg: libc::msghdr = zeroed(); + msg.msg_control = buffer.as_mut_ptr().cast(); + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_controllen = *length as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_controllen = *length as libc::socklen_t; + } + } let mut cmsg = libc::CMSG_FIRSTHDR(&msg); let mut previous_cmsg = cmsg; @@ -125,7 +156,20 @@ fn add_to_ancillary_data( (*previous_cmsg).cmsg_level = cmsg_level; (*previous_cmsg).cmsg_type = cmsg_type; - (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as usize; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t; + } + } let data = libc::CMSG_DATA(previous_cmsg).cast(); @@ -295,10 +339,23 @@ impl<'a> AncillaryData<'a> { fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result { unsafe { - let cmsg_len_zero = libc::CMSG_LEN(0) as usize; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t; + } + } let data_len = (*cmsg).cmsg_len - cmsg_len_zero; let data = libc::CMSG_DATA(cmsg).cast(); - let data = from_raw_parts(data, data_len); + let data = from_raw_parts(data, data_len as usize); match (*cmsg).cmsg_level { libc::SOL_SOCKET => match (*cmsg).cmsg_type { @@ -330,15 +387,22 @@ impl<'a> Iterator for Messages<'a> { fn next(&mut self) -> Option { unsafe { - let msg = libc::msghdr { - msg_name: null_mut(), - msg_namelen: 0, - msg_iov: null_mut(), - msg_iovlen: 0, - msg_control: self.buffer.as_ptr() as *mut _, - msg_controllen: self.buffer.len(), - msg_flags: 0, - }; + let mut msg: libc::msghdr = zeroed(); + msg.msg_control = self.buffer.as_ptr() as *mut _; + cfg_if::cfg_if! { + if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] { + msg.msg_controllen = self.buffer.len() as libc::size_t; + } else if #[cfg(any( + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + all(target_os = "linux", target_env = "musl",), + target_os = "netbsd", + target_os = "openbsd", + ))] { + msg.msg_controllen = self.buffer.len() as libc::socklen_t;; + } + } let cmsg = if let Some(current) = self.current { libc::CMSG_NXTHDR(&msg, current) From 6b0c3dfe0028eee847675b6b3effc7d1b3078a20 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 26 Sep 2020 20:04:10 +0200 Subject: [PATCH 037/274] Remove unnecessary trailing semicolon --- library/std/src/sys/unix/ext/net/ancillary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index c53b213e0f9..547c9c7dcbe 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -400,7 +400,7 @@ impl<'a> Iterator for Messages<'a> { target_os = "netbsd", target_os = "openbsd", ))] { - msg.msg_controllen = self.buffer.len() as libc::socklen_t;; + msg.msg_controllen = self.buffer.len() as libc::socklen_t; } } From e9bf69954c942085a775f3cdd035ac3b1273f974 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 26 Sep 2020 22:40:02 +0200 Subject: [PATCH 038/274] Remove `passcred` for `emscripten` --- library/std/src/sys/unix/ext/net/datagram.rs | 4 ++-- library/std/src/sys/unix/ext/net/stream.rs | 4 ++-- library/std/src/sys/unix/net.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 99d90da3820..9d9df6959b2 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -757,7 +757,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) @@ -769,7 +769,7 @@ impl UnixDatagram { /// Get the socket option `SO_PASSCRED`. /// /// [`set_passcred`]: UnixDatagram::set_passcred - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 783a50e09b2..8337487ff47 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -375,7 +375,7 @@ impl UnixStream { /// Ok(()) /// } /// ``` - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { self.0.set_passcred(passcred) @@ -387,7 +387,7 @@ impl UnixStream { /// Get the socket option `SO_PASSCRED`. /// /// [`set_passcred`]: UnixStream::set_passcred - #[cfg(any(doc, target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(doc, target_os = "android", target_os = "linux",))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn passcred(&self) -> io::Result { self.0.passcred() diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index f27786dbf79..ddabb3f0547 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -341,12 +341,12 @@ impl Socket { Ok(raw != 0) } - #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(target_os = "android", target_os = "linux",))] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) } - #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] + #[cfg(any(target_os = "android", target_os = "linux",))] pub fn passcred(&self) -> io::Result { let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; Ok(passcred != 0) From 1ae54e560a7cf6021a28d2addc6253ae8baab96f Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 27 Sep 2020 22:29:02 +0200 Subject: [PATCH 039/274] Change imports for `cfg(doc)` --- library/std/src/sys/unix/ext/net/addr.rs | 2 +- library/std/src/sys/unix/ext/net/ancillary.rs | 4 +-- library/std/src/sys/unix/ext/net/datagram.rs | 20 +++++++------- library/std/src/sys/unix/ext/net/listener.rs | 5 ++-- library/std/src/sys/unix/ext/net/stream.rs | 26 +++++++++---------- library/std/src/sys/unix/ext/net/tests.rs | 2 +- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/addr.rs b/library/std/src/sys/unix/ext/net/addr.rs index 15fc5bb5b4e..1f9036242eb 100644 --- a/library/std/src/sys/unix/ext/net/addr.rs +++ b/library/std/src/sys/unix/ext/net/addr.rs @@ -1,7 +1,7 @@ use crate::ffi::OsStr; use crate::os::unix::ffi::OsStrExt; use crate::path::Path; -use crate::sys::unix::cvt; +use crate::sys::cvt; use crate::{ascii, fmt, io, mem}; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 547c9c7dcbe..9e8da6306ca 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -1,3 +1,4 @@ +use super::{sockaddr_un, SocketAddr}; use crate::convert::TryFrom; use crate::io::{self, IoSliceMut}; use crate::marker::PhantomData; @@ -6,8 +7,7 @@ use crate::os::unix::io::RawFd; use crate::path::Path; use crate::ptr::read_unaligned; use crate::slice::from_raw_parts; -use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; -use crate::sys::unix::net::Socket; +use crate::sys::net::Socket; #[cfg(any(target_os = "android", target_os = "linux",))] use libc::{gid_t, pid_t, uid_t}; diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 9d9df6959b2..ce91b403efd 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -7,12 +7,10 @@ target_os = "netbsd", target_os = "openbsd", ))] -use crate::io::IoSliceMut; -use crate::net::Shutdown; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::path::Path; -use crate::sys::unix::cvt; -use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; +use super::{ + recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, sockaddr_un, SocketAddr, + SocketAncillary, +}; #[cfg(any( target_os = "android", target_os = "dragonfly", @@ -22,10 +20,12 @@ use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; target_os = "netbsd", target_os = "openbsd", ))] -use crate::sys::unix::ext::net::ancillary::{ - recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, -}; -use crate::sys::unix::net::Socket; +use crate::io::IoSliceMut; +use crate::net::Shutdown; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::cvt; +use crate::sys::net::Socket; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; use crate::{fmt, io}; diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs index 2bedfb74dcb..9803c6e2746 100644 --- a/library/std/src/sys/unix/ext/net/listener.rs +++ b/library/std/src/sys/unix/ext/net/listener.rs @@ -1,9 +1,8 @@ +use super::{sockaddr_un, SocketAddr, UnixStream}; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::Path; +use crate::sys::cvt; use crate::sys::net::Socket; -use crate::sys::unix::cvt; -use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; -use crate::sys::unix::ext::net::stream::UnixStream; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, io, mem}; diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 8337487ff47..e13c863bdbb 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -1,3 +1,16 @@ +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] +use super::{ + recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, sockaddr_un, SocketAddr, + SocketAncillary, +}; use crate::fmt; use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::net::Shutdown; @@ -15,19 +28,6 @@ use crate::os::unix::ucred; use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; -use crate::sys::unix::ext::net::addr::{sockaddr_un, SocketAddr}; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] -use crate::sys::unix::ext::net::ancillary::{ - recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary, -}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index cb04de18828..bf114bbe6e5 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -2,7 +2,7 @@ use super::*; use crate::io::prelude::*; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; use crate::iter::FromIterator; -use crate::sys::unix::ext::io::AsRawFd; +use crate::os::unix::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; use crate::time::Duration; From d0069a0cc525084770a035f5f6963f43ccdea26e Mon Sep 17 00:00:00 2001 From: LinkTed Date: Fri, 2 Oct 2020 22:02:16 +0200 Subject: [PATCH 040/274] Fix imports for MacOs --- library/std/src/sys/unix/ext/net/datagram.rs | 6 ++---- library/std/src/sys/unix/ext/net/stream.rs | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index ce91b403efd..3e0c7a98a45 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -7,10 +7,8 @@ target_os = "netbsd", target_os = "openbsd", ))] -use super::{ - recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, sockaddr_un, SocketAddr, - SocketAncillary, -}; +use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; +use super::{sockaddr_un, SocketAddr}; #[cfg(any( target_os = "android", target_os = "dragonfly", diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index e13c863bdbb..ac0b53e1ede 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -7,10 +7,8 @@ target_os = "netbsd", target_os = "openbsd", ))] -use super::{ - recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, sockaddr_un, SocketAddr, - SocketAncillary, -}; +use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; +use super::{sockaddr_un, SocketAddr}; use crate::fmt; use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::net::Shutdown; From a81764731cade72b551b213941ac2cd16a980788 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 4 Oct 2020 15:22:44 +0200 Subject: [PATCH 041/274] Add fake definitions for Windows --- library/std/src/sys/unix/ext/net/ancillary.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 9e8da6306ca..e36ad8b956a 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -11,6 +11,16 @@ use crate::sys::net::Socket; #[cfg(any(target_os = "android", target_os = "linux",))] use libc::{gid_t, pid_t, uid_t}; +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(not(unix))] +#[allow(non_camel_case_types)] +mod libc { + pub struct ucred; + pub struct cmsghdr; + pub type pid_t = i32; + pub type gid_t = u32; + pub type uid_t = u32; +} pub(super) fn recv_vectored_with_ancillary_from( socket: &Socket, From fc65f6a0ce74a2d325a04f1b87edfa5ecbfa6ccd Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 4 Oct 2020 19:28:38 +0200 Subject: [PATCH 042/274] Fix import errors for `#[cfg(doc)]` target --- library/std/src/sys/unix/ext/net/ancillary.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index e36ad8b956a..e1d0fe125cc 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -9,12 +9,11 @@ use crate::ptr::read_unaligned; use crate::slice::from_raw_parts; use crate::sys::net::Socket; -#[cfg(any(target_os = "android", target_os = "linux",))] -use libc::{gid_t, pid_t, uid_t}; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] #[allow(non_camel_case_types)] mod libc { + pub use libc::c_int; pub struct ucred; pub struct cmsghdr; pub type pid_t = i32; @@ -22,6 +21,9 @@ mod libc { pub type uid_t = u32; } +#[cfg(any(doc, target_os = "android", target_os = "linux",))] +use libc::{gid_t, pid_t, uid_t}; + pub(super) fn recv_vectored_with_ancillary_from( socket: &Socket, bufs: &mut [IoSliceMut<'_>], From 7b596f2e1330403ebb69c0c5ea8bd8a4eab256a0 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Mon, 5 Oct 2020 21:26:23 +0200 Subject: [PATCH 043/274] Fix `libc` is ambiguous for Windows --- library/std/src/sys/unix/ext/net/ancillary.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index e1d0fe125cc..9442d340a32 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -21,9 +21,6 @@ mod libc { pub type uid_t = u32; } -#[cfg(any(doc, target_os = "android", target_os = "linux",))] -use libc::{gid_t, pid_t, uid_t}; - pub(super) fn recv_vectored_with_ancillary_from( socket: &Socket, bufs: &mut [IoSliceMut<'_>], @@ -240,37 +237,37 @@ impl SocketCred { /// Set the PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn set_pid(&mut self, pid: pid_t) { + pub fn set_pid(&mut self, pid: libc::pid_t) { self.0.pid = pid; } /// Get the current PID. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn get_pid(&self) -> pid_t { + pub fn get_pid(&self) -> libc::pid_t { self.0.pid } /// Set the UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn set_uid(&mut self, uid: uid_t) { + pub fn set_uid(&mut self, uid: libc::uid_t) { self.0.uid = uid; } /// Get the current UID. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn get_uid(&self) -> uid_t { + pub fn get_uid(&self) -> libc::uid_t { self.0.uid } /// Set the GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn set_gid(&mut self, gid: gid_t) { + pub fn set_gid(&mut self, gid: libc::gid_t) { self.0.gid = gid; } /// Get the current GID. #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] - pub fn get_gid(&self) -> gid_t { + pub fn get_gid(&self) -> libc::gid_t { self.0.gid } } From 64facfef51a5fa3ebb3622b87bb0752b26d8b3ab Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 6 Oct 2020 19:08:21 +0200 Subject: [PATCH 044/274] Fix unresolved link to `SocketAncillary` --- library/std/src/sys/unix/ext/net/datagram.rs | 1 + library/std/src/sys/unix/ext/net/stream.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 3e0c7a98a45..8f3120b246d 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -1,4 +1,5 @@ #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index ac0b53e1ede..4b3221f1022 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -1,4 +1,5 @@ #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", From d8c75d9f91fe737bc3ef3ac7592f055bf846270e Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sun, 11 Oct 2020 19:23:41 +0200 Subject: [PATCH 045/274] Fix unresolved imports for `recv_vectored_with_ancillary_from`, `send_vectored_with_ancillary_to` and `SocketAncillary` --- library/std/src/sys/unix/ext/net/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs index d2799bbcaf8..3088ffb5e5c 100644 --- a/library/std/src/sys/unix/ext/net/mod.rs +++ b/library/std/src/sys/unix/ext/net/mod.rs @@ -33,6 +33,7 @@ mod tests; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::addr::*; #[cfg(any( + doc, target_os = "android", target_os = "dragonfly", target_os = "emscripten", From 79273fa30c62f2277688ed19649a0b45b902c8a1 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Sat, 17 Oct 2020 19:36:11 +0200 Subject: [PATCH 046/274] Fix cannot find type `ucred` for MacOs by using fake definitions --- library/std/src/sys/unix/ext/net/ancillary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index 9442d340a32..a68475ab985 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -10,7 +10,7 @@ use crate::slice::from_raw_parts; use crate::sys::net::Socket; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(not(unix))] +#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android")))] #[allow(non_camel_case_types)] mod libc { pub use libc::c_int; From ea5e012ba73e914629360db7ea114c0a89699612 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Wed, 21 Oct 2020 17:51:53 +0200 Subject: [PATCH 047/274] Fix test cases for MacOs --- library/std/src/sys/unix/ext/net/tests.rs | 30 +++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs index bf114bbe6e5..97a016904b4 100644 --- a/library/std/src/sys/unix/ext/net/tests.rs +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -1,7 +1,25 @@ use super::*; use crate::io::prelude::*; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] use crate::iter::FromIterator; +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] use crate::os::unix::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; @@ -454,6 +472,15 @@ fn test_unix_datagram_peek_from() { assert_eq!(msg, &buf[..]); } +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", +))] #[test] fn test_send_vectored_fds_unix_stream() { let (s1, s2) = or_panic!(UnixStream::pair()); @@ -491,7 +518,7 @@ fn test_send_vectored_fds_unix_stream() { } } -#[cfg(any(test, target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] #[test] fn test_send_vectored_with_ancillary_to_unix_datagram() { fn getpid() -> libc::pid_t { @@ -559,7 +586,6 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { } #[cfg(any( - test, target_os = "android", target_os = "dragonfly", target_os = "emscripten", From c7794056865401686e37636ba6453532a0923843 Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 3 Nov 2020 18:28:04 +0100 Subject: [PATCH 048/274] Fix docs for MacOs (correction) --- library/std/src/sys/unix/ext/net/stream.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index 4b3221f1022..9fe6b85837e 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -364,7 +364,8 @@ impl UnixStream { /// /// # Examples /// - /// ```no_run + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::UnixStream; /// From ead7185db69d84e6af53712508600cad136f972b Mon Sep 17 00:00:00 2001 From: LinkTed Date: Wed, 4 Nov 2020 19:45:48 +0100 Subject: [PATCH 049/274] Fix docs for MacOs (again) --- library/std/src/sys/unix/ext/net/datagram.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index 8f3120b246d..0f532c47c8f 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -746,7 +746,8 @@ impl UnixDatagram { /// /// # Examples /// - /// ```no_run + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::UnixDatagram; /// From faa3e233169523f6bb1537d9b6b2aabe66efd01b Mon Sep 17 00:00:00 2001 From: chansuke Date: Tue, 3 Nov 2020 09:00:30 +0900 Subject: [PATCH 050/274] Add exteranal macros for as_conversions --- tests/ui/as_conversions.rs | 14 +++++++++++++- tests/ui/as_conversions.stderr | 6 +++--- tests/ui/auxiliary/macro_rules.rs | 14 ++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs index e01ba0c64df..cd745feec6d 100644 --- a/tests/ui/as_conversions.rs +++ b/tests/ui/as_conversions.rs @@ -1,7 +1,19 @@ -#[warn(clippy::as_conversions)] +// aux-build:macro_rules.rs + +#![warn(clippy::as_conversions)] + +#[macro_use] +extern crate macro_rules; + +fn with_external_macro() { + as_conv_with_arg!(0u32 as u64); + as_conv!(); +} fn main() { let i = 0u32 as u64; let j = &i as *const u64 as *mut u64; + + with_external_macro(); } diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr index 312d3a7460e..f5f75d3aee0 100644 --- a/tests/ui/as_conversions.stderr +++ b/tests/ui/as_conversions.stderr @@ -1,5 +1,5 @@ error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:4:13 + --> $DIR/as_conversions.rs:14:13 | LL | let i = 0u32 as u64; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let i = 0u32 as u64; = help: consider using a safe wrapper for this conversion error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:6:13 + --> $DIR/as_conversions.rs:16:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let j = &i as *const u64 as *mut u64; = help: consider using a safe wrapper for this conversion error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:6:13 + --> $DIR/as_conversions.rs:16:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index 93303865e17..f985a15eda2 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -70,3 +70,17 @@ macro_rules! ref_arg_function { fn fun_example(ref _x: usize) {} }; } + +#[macro_export] +macro_rules! as_conv_with_arg { + (0u32 as u64) => { + () + }; +} + +#[macro_export] +macro_rules! as_conv { + () => { + 0u32 as u64 + }; +} From 8f89108533690afe964799d8f514956ec8b72377 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Mon, 9 Nov 2020 22:14:11 +0900 Subject: [PATCH 051/274] Fix FP in indirect `needless_collect` when used multiple times --- clippy_lints/src/loops.rs | 34 ++++++++++++++++++++++++++- tests/ui/needless_collect_indirect.rs | 20 ++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 0d31e9cfc3d..143cbea5537 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2950,7 +2950,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo for ref stmt in block.stmts { if_chain! { if let StmtKind::Local( - Local { pat: Pat { kind: PatKind::Binding(_, _, ident, .. ), .. }, + Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. }, init: Some(ref init_expr), .. } ) = stmt.kind; if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind; @@ -2964,6 +2964,16 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident); if iter_calls.len() == 1; then { + let mut used_count_visitor = UsedCountVisitor { + cx, + id: *pat_id, + count: 0, + }; + walk_block(&mut used_count_visitor, block); + if used_count_visitor.count > 1 { + return; + } + // Suggest replacing iter_call with iter_replacement, and removing stmt let iter_call = &iter_calls[0]; span_lint_and_then( @@ -3087,6 +3097,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor { } } +struct UsedCountVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + id: HirId, + count: usize, +} + +impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + if same_var(self.cx, expr, self.id) { + self.count += 1; + } else { + walk_expr(self, expr); + } + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } +} + /// Detect the occurrences of calls to `iter` or `into_iter` for the /// given identifier fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option> { diff --git a/tests/ui/needless_collect_indirect.rs b/tests/ui/needless_collect_indirect.rs index 4f6e5357727..0918a6868ab 100644 --- a/tests/ui/needless_collect_indirect.rs +++ b/tests/ui/needless_collect_indirect.rs @@ -22,4 +22,24 @@ fn main() { let sample = vec![a.clone(), "b".to_string(), "c".to_string()]; let non_copy_contains = sample.into_iter().collect::>(); non_copy_contains.contains(&a); + + // Fix #5991 + let vec_a = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let vec_b = vec_a.iter().collect::>(); + if vec_b.len() > 3 {} + let other_vec = vec![1, 3, 12, 4, 16, 2]; + let we_got_the_same_numbers = other_vec.iter().filter(|item| vec_b.contains(item)).collect::>(); + + // Fix #6297 + let sample = [1; 5]; + let multiple_indirect = sample.iter().collect::>(); + let sample2 = vec![2, 3]; + if multiple_indirect.is_empty() { + // do something + } else { + let found = sample2 + .iter() + .filter(|i| multiple_indirect.iter().any(|s| **s % **i == 0)) + .collect::>(); + } } From 5a8396887714fb75f44eae2a3775b1b2a12f38ae Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Tue, 17 Nov 2020 22:34:39 +0100 Subject: [PATCH 052/274] Change `redundant_pattern_matching` to also lint `std::task::Poll` Suggest using utility methods `is_pending` and `is_ready`. --- clippy_lints/src/matches.rs | 33 ++++- clippy_lints/src/utils/paths.rs | 2 + .../redundant_pattern_matching_option.fixed | 8 +- tests/ui/redundant_pattern_matching_option.rs | 8 +- .../redundant_pattern_matching_option.stderr | 38 +++--- .../ui/redundant_pattern_matching_poll.fixed | 73 ++++++++++ tests/ui/redundant_pattern_matching_poll.rs | 88 ++++++++++++ .../ui/redundant_pattern_matching_poll.stderr | 128 ++++++++++++++++++ ...> redundant_pattern_matching_result.fixed} | 1 - ...s => redundant_pattern_matching_result.rs} | 1 - ... redundant_pattern_matching_result.stderr} | 44 +++--- 11 files changed, 364 insertions(+), 60 deletions(-) create mode 100644 tests/ui/redundant_pattern_matching_poll.fixed create mode 100644 tests/ui/redundant_pattern_matching_poll.rs create mode 100644 tests/ui/redundant_pattern_matching_poll.stderr rename tests/ui/{redundant_pattern_matching.fixed => redundant_pattern_matching_result.fixed} (98%) rename tests/ui/{redundant_pattern_matching.rs => redundant_pattern_matching_result.rs} (99%) rename tests/ui/{redundant_pattern_matching.stderr => redundant_pattern_matching_result.stderr} (80%) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index c6dca54e250..af59917e801 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -411,8 +411,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Lint for redundant pattern matching over `Result` or - /// `Option` + /// **What it does:** Lint for redundant pattern matching over `Result`, `Option` or + /// `std::task::Poll` /// /// **Why is this bad?** It's more concise and clear to just use the proper /// utility function @@ -422,10 +422,13 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// # use std::task::Poll; /// if let Ok(_) = Ok::(42) {} /// if let Err(_) = Err::(42) {} /// if let None = None::<()> {} /// if let Some(_) = Some(42) {} + /// if let Poll::Pending = Poll::Pending::<()> {} + /// if let Poll::Ready(_) = Poll::Ready(42) {} /// match Ok::(42) { /// Ok(_) => true, /// Err(_) => false, @@ -435,10 +438,13 @@ declare_clippy_lint! { /// The more idiomatic use would be: /// /// ```rust + /// # use std::task::Poll; /// if Ok::(42).is_ok() {} /// if Err::(42).is_err() {} /// if None::<()>.is_none() {} /// if Some(42).is_some() {} + /// if Poll::Pending::<()>.is_pending() {} + /// if Poll::Ready(42).is_ready() {} /// Ok::(42).is_ok(); /// ``` pub REDUNDANT_PATTERN_MATCHING, @@ -1538,6 +1544,8 @@ mod redundant_pattern_match { "is_err()" } else if match_qpath(path, &paths::OPTION_SOME) { "is_some()" + } else if match_qpath(path, &paths::POLL_READY) { + "is_ready()" } else { return; } @@ -1545,7 +1553,15 @@ mod redundant_pattern_match { return; } }, - PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()", + PatKind::Path(ref path) => { + if match_qpath(path, &paths::OPTION_NONE) { + "is_none()" + } else if match_qpath(path, &paths::POLL_PENDING) { + "is_pending()" + } else { + return; + } + }, _ => return, }; @@ -1628,6 +1644,17 @@ mod redundant_pattern_match { "is_some()", "is_none()", ) + .or_else(|| { + find_good_method_for_match( + arms, + path_left, + path_right, + &paths::POLL_READY, + &paths::POLL_PENDING, + "is_ready()", + "is_pending()", + ) + }) } else { None } diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 2be5ff93f86..e20f146f145 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -86,6 +86,8 @@ pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"]; +pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"]; +pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"]; pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; pub const PTR_NULL: [&str; 3] = ["core", "ptr", "null"]; pub const PTR_NULL_MUT: [&str; 3] = ["core", "ptr", "null_mut"]; diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 499b975b2bb..bc369dd2491 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -2,13 +2,7 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow( - clippy::unit_arg, - unused_must_use, - clippy::needless_bool, - clippy::match_like_matches_macro, - deprecated -)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] fn main() { if None::<()>.is_none() {} diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 2a98435e790..d7616a72913 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -2,13 +2,7 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow( - clippy::unit_arg, - unused_must_use, - clippy::needless_bool, - clippy::match_like_matches_macro, - deprecated -)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] fn main() { if let None = None::<()> {} diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index eebb3448491..7ddfbe503a2 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:14:12 + --> $DIR/redundant_pattern_matching_option.rs:8:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` @@ -7,43 +7,43 @@ LL | if let None = None::<()> {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:16:12 + --> $DIR/redundant_pattern_matching_option.rs:10:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:18:12 + --> $DIR/redundant_pattern_matching_option.rs:12:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:24:15 + --> $DIR/redundant_pattern_matching_option.rs:18:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:26:15 + --> $DIR/redundant_pattern_matching_option.rs:20:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try this: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:28:15 + --> $DIR/redundant_pattern_matching_option.rs:22:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:31:15 + --> $DIR/redundant_pattern_matching_option.rs:25:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:39:5 + --> $DIR/redundant_pattern_matching_option.rs:33:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:44:5 + --> $DIR/redundant_pattern_matching_option.rs:38:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:49:13 + --> $DIR/redundant_pattern_matching_option.rs:43:13 | LL | let _ = match None::<()> { | _____________^ @@ -71,49 +71,49 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:55:20 + --> $DIR/redundant_pattern_matching_option.rs:49:20 | LL | let x = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:60:20 + --> $DIR/redundant_pattern_matching_option.rs:54:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:62:19 + --> $DIR/redundant_pattern_matching_option.rs:56:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:83:12 + --> $DIR/redundant_pattern_matching_option.rs:77:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:85:12 + --> $DIR/redundant_pattern_matching_option.rs:79:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:87:15 + --> $DIR/redundant_pattern_matching_option.rs:81:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:89:15 + --> $DIR/redundant_pattern_matching_option.rs:83:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:91:5 + --> $DIR/redundant_pattern_matching_option.rs:85:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -122,7 +122,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:96:5 + --> $DIR/redundant_pattern_matching_option.rs:90:5 | LL | / match None::<()> { LL | | Some(_) => false, diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed new file mode 100644 index 00000000000..564c427f063 --- /dev/null +++ b/tests/ui/redundant_pattern_matching_poll.fixed @@ -0,0 +1,73 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] + +use std::task::Poll::{self, Pending, Ready}; + +fn main() { + if Pending::<()>.is_pending() {} + + if Ready(42).is_ready() {} + + if Ready(42).is_ready() { + foo(); + } else { + bar(); + } + + while Ready(42).is_ready() {} + + while Ready(42).is_pending() {} + + while Pending::<()>.is_pending() {} + + if Pending::.is_pending() {} + + if Ready(42).is_ready() {} + + Ready(42).is_ready(); + + Pending::<()>.is_pending(); + + let _ = Pending::<()>.is_pending(); + + let poll = Ready(false); + let x = if poll.is_ready() { true } else { false }; + takes_poll(x); + + poll_const(); + + let _ = if gen_poll().is_ready() { + 1 + } else if gen_poll().is_pending() { + 2 + } else { + 3 + }; +} + +fn gen_poll() -> Poll<()> { + Pending +} + +fn takes_poll(_: bool) {} + +fn foo() {} + +fn bar() {} + +const fn poll_const() { + if Ready(42).is_ready() {} + + if Pending::<()>.is_pending() {} + + while Ready(42).is_ready() {} + + while Pending::<()>.is_pending() {} + + Ready(42).is_ready(); + + Pending::<()>.is_pending(); +} diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs new file mode 100644 index 00000000000..d453d4184af --- /dev/null +++ b/tests/ui/redundant_pattern_matching_poll.rs @@ -0,0 +1,88 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] + +use std::task::Poll::{self, Pending, Ready}; + +fn main() { + if let Pending = Pending::<()> {} + + if let Ready(_) = Ready(42) {} + + if let Ready(_) = Ready(42) { + foo(); + } else { + bar(); + } + + while let Ready(_) = Ready(42) {} + + while let Pending = Ready(42) {} + + while let Pending = Pending::<()> {} + + if Pending::.is_pending() {} + + if Ready(42).is_ready() {} + + match Ready(42) { + Ready(_) => true, + Pending => false, + }; + + match Pending::<()> { + Ready(_) => false, + Pending => true, + }; + + let _ = match Pending::<()> { + Ready(_) => false, + Pending => true, + }; + + let poll = Ready(false); + let x = if let Ready(_) = poll { true } else { false }; + takes_poll(x); + + poll_const(); + + let _ = if let Ready(_) = gen_poll() { + 1 + } else if let Pending = gen_poll() { + 2 + } else { + 3 + }; +} + +fn gen_poll() -> Poll<()> { + Pending +} + +fn takes_poll(_: bool) {} + +fn foo() {} + +fn bar() {} + +const fn poll_const() { + if let Ready(_) = Ready(42) {} + + if let Pending = Pending::<()> {} + + while let Ready(_) = Ready(42) {} + + while let Pending = Pending::<()> {} + + match Ready(42) { + Ready(_) => true, + Pending => false, + }; + + match Pending::<()> { + Ready(_) => false, + Pending => true, + }; +} diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr new file mode 100644 index 00000000000..42e5d6f41fe --- /dev/null +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -0,0 +1,128 @@ +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:10:12 + | +LL | if let Pending = Pending::<()> {} + | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:12:12 + | +LL | if let Ready(_) = Ready(42) {} + | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:14:12 + | +LL | if let Ready(_) = Ready(42) { + | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:20:15 + | +LL | while let Ready(_) = Ready(42) {} + | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:22:15 + | +LL | while let Pending = Ready(42) {} + | ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:24:15 + | +LL | while let Pending = Pending::<()> {} + | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:30:5 + | +LL | / match Ready(42) { +LL | | Ready(_) => true, +LL | | Pending => false, +LL | | }; + | |_____^ help: try this: `Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:35:5 + | +LL | / match Pending::<()> { +LL | | Ready(_) => false, +LL | | Pending => true, +LL | | }; + | |_____^ help: try this: `Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:40:13 + | +LL | let _ = match Pending::<()> { + | _____________^ +LL | | Ready(_) => false, +LL | | Pending => true, +LL | | }; + | |_____^ help: try this: `Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:46:20 + | +LL | let x = if let Ready(_) = poll { true } else { false }; + | -------^^^^^^^^------- help: try this: `if poll.is_ready()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:51:20 + | +LL | let _ = if let Ready(_) = gen_poll() { + | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:53:19 + | +LL | } else if let Pending = gen_poll() { + | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:71:12 + | +LL | if let Ready(_) = Ready(42) {} + | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:73:12 + | +LL | if let Pending = Pending::<()> {} + | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:75:15 + | +LL | while let Ready(_) = Ready(42) {} + | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:77:15 + | +LL | while let Pending = Pending::<()> {} + | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` + +error: redundant pattern matching, consider using `is_ready()` + --> $DIR/redundant_pattern_matching_poll.rs:79:5 + | +LL | / match Ready(42) { +LL | | Ready(_) => true, +LL | | Pending => false, +LL | | }; + | |_____^ help: try this: `Ready(42).is_ready()` + +error: redundant pattern matching, consider using `is_pending()` + --> $DIR/redundant_pattern_matching_poll.rs:84:5 + | +LL | / match Pending::<()> { +LL | | Ready(_) => false, +LL | | Pending => true, +LL | | }; + | |_____^ help: try this: `Pending::<()>.is_pending()` + +error: aborting due to 18 previous errors + diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching_result.fixed similarity index 98% rename from tests/ui/redundant_pattern_matching.fixed rename to tests/ui/redundant_pattern_matching_result.fixed index aa20512296a..e94c5704b48 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -3,7 +3,6 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow( - clippy::unit_arg, unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching_result.rs similarity index 99% rename from tests/ui/redundant_pattern_matching.rs rename to tests/ui/redundant_pattern_matching_result.rs index d76f9c288ff..5d175294232 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -3,7 +3,6 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow( - clippy::unit_arg, unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching_result.stderr similarity index 80% rename from tests/ui/redundant_pattern_matching.stderr rename to tests/ui/redundant_pattern_matching_result.stderr index aeb309f5ba1..d6a46babb77 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:16:12 + --> $DIR/redundant_pattern_matching_result.rs:15:12 | LL | if let Ok(_) = &result {} | -------^^^^^---------- help: try this: `if result.is_ok()` @@ -7,31 +7,31 @@ LL | if let Ok(_) = &result {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:18:12 + --> $DIR/redundant_pattern_matching_result.rs:17:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:20:12 + --> $DIR/redundant_pattern_matching_result.rs:19:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:22:15 + --> $DIR/redundant_pattern_matching_result.rs:21:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:24:15 + --> $DIR/redundant_pattern_matching_result.rs:23:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:34:5 + --> $DIR/redundant_pattern_matching_result.rs:33:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:39:5 + --> $DIR/redundant_pattern_matching_result.rs:38:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:44:5 + --> $DIR/redundant_pattern_matching_result.rs:43:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:49:5 + --> $DIR/redundant_pattern_matching_result.rs:48:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -67,73 +67,73 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:54:20 + --> $DIR/redundant_pattern_matching_result.rs:53:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:60:20 + --> $DIR/redundant_pattern_matching_result.rs:59:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:62:19 + --> $DIR/redundant_pattern_matching_result.rs:61:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:85:19 + --> $DIR/redundant_pattern_matching_result.rs:84:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:86:16 + --> $DIR/redundant_pattern_matching_result.rs:85:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:92:12 + --> $DIR/redundant_pattern_matching_result.rs:91:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:93:15 + --> $DIR/redundant_pattern_matching_result.rs:92:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:111:12 + --> $DIR/redundant_pattern_matching_result.rs:110:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:113:12 + --> $DIR/redundant_pattern_matching_result.rs:112:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:115:15 + --> $DIR/redundant_pattern_matching_result.rs:114:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:117:15 + --> $DIR/redundant_pattern_matching_result.rs:116:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:119:5 + --> $DIR/redundant_pattern_matching_result.rs:118:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:124:5 + --> $DIR/redundant_pattern_matching_result.rs:123:5 | LL | / match Err::(42) { LL | | Ok(_) => false, From 1464dcedfbb4e5bb7f88664e2e02e064eeda2a56 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 22 Nov 2020 02:13:53 +0100 Subject: [PATCH 053/274] Thread `Constness` through selection --- clippy_lints/src/future_not_send.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index d2a322e1223..f9697afe405 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { for &(p, _span) in preds { let p = p.subst(cx.tcx, subst); if let Some(trait_ref) = p.to_opt_poly_trait_ref() { - if Some(trait_ref.def_id()) == cx.tcx.lang_items().future_trait() { + if Some(trait_ref.value.def_id()) == cx.tcx.lang_items().future_trait() { is_future = true; break; } From 53196a8bcfe80db551aa9417ce93766c7ee0e46d Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Wed, 4 Nov 2020 23:55:41 +0200 Subject: [PATCH 054/274] Optimize write_vectored for BufWriter If the underlying writer does not support efficient vectored output, do it differently: always try to coalesce the slices in the buffer until one comes that does not fit entirely. Flush the buffer before the first slice if needed. --- library/std/src/io/buffered/bufwriter.rs | 62 +++++++++++++++++++----- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 067ed6ba7ff..d8d62c4b314 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -328,19 +328,57 @@ impl Write for BufWriter { } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total_len = bufs.iter().map(|b| b.len()).sum::(); - if self.buf.len() + total_len > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if total_len >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write_vectored(bufs); - self.panicked = false; - r + if self.get_ref().is_write_vectored() { + let total_len = bufs.iter().map(|b| b.len()).sum::(); + if self.buf.len() + total_len > self.buf.capacity() { + self.flush_buf()?; + } + if total_len >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_vectored(bufs); + self.panicked = false; + r + } else { + bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); + Ok(total_len) + } } else { - bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); - Ok(total_len) + let mut total_written = 0; + let mut iter = bufs.iter(); + if let Some(buf) = iter.by_ref().find(|&buf| !buf.is_empty()) { + // This is the first non-empty slice to write, so if it does + // not fit in the buffer, we still get to flush and proceed. + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + if buf.len() >= self.buf.capacity() { + // The slice is at least as large as the buffering capacity, + // so it's better to write it directly, bypassing the buffer. + self.panicked = true; + let r = self.get_mut().write(buf); + self.panicked = false; + return r; + } else { + self.buf.extend_from_slice(buf); + total_written += buf.len(); + } + debug_assert!(total_written != 0); + } + for buf in iter { + if buf.len() >= self.buf.capacity() { + // This slice should be written directly, but we have + // already buffered some of the input. Bail out, + // expecting it to be handled as the first slice in the + // next call to write_vectored. + break; + } else { + total_written += self.write_to_buf(buf); + if self.buf.capacity() == self.buf.len() { + break; + } + } + } + Ok(total_written) } } From 9fc44239ec7e9f682797bd9e38368d0ec4457077 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Sat, 7 Nov 2020 23:57:27 +0200 Subject: [PATCH 055/274] Make is_write_vectored return true for BufWriter BufWriter provides an efficient implementation of write_vectored also when the underlying writer does not support vectored writes. --- library/std/src/io/buffered/bufwriter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index d8d62c4b314..e42fa4297ef 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -383,7 +383,7 @@ impl Write for BufWriter { } fn is_write_vectored(&self) -> bool { - self.get_ref().is_write_vectored() + true } fn flush(&mut self) -> io::Result<()> { From 00deeb35c8149508240549f5c9f3908a7ba9ee11 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Sun, 8 Nov 2020 01:46:05 +0200 Subject: [PATCH 056/274] Fix is_write_vectored in LineWriterShim Now that BufWriter always claims to support vectored writes, look through it at the wrapped writer to decide whether to use vectored writes for LineWriter. --- library/std/src/io/buffered/linewritershim.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs index a80d08db869..d0c859d2e0c 100644 --- a/library/std/src/io/buffered/linewritershim.rs +++ b/library/std/src/io/buffered/linewritershim.rs @@ -20,6 +20,12 @@ impl<'a, W: Write> LineWriterShim<'a, W> { Self { buffer } } + /// Get a reference to the inner writer (that is, the writer + /// wrapped by the BufWriter). + fn inner(&self) -> &W { + self.buffer.get_ref() + } + /// Get a mutable reference to the inner writer (that is, the writer /// wrapped by the BufWriter). Be careful with this writer, as writes to /// it will bypass the buffer. @@ -227,7 +233,7 @@ impl<'a, W: Write> Write for LineWriterShim<'a, W> { } fn is_write_vectored(&self) -> bool { - self.buffer.is_write_vectored() + self.inner().is_write_vectored() } /// Write some data into this BufReader with line buffering. This means From 674dd623ee067d4298fda867f72442b13014eaa3 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Sun, 22 Nov 2020 17:00:48 +0200 Subject: [PATCH 057/274] Reduce branching in write_vectored for BufWriter Do what write does and optimize for the most likely case: slices are much smaller than the buffer. If a slice does not fit completely in the remaining capacity of the buffer, it is left out rather than buffered partially. Special treatment is only left for oversized slices that are written directly to the underlying writer. --- library/std/src/io/buffered/bufwriter.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index e42fa4297ef..3b3399860ba 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -343,9 +343,8 @@ impl Write for BufWriter { Ok(total_len) } } else { - let mut total_written = 0; let mut iter = bufs.iter(); - if let Some(buf) = iter.by_ref().find(|&buf| !buf.is_empty()) { + let mut total_written = if let Some(buf) = iter.by_ref().find(|&buf| !buf.is_empty()) { // This is the first non-empty slice to write, so if it does // not fit in the buffer, we still get to flush and proceed. if self.buf.len() + buf.len() > self.buf.capacity() { @@ -360,22 +359,18 @@ impl Write for BufWriter { return r; } else { self.buf.extend_from_slice(buf); - total_written += buf.len(); + buf.len() } - debug_assert!(total_written != 0); - } + } else { + return Ok(0); + }; + debug_assert!(total_written != 0); for buf in iter { - if buf.len() >= self.buf.capacity() { - // This slice should be written directly, but we have - // already buffered some of the input. Bail out, - // expecting it to be handled as the first slice in the - // next call to write_vectored. + if self.buf.len() + buf.len() > self.buf.capacity() { break; } else { - total_written += self.write_to_buf(buf); - if self.buf.capacity() == self.buf.len() { - break; - } + self.buf.extend_from_slice(buf); + total_written += buf.len(); } } Ok(total_written) From 4b698f20691b12e76dd916bdc6ee187270208649 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Tue, 27 Oct 2020 13:10:31 +0000 Subject: [PATCH 058/274] Drop support for cloudabi targets --- clippy_lints/src/attrs.rs | 2 +- tests/ui/mismatched_target_os_non_unix.fixed | 5 +-- tests/ui/mismatched_target_os_non_unix.rs | 5 +-- tests/ui/mismatched_target_os_non_unix.stderr | 35 ++++++------------- 4 files changed, 13 insertions(+), 34 deletions(-) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 57702dafa6a..9a667aa61b4 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -40,7 +40,7 @@ static UNIX_SYSTEMS: &[&str] = &[ ]; // NOTE: windows is excluded from the list because it's also a valid target family. -static NON_UNIX_SYSTEMS: &[&str] = &["cloudabi", "hermit", "none", "wasi"]; +static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"]; declare_clippy_lint! { /// **What it does:** Checks for items annotated with `#[inline(always)]`, diff --git a/tests/ui/mismatched_target_os_non_unix.fixed b/tests/ui/mismatched_target_os_non_unix.fixed index 3ee77dcac31..f219a570e7f 100644 --- a/tests/ui/mismatched_target_os_non_unix.fixed +++ b/tests/ui/mismatched_target_os_non_unix.fixed @@ -3,9 +3,6 @@ #![warn(clippy::mismatched_target_os)] #![allow(unused)] -#[cfg(target_os = "cloudabi")] -fn cloudabi() {} - #[cfg(target_os = "hermit")] fn hermit() {} @@ -16,7 +13,7 @@ fn wasi() {} fn none() {} // list with conditions -#[cfg(all(not(any(windows, target_os = "cloudabi")), target_os = "wasi"))] +#[cfg(all(not(windows), target_os = "wasi"))] fn list() {} // windows is a valid target family, should be ignored diff --git a/tests/ui/mismatched_target_os_non_unix.rs b/tests/ui/mismatched_target_os_non_unix.rs index 9cc411418e4..8a8ae756a4f 100644 --- a/tests/ui/mismatched_target_os_non_unix.rs +++ b/tests/ui/mismatched_target_os_non_unix.rs @@ -3,9 +3,6 @@ #![warn(clippy::mismatched_target_os)] #![allow(unused)] -#[cfg(cloudabi)] -fn cloudabi() {} - #[cfg(hermit)] fn hermit() {} @@ -16,7 +13,7 @@ fn wasi() {} fn none() {} // list with conditions -#[cfg(all(not(any(windows, cloudabi)), wasi))] +#[cfg(all(not(windows), wasi))] fn list() {} // windows is a valid target family, should be ignored diff --git a/tests/ui/mismatched_target_os_non_unix.stderr b/tests/ui/mismatched_target_os_non_unix.stderr index 78fc27752d2..5f1b0908304 100644 --- a/tests/ui/mismatched_target_os_non_unix.stderr +++ b/tests/ui/mismatched_target_os_non_unix.stderr @@ -1,23 +1,15 @@ error: operating system used in target family position --> $DIR/mismatched_target_os_non_unix.rs:6:1 | -LL | #[cfg(cloudabi)] - | ^^^^^^--------^^ - | | - | help: try: `target_os = "cloudabi"` - | - = note: `-D clippy::mismatched-target-os` implied by `-D warnings` - -error: operating system used in target family position - --> $DIR/mismatched_target_os_non_unix.rs:9:1 - | LL | #[cfg(hermit)] | ^^^^^^------^^ | | | help: try: `target_os = "hermit"` + | + = note: `-D clippy::mismatched-target-os` implied by `-D warnings` error: operating system used in target family position - --> $DIR/mismatched_target_os_non_unix.rs:12:1 + --> $DIR/mismatched_target_os_non_unix.rs:9:1 | LL | #[cfg(wasi)] | ^^^^^^----^^ @@ -25,7 +17,7 @@ LL | #[cfg(wasi)] | help: try: `target_os = "wasi"` error: operating system used in target family position - --> $DIR/mismatched_target_os_non_unix.rs:15:1 + --> $DIR/mismatched_target_os_non_unix.rs:12:1 | LL | #[cfg(none)] | ^^^^^^----^^ @@ -33,19 +25,12 @@ LL | #[cfg(none)] | help: try: `target_os = "none"` error: operating system used in target family position - --> $DIR/mismatched_target_os_non_unix.rs:19:1 - | -LL | #[cfg(all(not(any(windows, cloudabi)), wasi))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: try - | -LL | #[cfg(all(not(any(windows, target_os = "cloudabi")), wasi))] - | ^^^^^^^^^^^^^^^^^^^^^^ -help: try + --> $DIR/mismatched_target_os_non_unix.rs:16:1 | -LL | #[cfg(all(not(any(windows, cloudabi)), target_os = "wasi"))] - | ^^^^^^^^^^^^^^^^^^ +LL | #[cfg(all(not(windows), wasi))] + | ^^^^^^^^^^^^^^^^^^^^^^^^----^^^ + | | + | help: try: `target_os = "wasi"` -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors From a39a93faeb4969fac62e896138cdf72377fa5502 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 22 Nov 2020 19:21:01 -0600 Subject: [PATCH 059/274] Disable unnecessary_cast for cfg-dependant types --- clippy_lints/src/types.rs | 10 +++++++++- tests/ui/unnecessary_cast.rs | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index f0e10e374e1..840adbbc57a 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -8,6 +8,7 @@ use if_chain::if_chain; use rustc_ast::{FloatTy, IntTy, LitFloatType, LitIntType, LitKind, UintTy}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; +use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericBounds, GenericParamKind, HirId, @@ -1632,7 +1633,14 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if expr.span.from_expansion() { return; } - if let ExprKind::Cast(ref ex, _) = expr.kind { + if let ExprKind::Cast(ref ex, cast_to) = expr.kind { + if let TyKind::Path(QPath::Resolved(_, path)) = cast_to.kind { + if let Res::Def(_, def_id) = path.res { + if cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr) { + return; + } + } + } let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr)); lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to); if let Some(lit) = get_numeric_literal(ex) { diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index df9b227eeb3..e8f2fb46665 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -20,4 +20,7 @@ fn main() { foo!(a, i32); foo!(b, f32); foo!(c, f64); + + // do not lint cast to cfg-dependant type + 1 as std::os::raw::c_char; } From d3d2018eadff575566604c9b883a52fd56dde1c0 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 23 Nov 2020 13:51:04 +0100 Subject: [PATCH 060/274] Merge commit '3e7c6dec244539970b593824334876f8b6ed0b18' into clippyup --- .github/PULL_REQUEST_TEMPLATE.md | 8 +- CHANGELOG.md | 127 ++++++++++- README.md | 32 ++- clippy_lints/src/assertions_on_constants.rs | 2 +- clippy_lints/src/await_holding_invalid.rs | 12 +- clippy_lints/src/cargo_common_metadata.rs | 15 ++ clippy_lints/src/deprecated_lints.rs | 5 + clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_underscore.rs | 64 +++++- clippy_lints/src/lib.rs | 20 +- clippy_lints/src/loops.rs | 28 ++- clippy_lints/src/manual_async_fn.rs | 6 +- clippy_lints/src/map_clone.rs | 27 ++- .../src/methods/bind_instead_of_map.rs | 125 +---------- clippy_lints/src/methods/mod.rs | 142 +++++++----- .../src/methods/unnecessary_lazy_eval.rs | 13 +- clippy_lints/src/mut_key.rs | 6 +- clippy_lints/src/non_copy_const.rs | 170 ++++++++++++--- clippy_lints/src/non_expressive_names.rs | 4 +- clippy_lints/src/panic_unimplemented.rs | 2 +- clippy_lints/src/ranges.rs | 6 +- clippy_lints/src/redundant_clone.rs | 8 +- clippy_lints/src/reference.rs | 61 ++++-- clippy_lints/src/regex.rs | 4 +- clippy_lints/src/strings.rs | 68 +++++- clippy_lints/src/try_err.rs | 9 +- clippy_lints/src/types.rs | 2 +- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 143 +++++++++++++ clippy_lints/src/unused_unit.rs | 29 +-- clippy_lints/src/useless_conversion.rs | 6 +- clippy_lints/src/utils/ast_utils.rs | 3 +- clippy_lints/src/utils/eager_or_lazy.rs | 7 +- clippy_lints/src/utils/mod.rs | 37 ++++ clippy_lints/src/utils/paths.rs | 1 + clippy_lints/src/utils/visitors.rs | 125 +++++++++++ doc/changelog_update.md | 21 +- src/lintlist/mod.rs | 36 +++- .../auxiliary/helper.rs | 16 ++ .../ui/borrow_interior_mutable_const/enums.rs | 101 +++++++++ .../enums.stderr | 75 +++++++ .../others.rs} | 33 +-- .../others.stderr} | 56 ++--- .../borrow_interior_mutable_const/traits.rs | 202 ++++++++++++++++++ .../traits.stderr | 123 +++++++++++ tests/ui/crashes/ice-360.stderr | 2 +- tests/ui/crashes/ice-6332.rs | 11 + .../declare_interior_mutable_const/enums.rs | 123 +++++++++++ .../enums.stderr | 89 ++++++++ .../declare_interior_mutable_const/others.rs | 34 +++ .../others.stderr | 39 ++++ .../traits.rs} | 24 --- .../traits.stderr} | 63 ++---- tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 8 +- tests/ui/deref_addrof.fixed | 26 ++- tests/ui/deref_addrof.rs | 26 ++- tests/ui/deref_addrof.stderr | 24 ++- tests/ui/derive_ord_xor_partial_ord.rs | 1 + tests/ui/derive_ord_xor_partial_ord.stderr | 16 +- tests/ui/doc_errors.rs | 1 + tests/ui/doc_errors.stderr | 14 +- tests/ui/drop_ref.rs | 1 + tests/ui/drop_ref.stderr | 36 ++-- tests/ui/empty_loop.stderr | 6 +- tests/ui/empty_loop_no_std.rs | 7 +- tests/ui/empty_loop_no_std.stderr | 19 ++ tests/ui/filter_methods.rs | 1 + tests/ui/filter_methods.stderr | 8 +- tests/ui/forget_ref.rs | 1 + tests/ui/forget_ref.stderr | 36 ++-- tests/ui/let_underscore_drop.rs | 19 ++ tests/ui/let_underscore_drop.stderr | 27 +++ tests/ui/let_underscore_must_use.rs | 1 + tests/ui/let_underscore_must_use.stderr | 24 +-- tests/ui/manual_async_fn.fixed | 14 +- tests/ui/manual_async_fn.rs | 20 ++ tests/ui/manual_async_fn.stderr | 74 ++++++- tests/ui/manual_ok_or.fixed | 2 +- tests/ui/manual_ok_or.rs | 2 +- tests/ui/manual_unwrap_or.fixed | 2 +- tests/ui/manual_unwrap_or.rs | 2 +- tests/ui/map_clone.fixed | 16 ++ tests/ui/map_clone.rs | 16 ++ tests/ui/map_clone.stderr | 12 +- tests/ui/map_err.rs | 1 + tests/ui/map_err.stderr | 2 +- tests/ui/map_flatten.fixed | 2 + tests/ui/map_flatten.rs | 2 + tests/ui/map_flatten.stderr | 12 +- tests/ui/methods.rs | 44 ---- tests/ui/methods.stderr | 70 +----- tests/ui/needless_lifetimes.rs | 2 +- tests/ui/option_map_unit_fn_fixable.fixed | 1 + tests/ui/option_map_unit_fn_fixable.rs | 1 + tests/ui/option_map_unit_fn_fixable.stderr | 36 ++-- tests/ui/option_option.rs | 3 +- tests/ui/option_option.stderr | 20 +- tests/ui/or_fun_call.fixed | 10 + tests/ui/or_fun_call.rs | 10 + tests/ui/or_fun_call.stderr | 44 ++-- tests/ui/panic_in_result_fn.rs | 1 + tests/ui/panic_in_result_fn.stderr | 24 +-- tests/ui/question_mark.fixed | 1 + tests/ui/question_mark.rs | 1 + tests/ui/question_mark.stderr | 22 +- tests/ui/range_contains.fixed | 5 + tests/ui/range_contains.rs | 5 + tests/ui/range_contains.stderr | 14 +- tests/ui/redundant_pattern_matching.fixed | 1 + tests/ui/redundant_pattern_matching.rs | 1 + tests/ui/redundant_pattern_matching.stderr | 44 ++-- tests/ui/result_unit_error.rs | 1 + tests/ui/result_unit_error.stderr | 8 +- tests/ui/search_is_some.rs | 38 ++++ tests/ui/search_is_some.stderr | 39 ++++ tests/ui/search_is_some_fixable.fixed | 35 +++ tests/ui/search_is_some_fixable.rs | 35 +++ tests/ui/search_is_some_fixable.stderr | 94 ++++++++ tests/ui/string_from_utf8_as_bytes.fixed | 6 + tests/ui/string_from_utf8_as_bytes.rs | 6 + tests/ui/string_from_utf8_as_bytes.stderr | 10 + tests/ui/try_err.fixed | 35 +++ tests/ui/try_err.rs | 35 +++ tests/ui/try_err.stderr | 40 +++- tests/ui/unit_arg.rs | 1 + tests/ui/unit_arg.stderr | 20 +- tests/ui/unnecessary_clone.rs | 2 +- tests/ui/unnecessary_lazy_eval_unfixable.rs | 18 ++ .../ui/unnecessary_lazy_eval_unfixable.stderr | 22 ++ tests/ui/unnecessary_wraps.rs | 116 ++++++++++ tests/ui/unnecessary_wraps.stderr | 106 +++++++++ tests/ui/useless_conversion.fixed | 1 + tests/ui/useless_conversion.rs | 1 + tests/ui/useless_conversion.stderr | 22 +- tests/ui/vec_box_sized.fixed | 14 ++ tests/ui/vec_box_sized.rs | 14 ++ tests/ui/vec_box_sized.stderr | 8 +- tests/ui/wildcard_imports.fixed | 1 + tests/ui/wildcard_imports.rs | 1 + tests/ui/wildcard_imports.stderr | 40 ++-- 141 files changed, 3104 insertions(+), 876 deletions(-) create mode 100644 clippy_lints/src/unnecessary_wraps.rs create mode 100644 clippy_lints/src/utils/visitors.rs create mode 100644 tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs create mode 100644 tests/ui/borrow_interior_mutable_const/enums.rs create mode 100644 tests/ui/borrow_interior_mutable_const/enums.stderr rename tests/ui/{borrow_interior_mutable_const.rs => borrow_interior_mutable_const/others.rs} (81%) rename tests/ui/{borrow_interior_mutable_const.stderr => borrow_interior_mutable_const/others.stderr} (68%) create mode 100644 tests/ui/borrow_interior_mutable_const/traits.rs create mode 100644 tests/ui/borrow_interior_mutable_const/traits.stderr create mode 100644 tests/ui/crashes/ice-6332.rs create mode 100644 tests/ui/declare_interior_mutable_const/enums.rs create mode 100644 tests/ui/declare_interior_mutable_const/enums.stderr create mode 100644 tests/ui/declare_interior_mutable_const/others.rs create mode 100644 tests/ui/declare_interior_mutable_const/others.stderr rename tests/ui/{declare_interior_mutable_const.rs => declare_interior_mutable_const/traits.rs} (84%) rename tests/ui/{declare_interior_mutable_const.stderr => declare_interior_mutable_const/traits.stderr} (56%) create mode 100644 tests/ui/empty_loop_no_std.stderr create mode 100644 tests/ui/let_underscore_drop.rs create mode 100644 tests/ui/let_underscore_drop.stderr create mode 100644 tests/ui/search_is_some.rs create mode 100644 tests/ui/search_is_some.stderr create mode 100644 tests/ui/search_is_some_fixable.fixed create mode 100644 tests/ui/search_is_some_fixable.rs create mode 100644 tests/ui/search_is_some_fixable.stderr create mode 100644 tests/ui/string_from_utf8_as_bytes.fixed create mode 100644 tests/ui/string_from_utf8_as_bytes.rs create mode 100644 tests/ui/string_from_utf8_as_bytes.stderr create mode 100644 tests/ui/unnecessary_lazy_eval_unfixable.rs create mode 100644 tests/ui/unnecessary_lazy_eval_unfixable.stderr create mode 100644 tests/ui/unnecessary_wraps.rs create mode 100644 tests/ui/unnecessary_wraps.stderr diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6c92e10522c..a3f114e0bb3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,8 @@ Thank you for making Clippy better! We're collecting our changelog from pull request descriptions. -If your PR only updates to the latest nightly, you can leave the -`changelog` entry as `none`. Otherwise, please write a short comment +If your PR only includes internal changes, you can just write +`changelog: none`. Otherwise, please write a short comment explaining your change. If your PR fixes an issue, you can add "fixes #issue_number" into this @@ -28,5 +28,5 @@ Delete this line and everything above before opening your PR. --- -*Please keep the line below* -changelog: none +*Please write a short comment explaining your change (or "none" for internal only changes)* +changelog: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b9b33803de..b9e4b0e6704 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,117 @@ document. ## Unreleased / In Rust Nightly -[e636b88...master](https://github.com/rust-lang/rust-clippy/compare/e636b88...master) +[b20d4c1...master](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...master) + +## Rust 1.49 + +Current beta, release 2020-12-31 + +[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1) + +### New Lints + +* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911) +* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029) +* [`disallowed_method`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081) +* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092) +* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092) +* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101) +* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103) +* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109) +* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123) +* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135) +* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157) +* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165) +* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177) +* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183) +* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226) +* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227) +* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233) + +### Moves and Deprecations + +* Rename `single_char_push_str` to [`single_char_add_str`] + [#6037](https://github.com/rust-lang/rust-clippy/pull/6037) +* Rename `zero_width_space` to [`invisible_characters`] + [#6105](https://github.com/rust-lang/rust-clippy/pull/6105) +* Deprecate [`drop_bounds`] (uplifted) + [#6111](https://github.com/rust-lang/rust-clippy/pull/6111) +* Move [`string_lit_as_bytes`] to `nursery` + [#6117](https://github.com/rust-lang/rust-clippy/pull/6117) +* Move [`rc_buffer`] to `restriction` + [#6128](https://github.com/rust-lang/rust-clippy/pull/6128) + +### Enhancements + +* [`manual_memcpy`]: Also lint when there are loop counters (and produce a + reliable suggestion) + [#5727](https://github.com/rust-lang/rust-clippy/pull/5727) +* [`single_char_add_str`]: Also lint on `String::insert_str` + [#6037](https://github.com/rust-lang/rust-clippy/pull/6037) +* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}` + [#6105](https://github.com/rust-lang/rust-clippy/pull/6105) +* [`eq_op`]: Also lint on the `assert_*!` macro family + [#6167](https://github.com/rust-lang/rust-clippy/pull/6167) +* [`items_after_statements`]: Also lint in local macro expansions + [#6176](https://github.com/rust-lang/rust-clippy/pull/6176) +* [`unnecessary_cast`]: Also lint casts on integer and float literals + [#6187](https://github.com/rust-lang/rust-clippy/pull/6187) +* [`manual_unwrap_or`]: Also lint `Result::unwrap_or` + [#6190](https://github.com/rust-lang/rust-clippy/pull/6190) +* [`match_like_matches_macro`]: Also lint when `match` has more than two arms + [#6216](https://github.com/rust-lang/rust-clippy/pull/6216) +* [`integer_arithmetic`]: Better handle `/` an `%` operators + [#6229](https://github.com/rust-lang/rust-clippy/pull/6229) + +### False Positive Fixes + +* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the + lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978) +* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it + is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076) +* [`or_fun_call`]: Revert changes addressing the handling of `const fn` + [#6077](https://github.com/rust-lang/rust-clippy/pull/6077) +* [`needless_range_loop`]: No longer lints, when the iterable is used in the + range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102) +* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent + [#6104](https://github.com/rust-lang/rust-clippy/pull/6104) +* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a + float (e.g. `713.32_64`) + [#6114](https://github.com/rust-lang/rust-clippy/pull/6114) +* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex` + [#6132](https://github.com/rust-lang/rust-clippy/pull/6132) +* [`boxed_local`]: No longer lints on `extern fn` arguments + [#6133](https://github.com/rust-lang/rust-clippy/pull/6133) +* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where` + clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198) + +### Suggestion Fixes/Improvements + +* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter + [#6078](https://github.com/rust-lang/rust-clippy/pull/6078) +* [`needless_arbitrary_self_type`]: Correctly handle expanded code + [#6093](https://github.com/rust-lang/rust-clippy/pull/6093) +* [`useless_format`]: Preserve raw strings in suggestion + [#6151](https://github.com/rust-lang/rust-clippy/pull/6151) +* [`empty_loop`]: Suggest alternatives + [#6162](https://github.com/rust-lang/rust-clippy/pull/6162) +* [`borrowed_box`]: Correctly add parentheses in suggestion + [#6200](https://github.com/rust-lang/rust-clippy/pull/6200) +* [`unused_unit`]: Improve suggestion formatting + [#6247](https://github.com/rust-lang/rust-clippy/pull/6247) + +### Documentation Improvements + +* Some doc improvements: + * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090) + * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162) +* [`doc_markdown`]: Document problematic link text style + [#6107](https://github.com/rust-lang/rust-clippy/pull/6107) ## Rust 1.48 -Current beta, release 2020-11-19 +Current stable, released 2020-11-19 [09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88) @@ -56,7 +162,7 @@ Current beta, release 2020-11-19 * [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`] [#5994](https://github.com/rust-lang/rust-clippy/pull/5994) -* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts +* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts [#5999](https://github.com/rust-lang/rust-clippy/pull/5999) * [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures [#5920](https://github.com/rust-lang/rust-clippy/pull/5920) @@ -64,7 +170,7 @@ Current beta, release 2020-11-19 [#5949](https://github.com/rust-lang/rust-clippy/pull/5949) * [`doc_markdown`]: allow using "GraphQL" without backticks [#5996](https://github.com/rust-lang/rust-clippy/pull/5996) -* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` +* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` [#5971](https://github.com/rust-lang/rust-clippy/pull/5971) * [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays [#6034](https://github.com/rust-lang/rust-clippy/pull/6034) @@ -85,19 +191,19 @@ Current beta, release 2020-11-19 [#5946](https://github.com/rust-lang/rust-clippy/pull/5946) * [`useless_conversion`]: show the type in the error message [#6035](https://github.com/rust-lang/rust-clippy/pull/6035) -* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message +* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message [#5892](https://github.com/rust-lang/rust-clippy/pull/5892) * [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous [#6043](https://github.com/rust-lang/rust-clippy/pull/6043) * [`default_trait_access`]: do not use unnecessary type parameters in the suggestion [#5993](https://github.com/rust-lang/rust-clippy/pull/5993) -* [`collapsible_if`]: don't use expanded code in the suggestion +* [`collapsible_if`]: don't use expanded code in the suggestion [#5992](https://github.com/rust-lang/rust-clippy/pull/5992) * Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`] [#6042](https://github.com/rust-lang/rust-clippy/pull/6042) * [`unit_arg`]: improve the readability of the suggestion [#5931](https://github.com/rust-lang/rust-clippy/pull/5931) -* [`stable_sort_primitive`]: print the type that is being sorted in the lint message +* [`stable_sort_primitive`]: print the type that is being sorted in the lint message [#5935](https://github.com/rust-lang/rust-clippy/pull/5935) * Show line count and max lines in [`too_many_lines`] lint message [#6009](https://github.com/rust-lang/rust-clippy/pull/6009) @@ -105,7 +211,7 @@ Current beta, release 2020-11-19 [#5900](https://github.com/rust-lang/rust-clippy/pull/5900) * [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly [#6024](https://github.com/rust-lang/rust-clippy/pull/6024) -* [`redundant_allocation`]: suggest replacing `Rc>` with `Rc` +* [`redundant_allocation`]: suggest replacing `Rc>` with `Rc` [#5899](https://github.com/rust-lang/rust-clippy/pull/5899) * Make lint messages adhere to rustc dev guide conventions [#5893](https://github.com/rust-lang/rust-clippy/pull/5893) @@ -128,7 +234,7 @@ Current beta, release 2020-11-19 ## Rust 1.47 -Current stable, released 2020-10-08 +Released 2020-10-08 [c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400) @@ -1787,6 +1893,7 @@ Released 2018-09-13 [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return +[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop [`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock [`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value @@ -1956,6 +2063,7 @@ Released 2018-09-13 [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars +[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools @@ -2006,6 +2114,7 @@ Released 2018-09-13 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap +[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern [`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns diff --git a/README.md b/README.md index 8a5975e1f97..1da626b505d 100644 --- a/README.md +++ b/README.md @@ -7,28 +7,22 @@ A collection of lints to catch common mistakes and improve your [Rust](https://g [There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) -We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: - -* `clippy::all` (everything that is on by default: all the categories below except for `nursery`, `pedantic`, and `cargo`) -* `clippy::correctness` (code that is just **outright wrong** or **very very useless**, causes hard errors by default) -* `clippy::style` (code that should be written in a more idiomatic way) -* `clippy::complexity` (code that does something simple but in a complex way) -* `clippy::perf` (code that can be written in a faster way) -* `clippy::pedantic` (lints which are rather strict, off by default) -* `clippy::nursery` (new lints that aren't quite ready yet, off by default) -* `clippy::cargo` (checks against the cargo manifest, off by default) +Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). +You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. + +Category | Description | Default level +-- | -- | -- +`clippy::all` | all lints that are on by default (correctness, style, complexity, perf) | **warn/deny** +`clippy::correctness` | code that is outright wrong or very useless | **deny** +`clippy::style` | code that should be written in a more idiomatic way | **warn** +`clippy::complexity` | code that does something simple but in a complex way | **warn** +`clippy::perf` | code that can be written to run faster | **warn** +`clippy::pedantic` | lints which are rather strict or might have false positives | allow +`clippy::nursery` | new lints that are still under development | allow +`clippy::cargo` | lints for the cargo manifest | allow More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas! -Only the following of those categories are enabled by default: - -* `clippy::style` -* `clippy::correctness` -* `clippy::complexity` -* `clippy::perf` - -Other categories need to be enabled in order for their lints to be executed. - The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used very selectively, if at all. diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index a52f0997d43..62c73dbac48 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -129,7 +129,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) if let ExprKind::Block(ref block, _) = arms[0].body.kind; if block.stmts.is_empty(); if let Some(block_expr) = &block.expr; - // inner block is optional. unwarp it if it exists, or use the expression as is otherwise. + // inner block is optional. unwrap it if it exists, or use the expression as is otherwise. if let Some(begin_panic_call) = match block_expr.kind { ExprKind::Block(ref inner_block, _) => &inner_block.expr, _ => &block.expr, diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index fcebb54c6c2..58892024ce2 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// } /// ``` pub AWAIT_HOLDING_LOCK, - correctness, + pedantic, "Inside an async function, holding a MutexGuard while calling await" } @@ -65,8 +65,8 @@ declare_clippy_lint! { /// use std::cell::RefCell; /// /// async fn foo(x: &RefCell) { - /// let b = x.borrow_mut()(); - /// *ref += 1; + /// let mut y = x.borrow_mut(); + /// *y += 1; /// bar.await; /// } /// ``` @@ -77,14 +77,14 @@ declare_clippy_lint! { /// /// async fn foo(x: &RefCell) { /// { - /// let b = x.borrow_mut(); - /// *ref += 1; + /// let mut y = x.borrow_mut(); + /// *y += 1; /// } /// bar.await; /// } /// ``` pub AWAIT_HOLDING_REFCELL_REF, - correctness, + pedantic, "Inside an async function, holding a RefCell ref while calling await" } diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 76a000157df..0d294761af5 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -23,6 +23,21 @@ declare_clippy_lint! { /// [package] /// name = "clippy" /// version = "0.0.212" + /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" + /// repository = "https://github.com/rust-lang/rust-clippy" + /// readme = "README.md" + /// license = "MIT OR Apache-2.0" + /// keywords = ["clippy", "lint", "plugin"] + /// categories = ["development-tools", "development-tools::cargo-plugins"] + /// ``` + /// + /// Should include an authors field like: + /// + /// ```toml + /// # This `Cargo.toml` includes all common metadata + /// [package] + /// name = "clippy" + /// version = "0.0.212" /// authors = ["Someone "] /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" /// repository = "https://github.com/rust-lang/rust-clippy" diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 461c6e31d3e..1c3285ed701 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -181,3 +181,8 @@ declare_deprecated_lint! { pub TEMPORARY_CSTRING_AS_PTR, "this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`" } + +declare_deprecated_lint! { + pub PANIC_PARAMS, + "this lint has been uplifted to rustc and is now called `panic_fmt`" +} diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 8e2f03d6e4e..8842901d90b 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -69,7 +69,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for comparing to an empty slice such as "" or [],` + /// **What it does:** Checks for comparing to an empty slice such as `""` or `[]`, /// and suggests using `.is_empty()` where applicable. /// /// **Why is this bad?** Some structures can answer `.is_empty()` much faster diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index ae2f6131b5b..6a5a77f8690 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; +use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for `let _ = ` @@ -58,7 +58,48 @@ declare_clippy_lint! { "non-binding let on a synchronization lock" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK]); +declare_clippy_lint! { + /// **What it does:** Checks for `let _ = ` + /// where expr has a type that implements `Drop` + /// + /// **Why is this bad?** This statement immediately drops the initializer + /// expression instead of extending its lifetime to the end of the scope, which + /// is often not intended. To extend the expression's lifetime to the end of the + /// scope, use an underscore-prefixed name instead (i.e. _var). If you want to + /// explicitly drop the expression, `std::mem::drop` conveys your intention + /// better and is less error-prone. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// Bad: + /// ```rust,ignore + /// struct Droppable; + /// impl Drop for Droppable { + /// fn drop(&mut self) {} + /// } + /// { + /// let _ = Droppable; + /// // ^ dropped here + /// /* more code */ + /// } + /// ``` + /// + /// Good: + /// ```rust,ignore + /// { + /// let _droppable = Droppable; + /// /* more code */ + /// // dropped at end of scope + /// } + /// ``` + pub LET_UNDERSCORE_DROP, + pedantic, + "non-binding let on a type that implements `Drop`" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]); const SYNC_GUARD_PATHS: [&[&str]; 3] = [ &paths::MUTEX_GUARD, @@ -84,6 +125,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }); + let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait| + init_ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => { + implements_trait(cx, inner_ty, drop_trait, &[]) + }, + + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) + ); if contains_sync_guard { span_lint_and_help( cx, @@ -94,6 +144,16 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" ) + } else if implements_drop { + span_lint_and_help( + cx, + LET_UNDERSCORE_DROP, + local.span, + "non-binding `let` on a type that implements `Drop`", + None, + "consider using an underscore-prefixed named \ + binding or dropping explicitly with `std::mem::drop`" + ) } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( cx, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 19bf67d80c4..7e8cbd00c22 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -323,6 +323,7 @@ mod unicode; mod unit_return_expecting_ord; mod unnamed_address; mod unnecessary_sort_by; +mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_io_amount; @@ -495,6 +496,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::temporary_cstring_as_ptr", "this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`", ); + store.register_removed( + "clippy::panic_params", + "this lint has been uplifted to rustc and is now called `panic_fmt`", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` @@ -622,6 +627,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, &let_if_seq::USELESS_LET_IF_SEQ, + &let_underscore::LET_UNDERSCORE_DROP, &let_underscore::LET_UNDERSCORE_LOCK, &let_underscore::LET_UNDERSCORE_MUST_USE, &lifetimes::EXTRA_UNUSED_LIFETIMES, @@ -831,6 +837,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &stable_sort_primitive::STABLE_SORT_PRIMITIVE, &strings::STRING_ADD, &strings::STRING_ADD_ASSIGN, + &strings::STRING_FROM_UTF8_AS_BYTES, &strings::STRING_LIT_AS_BYTES, &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, @@ -889,6 +896,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnamed_address::FN_ADDRESS_COMPARISONS, &unnamed_address::VTABLE_ADDRESS_COMPARISONS, &unnecessary_sort_by::UNNECESSARY_SORT_BY, + &unnecessary_wraps::UNNECESSARY_WRAPS, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, &unused_io_amount::UNUSED_IO_AMOUNT, @@ -1061,6 +1069,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box redundant_clone::RedundantClone); store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy); + store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); @@ -1215,6 +1224,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(&attrs::INLINE_ALWAYS), + LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), + LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&checked_conversions::CHECKED_CONVERSIONS), LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), @@ -1238,6 +1249,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS), + LintId::of(&let_underscore::LET_UNDERSCORE_DROP), LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), LintId::of(&literal_representation::UNREADABLE_LITERAL), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), @@ -1317,8 +1329,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&attrs::MISMATCHED_TARGET_OS), LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), LintId::of(&attrs::USELESS_ATTRIBUTE), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(&bit_mask::BAD_BIT_MASK), LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(&blacklisted_name::BLACKLISTED_NAME), @@ -1525,6 +1535,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), + LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), @@ -1565,6 +1576,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), @@ -1749,6 +1761,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), LintId::of(&repeat_once::REPEAT_ONCE), + LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), @@ -1767,6 +1780,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), @@ -1779,8 +1793,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&attrs::DEPRECATED_SEMVER), LintId::of(&attrs::MISMATCHED_TARGET_OS), LintId::of(&attrs::USELESS_ATTRIBUTE), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(&bit_mask::BAD_BIT_MASK), LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(&booleans::LOGIC_BUG), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 5a4264f9b5c..0d31e9cfc3d 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -4,10 +4,10 @@ use crate::utils::sugg::Sugg; use crate::utils::usage::{is_unused, mutated_variables}; use crate::utils::{ contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, - indent_of, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, - match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, snippet, - snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, - span_lint_and_then, sugg, SpanlessEq, + indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, + last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, + snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, + span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -543,17 +543,15 @@ impl<'tcx> LateLintPass<'tcx> for Loops { // (also matches an explicit "match" instead of "if let") // (even if the "match" or "if let" is used for declaration) if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind { - // also check for empty `loop {}` statements - // TODO(issue #6161): Enable for no_std crates (outside of #[panic_handler]) - if block.stmts.is_empty() && block.expr.is_none() && !is_no_std_crate(cx.tcx.hir().krate()) { - span_lint_and_help( - cx, - EMPTY_LOOP, - expr.span, - "empty `loop {}` wastes CPU cycles", - None, - "You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.", - ); + // also check for empty `loop {}` statements, skipping those in #[panic_handler] + if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) { + let msg = "empty `loop {}` wastes CPU cycles"; + let help = if is_no_std_crate(cx.tcx.hir().krate()) { + "you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body" + } else { + "you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body" + }; + span_lint_and_help(cx, EMPTY_LOOP, expr.span, msg, None, help); } // extract the expression from the first statement (if any) in a block diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 864d1ea87f5..7b3b450ef93 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use crate::utils::paths::FUTURE_FROM_GENERATOR; -use crate::utils::{match_function_call, snippet_block, snippet_opt, span_lint_and_then}; +use crate::utils::{match_function_call, position_before_rarrow, snippet_block, snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { |diag| { if_chain! { if let Some(header_snip) = snippet_opt(cx, header_span); - if let Some(ret_pos) = header_snip.rfind("->"); + if let Some(ret_pos) = position_before_rarrow(header_snip.clone()); if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); then { let help = format!("make the function `async` and {}", ret_sugg); @@ -194,7 +194,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, }, _ => { let sugg = "return the output of the future directly"; - snippet_opt(cx, output.span).map(|snip| (sugg, format!("-> {}", snip))) + snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {}", snip))) }, } } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 034cd99a9be..220240acb7a 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -8,13 +8,15 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::Mutability; use rustc_middle::ty; +use rustc_middle::ty::adjustment::Adjust; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests - /// `iterator.cloned()` instead + /// **What it does:** Checks for usage of `map(|x| x.clone())` or + /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, + /// and suggests `cloned()` or `copied()` instead /// /// **Why is this bad?** Readability, this can be written more concisely /// @@ -75,14 +77,19 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { } } }, - hir::ExprKind::MethodCall(ref method, _, ref obj, _) => { - if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone" - && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) { - - let obj_ty = cx.typeck_results().expr_ty(&obj[0]); - if let ty::Ref(_, ty, _) = obj_ty.kind() { - let copy = is_copy(cx, ty); - lint(cx, e.span, args[0].span, copy); + hir::ExprKind::MethodCall(ref method, _, [obj], _) => if_chain! { + if ident_eq(name, obj) && method.ident.name == sym::clone; + if match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT); + // no autoderefs + if !cx.typeck_results().expr_adjustments(obj).iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); + then { + let obj_ty = cx.typeck_results().expr_ty(obj); + if let ty::Ref(_, ty, mutability) = obj_ty.kind() { + if matches!(mutability, Mutability::Not) { + let copy = is_copy(cx, ty); + lint(cx, e.span, args[0].span, copy); + } } else { lint_needless_cloning(cx, e.span, args[0].span); } diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index ae37942e55a..540a1484a85 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,14 +1,12 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use crate::utils::{ in_macro, match_qpath, match_type, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet, - snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, + snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, visitors::find_all_ret_expressions, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::LateContext; -use rustc_middle::hir::map::Map; use rustc_span::Span; pub(crate) struct OptionAndThenSome; @@ -193,124 +191,3 @@ pub(crate) trait BindInsteadOfMap { } } } - -/// returns `true` if expr contains match expr desugared from try -fn contains_try(expr: &hir::Expr<'_>) -> bool { - struct TryFinder { - found: bool, - } - - impl<'hir> intravisit::Visitor<'hir> for TryFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - if self.found { - return; - } - match expr.kind { - hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true, - _ => intravisit::walk_expr(self, expr), - } - } - } - - let mut visitor = TryFinder { found: false }; - visitor.visit_expr(expr); - visitor.found -} - -fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool -where - F: FnMut(&'hir hir::Expr<'hir>) -> bool, -{ - struct RetFinder { - in_stmt: bool, - failed: bool, - cb: F, - } - - struct WithStmtGuarg<'a, F> { - val: &'a mut RetFinder, - prev_in_stmt: bool, - } - - impl RetFinder { - fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { - let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); - WithStmtGuarg { - val: self, - prev_in_stmt, - } - } - } - - impl std::ops::Deref for WithStmtGuarg<'_, F> { - type Target = RetFinder; - - fn deref(&self) -> &Self::Target { - self.val - } - } - - impl std::ops::DerefMut for WithStmtGuarg<'_, F> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.val - } - } - - impl Drop for WithStmtGuarg<'_, F> { - fn drop(&mut self) { - self.val.in_stmt = self.prev_in_stmt; - } - } - - impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { - if self.failed { - return; - } - if self.in_stmt { - match expr.kind { - hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), - _ => intravisit::walk_expr(self, expr), - } - } else { - match expr.kind { - hir::ExprKind::Match(cond, arms, _) => { - self.inside_stmt(true).visit_expr(cond); - for arm in arms { - self.visit_expr(arm.body); - } - }, - hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), - hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), - _ => self.failed |= !(self.cb)(expr), - } - } - } - } - - !contains_try(expr) && { - let mut ret_finder = RetFinder { - in_stmt: false, - failed: false, - cb: callback, - }; - ret_finder.visit_expr(expr); - !ret_finder.failed - } -} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 30f4c0c56d2..fa174404365 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -515,11 +515,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for an iterator search (such as `find()`, + /// **What it does:** Checks for an iterator or string search (such as `find()`, /// `position()`, or `rposition()`) followed by a call to `is_some()`. /// /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.any(_)`. + /// `_.any(_)` or `_.contains(_)`. /// /// **Known problems:** None. /// @@ -535,7 +535,7 @@ declare_clippy_lint! { /// ``` pub SEARCH_IS_SOME, complexity, - "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`" + "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`" } declare_clippy_lint! { @@ -1351,7 +1351,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map(_).collect::()`. + /// **What it does:** Checks for usage of `_.map(_).collect::()`. /// /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic. /// @@ -1797,12 +1797,20 @@ fn lint_or_fun_call<'tcx>( cx: &LateContext<'tcx>, name: &str, method_span: Span, - fun_span: Span, self_expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, - or_has_args: bool, span: Span, + // None if lambda is required + fun_span: Option, ) { + // (path, fn_has_argument, methods, suffix) + static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ + (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), + (&paths::RESULT, true, &["or", "unwrap_or"], "else"), + ]; + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { if path.ident.as_str() == "len" { let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); @@ -1818,16 +1826,8 @@ fn lint_or_fun_call<'tcx>( } } - // (path, fn_has_argument, methods, suffix) - let know_types: &[(&[_], _, &[_], _)] = &[ - (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), - (&paths::RESULT, true, &["or", "unwrap_or"], "else"), - ]; - if_chain! { - if know_types.iter().any(|k| k.2.contains(&name)); + if KNOW_TYPES.iter().any(|k| k.2.contains(&name)); if is_lazyness_candidate(cx, arg); if !contains_return(&arg); @@ -1835,15 +1835,23 @@ fn lint_or_fun_call<'tcx>( let self_ty = cx.typeck_results().expr_ty(self_expr); if let Some(&(_, fn_has_arguments, poss, suffix)) = - know_types.iter().find(|&&i| match_type(cx, self_ty, i.0)); + KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0)); if poss.contains(&name); then { - let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) { - (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), - (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), - (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."), + let sugg: Cow<'_, str> = { + let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { + (false, Some(fun_span)) => (fun_span, false), + _ => (arg.span, true), + }; + let snippet = snippet_with_macro_callsite(cx, snippet_span, ".."); + if use_lambda { + let l_arg = if fn_has_arguments { "_" } else { "" }; + format!("|{}| {}", l_arg, snippet).into() + } else { + snippet + } }; let span_replace_word = method_span.with_hi(span.hi()); span_lint_and_sugg( @@ -1864,28 +1872,13 @@ fn lint_or_fun_call<'tcx>( hir::ExprKind::Call(ref fun, ref or_args) => { let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { - check_general_case( - cx, - name, - method_span, - fun.span, - &args[0], - &args[1], - or_has_args, - expr.span, - ); + let fun_span = if or_has_args { None } else { Some(fun.span) }; + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span); } }, - hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case( - cx, - name, - method_span, - span, - &args[0], - &args[1], - !or_args.is_empty(), - expr.span, - ), + hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); + }, _ => {}, } } @@ -3048,6 +3041,7 @@ fn lint_flat_map_identity<'tcx>( } /// lint searching an Iterator followed by `is_some()` +/// or calling `find()` on a string followed by `is_some()` fn lint_search_is_some<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, @@ -3059,10 +3053,10 @@ fn lint_search_is_some<'tcx>( // lint if caller of search is an Iterator if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { let msg = format!( - "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \ - expressed by calling `any()`.", + "called `is_some()` after searching an `Iterator` with `{}`", search_method ); + let hint = "this is more succinctly expressed by calling `any()`"; let search_snippet = snippet(cx, search_args[1].span, ".."); if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` @@ -3090,7 +3084,7 @@ fn lint_search_is_some<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), &msg, - "try this", + "use `any()` instead", format!( "any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) @@ -3098,7 +3092,36 @@ fn lint_search_is_some<'tcx>( Applicability::MachineApplicable, ); } else { - span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint); + } + } + // lint if `find()` is called by `String` or `&str` + else if search_method == "find" { + let is_string_or_str_slice = |e| { + let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); + if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { + true + } else { + *self_ty.kind() == ty::Str + } + }; + if_chain! { + if is_string_or_str_slice(&search_args[0]); + if is_string_or_str_slice(&search_args[1]); + then { + let msg = "called `is_some()` after calling `find()` on a string"; + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + msg, + "use `contains()` instead", + format!("contains({})", find_arg), + applicability, + ); + } } } } @@ -3901,21 +3924,24 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); - let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); - let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap(); + if_chain! { + if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); + if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR); - if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) { - // `expr` implements `FromIterator` trait - let iter_expr = snippet(cx, args[0].span, ".."); - span_lint_and_sugg( - cx, - FROM_ITER_INSTEAD_OF_COLLECT, - expr.span, - "usage of `FromIterator::from_iter`", - "use `.collect()` instead of `::from_iter()`", - format!("{}.collect()", iter_expr), - Applicability::MaybeIncorrect, - ); + if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); + then { + // `expr` implements `FromIterator` trait + let iter_expr = snippet(cx, args[0].span, ".."); + span_lint_and_sugg( + cx, + FROM_ITER_INSTEAD_OF_COLLECT, + expr.span, + "usage of `FromIterator::from_iter`", + "use `.collect()` instead of `::from_iter()`", + format!("{}.collect()", iter_expr), + Applicability::MaybeIncorrect, + ); + } } } diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index cde89983a26..a867bdb326d 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -33,6 +33,17 @@ pub(super) fn lint<'tcx>( } else { "unnecessary closure used to substitute value for `Result::Err`" }; + let applicability = if body + .params + .iter() + // bindings are checked to be unused above + .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) + { + Applicability::MachineApplicable + } else { + // replacing the lambda may break type inference + Applicability::MaybeIncorrect + }; span_lint_and_sugg( cx, @@ -46,7 +57,7 @@ pub(super) fn lint<'tcx>( simplify_using, snippet(cx, body_expr.span, ".."), ), - Applicability::MachineApplicable, + applicability, ); } } diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 9cceecc785a..11044e0c2fb 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -89,11 +89,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir:: for (hir_ty, ty) in decl.inputs.iter().zip(fn_sig.inputs().skip_binder().iter()) { check_ty(cx, hir_ty.span, ty); } - check_ty( - cx, - decl.output.span(), - cx.tcx.erase_late_bound_regions(fn_sig.output()), - ); + check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output())); } // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 7b662eae775..6b0d198edcf 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -5,11 +5,15 @@ use std::ptr; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp}; +use rustc_hir::def_id::DefId; +use rustc_hir::{ + BodyId, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, +}; use rustc_infer::traits::specialization_graph; use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::mir::interpret::{ConstValue, ErrorHandled}; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{AssocKind, Ty}; +use rustc_middle::ty::{self, AssocKind, Const, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; @@ -36,14 +40,17 @@ declare_clippy_lint! { /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, /// and this lint should be suppressed. /// - /// When an enum has variants with interior mutability, use of its non interior mutable - /// variants can generate false positives. See issue - /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) + /// Even though the lint avoids triggering on a constant whose type has enums that have variants + /// with interior mutability, and its value uses non interior mutable variants (see + /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and + /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples); + /// it complains about associated constants without default values only based on its types; + /// which might not be preferable. + /// There're other enums plus associated constants cases that the lint cannot handle. /// /// Types that have underlying or potential interior mutability trigger the lint whether /// the interior mutable field is used or not. See issues /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and - /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) /// /// **Example:** /// ```rust @@ -105,6 +112,79 @@ declare_clippy_lint! { "referencing `const` with interior mutability" } +fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, + // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is + // 'unfrozen'. However, this code causes a false negative in which + // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell`. + // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` + // since it works when a pointer indirection involves (`Cell<*const T>`). + // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; + // but I'm not sure whether it's a decent way, if possible. + cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) +} + +fn is_value_unfrozen_raw<'tcx>( + cx: &LateContext<'tcx>, + result: Result, ErrorHandled>, + ty: Ty<'tcx>, +) -> bool { + fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool { + match val.ty.kind() { + // the fact that we have to dig into every structs to search enums + // leads us to the point checking `UnsafeCell` directly is the only option. + ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true, + ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { + let val = cx.tcx.destructure_const(cx.param_env.and(val)); + val.fields.iter().any(|field| inner(cx, field)) + }, + _ => false, + } + } + + result.map_or_else( + |err| { + // Consider `TooGeneric` cases as being unfrozen. + // This causes a false positive where an assoc const whose type is unfrozen + // have a value that is a frozen variant with a generic param (an example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). + // However, it prevents a number of false negatives that is, I think, important: + // 1. assoc consts in trait defs referring to consts of themselves + // (an example is `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). + // 2. a path expr referring to assoc consts whose type is doesn't have + // any frozen variants in trait defs (i.e. without substitute for `Self`). + // (e.g. borrowing `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) + // 3. similar to the false positive above; + // but the value is an unfrozen variant, or the type has no enums. (An example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` + // and `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). + // One might be able to prevent these FNs correctly, and replace this with `false`; + // e.g. implementing `has_frozen_variant` described above, and not running this function + // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd + // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, + // similar to 2., but with the a frozen variant) (e.g. borrowing + // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). + // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). + err == ErrorHandled::TooGeneric + }, + |val| inner(cx, Const::from_value(cx.tcx, val, ty)), + ) +} + +fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { + let result = cx.tcx.const_eval_poly(body_id.hir_id.owner.to_def_id()); + is_value_unfrozen_raw(cx, result, ty) +} + +fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { + let substs = cx.typeck_results().node_substs(hir_id); + + let result = cx + .tcx + .const_eval_resolve(cx.param_env, ty::WithOptConstParam::unknown(def_id), substs, None, None); + is_value_unfrozen_raw(cx, result, ty) +} + #[derive(Copy, Clone)] enum Source { Item { item: Span }, @@ -130,19 +210,7 @@ impl Source { } } -fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) { - // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, - // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is - // 'unfrozen'. However, this code causes a false negative in which - // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell`. - // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` - // since it works when a pointer indirection involves (`Cell<*const T>`). - // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; - // but I'm not sure whether it's a decent way, if possible. - if cx.tcx.layout_of(cx.param_env.and(ty)).is_err() || ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) { - return; - } - +fn lint(cx: &LateContext<'_>, source: Source) { let (lint, msg, span) = source.lint(); span_lint_and_then(cx, lint, span, msg, |diag| { if span.from_expansion() { @@ -165,24 +233,44 @@ declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTER impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { - if let ItemKind::Const(hir_ty, ..) = &it.kind { + if let ItemKind::Const(hir_ty, body_id) = it.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); - verify_ty_bound(cx, ty, Source::Item { item: it.span }); + + if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { + lint(cx, Source::Item { item: it.span }); + } } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind { + if let TraitItemKind::Const(hir_ty, body_id_opt) = &trait_item.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); + // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - verify_ty_bound(cx, normalized, Source::Assoc { item: trait_item.span }); + if is_unfrozen(cx, normalized) + // When there's no default value, lint it only according to its type; + // in other words, lint consts whose value *could* be unfrozen, not definitely is. + // This feels inconsistent with how the lint treats generic types, + // which avoids linting types which potentially become unfrozen. + // One could check whether a unfrozen type have a *frozen variant* + // (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`), + // and do the same as the case of generic types at impl items. + // Note that it isn't sufficient to check if it has an enum + // since all of that enum's variants can be unfrozen: + // i.e. having an enum doesn't necessary mean a type has a frozen variant. + // And, implementing it isn't a trivial task; it'll probably end up + // re-implementing the trait predicate evaluation specific to `Freeze`. + && body_id_opt.map_or(true, |body_id| is_value_unfrozen_poly(cx, body_id, normalized)) + { + lint(cx, Source::Assoc { item: trait_item.span }); + } } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind { + if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind { let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id); let item = cx.tcx.hir().expect_item(item_hir_id); @@ -209,16 +297,23 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { ), )) .is_err(); + // If there were a function like `has_frozen_variant` described above, + // we should use here as a frozen variant is a potential to be frozen + // similar to unknown layouts. + // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` then { let ty = hir_ty_to_ty(cx.tcx, hir_ty); let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - verify_ty_bound( - cx, - normalized, - Source::Assoc { - item: impl_item.span, - }, - ); + if is_unfrozen(cx, normalized) + && is_value_unfrozen_poly(cx, *body_id, normalized) + { + lint( + cx, + Source::Assoc { + item: impl_item.span, + }, + ); + } } } }, @@ -226,7 +321,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { let ty = hir_ty_to_ty(cx.tcx, hir_ty); // Normalize assoc types originated from generic params. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - verify_ty_bound(cx, normalized, Source::Assoc { item: impl_item.span }); + + if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) { + lint(cx, Source::Assoc { item: impl_item.span }); + } }, _ => (), } @@ -241,8 +339,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } // Make sure it is a const item. - match qpath_res(cx, qpath, expr.hir_id) { - Res::Def(DefKind::Const | DefKind::AssocConst, _) => {}, + let item_def_id = match qpath_res(cx, qpath, expr.hir_id) { + Res::Def(DefKind::Const | DefKind::AssocConst, did) => did, _ => return, }; @@ -319,7 +417,9 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { cx.typeck_results().expr_ty(dereferenced_expr) }; - verify_ty_bound(cx, ty, Source::Expr { expr: expr.span }); + if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) { + lint(cx, Source::Expr { expr: expr.span }); + } } } } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 6b175490cc8..5b42b61fcde 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -1,7 +1,5 @@ use crate::utils::{span_lint, span_lint_and_then}; -use rustc_ast::ast::{ - Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind, -}; +use rustc_ast::ast::{Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind}; use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_middle::lint::in_external_macro; diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 8b10d071647..31b03ecd101 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -73,7 +73,7 @@ declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANI impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(_) = match_panic_call(cx, expr) { + if match_panic_call(cx, expr).is_some() { let span = get_outer_span(expr); if is_expn_of(expr.span, "unimplemented").is_some() { span_lint( diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 79e9a56af9a..4b514bbd42c 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -222,13 +222,14 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' let name = snippet_with_applicability(cx, name_span, "_", &mut applicability); let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability); let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability); + let space = if lo.ends_with('.') { " " } else { "" }; span_lint_and_sugg( cx, MANUAL_RANGE_CONTAINS, span, &format!("manual `{}::contains` implementation", range_type), "use", - format!("({}{}{}).contains(&{})", lo, range_op, hi, name), + format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), applicability, ); } else if !combine_and && ord == Some(lord) { @@ -251,13 +252,14 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' let name = snippet_with_applicability(cx, name_span, "_", &mut applicability); let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability); let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability); + let space = if lo.ends_with('.') { " " } else { "" }; span_lint_and_sugg( cx, MANUAL_RANGE_CONTAINS, span, &format!("manual `!{}::contains` implementation", range_type), "use", - format!("!({}{}{}).contains(&{})", lo, range_op, hi, name), + format!("!({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), applicability, ); } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 602facbe062..f0e507105a6 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -320,11 +320,11 @@ fn find_stmt_assigns_to<'tcx>( match (by_ref, &*rvalue) { (true, mir::Rvalue::Ref(_, _, place)) | (false, mir::Rvalue::Use(mir::Operand::Copy(place))) => { - base_local_and_movability(cx, mir, *place) + Some(base_local_and_movability(cx, mir, *place)) }, (false, mir::Rvalue::Ref(_, _, place)) => { if let [mir::ProjectionElem::Deref] = place.as_ref().projection { - base_local_and_movability(cx, mir, *place) + Some(base_local_and_movability(cx, mir, *place)) } else { None } @@ -341,7 +341,7 @@ fn base_local_and_movability<'tcx>( cx: &LateContext<'tcx>, mir: &mir::Body<'tcx>, place: mir::Place<'tcx>, -) -> Option<(mir::Local, CannotMoveOut)> { +) -> (mir::Local, CannotMoveOut) { use rustc_middle::mir::PlaceRef; // Dereference. You cannot move things out from a borrowed value. @@ -362,7 +362,7 @@ fn base_local_and_movability<'tcx>( && !is_copy(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty); } - Some((local, deref || field || slice)) + (local, deref || field || slice) } struct LocalUseVisitor { diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 3fda00403c6..efe3237990d 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,9 +1,10 @@ -use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use rustc_ast::ast::{Expr, ExprKind, UnOp}; +use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::BytePos; declare_clippy_lint! { /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. @@ -42,19 +43,55 @@ impl EarlyLintPass for DerefAddrOf { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; - if let ExprKind::AddrOf(_, _, ref addrof_target) = without_parens(deref_target).kind; + if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; if !in_macro(addrof_target.span); then { let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - DEREF_ADDROF, - e.span, - "immediately dereferencing a reference", - "try this", - format!("{}", snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)), - applicability, - ); + let sugg = if e.span.from_expansion() { + if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) { + // Remove leading whitespace from the given span + // e.g: ` $visitor` turns into `$visitor` + let trim_leading_whitespaces = |span| { + snippet_opt(cx, span).and_then(|snip| { + #[allow(clippy::cast_possible_truncation)] + snip.find(|c: char| !c.is_whitespace()).map(|pos| { + span.lo() + BytePos(pos as u32) + }) + }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) + }; + + let mut generate_snippet = |pattern: &str| { + #[allow(clippy::cast_possible_truncation)] + macro_source.rfind(pattern).map(|pattern_pos| { + let rpos = pattern_pos + pattern.len(); + let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); + let span = trim_leading_whitespaces(span_after_ref); + snippet_with_applicability(cx, span, "_", &mut applicability) + }) + }; + + if *mutability == Mutability::Mut { + generate_snippet("mut") + } else { + generate_snippet("&") + } + } else { + Some(snippet_with_applicability(cx, e.span, "_", &mut applicability)) + } + } else { + Some(snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)) + }; + if let Some(sugg) = sugg { + span_lint_and_sugg( + cx, + DEREF_ADDROF, + e.span, + "immediately dereferencing a reference", + "try this", + sugg.to_string(), + applicability, + ); + } } } } diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 95594e38c9e..d06ab143482 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -11,7 +11,7 @@ use std::convert::TryFrom; declare_clippy_lint! { /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation - /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct + /// (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct /// regex syntax. /// /// **Why is this bad?** This will lead to a runtime panic. @@ -29,7 +29,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for trivial [regex](https://crates.io/crates/regex) - /// creation (with `Regex::new`, `RegexBuilder::new` or `RegexSet::new`). + /// creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`). /// /// **Why is this bad?** Matching the regex can likely be replaced by `==` or /// `str::starts_with`, `str::ends_with` or `std::contains` or other `str` diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 0dd2da949c4..ede37624f71 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,5 +1,5 @@ use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -9,7 +9,10 @@ use rustc_span::sym; use if_chain::if_chain; use crate::utils::SpanlessEq; -use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg}; +use crate::utils::{ + get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint, + span_lint_and_sugg, +}; declare_clippy_lint! { /// **What it does:** Checks for string appends of the form `x = x + y` (without @@ -174,16 +177,75 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { } } +declare_clippy_lint! { + /// **What it does:** Check if the string is transformed to byte array and casted back to string. + /// + /// **Why is this bad?** It's unnecessary, the string can be used directly. + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```rust + /// let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); + /// ``` + /// could be written as + /// ```rust + /// let _ = &"Hello World!"[6..11]; + /// ``` + pub STRING_FROM_UTF8_AS_BYTES, + complexity, + "casting string slices to byte slices and back" +} + // Max length a b"foo" string can take const MAX_LENGTH_BYTE_STRING_LIT: usize = 32; -declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]); +declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]); impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use crate::utils::{snippet, snippet_with_applicability}; use rustc_ast::LitKind; + if_chain! { + // Find std::str::converts::from_utf8 + if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8); + + // Find string::as_bytes + if let ExprKind::AddrOf(BorrowKind::Ref, _, ref args) = args[0].kind; + if let ExprKind::Index(ref left, ref right) = args.kind; + let (method_names, expressions, _) = method_calls(left, 1); + if method_names.len() == 1; + if expressions.len() == 1; + if expressions[0].len() == 1; + if method_names[0] == sym!(as_bytes); + + // Check for slicer + if let ExprKind::Struct(ref path, _, _) = right.kind; + if let QPath::LangItem(LangItem::Range, _) = path; + + then { + let mut applicability = Applicability::MachineApplicable; + let string_expression = &expressions[0][0]; + + let snippet_app = snippet_with_applicability( + cx, + string_expression.span, "..", + &mut applicability, + ); + + span_lint_and_sugg( + cx, + STRING_FROM_UTF8_AS_BYTES, + e.span, + "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", + "try", + format!("Some(&{}[{}])", snippet_app, snippet(cx, right.span, "..")), + applicability + ) + } + } + if_chain! { if let ExprKind::MethodCall(path, _, args, _) = &e.kind; if path.ident.name == sym!(as_bytes); diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 6f6b6999bf0..73e3a04aec9 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,6 +1,6 @@ use crate::utils::{ - is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, - span_lint_and_sugg, + differing_macro_contexts, in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, + snippet_with_macro_callsite, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -92,8 +92,11 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { }; let expr_err_ty = cx.typeck_results().expr_ty(err_arg); + let differing_contexts = differing_macro_contexts(expr.span, err_arg.span); - let origin_snippet = if err_arg.span.from_expansion() { + let origin_snippet = if in_macro(expr.span) && in_macro(err_arg.span) && differing_contexts { + snippet(cx, err_arg.span.ctxt().outer_expn_data().call_site, "_") + } else if err_arg.span.from_expansion() && !in_macro(expr.span) { snippet_with_macro_callsite(cx, err_arg.span, "_") } else { snippet(cx, err_arg.span, "_") diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index c7d82da3b8b..f0e10e374e1 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -553,7 +553,7 @@ impl Types { hir_ty.span, "`Vec` is already on the heap, the boxing is unnecessary.", "try", - format!("Vec<{}>", ty_ty), + format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), Applicability::MachineApplicable, ); return; // don't recurse into the type diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index ade5fff5ffc..2501635e7ef 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust - /// let mut twins = vec!((1,1), (2,2)); + /// let mut twins = vec!((1, 1), (2, 2)); /// twins.sort_by_key(|x| { x.1; }); /// ``` pub UNIT_RETURN_EXPECTING_ORD, diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs new file mode 100644 index 00000000000..25ecc7a82f1 --- /dev/null +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -0,0 +1,143 @@ +use crate::utils::{ + in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, + visitors::find_all_ret_expressions, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for private functions that only return `Ok` or `Some`. + /// + /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned. + /// + /// **Known problems:** Since this lint changes function type signature, you may need to + /// adjust some code at callee side. + /// + /// **Example:** + /// + /// ```rust + /// fn get_cool_number(a: bool, b: bool) -> Option { + /// if a && b { + /// return Some(50); + /// } + /// if a { + /// Some(0) + /// } else { + /// Some(10) + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn get_cool_number(a: bool, b: bool) -> i32 { + /// if a && b { + /// return 50; + /// } + /// if a { + /// 0 + /// } else { + /// 10 + /// } + /// } + /// ``` + pub UNNECESSARY_WRAPS, + complexity, + "functions that only return `Ok` or `Some`" +} + +declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]); + +impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &FnDecl<'tcx>, + body: &Body<'tcx>, + span: Span, + hir_id: HirId, + ) { + match fn_kind { + FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => { + if visibility.node.is_pub() { + return; + } + }, + FnKind::Closure(..) => return, + _ => (), + } + + if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { + if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), ..} | ItemKind::Trait(..)) { + return; + } + } + + let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { + ("Option", &paths::OPTION_SOME) + } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { + ("Result", &paths::RESULT_OK) + } else { + return; + }; + + let mut suggs = Vec::new(); + let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| { + if_chain! { + if !in_macro(ret_expr.span); + if let ExprKind::Call(ref func, ref args) = ret_expr.kind; + if let ExprKind::Path(ref qpath) = func.kind; + if match_qpath(qpath, path); + if args.len() == 1; + then { + suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string())); + true + } else { + false + } + } + }); + + if can_sugg && !suggs.is_empty() { + span_lint_and_then( + cx, + UNNECESSARY_WRAPS, + span, + format!( + "this function's return value is unnecessarily wrapped by `{}`", + return_type + ) + .as_str(), + |diag| { + let inner_ty = return_ty(cx, hir_id) + .walk() + .skip(1) // skip `std::option::Option` or `std::result::Result` + .take(1) // take the first outermost inner type + .filter_map(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()), + _ => None, + }); + inner_ty.for_each(|inner_ty| { + diag.span_suggestion( + fn_decl.output.span(), + format!("remove `{}` from the return type...", return_type).as_str(), + inner_ty, + Applicability::MaybeIncorrect, + ); + }); + diag.multipart_suggestion( + "...and change the returning expressions", + suggs, + Applicability::MachineApplicable, + ); + }, + ); + } + } +} diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index b1339c3d639..f61fd2ecd73 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -7,7 +7,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; -use crate::utils::span_lint_and_sugg; +use crate::utils::{position_before_rarrow, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for unit (`()`) expressions that can be removed. @@ -120,26 +120,13 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) { - fn_source - .rfind("->") - .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { - let mut rpos = rpos; - let chars: Vec = fn_source.chars().collect(); - while rpos > 1 { - if let Some(c) = chars.get(rpos - 1) { - if c.is_whitespace() { - rpos -= 1; - continue; - } - } - break; - } - ( - #[allow(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - }) + position_before_rarrow(fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + ( + #[allow(clippy::cast_possible_truncation)] + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + }) } else { (ty.span, Applicability::MaybeIncorrect) }; diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index c6194b0c6de..efa9c3fab4a 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -12,8 +12,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls - /// that useless converts to the same type as caller. + /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls + /// which uselessly convert to the same type. /// /// **Why is this bad?** Redundant code. /// @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` pub USELESS_CONVERSION, complexity, - "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type" + "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type" } #[derive(Default)] diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 9050b9b2d9a..fcf7a4b1367 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -110,8 +110,7 @@ pub fn eq_expr_opt(l: &Option>, r: &Option>) -> bool { pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool { match (l, r) { (StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb), - (StructRest::Rest(_), StructRest::Rest(_)) => true, - (StructRest::None, StructRest::None) => true, + (StructRest::Rest(_), StructRest::Rest(_)) | (StructRest::None, StructRest::None) => true, _ => false, } } diff --git a/clippy_lints/src/utils/eager_or_lazy.rs b/clippy_lints/src/utils/eager_or_lazy.rs index 4ceea13df37..8fe5ddee1ca 100644 --- a/clippy_lints/src/utils/eager_or_lazy.rs +++ b/clippy_lints/src/utils/eager_or_lazy.rs @@ -9,7 +9,7 @@ //! - or-fun-call //! - option-if-let-else -use crate::utils::is_ctor_or_promotable_const_function; +use crate::utils::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -96,6 +96,11 @@ fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, ex let call_found = match &expr.kind { // ignore enum and struct constructors ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), + ExprKind::Index(obj, _) => { + let ty = self.cx.typeck_results().expr_ty(obj); + is_type_diagnostic_item(self.cx, ty, sym!(hashmap_type)) + || match_type(self.cx, ty, &paths::BTREEMAP) + }, ExprKind::MethodCall(..) => true, _ => false, }; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 270fdc9bf46..5bd64dcb541 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -21,6 +21,7 @@ pub mod ptr; pub mod qualify_min_const_fn; pub mod sugg; pub mod usage; +pub mod visitors; pub use self::attrs::*; pub use self::diagnostics::*; @@ -468,6 +469,13 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool { .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id()) } +/// Returns `true` if the expression is in the program's `#[panic_handler]`. +pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { + let parent = cx.tcx.hir().get_parent_item(e.hir_id); + let def_id = cx.tcx.hir().local_def_id(parent).to_def_id(); + Some(def_id) == cx.tcx.lang_items().panic_impl() +} + /// Gets the name of the item the expression is in, if available. pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id); @@ -659,6 +667,35 @@ pub fn indent_of(cx: &T, span: Span) -> Option { snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) } +/// Returns the positon just before rarrow +/// +/// ```rust,ignore +/// fn into(self) -> () {} +/// ^ +/// // in case of unformatted code +/// fn into2(self)-> () {} +/// ^ +/// fn into3(self) -> () {} +/// ^ +/// ``` +#[allow(clippy::needless_pass_by_value)] +pub fn position_before_rarrow(s: String) -> Option { + s.rfind("->").map(|rpos| { + let mut rpos = rpos; + let chars: Vec = s.chars().collect(); + while rpos > 1 { + if let Some(c) = chars.get(rpos - 1) { + if c.is_whitespace() { + rpos -= 1; + continue; + } + } + break; + } + rpos + }) +} + /// Extends the span to the beginning of the spans line, incl. whitespaces. /// /// ```rust,ignore diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 8f5fbfd9f84..137f5d18b66 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -126,6 +126,7 @@ pub const STRING: [&str; 3] = ["alloc", "string", "String"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; +pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "", "starts_with"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs new file mode 100644 index 00000000000..b0837b6c43e --- /dev/null +++ b/clippy_lints/src/utils/visitors.rs @@ -0,0 +1,125 @@ +use rustc_hir as hir; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; + +/// returns `true` if expr contains match expr desugared from try +fn contains_try(expr: &hir::Expr<'_>) -> bool { + struct TryFinder { + found: bool, + } + + impl<'hir> intravisit::Visitor<'hir> for TryFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { + if self.found { + return; + } + match expr.kind { + hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true, + _ => intravisit::walk_expr(self, expr), + } + } + } + + let mut visitor = TryFinder { found: false }; + visitor.visit_expr(expr); + visitor.found +} + +pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool +where + F: FnMut(&'hir hir::Expr<'hir>) -> bool, +{ + struct RetFinder { + in_stmt: bool, + failed: bool, + cb: F, + } + + struct WithStmtGuarg<'a, F> { + val: &'a mut RetFinder, + prev_in_stmt: bool, + } + + impl RetFinder { + fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { + let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); + WithStmtGuarg { + val: self, + prev_in_stmt, + } + } + } + + impl std::ops::Deref for WithStmtGuarg<'_, F> { + type Target = RetFinder; + + fn deref(&self) -> &Self::Target { + self.val + } + } + + impl std::ops::DerefMut for WithStmtGuarg<'_, F> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.val + } + } + + impl Drop for WithStmtGuarg<'_, F> { + fn drop(&mut self) { + self.val.in_stmt = self.prev_in_stmt; + } + } + + impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { + if self.failed { + return; + } + if self.in_stmt { + match expr.kind { + hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), + _ => intravisit::walk_expr(self, expr), + } + } else { + match expr.kind { + hir::ExprKind::Match(cond, arms, _) => { + self.inside_stmt(true).visit_expr(cond); + for arm in arms { + self.visit_expr(arm.body); + } + }, + hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), + hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), + _ => self.failed |= !(self.cb)(expr), + } + } + } + } + + !contains_try(expr) && { + let mut ret_finder = RetFinder { + in_stmt: false, + failed: false, + cb: callback, + }; + ret_finder.visit_expr(expr); + !ret_finder.failed + } +} diff --git a/doc/changelog_update.md b/doc/changelog_update.md index 49726464957..115848c4804 100644 --- a/doc/changelog_update.md +++ b/doc/changelog_update.md @@ -29,8 +29,11 @@ bullet points might be helpful: * When writing the release notes for the **upcoming beta release**, you need to check out the Clippy commit of the current Rust `master`. [Link][rust_master_tools] * When writing the (forgotten) release notes for a **past stable release**, you - need to select the Rust release tag from the dropdown and then check the - commit of the Clippy directory: + need to check out the Rust release tag of the stable release. + [Link][rust_stable_tools] + +Usually you want to wirte the changelog of the **upcoming stable release**. Make +sure though, that `beta` was already branched in the Rust repository. To find the commit hash, issue the following command when in a `rust-lang/rust` checkout: ``` @@ -71,6 +74,19 @@ The order should roughly be: 7. Documentation improvements 8. Others +As section headers, we use: + +``` +### New Lints +### Moves and Deprecations +### Enhancements +### False Positive Fixes +### Suggestion Fixes/Improvements +### ICE Fixes +### Documentation Improvements +### Others +``` + Please also be sure to update the Beta/Unreleased sections at the top with the relevant commit ranges. @@ -78,3 +94,4 @@ relevant commit ranges. [forge]: https://forge.rust-lang.org/ [rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy [rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy +[rust_stable_tools]: https://github.com/rust-lang/rust/releases diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 702f9d86de6..1d906d20ad4 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -62,14 +62,14 @@ vec![ }, Lint { name: "await_holding_lock", - group: "correctness", + group: "pedantic", desc: "Inside an async function, holding a MutexGuard while calling await", deprecation: None, module: "await_holding_invalid", }, Lint { name: "await_holding_refcell_ref", - group: "correctness", + group: "pedantic", desc: "Inside an async function, holding a RefCell ref while calling await", deprecation: None, module: "await_holding_invalid", @@ -1117,6 +1117,13 @@ vec![ deprecation: None, module: "returns", }, + Lint { + name: "let_underscore_drop", + group: "pedantic", + desc: "non-binding let on a type that implements `Drop`", + deprecation: None, + module: "let_underscore", + }, Lint { name: "let_underscore_lock", group: "correctness", @@ -1831,13 +1838,6 @@ vec![ deprecation: None, module: "panic_in_result_fn", }, - Lint { - name: "panic_params", - group: "style", - desc: "missing parameters in `panic!` calls", - deprecation: None, - module: "panic_unimplemented", - }, Lint { name: "panicking_unwrap", group: "correctness", @@ -2114,7 +2114,7 @@ vec![ Lint { name: "search_is_some", group: "complexity", - desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`", + desc: "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`", deprecation: None, module: "methods", }, @@ -2258,6 +2258,13 @@ vec![ deprecation: None, module: "methods", }, + Lint { + name: "string_from_utf8_as_bytes", + group: "complexity", + desc: "casting string slices to byte slices and back", + deprecation: None, + module: "strings", + }, Lint { name: "string_lit_as_bytes", group: "nursery", @@ -2594,6 +2601,13 @@ vec![ deprecation: None, module: "unwrap", }, + Lint { + name: "unnecessary_wraps", + group: "complexity", + desc: "functions that only return `Ok` or `Some`", + deprecation: None, + module: "unnecessary_wraps", + }, Lint { name: "unneeded_field_pattern", group: "restriction", @@ -2737,7 +2751,7 @@ vec![ Lint { name: "useless_conversion", group: "complexity", - desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type", + desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type", deprecation: None, module: "useless_conversion", }, diff --git a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs new file mode 100644 index 00000000000..2289f7875f0 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs @@ -0,0 +1,16 @@ +// this file solely exists to test constants defined in foreign crates. +// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure. + +#![allow(clippy::declare_interior_mutable_const)] + +use std::sync::atomic::AtomicUsize; + +enum Private { + ToBeUnfrozen(T), + Frozen(usize), +} + +pub struct Wrapper(Private); + +pub const WRAPPED_PRIVATE_UNFROZEN_VARIANT: Wrapper = Wrapper(Private::ToBeUnfrozen(AtomicUsize::new(6))); +pub const WRAPPED_PRIVATE_FROZEN_VARIANT: Wrapper = Wrapper(Private::Frozen(7)); diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs new file mode 100644 index 00000000000..5027db44561 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/enums.rs @@ -0,0 +1,101 @@ +// aux-build:helper.rs + +#![warn(clippy::borrow_interior_mutable_const)] +#![allow(clippy::declare_interior_mutable_const)] + +// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions. + +extern crate helper; + +use std::cell::Cell; +use std::sync::atomic::AtomicUsize; + +enum OptionalCell { + Unfrozen(Cell), + Frozen, +} + +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); +const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + +fn borrow_optional_cell() { + let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &FROZEN_VARIANT; +} + +trait AssocConsts { + const TO_BE_UNFROZEN_VARIANT: OptionalCell; + const TO_BE_FROZEN_VARIANT: OptionalCell; + + const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + + fn function() { + // This is the "suboptimal behavior" mentioned in `is_value_unfrozen` + // caused by a similar reason to unfrozen types without any default values + // get linted even if it has frozen variants'. + let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable + + // The lint ignores default values because an impl of this trait can set + // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`. + let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable + } +} + +impl AssocConsts for u64 { + const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + + fn function() { + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &::TO_BE_FROZEN_VARIANT; + let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; + } +} + +trait AssocTypes { + type ToBeUnfrozen; + + const TO_BE_UNFROZEN_VARIANT: Option; + const TO_BE_FROZEN_VARIANT: Option; + + // there's no need to test here because it's the exactly same as `trait::AssocTypes` + fn function(); +} + +impl AssocTypes for u64 { + type ToBeUnfrozen = AtomicUsize; + + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + const TO_BE_FROZEN_VARIANT: Option = None; + + fn function() { + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &::TO_BE_FROZEN_VARIANT; + } +} + +enum BothOfCellAndGeneric { + Unfrozen(Cell<*const T>), + Generic(*const T), + Frozen(usize), +} + +impl BothOfCellAndGeneric { + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); + + fn function() { + let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability + let _ = &Self::FROZEN_VARIANT; + } +} + +fn main() { + // constants defined in foreign crates + let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT; +} diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr new file mode 100644 index 00000000000..654a1ee7df6 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/enums.stderr @@ -0,0 +1,75 @@ +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:22:14 + | +LL | let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:37:18 + | +LL | let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:41:18 + | +LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:50:18 + | +LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:52:18 + | +LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:74:18 + | +LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:91:18 + | +LL | let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:92:18 + | +LL | let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:99:14 + | +LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: aborting due to 9 previous errors + diff --git a/tests/ui/borrow_interior_mutable_const.rs b/tests/ui/borrow_interior_mutable_const/others.rs similarity index 81% rename from tests/ui/borrow_interior_mutable_const.rs rename to tests/ui/borrow_interior_mutable_const/others.rs index 9fcc9ece49b..ea25729d11d 100644 --- a/tests/ui/borrow_interior_mutable_const.rs +++ b/tests/ui/borrow_interior_mutable_const/others.rs @@ -19,33 +19,7 @@ const NO_ANN: &dyn Display = &70; static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); const ONCE_INIT: Once = Once::new(); -trait Trait { - type AssocType; - - const ATOMIC: AtomicUsize; - const INPUT: T; - const ASSOC: Self::AssocType; - - fn function() { - let _ = &Self::INPUT; - let _ = &Self::ASSOC; - } -} - -impl Trait for u64 { - type AssocType = AtomicUsize; - - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const INPUT: u32 = 10; - const ASSOC: Self::AssocType = AtomicUsize::new(11); - - fn function() { - let _ = &Self::INPUT; - let _ = &Self::ASSOC; //~ ERROR interior mutability - } -} - -// This is just a pointer that can be safely dereferended, +// This is just a pointer that can be safely dereferenced, // it's semantically the same as `&'static T`; // but it isn't allowed to make a static reference from an arbitrary integer value at the moment. // For more information, please see the issue #5918. @@ -100,7 +74,7 @@ fn main() { let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability - let _ = &*ATOMIC_TUPLE.1; //~ ERROR interior mutability + let _ = &*ATOMIC_TUPLE.1; let _ = &ATOMIC_TUPLE.2; let _ = (&&&&ATOMIC_TUPLE).0; let _ = (&&&&ATOMIC_TUPLE).2; @@ -124,9 +98,6 @@ fn main() { assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3); assert!(STATIC_TUPLE.1.is_empty()); - u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability - assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability - assert_eq!(NO_ANN.to_string(), "70"); // should never lint this. let _ = &CELL_REF.0; diff --git a/tests/ui/borrow_interior_mutable_const.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr similarity index 68% rename from tests/ui/borrow_interior_mutable_const.stderr rename to tests/ui/borrow_interior_mutable_const/others.stderr index ed726a6b46e..9a908cf30e9 100644 --- a/tests/ui/borrow_interior_mutable_const.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -1,22 +1,14 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:44:18 - | -LL | let _ = &Self::ASSOC; //~ ERROR interior mutability - | ^^^^^^^^^^^ - | - = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:80:5 + --> $DIR/others.rs:54:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ | + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:81:16 + --> $DIR/others.rs:55:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -24,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:84:22 + --> $DIR/others.rs:58:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +24,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:85:25 + --> $DIR/others.rs:59:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +32,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:86:27 + --> $DIR/others.rs:60:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +40,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:87:26 + --> $DIR/others.rs:61:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -56,7 +48,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:98:14 + --> $DIR/others.rs:72:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +56,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:99:14 + --> $DIR/others.rs:73:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +64,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:100:19 + --> $DIR/others.rs:74:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +72,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:101:14 + --> $DIR/others.rs:75:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +80,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:102:13 + --> $DIR/others.rs:76:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:108:13 + --> $DIR/others.rs:82:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -104,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:113:5 + --> $DIR/others.rs:87:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -112,28 +104,12 @@ LL | CELL.set(2); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:114:16 + --> $DIR/others.rs:88:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ | = help: assign this const to a local or static variable, and use the variable here -error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:127:5 - | -LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability - | ^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:128:16 - | -LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability - | ^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: aborting due to 17 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/traits.rs b/tests/ui/borrow_interior_mutable_const/traits.rs new file mode 100644 index 00000000000..06b5d62e8f9 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/traits.rs @@ -0,0 +1,202 @@ +#![warn(clippy::borrow_interior_mutable_const)] +#![allow(clippy::declare_interior_mutable_const)] + +// this file replicates its `declare` counterpart. Please see it for more discussions. + +use std::borrow::Cow; +use std::cell::Cell; +use std::sync::atomic::{AtomicUsize, Ordering}; + +trait ConcreteTypes { + const ATOMIC: AtomicUsize; + const STRING: String; + + fn function() { + let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::STRING; + } +} + +impl ConcreteTypes for u64 { + const ATOMIC: AtomicUsize = AtomicUsize::new(9); + const STRING: String = String::new(); + + fn function() { + // Lint this again since implementers can choose not to borrow it. + let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::STRING; + } +} + +// a helper trait used below +trait ConstDefault { + const DEFAULT: Self; +} + +trait GenericTypes { + const TO_REMAIN_GENERIC: T; + const TO_BE_CONCRETE: U; + + fn function() { + let _ = &Self::TO_REMAIN_GENERIC; + } +} + +impl GenericTypes for Vec { + const TO_REMAIN_GENERIC: T = T::DEFAULT; + const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); + + fn function() { + let _ = &Self::TO_REMAIN_GENERIC; + let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable + } +} + +// a helper type used below +pub struct Wrapper(T); + +trait AssocTypes { + type ToBeFrozen; + type ToBeUnfrozen; + type ToBeGenericParam; + + const TO_BE_FROZEN: Self::ToBeFrozen; + const TO_BE_UNFROZEN: Self::ToBeUnfrozen; + const WRAPPED_TO_BE_UNFROZEN: Wrapper; + const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; + + fn function() { + let _ = &Self::TO_BE_FROZEN; + let _ = &Self::WRAPPED_TO_BE_UNFROZEN; + } +} + +impl AssocTypes for Vec { + type ToBeFrozen = u16; + type ToBeUnfrozen = AtomicUsize; + type ToBeGenericParam = T; + + const TO_BE_FROZEN: Self::ToBeFrozen = 12; + const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); + const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); + const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); + + fn function() { + let _ = &Self::TO_BE_FROZEN; + let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable + let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable + let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM; + } +} + +// a helper trait used below +trait AssocTypesHelper { + type NotToBeBounded; + type ToBeBounded; + + const NOT_TO_BE_BOUNDED: Self::NotToBeBounded; +} + +trait AssocTypesFromGenericParam +where + T: AssocTypesHelper, +{ + const NOT_BOUNDED: T::NotToBeBounded; + const BOUNDED: T::ToBeBounded; + + fn function() { + let _ = &Self::NOT_BOUNDED; + let _ = &Self::BOUNDED; //~ ERROR interior mutable + } +} + +impl AssocTypesFromGenericParam for Vec +where + T: AssocTypesHelper, +{ + const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; + const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); + + fn function() { + let _ = &Self::NOT_BOUNDED; + let _ = &Self::BOUNDED; //~ ERROR interior mutable + } +} + +trait SelfType: Sized { + const SELF: Self; + const WRAPPED_SELF: Option; + + fn function() { + let _ = &Self::SELF; + let _ = &Self::WRAPPED_SELF; + } +} + +impl SelfType for u64 { + const SELF: Self = 16; + const WRAPPED_SELF: Option = Some(20); + + fn function() { + let _ = &Self::SELF; + let _ = &Self::WRAPPED_SELF; + } +} + +impl SelfType for AtomicUsize { + const SELF: Self = AtomicUsize::new(17); + const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); + + fn function() { + let _ = &Self::SELF; //~ ERROR interior mutable + let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable + } +} + +trait BothOfCellAndGeneric { + const DIRECT: Cell; + const INDIRECT: Cell<*const T>; + + fn function() { + let _ = &Self::DIRECT; + let _ = &Self::INDIRECT; //~ ERROR interior mutable + } +} + +impl BothOfCellAndGeneric for Vec { + const DIRECT: Cell = Cell::new(T::DEFAULT); + const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); + + fn function() { + let _ = &Self::DIRECT; + let _ = &Self::INDIRECT; //~ ERROR interior mutable + } +} + +struct Local(T); + +impl Local +where + T: ConstDefault + AssocTypesHelper, +{ + const ATOMIC: AtomicUsize = AtomicUsize::new(18); + const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); + + const GENERIC_TYPE: T = T::DEFAULT; + + const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; + const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); + + fn function() { + let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::COW; + let _ = &Self::GENERIC_TYPE; + let _ = &Self::ASSOC_TYPE; + let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable + } +} + +fn main() { + u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability + assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability +} diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr new file mode 100644 index 00000000000..8f26403abd3 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -0,0 +1,123 @@ +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:15:18 + | +LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable + | ^^^^^^^^^^^^ + | + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:26:18 + | +LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:51:18 + | +LL | let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:86:18 + | +LL | let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:87:18 + | +LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:109:18 + | +LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable + | ^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:122:18 + | +LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable + | ^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:151:18 + | +LL | let _ = &Self::SELF; //~ ERROR interior mutable + | ^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:152:18 + | +LL | let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:162:18 + | +LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:172:18 + | +LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:191:18 + | +LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:195:18 + | +LL | let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:200:5 + | +LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability + | ^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:201:16 + | +LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability + | ^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: aborting due to 15 previous errors + diff --git a/tests/ui/crashes/ice-360.stderr b/tests/ui/crashes/ice-360.stderr index bb03ce40355..0eb7bb12b35 100644 --- a/tests/ui/crashes/ice-360.stderr +++ b/tests/ui/crashes/ice-360.stderr @@ -19,7 +19,7 @@ LL | loop {} | ^^^^^^^ | = note: `-D clippy::empty-loop` implied by `-D warnings` - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: aborting due to 2 previous errors diff --git a/tests/ui/crashes/ice-6332.rs b/tests/ui/crashes/ice-6332.rs new file mode 100644 index 00000000000..9dc92aa500b --- /dev/null +++ b/tests/ui/crashes/ice-6332.rs @@ -0,0 +1,11 @@ +fn cmark_check() { + let mut link_err = false; + macro_rules! cmark_error { + ($bad:expr) => { + *$bad = true; + }; + } + cmark_error!(&mut link_err); +} + +pub fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/enums.rs b/tests/ui/declare_interior_mutable_const/enums.rs new file mode 100644 index 00000000000..f44518694b8 --- /dev/null +++ b/tests/ui/declare_interior_mutable_const/enums.rs @@ -0,0 +1,123 @@ +#![warn(clippy::declare_interior_mutable_const)] + +use std::cell::Cell; +use std::sync::atomic::AtomicUsize; + +enum OptionalCell { + Unfrozen(Cell), + Frozen, +} + +// a constant with enums should be linted only when the used variant is unfrozen (#3962). +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable +const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + +const fn unfrozen_variant() -> OptionalCell { + OptionalCell::Unfrozen(Cell::new(false)) +} + +const fn frozen_variant() -> OptionalCell { + OptionalCell::Frozen +} + +const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable +const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); + +enum NestedInnermost { + Unfrozen(AtomicUsize), + Frozen, +} + +struct NestedInner { + inner: NestedInnermost, +} + +enum NestedOuter { + NestedInner(NestedInner), + NotNested(usize), +} + +struct NestedOutermost { + outer: NestedOuter, +} + +// a constant with enums should be linted according to its value, no matter how structs involve. +const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { + outer: NestedOuter::NestedInner(NestedInner { + inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), + }), +}; //~ ERROR interior mutable +const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost { + outer: NestedOuter::NestedInner(NestedInner { + inner: NestedInnermost::Frozen, + }), +}; + +trait AssocConsts { + // When there's no default value, lint it only according to its type. + // Further details are on the corresponding code (`NonCopyConst::check_trait_item`). + const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + + // Lint default values accordingly. + const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; +} + +// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it +// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'. +impl AssocConsts for u64 { + const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + + // even if this sets an unfrozen variant, the lint ignores it. + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); +} + +// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters +// here are values; and I think substituted generics at definitions won't appear in MIR. +trait AssocTypes { + type ToBeUnfrozen; + + const TO_BE_UNFROZEN_VARIANT: Option; + const TO_BE_FROZEN_VARIANT: Option; +} + +impl AssocTypes for u64 { + type ToBeUnfrozen = AtomicUsize; + + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + const TO_BE_FROZEN_VARIANT: Option = None; +} + +// Use raw pointers since direct generics have a false negative at the type level. +enum BothOfCellAndGeneric { + Unfrozen(Cell<*const T>), + Generic(*const T), + Frozen(usize), +} + +impl BothOfCellAndGeneric { + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + + // This is a false positive. The argument about this is on `is_value_unfrozen_raw` + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + + const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); + + // This is what is likely to be a false negative when one tries to fix + // the `GENERIC_VARIANT` false positive. + const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable +} + +// associated types here is basically the same as the one above. +trait BothOfCellAndGenericWithAssocType { + type AssocType; + + const UNFROZEN_VARIANT: BothOfCellAndGeneric = + BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); +} + +fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr new file mode 100644 index 00000000000..84198d54615 --- /dev/null +++ b/tests/ui/declare_interior_mutable_const/enums.stderr @@ -0,0 +1,89 @@ +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:12:1 + | +LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + | + = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:23:1 + | +LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:45:1 + | +LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { + | ^---- + | | + | _make this a static item (maybe with lazy_static) + | | +LL | | outer: NestedOuter::NestedInner(NestedInner { +LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), +LL | | }), +LL | | }; //~ ERROR interior mutable + | |__^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:59:5 + | +LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:60:5 + | +LL | const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:63:5 + | +LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:89:5 + | +LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:101:5 + | +LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mut... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:104:5 + | +LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:110:5 + | +LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:117:5 + | +LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric = +LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + | |____________________________________________________________________^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:119:5 + | +LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mu... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs new file mode 100644 index 00000000000..48c5e9537d6 --- /dev/null +++ b/tests/ui/declare_interior_mutable_const/others.rs @@ -0,0 +1,34 @@ +#![warn(clippy::declare_interior_mutable_const)] + +use std::borrow::Cow; +use std::cell::Cell; +use std::fmt::Display; +use std::sync::atomic::AtomicUsize; +use std::sync::Once; + +const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable +const CELL: Cell = Cell::new(6); //~ ERROR interior mutable +const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); +//~^ ERROR interior mutable + +macro_rules! declare_const { + ($name:ident: $ty:ty = $e:expr) => { + const $name: $ty = $e; + }; +} +declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable + +// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. + +const INTEGER: u8 = 8; +const STRING: String = String::new(); +const STR: &str = "012345"; +const COW: Cow = Cow::Borrowed("abcdef"); +//^ note: a const item of Cow is used in the `postgres` package. + +const NO_ANN: &dyn Display = &70; + +static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); +//^ there should be no lints on this line + +fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr new file mode 100644 index 00000000000..6153c96edc4 --- /dev/null +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -0,0 +1,39 @@ +error: a `const` item should never be interior mutable + --> $DIR/others.rs:9:1 + | +LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + | + = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + +error: a `const` item should never be interior mutable + --> $DIR/others.rs:10:1 + | +LL | const CELL: Cell = Cell::new(6); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + +error: a `const` item should never be interior mutable + --> $DIR/others.rs:11:1 + | +LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + +error: a `const` item should never be interior mutable + --> $DIR/others.rs:16:9 + | +LL | const $name: $ty = $e; + | ^^^^^^^^^^^^^^^^^^^^^^ +... +LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable + | ------------------------------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + diff --git a/tests/ui/declare_interior_mutable_const.rs b/tests/ui/declare_interior_mutable_const/traits.rs similarity index 84% rename from tests/ui/declare_interior_mutable_const.rs rename to tests/ui/declare_interior_mutable_const/traits.rs index 3afcdca2f04..535147ccc64 100644 --- a/tests/ui/declare_interior_mutable_const.rs +++ b/tests/ui/declare_interior_mutable_const/traits.rs @@ -2,37 +2,13 @@ use std::borrow::Cow; use std::cell::Cell; -use std::fmt::Display; use std::sync::atomic::AtomicUsize; -use std::sync::Once; - -const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable -const CELL: Cell = Cell::new(6); //~ ERROR interior mutable -const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); -//~^ ERROR interior mutable macro_rules! declare_const { ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; } -declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable - -// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. - -const INTEGER: u8 = 8; -const STRING: String = String::new(); -const STR: &str = "012345"; -const COW: Cow = Cow::Borrowed("abcdef"); -//^ note: a const item of Cow is used in the `postgres` package. - -const NO_ANN: &dyn Display = &70; - -static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -//^ there should be no lints on this line - -#[allow(clippy::declare_interior_mutable_const)] -const ONCE_INIT: Once = Once::new(); // a constant whose type is a concrete type should be linted at the definition site. trait ConcreteTypes { diff --git a/tests/ui/declare_interior_mutable_const.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr similarity index 56% rename from tests/ui/declare_interior_mutable_const.stderr rename to tests/ui/declare_interior_mutable_const/traits.stderr index 5cb10be88d8..bb77f39b62c 100644 --- a/tests/ui/declare_interior_mutable_const.stderr +++ b/tests/ui/declare_interior_mutable_const/traits.stderr @@ -1,48 +1,13 @@ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:9:1 - | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) - | - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:10:1 - | -LL | const CELL: Cell = Cell::new(6); //~ ERROR interior mutable - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:11:1 - | -LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:16:9 - | -LL | const $name: $ty = $e; - | ^^^^^^^^^^^^^^^^^^^^^^ -... -LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable - | ------------------------------------------ in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:39:5 + --> $DIR/traits.rs:15:5 | LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:16:9 + --> $DIR/traits.rs:9:9 | LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -53,58 +18,58 @@ LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR i = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:67:5 + --> $DIR/traits.rs:43:5 | LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:92:5 + --> $DIR/traits.rs:68:5 | LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:93:5 + --> $DIR/traits.rs:69:5 | LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:112:5 + --> $DIR/traits.rs:88:5 | LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:140:5 + --> $DIR/traits.rs:116:5 | LL | const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:141:5 + --> $DIR/traits.rs:117:5 | LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:149:5 + --> $DIR/traits.rs:125:5 | LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:165:5 + --> $DIR/traits.rs:141:5 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:171:5 + --> $DIR/traits.rs:147:5 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 56755596c97..4cbc5630d75 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -10,5 +10,6 @@ #[warn(clippy::regex_macro)] #[warn(clippy::drop_bounds)] #[warn(clippy::temporary_cstring_as_ptr)] +#[warn(clippy::panic_params)] fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 37b726fc00f..a348d01d734 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -72,11 +72,17 @@ error: lint `clippy::temporary_cstring_as_ptr` has been removed: `this lint has LL | #[warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: lint `clippy::panic_params` has been removed: `this lint has been uplifted to rustc and is now called `panic_fmt`` + --> $DIR/deprecated.rs:13:8 + | +LL | #[warn(clippy::panic_params)] + | ^^^^^^^^^^^^^^^^^^^^ + error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::str_to_string)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index 9e5b51d6d5e..0795900558b 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![warn(clippy::deref_addrof)] fn get_number() -> usize { 10 @@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize { #[allow(clippy::many_single_char_names, clippy::double_parens)] #[allow(unused_variables, unused_parens)] -#[warn(clippy::deref_addrof)] fn main() { let a = 10; let aref = &a; @@ -37,3 +37,27 @@ fn main() { let b = *aref; } + +#[rustfmt::skip] +macro_rules! m { + ($visitor: expr) => { + $visitor + }; +} + +#[rustfmt::skip] +macro_rules! m_mut { + ($visitor: expr) => { + $visitor + }; +} + +pub struct S; +impl S { + pub fn f(&self) -> &Self { + m!(self) + } + pub fn f_mut(&self) -> &Self { + m_mut!(self) + } +} diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 5641a73cbc1..60c4318601b 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -1,4 +1,5 @@ // run-rustfix +#![warn(clippy::deref_addrof)] fn get_number() -> usize { 10 @@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize { #[allow(clippy::many_single_char_names, clippy::double_parens)] #[allow(unused_variables, unused_parens)] -#[warn(clippy::deref_addrof)] fn main() { let a = 10; let aref = &a; @@ -37,3 +37,27 @@ fn main() { let b = **&aref; } + +#[rustfmt::skip] +macro_rules! m { + ($visitor: expr) => { + *& $visitor + }; +} + +#[rustfmt::skip] +macro_rules! m_mut { + ($visitor: expr) => { + *& mut $visitor + }; +} + +pub struct S; +impl S { + pub fn f(&self) -> &Self { + m!(self) + } + pub fn f_mut(&self) -> &Self { + m_mut!(self) + } +} diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index bc51719e8a7..e85b30fa56e 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -48,5 +48,27 @@ error: immediately dereferencing a reference LL | let b = **&aref; | ^^^^^^ help: try this: `aref` -error: aborting due to 8 previous errors +error: immediately dereferencing a reference + --> $DIR/deref_addrof.rs:44:9 + | +LL | *& $visitor + | ^^^^^^^^^^^ help: try this: `$visitor` +... +LL | m!(self) + | -------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: immediately dereferencing a reference + --> $DIR/deref_addrof.rs:51:9 + | +LL | *& mut $visitor + | ^^^^^^^^^^^^^^^ help: try this: `$visitor` +... +LL | m_mut!(self) + | ------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors diff --git a/tests/ui/derive_ord_xor_partial_ord.rs b/tests/ui/derive_ord_xor_partial_ord.rs index b82dc518a3b..6f12d36d777 100644 --- a/tests/ui/derive_ord_xor_partial_ord.rs +++ b/tests/ui/derive_ord_xor_partial_ord.rs @@ -1,4 +1,5 @@ #![warn(clippy::derive_ord_xor_partial_ord)] +#![allow(clippy::unnecessary_wraps)] use std::cmp::Ordering; diff --git a/tests/ui/derive_ord_xor_partial_ord.stderr b/tests/ui/derive_ord_xor_partial_ord.stderr index 66bc4d42ce8..97b46a4aa89 100644 --- a/tests/ui/derive_ord_xor_partial_ord.stderr +++ b/tests/ui/derive_ord_xor_partial_ord.stderr @@ -1,12 +1,12 @@ error: you are deriving `Ord` but have implemented `PartialOrd` explicitly - --> $DIR/derive_ord_xor_partial_ord.rs:20:10 + --> $DIR/derive_ord_xor_partial_ord.rs:21:10 | LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings` note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:23:1 + --> $DIR/derive_ord_xor_partial_ord.rs:24:1 | LL | / impl PartialOrd for DeriveOrd { LL | | fn partial_cmp(&self, other: &Self) -> Option { @@ -17,13 +17,13 @@ LL | | } = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Ord` but have implemented `PartialOrd` explicitly - --> $DIR/derive_ord_xor_partial_ord.rs:29:10 + --> $DIR/derive_ord_xor_partial_ord.rs:30:10 | LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:32:1 + --> $DIR/derive_ord_xor_partial_ord.rs:33:1 | LL | / impl PartialOrd for DeriveOrdWithExplicitTypeVariable { LL | | fn partial_cmp(&self, other: &Self) -> Option { @@ -34,7 +34,7 @@ LL | | } = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> $DIR/derive_ord_xor_partial_ord.rs:41:1 + --> $DIR/derive_ord_xor_partial_ord.rs:42:1 | LL | / impl std::cmp::Ord for DerivePartialOrd { LL | | fn cmp(&self, other: &Self) -> Ordering { @@ -44,14 +44,14 @@ LL | | } | |_^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:38:10 + --> $DIR/derive_ord_xor_partial_ord.rs:39:10 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> $DIR/derive_ord_xor_partial_ord.rs:61:5 + --> $DIR/derive_ord_xor_partial_ord.rs:62:5 | LL | / impl Ord for DerivePartialOrdInUseOrd { LL | | fn cmp(&self, other: &Self) -> Ordering { @@ -61,7 +61,7 @@ LL | | } | |_____^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:58:14 + --> $DIR/derive_ord_xor_partial_ord.rs:59:14 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ diff --git a/tests/ui/doc_errors.rs b/tests/ui/doc_errors.rs index f47b81a450e..c77a74a58f2 100644 --- a/tests/ui/doc_errors.rs +++ b/tests/ui/doc_errors.rs @@ -1,6 +1,7 @@ // edition:2018 #![warn(clippy::missing_errors_doc)] #![allow(clippy::result_unit_err)] +#![allow(clippy::unnecessary_wraps)] use std::io; diff --git a/tests/ui/doc_errors.stderr b/tests/ui/doc_errors.stderr index c7b616e2897..b5a81419dae 100644 --- a/tests/ui/doc_errors.stderr +++ b/tests/ui/doc_errors.stderr @@ -1,5 +1,5 @@ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:7:1 + --> $DIR/doc_errors.rs:8:1 | LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::missing-errors-doc` implied by `-D warnings` error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:11:1 + --> $DIR/doc_errors.rs:12:1 | LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -17,7 +17,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:16:1 + --> $DIR/doc_errors.rs:17:1 | LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -25,7 +25,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:21:1 + --> $DIR/doc_errors.rs:22:1 | LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -33,7 +33,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:51:5 + --> $DIR/doc_errors.rs:52:5 | LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -41,7 +41,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:56:5 + --> $DIR/doc_errors.rs:57:5 | LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -49,7 +49,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:85:5 + --> $DIR/doc_errors.rs:86:5 | LL | fn trait_method_missing_errors_header() -> Result<(), ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/drop_ref.rs b/tests/ui/drop_ref.rs index 6b5bcdaa78e..e1a15c609fd 100644 --- a/tests/ui/drop_ref.rs +++ b/tests/ui/drop_ref.rs @@ -1,6 +1,7 @@ #![warn(clippy::drop_ref)] #![allow(clippy::toplevel_ref_arg)] #![allow(clippy::map_err_ignore)] +#![allow(clippy::unnecessary_wraps)] use std::mem::drop; diff --git a/tests/ui/drop_ref.stderr b/tests/ui/drop_ref.stderr index 7974bf56d44..10087cb4820 100644 --- a/tests/ui/drop_ref.stderr +++ b/tests/ui/drop_ref.stderr @@ -1,108 +1,108 @@ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:10:5 + --> $DIR/drop_ref.rs:11:5 | LL | drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::drop-ref` implied by `-D warnings` note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:10:10 + --> $DIR/drop_ref.rs:11:10 | LL | drop(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:13:5 + --> $DIR/drop_ref.rs:14:5 | LL | drop(&owned1); | ^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:13:10 + --> $DIR/drop_ref.rs:14:10 | LL | drop(&owned1); | ^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:14:5 + --> $DIR/drop_ref.rs:15:5 | LL | drop(&&owned1); | ^^^^^^^^^^^^^^ | note: argument has type `&&SomeStruct` - --> $DIR/drop_ref.rs:14:10 + --> $DIR/drop_ref.rs:15:10 | LL | drop(&&owned1); | ^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:15:5 + --> $DIR/drop_ref.rs:16:5 | LL | drop(&mut owned1); | ^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:15:10 + --> $DIR/drop_ref.rs:16:10 | LL | drop(&mut owned1); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:19:5 + --> $DIR/drop_ref.rs:20:5 | LL | drop(reference1); | ^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:19:10 + --> $DIR/drop_ref.rs:20:10 | LL | drop(reference1); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:22:5 + --> $DIR/drop_ref.rs:23:5 | LL | drop(reference2); | ^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:22:10 + --> $DIR/drop_ref.rs:23:10 | LL | drop(reference2); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:25:5 + --> $DIR/drop_ref.rs:26:5 | LL | drop(reference3); | ^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:25:10 + --> $DIR/drop_ref.rs:26:10 | LL | drop(reference3); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:30:5 + --> $DIR/drop_ref.rs:31:5 | LL | drop(&val); | ^^^^^^^^^^ | note: argument has type `&T` - --> $DIR/drop_ref.rs:30:10 + --> $DIR/drop_ref.rs:31:10 | LL | drop(&val); | ^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:38:5 + --> $DIR/drop_ref.rs:39:5 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:38:20 + --> $DIR/drop_ref.rs:39:20 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^ diff --git a/tests/ui/empty_loop.stderr b/tests/ui/empty_loop.stderr index fd3979f259a..555f3d3d884 100644 --- a/tests/ui/empty_loop.stderr +++ b/tests/ui/empty_loop.stderr @@ -5,7 +5,7 @@ LL | loop {} | ^^^^^^^ | = note: `-D clippy::empty-loop` implied by `-D warnings` - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop.rs:11:9 @@ -13,7 +13,7 @@ error: empty `loop {}` wastes CPU cycles LL | loop {} | ^^^^^^^ | - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop.rs:15:9 @@ -21,7 +21,7 @@ error: empty `loop {}` wastes CPU cycles LL | 'inner: loop {} | ^^^^^^^^^^^^^^^ | - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: aborting due to 3 previous errors diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index 879d1d5d916..4553d3ec505 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -10,13 +10,18 @@ use core::panic::PanicInfo; #[start] fn main(argc: isize, argv: *const *const u8) -> isize { + // This should trigger the lint loop {} } #[panic_handler] fn panic(_info: &PanicInfo) -> ! { + // This should NOT trigger the lint loop {} } #[lang = "eh_personality"] -extern "C" fn eh_personality() {} +extern "C" fn eh_personality() { + // This should also trigger the lint + loop {} +} diff --git a/tests/ui/empty_loop_no_std.stderr b/tests/ui/empty_loop_no_std.stderr new file mode 100644 index 00000000000..520248fcb68 --- /dev/null +++ b/tests/ui/empty_loop_no_std.stderr @@ -0,0 +1,19 @@ +error: empty `loop {}` wastes CPU cycles + --> $DIR/empty_loop_no_std.rs:14:5 + | +LL | loop {} + | ^^^^^^^ + | + = note: `-D clippy::empty-loop` implied by `-D warnings` + = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body + +error: empty `loop {}` wastes CPU cycles + --> $DIR/empty_loop_no_std.rs:26:5 + | +LL | loop {} + | ^^^^^^^ + | + = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body + +error: aborting due to 2 previous errors + diff --git a/tests/ui/filter_methods.rs b/tests/ui/filter_methods.rs index ef434245fd7..51450241619 100644 --- a/tests/ui/filter_methods.rs +++ b/tests/ui/filter_methods.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] fn main() { diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index 91718dd1175..11922681379 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -1,5 +1,5 @@ error: called `filter(..).map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:5:21 + --> $DIR/filter_methods.rs:6:21 | LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * = help: this is more succinctly expressed by calling `.filter_map(..)` instead error: called `filter(..).flat_map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:7:21 + --> $DIR/filter_methods.rs:8:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ @@ -20,7 +20,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` error: called `filter_map(..).flat_map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:13:21 + --> $DIR/filter_methods.rs:14:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ @@ -32,7 +32,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` error: called `filter_map(..).map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:19:21 + --> $DIR/filter_methods.rs:20:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ diff --git a/tests/ui/forget_ref.rs b/tests/ui/forget_ref.rs index 447fdbe1fac..c49e6756a6c 100644 --- a/tests/ui/forget_ref.rs +++ b/tests/ui/forget_ref.rs @@ -1,5 +1,6 @@ #![warn(clippy::forget_ref)] #![allow(clippy::toplevel_ref_arg)] +#![allow(clippy::unnecessary_wraps)] use std::mem::forget; diff --git a/tests/ui/forget_ref.stderr b/tests/ui/forget_ref.stderr index f90bcc2762c..b2c7f2023bf 100644 --- a/tests/ui/forget_ref.stderr +++ b/tests/ui/forget_ref.stderr @@ -1,108 +1,108 @@ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:9:5 + --> $DIR/forget_ref.rs:10:5 | LL | forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::forget-ref` implied by `-D warnings` note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:9:12 + --> $DIR/forget_ref.rs:10:12 | LL | forget(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:12:5 + --> $DIR/forget_ref.rs:13:5 | LL | forget(&owned); | ^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:12:12 + --> $DIR/forget_ref.rs:13:12 | LL | forget(&owned); | ^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:13:5 + --> $DIR/forget_ref.rs:14:5 | LL | forget(&&owned); | ^^^^^^^^^^^^^^^ | note: argument has type `&&SomeStruct` - --> $DIR/forget_ref.rs:13:12 + --> $DIR/forget_ref.rs:14:12 | LL | forget(&&owned); | ^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:14:5 + --> $DIR/forget_ref.rs:15:5 | LL | forget(&mut owned); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:14:12 + --> $DIR/forget_ref.rs:15:12 | LL | forget(&mut owned); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:18:5 + --> $DIR/forget_ref.rs:19:5 | LL | forget(&*reference1); | ^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:18:12 + --> $DIR/forget_ref.rs:19:12 | LL | forget(&*reference1); | ^^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:21:5 + --> $DIR/forget_ref.rs:22:5 | LL | forget(reference2); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:21:12 + --> $DIR/forget_ref.rs:22:12 | LL | forget(reference2); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:24:5 + --> $DIR/forget_ref.rs:25:5 | LL | forget(reference3); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:24:12 + --> $DIR/forget_ref.rs:25:12 | LL | forget(reference3); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:29:5 + --> $DIR/forget_ref.rs:30:5 | LL | forget(&val); | ^^^^^^^^^^^^ | note: argument has type `&T` - --> $DIR/forget_ref.rs:29:12 + --> $DIR/forget_ref.rs:30:12 | LL | forget(&val); | ^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:37:5 + --> $DIR/forget_ref.rs:38:5 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:37:22 + --> $DIR/forget_ref.rs:38:22 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^ diff --git a/tests/ui/let_underscore_drop.rs b/tests/ui/let_underscore_drop.rs new file mode 100644 index 00000000000..98593edb9c5 --- /dev/null +++ b/tests/ui/let_underscore_drop.rs @@ -0,0 +1,19 @@ +#![warn(clippy::let_underscore_drop)] + +struct Droppable; + +impl Drop for Droppable { + fn drop(&mut self) {} +} + +fn main() { + let unit = (); + let boxed = Box::new(()); + let droppable = Droppable; + let optional = Some(Droppable); + + let _ = (); + let _ = Box::new(()); + let _ = Droppable; + let _ = Some(Droppable); +} diff --git a/tests/ui/let_underscore_drop.stderr b/tests/ui/let_underscore_drop.stderr new file mode 100644 index 00000000000..66069e0c5e1 --- /dev/null +++ b/tests/ui/let_underscore_drop.stderr @@ -0,0 +1,27 @@ +error: non-binding `let` on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:16:5 + | +LL | let _ = Box::new(()); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::let-underscore-drop` implied by `-D warnings` + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding `let` on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:17:5 + | +LL | let _ = Droppable; + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding `let` on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:18:5 + | +LL | let _ = Some(Droppable); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/let_underscore_must_use.rs b/tests/ui/let_underscore_must_use.rs index 27dda606067..a842e872a37 100644 --- a/tests/ui/let_underscore_must_use.rs +++ b/tests/ui/let_underscore_must_use.rs @@ -1,4 +1,5 @@ #![warn(clippy::let_underscore_must_use)] +#![allow(clippy::unnecessary_wraps)] // Debug implementations can fire this lint, // so we shouldn't lint external macros diff --git a/tests/ui/let_underscore_must_use.stderr b/tests/ui/let_underscore_must_use.stderr index 447f2419e3b..5b751ea56de 100644 --- a/tests/ui/let_underscore_must_use.stderr +++ b/tests/ui/let_underscore_must_use.stderr @@ -1,5 +1,5 @@ error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:66:5 + --> $DIR/let_underscore_must_use.rs:67:5 | LL | let _ = f(); | ^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = f(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:67:5 + --> $DIR/let_underscore_must_use.rs:68:5 | LL | let _ = g(); | ^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = g(); = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:69:5 + --> $DIR/let_underscore_must_use.rs:70:5 | LL | let _ = l(0_u32); | ^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _ = l(0_u32); = help: consider explicitly using function result error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:73:5 + --> $DIR/let_underscore_must_use.rs:74:5 | LL | let _ = s.f(); | ^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let _ = s.f(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:74:5 + --> $DIR/let_underscore_must_use.rs:75:5 | LL | let _ = s.g(); | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _ = s.g(); = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:77:5 + --> $DIR/let_underscore_must_use.rs:78:5 | LL | let _ = S::h(); | ^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let _ = S::h(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:78:5 + --> $DIR/let_underscore_must_use.rs:79:5 | LL | let _ = S::p(); | ^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = S::p(); = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:80:5 + --> $DIR/let_underscore_must_use.rs:81:5 | LL | let _ = S::a(); | ^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = S::a(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:82:5 + --> $DIR/let_underscore_must_use.rs:83:5 | LL | let _ = if true { Ok(()) } else { Err(()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = if true { Ok(()) } else { Err(()) }; = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:86:5 + --> $DIR/let_underscore_must_use.rs:87:5 | LL | let _ = a.is_ok(); | ^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _ = a.is_ok(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:88:5 + --> $DIR/let_underscore_must_use.rs:89:5 | LL | let _ = a.map(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = a.map(|_| ()); = help: consider explicitly using expression value error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:90:5 + --> $DIR/let_underscore_must_use.rs:91:5 | LL | let _ = a; | ^^^^^^^^^^ diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index 4f551690c43..5184f6fdb88 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -7,7 +7,19 @@ use std::future::Future; async fn fut() -> i32 { 42 } -async fn empty_fut() {} +#[rustfmt::skip] +async fn fut2() -> i32 { 42 } + +#[rustfmt::skip] +async fn fut3() -> i32 { 42 } + +async fn empty_fut() {} + +#[rustfmt::skip] +async fn empty_fut2() {} + +#[rustfmt::skip] +async fn empty_fut3() {} async fn core_fut() -> i32 { 42 } diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index 6ed60309947..68c0e591f0b 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -9,10 +9,30 @@ fn fut() -> impl Future { async { 42 } } +#[rustfmt::skip] +fn fut2() ->impl Future { + async { 42 } +} + +#[rustfmt::skip] +fn fut3()-> impl Future { + async { 42 } +} + fn empty_fut() -> impl Future { async {} } +#[rustfmt::skip] +fn empty_fut2() ->impl Future { + async {} +} + +#[rustfmt::skip] +fn empty_fut3()-> impl Future { + async {} +} + fn core_fut() -> impl core::future::Future { async move { 42 } } diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index ccd82867427..fdd43db3255 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -15,14 +15,44 @@ LL | fn fut() -> impl Future { 42 } | ^^^^^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:12:1 + --> $DIR/manual_async_fn.rs:13:1 + | +LL | fn fut2() ->impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | async fn fut2() -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn fut2() ->impl Future { 42 } + | ^^^^^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:18:1 + | +LL | fn fut3()-> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | async fn fut3() -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn fut3()-> impl Future { 42 } + | ^^^^^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:22:1 | LL | fn empty_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and remove the return type | -LL | async fn empty_fut() { +LL | async fn empty_fut() { | ^^^^^^^^^^^^^^^^^^^^ help: move the body of the async block to the enclosing function | @@ -30,7 +60,37 @@ LL | fn empty_fut() -> impl Future {} | ^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:16:1 + --> $DIR/manual_async_fn.rs:27:1 + | +LL | fn empty_fut2() ->impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and remove the return type + | +LL | async fn empty_fut2() { + | ^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn empty_fut2() ->impl Future {} + | ^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:32:1 + | +LL | fn empty_fut3()-> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and remove the return type + | +LL | async fn empty_fut3() { + | ^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn empty_fut3()-> impl Future {} + | ^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:36:1 | LL | fn core_fut() -> impl core::future::Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +105,7 @@ LL | fn core_fut() -> impl core::future::Future { 42 } | ^^^^^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:38:5 + --> $DIR/manual_async_fn.rs:58:5 | LL | fn inh_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -65,7 +125,7 @@ LL | let c = 21; ... error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:73:1 + --> $DIR/manual_async_fn.rs:93:1 | LL | fn elided(_: &i32) -> impl Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +140,7 @@ LL | fn elided(_: &i32) -> impl Future + '_ { 42 } | ^^^^^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:82:1 + --> $DIR/manual_async_fn.rs:102:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -94,5 +154,5 @@ help: move the body of the async block to the enclosing function LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { 42 } | ^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/manual_ok_or.fixed b/tests/ui/manual_ok_or.fixed index b42e94bd727..887a97d7a01 100644 --- a/tests/ui/manual_ok_or.fixed +++ b/tests/ui/manual_ok_or.fixed @@ -28,7 +28,7 @@ fn main() { // not applicable, or side isn't `Result::Err` foo.map_or(Ok::(1), |v| Ok(v)); - // not applicatble, expr is not a `Result` value + // not applicable, expr is not a `Result` value foo.map_or(42, |v| v); // TODO patterns not covered yet diff --git a/tests/ui/manual_ok_or.rs b/tests/ui/manual_ok_or.rs index e5a6056fbf5..3c99872f502 100644 --- a/tests/ui/manual_ok_or.rs +++ b/tests/ui/manual_ok_or.rs @@ -32,7 +32,7 @@ fn main() { // not applicable, or side isn't `Result::Err` foo.map_or(Ok::(1), |v| Ok(v)); - // not applicatble, expr is not a `Result` value + // not applicable, expr is not a `Result` value foo.map_or(42, |v| v); // TODO patterns not covered yet diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 5aa5a43cb92..81d903c15d3 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code)] -#![allow(unused_variables)] +#![allow(unused_variables, clippy::unnecessary_wraps)] fn option_unwrap_or() { // int case diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index df534031f54..16105d379c3 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code)] -#![allow(unused_variables)] +#![allow(unused_variables, clippy::unnecessary_wraps)] fn option_unwrap_or() { // int case diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index 81c7f659efb..178d8705c2f 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::iter_cloned_collect)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::redundant_closure_for_method_calls)] #![allow(clippy::many_single_char_names)] @@ -44,4 +45,19 @@ fn main() { let v = vec![&mut d]; let _: Vec = v.into_iter().map(|&mut x| x).collect(); } + + // Issue #6299 + { + let mut aa = 5; + let mut bb = 3; + let items = vec![&mut aa, &mut bb]; + let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); + } + + // Issue #6239 deref coercion and clone deref + { + use std::cell::RefCell; + + let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone()); + } } diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 8ed164f0ed5..c73d81713b8 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::iter_cloned_collect)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::redundant_closure_for_method_calls)] #![allow(clippy::many_single_char_names)] @@ -44,4 +45,19 @@ fn main() { let v = vec![&mut d]; let _: Vec = v.into_iter().map(|&mut x| x).collect(); } + + // Issue #6299 + { + let mut aa = 5; + let mut bb = 3; + let items = vec![&mut aa, &mut bb]; + let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); + } + + // Issue #6239 deref coercion and clone deref + { + use std::cell::RefCell; + + let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone()); + } } diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index 4f43cff5024..d84a5bf8d4d 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -1,5 +1,5 @@ error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:10:22 + --> $DIR/map_clone.rs:11:22 | LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()` @@ -7,31 +7,31 @@ LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); = note: `-D clippy::map-clone` implied by `-D warnings` error: you are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:11:26 + --> $DIR/map_clone.rs:12:26 | LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:12:23 + --> $DIR/map_clone.rs:13:23 | LL | let _: Vec = vec![42, 43].iter().map(|&x| x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()` error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:14:26 + --> $DIR/map_clone.rs:15:26 | LL | let _: Option = Some(&16).map(|b| *b); | ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()` error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:15:25 + --> $DIR/map_clone.rs:16:25 | LL | let _: Option = Some(&1).map(|x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()` error: you are needlessly cloning iterator elements - --> $DIR/map_clone.rs:26:29 + --> $DIR/map_clone.rs:27:29 | LL | let _ = std::env::args().map(|v| v.clone()); | ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call diff --git a/tests/ui/map_err.rs b/tests/ui/map_err.rs index 617b6422872..05b9949f102 100644 --- a/tests/ui/map_err.rs +++ b/tests/ui/map_err.rs @@ -1,4 +1,5 @@ #![warn(clippy::map_err_ignore)] +#![allow(clippy::unnecessary_wraps)] use std::convert::TryFrom; use std::error::Error; use std::fmt; diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index 7273f460380..390d7ce2e4e 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -1,5 +1,5 @@ error: `map_err(|_|...` ignores the original error - --> $DIR/map_err.rs:22:32 + --> $DIR/map_err.rs:23:32 | LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | ^^^ diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed index a5fdf7df613..773b5914439 100644 --- a/tests/ui/map_flatten.fixed +++ b/tests/ui/map_flatten.fixed @@ -1,8 +1,10 @@ // run-rustfix #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] +#![allow(clippy::unnecessary_wraps)] fn main() { // mapping to Option on Iterator diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index abbc4e16e56..578bd877267 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -1,8 +1,10 @@ // run-rustfix #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] +#![allow(clippy::unnecessary_wraps)] fn main() { // mapping to Option on Iterator diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index b6479cd69ea..756e6e818ad 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:14:46 + --> $DIR/map_flatten.rs:16:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)` @@ -7,31 +7,31 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = note: `-D clippy::map-flatten` implied by `-D warnings` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:15:46 + --> $DIR/map_flatten.rs:17:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:16:46 + --> $DIR/map_flatten.rs:18:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:17:46 + --> $DIR/map_flatten.rs:19:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:20:46 + --> $DIR/map_flatten.rs:22:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)` error: called `map(..).flatten()` on an `Option` - --> $DIR/map_flatten.rs:23:39 + --> $DIR/map_flatten.rs:25:39 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index d93e5b114ec..513d930e056 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -133,50 +133,6 @@ fn filter_next() { let _ = foo.filter().next(); } -/// Checks implementation of `SEARCH_IS_SOME` lint. -#[rustfmt::skip] -fn search_is_some() { - let v = vec![3, 2, 1, 0, -1, -2, -3]; - let y = &&42; - - // Check `find().is_some()`, single-line case. - let _ = v.iter().find(|&x| *x < 0).is_some(); - let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - let _ = (0..1).find(|x| *x == 0).is_some(); - let _ = v.iter().find(|x| **x == 0).is_some(); - - // Check `find().is_some()`, multi-line case. - let _ = v.iter().find(|&x| { - *x < 0 - } - ).is_some(); - - // Check `position().is_some()`, single-line case. - let _ = v.iter().position(|&x| x < 0).is_some(); - - // Check `position().is_some()`, multi-line case. - let _ = v.iter().position(|&x| { - x < 0 - } - ).is_some(); - - // Check `rposition().is_some()`, single-line case. - let _ = v.iter().rposition(|&x| x < 0).is_some(); - - // Check `rposition().is_some()`, multi-line case. - let _ = v.iter().rposition(|&x| { - x < 0 - } - ).is_some(); - - // Check that we don't lint if the caller is not an `Iterator`. - let foo = IteratorFalsePositives { foo: 0 }; - let _ = foo.find().is_some(); - let _ = foo.position().is_some(); - let _ = foo.rposition().is_some(); -} - fn main() { filter_next(); - search_is_some(); } diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 8a281c2dbd2..33aba630a53 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -20,73 +20,5 @@ LL | | ).next(); | = note: `-D clippy::filter-next` implied by `-D warnings` -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:143:22 - | -LL | let _ = v.iter().find(|&x| *x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` - | - = note: `-D clippy::search-is-some` implied by `-D warnings` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:144:20 - | -LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:145:20 - | -LL | let _ = (0..1).find(|x| *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:146:22 - | -LL | let _ = v.iter().find(|x| **x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:149:13 - | -LL | let _ = v.iter().find(|&x| { - | _____________^ -LL | | *x < 0 -LL | | } -LL | | ).is_some(); - | |______________________________^ - -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:155:22 - | -LL | let _ = v.iter().position(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` - -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:158:13 - | -LL | let _ = v.iter().position(|&x| { - | _____________^ -LL | | x < 0 -LL | | } -LL | | ).is_some(); - | |______________________________^ - -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:164:22 - | -LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` - -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:167:13 - | -LL | let _ = v.iter().rposition(|&x| { - | _____________^ -LL | | x < 0 -LL | | } -LL | | ).is_some(); - | |______________________________^ - -error: aborting due to 11 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 6001ef37eb7..44972c8c639 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value)] +#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} diff --git a/tests/ui/option_map_unit_fn_fixable.fixed b/tests/ui/option_map_unit_fn_fixable.fixed index 96d1c54946c..7d29445e66c 100644 --- a/tests/ui/option_map_unit_fn_fixable.fixed +++ b/tests/ui/option_map_unit_fn_fixable.fixed @@ -2,6 +2,7 @@ #![warn(clippy::option_map_unit_fn)] #![allow(unused)] +#![allow(clippy::unnecessary_wraps)] fn do_nothing(_: T) {} diff --git a/tests/ui/option_map_unit_fn_fixable.rs b/tests/ui/option_map_unit_fn_fixable.rs index 931ffc18665..b6f834f686f 100644 --- a/tests/ui/option_map_unit_fn_fixable.rs +++ b/tests/ui/option_map_unit_fn_fixable.rs @@ -2,6 +2,7 @@ #![warn(clippy::option_map_unit_fn)] #![allow(unused)] +#![allow(clippy::unnecessary_wraps)] fn do_nothing(_: T) {} diff --git a/tests/ui/option_map_unit_fn_fixable.stderr b/tests/ui/option_map_unit_fn_fixable.stderr index d7d45ef9b0b..8abdbcafb6e 100644 --- a/tests/ui/option_map_unit_fn_fixable.stderr +++ b/tests/ui/option_map_unit_fn_fixable.stderr @@ -1,5 +1,5 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:38:5 + --> $DIR/option_map_unit_fn_fixable.rs:39:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -9,7 +9,7 @@ LL | x.field.map(do_nothing); = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:40:5 + --> $DIR/option_map_unit_fn_fixable.rs:41:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | x.field.map(do_nothing); | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:42:5 + --> $DIR/option_map_unit_fn_fixable.rs:43:5 | LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- @@ -25,7 +25,7 @@ LL | x.field.map(diverge); | help: try this: `if let Some(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:48:5 + --> $DIR/option_map_unit_fn_fixable.rs:49:5 | LL | x.field.map(|value| x.do_option_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -33,7 +33,7 @@ LL | x.field.map(|value| x.do_option_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:50:5 + --> $DIR/option_map_unit_fn_fixable.rs:51:5 | LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -41,7 +41,7 @@ LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:53:5 + --> $DIR/option_map_unit_fn_fixable.rs:54:5 | LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -49,7 +49,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:55:5 + --> $DIR/option_map_unit_fn_fixable.rs:56:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -57,7 +57,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:57:5 + --> $DIR/option_map_unit_fn_fixable.rs:58:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -65,7 +65,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:59:5 + --> $DIR/option_map_unit_fn_fixable.rs:60:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -73,7 +73,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:62:5 + --> $DIR/option_map_unit_fn_fixable.rs:63:5 | LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -81,7 +81,7 @@ LL | x.field.map(|value| diverge(value + captured)); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:64:5 + --> $DIR/option_map_unit_fn_fixable.rs:65:5 | LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -89,7 +89,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:66:5 + --> $DIR/option_map_unit_fn_fixable.rs:67:5 | LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -97,7 +97,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:68:5 + --> $DIR/option_map_unit_fn_fixable.rs:69:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -105,7 +105,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:73:5 + --> $DIR/option_map_unit_fn_fixable.rs:74:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -113,7 +113,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:75:5 + --> $DIR/option_map_unit_fn_fixable.rs:76:5 | LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -121,7 +121,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:77:5 + --> $DIR/option_map_unit_fn_fixable.rs:78:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -129,7 +129,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:80:5 + --> $DIR/option_map_unit_fn_fixable.rs:81:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -137,7 +137,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) }); | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:82:5 + --> $DIR/option_map_unit_fn_fixable.rs:83:5 | LL | option().map(do_nothing);} | ^^^^^^^^^^^^^^^^^^^^^^^^- diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index a2617a13eca..6859ba8e5bb 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -1,4 +1,5 @@ #![deny(clippy::option_option)] +#![allow(clippy::unnecessary_wraps)] fn input(_: Option>) {} @@ -72,8 +73,6 @@ mod issue_4298 { #[serde(skip_serializing_if = "Option::is_none")] #[serde(default)] #[serde(borrow)] - // FIXME: should not lint here - #[allow(clippy::option_option)] foo: Option>>, } diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 0cd4c96eb4f..ad7f081c713 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -1,5 +1,5 @@ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:3:13 + --> $DIR/option_option.rs:4:13 | LL | fn input(_: Option>) {} | ^^^^^^^^^^^^^^^^^^ @@ -11,55 +11,55 @@ LL | #![deny(clippy::option_option)] | ^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:5:16 + --> $DIR/option_option.rs:6:16 | LL | fn output() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:9:27 + --> $DIR/option_option.rs:10:27 | LL | fn output_nested() -> Vec>> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:14:30 + --> $DIR/option_option.rs:15:30 | LL | fn output_nested_nested() -> Option>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:19:8 + --> $DIR/option_option.rs:20:8 | LL | x: Option>, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:23:23 + --> $DIR/option_option.rs:24:23 | LL | fn struct_fn() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:29:22 + --> $DIR/option_option.rs:30:22 | LL | fn trait_fn() -> Option>; | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:33:11 + --> $DIR/option_option.rs:34:11 | LL | Tuple(Option>), | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:34:17 + --> $DIR/option_option.rs:35:17 | LL | Struct { x: Option> }, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:77:14 + --> $DIR/option_option.rs:76:14 | LL | foo: Option>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 2045ffdb5f0..2a63318c8c7 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -2,6 +2,7 @@ #![warn(clippy::or_fun_call)] #![allow(dead_code)] +#![allow(clippy::unnecessary_wraps)] use std::collections::BTreeMap; use std::collections::HashMap; @@ -70,6 +71,15 @@ fn or_fun_call() { let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or(format!("{} world.", hello)); + + // index + let map = HashMap::::new(); + let _ = Some(1).unwrap_or_else(|| map[&1]); + let map = BTreeMap::::new(); + let _ = Some(1).unwrap_or_else(|| map[&1]); + // don't lint index vec + let vec = vec![1]; + let _ = Some(1).unwrap_or(vec[1]); } struct Foo(u8); diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 522f31b72d0..026ef437caa 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -2,6 +2,7 @@ #![warn(clippy::or_fun_call)] #![allow(dead_code)] +#![allow(clippy::unnecessary_wraps)] use std::collections::BTreeMap; use std::collections::HashMap; @@ -70,6 +71,15 @@ fn or_fun_call() { let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or(format!("{} world.", hello)); + + // index + let map = HashMap::::new(); + let _ = Some(1).unwrap_or(map[&1]); + let map = BTreeMap::::new(); + let _ = Some(1).unwrap_or(map[&1]); + // don't lint index vec + let vec = vec![1]; + let _ = Some(1).unwrap_or(vec[1]); } struct Foo(u8); diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index bc5978b538f..fb8bf339828 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:32:19 + --> $DIR/or_fun_call.rs:33:19 | LL | with_const_fn.unwrap_or(Duration::from_secs(5)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))` @@ -7,88 +7,100 @@ LL | with_const_fn.unwrap_or(Duration::from_secs(5)); = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:35:22 + --> $DIR/or_fun_call.rs:36:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:38:5 + --> $DIR/or_fun_call.rs:39:5 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:41:21 + --> $DIR/or_fun_call.rs:42:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:44:14 + --> $DIR/or_fun_call.rs:45:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:47:19 + --> $DIR/or_fun_call.rs:48:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:50:5 + --> $DIR/or_fun_call.rs:51:5 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:53:5 + --> $DIR/or_fun_call.rs:54:5 | LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:56:5 + --> $DIR/or_fun_call.rs:57:5 | LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_vec.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:59:21 + --> $DIR/or_fun_call.rs:60:21 | LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:62:19 + --> $DIR/or_fun_call.rs:63:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:65:21 + --> $DIR/or_fun_call.rs:66:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:68:21 + --> $DIR/or_fun_call.rs:69:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:77:21 + | +LL | let _ = Some(1).unwrap_or(map[&1]); + | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:79:21 + | +LL | let _ = Some(1).unwrap_or(map[&1]); + | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:93:35 + --> $DIR/or_fun_call.rs:103:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:97:10 + --> $DIR/or_fun_call.rs:107:10 | LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/panic_in_result_fn.rs b/tests/ui/panic_in_result_fn.rs index 287726f7a2d..3d3c19a1be5 100644 --- a/tests/ui/panic_in_result_fn.rs +++ b/tests/ui/panic_in_result_fn.rs @@ -1,4 +1,5 @@ #![warn(clippy::panic_in_result_fn)] +#![allow(clippy::unnecessary_wraps)] struct A; diff --git a/tests/ui/panic_in_result_fn.stderr b/tests/ui/panic_in_result_fn.stderr index c6936fd8692..ca73ac5a411 100644 --- a/tests/ui/panic_in_result_fn.stderr +++ b/tests/ui/panic_in_result_fn.stderr @@ -1,5 +1,5 @@ error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:6:5 + --> $DIR/panic_in_result_fn.rs:7:5 | LL | / fn result_with_panic() -> Result // should emit lint LL | | { @@ -10,14 +10,14 @@ LL | | } = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:8:9 + --> $DIR/panic_in_result_fn.rs:9:9 | LL | panic!("error"); | ^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:11:5 + --> $DIR/panic_in_result_fn.rs:12:5 | LL | / fn result_with_unimplemented() -> Result // should emit lint LL | | { @@ -27,14 +27,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:13:9 + --> $DIR/panic_in_result_fn.rs:14:9 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:16:5 + --> $DIR/panic_in_result_fn.rs:17:5 | LL | / fn result_with_unreachable() -> Result // should emit lint LL | | { @@ -44,14 +44,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:18:9 + --> $DIR/panic_in_result_fn.rs:19:9 | LL | unreachable!(); | ^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:21:5 + --> $DIR/panic_in_result_fn.rs:22:5 | LL | / fn result_with_todo() -> Result // should emit lint LL | | { @@ -61,14 +61,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:23:9 + --> $DIR/panic_in_result_fn.rs:24:9 | LL | todo!("Finish this"); | ^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:52:1 + --> $DIR/panic_in_result_fn.rs:53:1 | LL | / fn function_result_with_panic() -> Result // should emit lint LL | | { @@ -78,14 +78,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:54:5 + --> $DIR/panic_in_result_fn.rs:55:5 | LL | panic!("error"); | ^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:67:1 + --> $DIR/panic_in_result_fn.rs:68:1 | LL | / fn main() -> Result<(), String> { LL | | todo!("finish main method"); @@ -95,7 +95,7 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:68:5 + --> $DIR/panic_in_result_fn.rs:69:5 | LL | todo!("finish main method"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 11dff94a288..0b5746cb522 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -1,5 +1,6 @@ // run-rustfix #![allow(unreachable_code)] +#![allow(clippy::unnecessary_wraps)] fn some_func(a: Option) -> Option { a?; diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 1d0ee82b4f7..0f0825c9334 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,5 +1,6 @@ // run-rustfix #![allow(unreachable_code)] +#![allow(clippy::unnecessary_wraps)] fn some_func(a: Option) -> Option { if a.is_none() { diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 502615fb175..6f330cfa385 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -1,5 +1,5 @@ error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:5:5 + --> $DIR/question_mark.rs:6:5 | LL | / if a.is_none() { LL | | return None; @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::question-mark` implied by `-D warnings` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:50:9 + --> $DIR/question_mark.rs:51:9 | LL | / if (self.opt).is_none() { LL | | return None; @@ -17,7 +17,7 @@ LL | | } | |_________^ help: replace it with: `(self.opt)?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:54:9 + --> $DIR/question_mark.rs:55:9 | LL | / if self.opt.is_none() { LL | | return None @@ -25,7 +25,7 @@ LL | | } | |_________^ help: replace it with: `self.opt?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:58:17 + --> $DIR/question_mark.rs:59:17 | LL | let _ = if self.opt.is_none() { | _________________^ @@ -36,7 +36,7 @@ LL | | }; | |_________^ help: replace it with: `Some(self.opt?)` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:64:17 + --> $DIR/question_mark.rs:65:17 | LL | let _ = if let Some(x) = self.opt { | _________________^ @@ -47,7 +47,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:81:9 + --> $DIR/question_mark.rs:82:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -55,7 +55,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:89:9 + --> $DIR/question_mark.rs:90:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -63,7 +63,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:97:9 + --> $DIR/question_mark.rs:98:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -71,7 +71,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:104:26 + --> $DIR/question_mark.rs:105:26 | LL | let v: &Vec<_> = if let Some(ref v) = self.opt { | __________________________^ @@ -82,7 +82,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt.as_ref()?` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:114:17 + --> $DIR/question_mark.rs:115:17 | LL | let v = if let Some(v) = self.opt { | _________________^ @@ -93,7 +93,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:129:5 + --> $DIR/question_mark.rs:130:5 | LL | / if f().is_none() { LL | | return None; diff --git a/tests/ui/range_contains.fixed b/tests/ui/range_contains.fixed index 632a6592a28..048874a7f82 100644 --- a/tests/ui/range_contains.fixed +++ b/tests/ui/range_contains.fixed @@ -38,4 +38,9 @@ fn main() { x >= 8 || x >= 12; x < 12 || 12 < x; x >= 8 || x <= 12; + + // Fix #6315 + let y = 3.; + (0. ..1.).contains(&y); + !(0. ..=1.).contains(&y); } diff --git a/tests/ui/range_contains.rs b/tests/ui/range_contains.rs index 6af0d034ef6..60ad259f404 100644 --- a/tests/ui/range_contains.rs +++ b/tests/ui/range_contains.rs @@ -38,4 +38,9 @@ fn main() { x >= 8 || x >= 12; x < 12 || 12 < x; x >= 8 || x <= 12; + + // Fix #6315 + let y = 3.; + y >= 0. && y < 1.; + y < 0. || y > 1.; } diff --git a/tests/ui/range_contains.stderr b/tests/ui/range_contains.stderr index 69b009eafc3..bc79f1bca84 100644 --- a/tests/ui/range_contains.stderr +++ b/tests/ui/range_contains.stderr @@ -72,5 +72,17 @@ error: manual `!RangeInclusive::contains` implementation LL | 999 < x || 1 > x; | ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)` -error: aborting due to 12 previous errors +error: manual `Range::contains` implementation + --> $DIR/range_contains.rs:44:5 + | +LL | y >= 0. && y < 1.; + | ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)` + +error: manual `!RangeInclusive::contains` implementation + --> $DIR/range_contains.rs:45:5 + | +LL | y < 0. || y > 1.; + | ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)` + +error: aborting due to 14 previous errors diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index fe8f62503b7..aa20512296a 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -7,6 +7,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::unnecessary_wraps, deprecated )] diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index 09426a6e590..d76f9c288ff 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -7,6 +7,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::unnecessary_wraps, deprecated )] diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index 3473ceea00e..aeb309f5ba1 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:15:12 + --> $DIR/redundant_pattern_matching.rs:16:12 | LL | if let Ok(_) = &result {} | -------^^^^^---------- help: try this: `if result.is_ok()` @@ -7,31 +7,31 @@ LL | if let Ok(_) = &result {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:17:12 + --> $DIR/redundant_pattern_matching.rs:18:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:19:12 + --> $DIR/redundant_pattern_matching.rs:20:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:21:15 + --> $DIR/redundant_pattern_matching.rs:22:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:23:15 + --> $DIR/redundant_pattern_matching.rs:24:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:33:5 + --> $DIR/redundant_pattern_matching.rs:34:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:38:5 + --> $DIR/redundant_pattern_matching.rs:39:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:43:5 + --> $DIR/redundant_pattern_matching.rs:44:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:48:5 + --> $DIR/redundant_pattern_matching.rs:49:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -67,73 +67,73 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:53:20 + --> $DIR/redundant_pattern_matching.rs:54:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:59:20 + --> $DIR/redundant_pattern_matching.rs:60:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:61:19 + --> $DIR/redundant_pattern_matching.rs:62:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:84:19 + --> $DIR/redundant_pattern_matching.rs:85:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:85:16 + --> $DIR/redundant_pattern_matching.rs:86:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:91:12 + --> $DIR/redundant_pattern_matching.rs:92:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:92:15 + --> $DIR/redundant_pattern_matching.rs:93:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:110:12 + --> $DIR/redundant_pattern_matching.rs:111:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:112:12 + --> $DIR/redundant_pattern_matching.rs:113:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:114:15 + --> $DIR/redundant_pattern_matching.rs:115:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:116:15 + --> $DIR/redundant_pattern_matching.rs:117:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:118:5 + --> $DIR/redundant_pattern_matching.rs:119:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:123:5 + --> $DIR/redundant_pattern_matching.rs:124:5 | LL | / match Err::(42) { LL | | Ok(_) => false, diff --git a/tests/ui/result_unit_error.rs b/tests/ui/result_unit_error.rs index a66f581b215..5e57c752b5a 100644 --- a/tests/ui/result_unit_error.rs +++ b/tests/ui/result_unit_error.rs @@ -1,3 +1,4 @@ +#![allow(clippy::unnecessary_wraps)] #[warn(clippy::result_unit_err)] #[allow(unused)] diff --git a/tests/ui/result_unit_error.stderr b/tests/ui/result_unit_error.stderr index b8230032491..12901b354f9 100644 --- a/tests/ui/result_unit_error.stderr +++ b/tests/ui/result_unit_error.stderr @@ -1,5 +1,5 @@ error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:4:1 + --> $DIR/result_unit_error.rs:5:1 | LL | pub fn returns_unit_error() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub fn returns_unit_error() -> Result { = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:13:5 + --> $DIR/result_unit_error.rs:14:5 | LL | fn get_that_error(&self) -> Result; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn get_that_error(&self) -> Result; = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:15:5 + --> $DIR/result_unit_error.rs:16:5 | LL | fn get_this_one_too(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | fn get_this_one_too(&self) -> Result { = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:33:5 + --> $DIR/result_unit_error.rs:34:5 | LL | pub fn unit_error(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs new file mode 100644 index 00000000000..f0dc3b3d06b --- /dev/null +++ b/tests/ui/search_is_some.rs @@ -0,0 +1,38 @@ +// aux-build:option_helpers.rs +extern crate option_helpers; +use option_helpers::IteratorFalsePositives; + +#[warn(clippy::search_is_some)] +#[rustfmt::skip] +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + + // Check `find().is_some()`, multi-line case. + let _ = v.iter().find(|&x| { + *x < 0 + } + ).is_some(); + + // Check `position().is_some()`, multi-line case. + let _ = v.iter().position(|&x| { + x < 0 + } + ).is_some(); + + // Check `rposition().is_some()`, multi-line case. + let _ = v.iter().rposition(|&x| { + x < 0 + } + ).is_some(); + + // Check that we don't lint if the caller is not an `Iterator` or string + let falsepos = IteratorFalsePositives { foo: 0 }; + let _ = falsepos.find().is_some(); + let _ = falsepos.position().is_some(); + let _ = falsepos.rposition().is_some(); + // check that we don't lint if `find()` is called with + // `Pattern` that is not a string + let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some(); +} diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr new file mode 100644 index 00000000000..c601f568c60 --- /dev/null +++ b/tests/ui/search_is_some.stderr @@ -0,0 +1,39 @@ +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some.rs:13:13 + | +LL | let _ = v.iter().find(|&x| { + | _____________^ +LL | | *x < 0 +LL | | } +LL | | ).is_some(); + | |______________________________^ + | + = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: this is more succinctly expressed by calling `any()` + +error: called `is_some()` after searching an `Iterator` with `position` + --> $DIR/search_is_some.rs:19:13 + | +LL | let _ = v.iter().position(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_some(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` + +error: called `is_some()` after searching an `Iterator` with `rposition` + --> $DIR/search_is_some.rs:25:13 + | +LL | let _ = v.iter().rposition(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_some(); + | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/search_is_some_fixable.fixed b/tests/ui/search_is_some_fixable.fixed new file mode 100644 index 00000000000..dc3f290e562 --- /dev/null +++ b/tests/ui/search_is_some_fixable.fixed @@ -0,0 +1,35 @@ +// run-rustfix + +#![warn(clippy::search_is_some)] + +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_some()`, single-line case. + let _ = v.iter().any(|x| *x < 0); + let _ = (0..1).any(|x| **y == x); // one dereference less + let _ = (0..1).any(|x| x == 0); + let _ = v.iter().any(|x| *x == 0); + + // Check `position().is_some()`, single-line case. + let _ = v.iter().any(|&x| x < 0); + + // Check `rposition().is_some()`, single-line case. + let _ = v.iter().any(|&x| x < 0); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + // caller of `find()` is a `&`static str` + let _ = "hello world".contains("world"); + let _ = "hello world".contains(&s2); + let _ = "hello world".contains(&s2[2..]); + // caller of `find()` is a `String` + let _ = s1.contains("world"); + let _ = s1.contains(&s2); + let _ = s1.contains(&s2[2..]); + // caller of `find()` is slice of `String` + let _ = s1[2..].contains("world"); + let _ = s1[2..].contains(&s2); + let _ = s1[2..].contains(&s2[2..]); +} diff --git a/tests/ui/search_is_some_fixable.rs b/tests/ui/search_is_some_fixable.rs new file mode 100644 index 00000000000..146cf5adf1b --- /dev/null +++ b/tests/ui/search_is_some_fixable.rs @@ -0,0 +1,35 @@ +// run-rustfix + +#![warn(clippy::search_is_some)] + +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_some()`, single-line case. + let _ = v.iter().find(|&x| *x < 0).is_some(); + let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + let _ = (0..1).find(|x| *x == 0).is_some(); + let _ = v.iter().find(|x| **x == 0).is_some(); + + // Check `position().is_some()`, single-line case. + let _ = v.iter().position(|&x| x < 0).is_some(); + + // Check `rposition().is_some()`, single-line case. + let _ = v.iter().rposition(|&x| x < 0).is_some(); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + // caller of `find()` is a `&`static str` + let _ = "hello world".find("world").is_some(); + let _ = "hello world".find(&s2).is_some(); + let _ = "hello world".find(&s2[2..]).is_some(); + // caller of `find()` is a `String` + let _ = s1.find("world").is_some(); + let _ = s1.find(&s2).is_some(); + let _ = s1.find(&s2[2..]).is_some(); + // caller of `find()` is slice of `String` + let _ = s1[2..].find("world").is_some(); + let _ = s1[2..].find(&s2).is_some(); + let _ = s1[2..].find(&s2[2..]).is_some(); +} diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr new file mode 100644 index 00000000000..23c1d9a901b --- /dev/null +++ b/tests/ui/search_is_some_fixable.stderr @@ -0,0 +1,94 @@ +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:10:22 + | +LL | let _ = v.iter().find(|&x| *x < 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)` + | + = note: `-D clippy::search-is-some` implied by `-D warnings` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:11:20 + | +LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:12:20 + | +LL | let _ = (0..1).find(|x| *x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)` + +error: called `is_some()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable.rs:13:22 + | +LL | let _ = v.iter().find(|x| **x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)` + +error: called `is_some()` after searching an `Iterator` with `position` + --> $DIR/search_is_some_fixable.rs:16:22 + | +LL | let _ = v.iter().position(|&x| x < 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` + +error: called `is_some()` after searching an `Iterator` with `rposition` + --> $DIR/search_is_some_fixable.rs:19:22 + | +LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:24:27 + | +LL | let _ = "hello world".find("world").is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:25:27 + | +LL | let _ = "hello world".find(&s2).is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:26:27 + | +LL | let _ = "hello world".find(&s2[2..]).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:28:16 + | +LL | let _ = s1.find("world").is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:29:16 + | +LL | let _ = s1.find(&s2).is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:30:16 + | +LL | let _ = s1.find(&s2[2..]).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:32:21 + | +LL | let _ = s1[2..].find("world").is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:33:21 + | +LL | let _ = s1[2..].find(&s2).is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` + +error: called `is_some()` after calling `find()` on a string + --> $DIR/search_is_some_fixable.rs:34:21 + | +LL | let _ = s1[2..].find(&s2[2..]).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` + +error: aborting due to 15 previous errors + diff --git a/tests/ui/string_from_utf8_as_bytes.fixed b/tests/ui/string_from_utf8_as_bytes.fixed new file mode 100644 index 00000000000..6e665cdd563 --- /dev/null +++ b/tests/ui/string_from_utf8_as_bytes.fixed @@ -0,0 +1,6 @@ +// run-rustfix +#![warn(clippy::string_from_utf8_as_bytes)] + +fn main() { + let _ = Some(&"Hello World!"[6..11]); +} diff --git a/tests/ui/string_from_utf8_as_bytes.rs b/tests/ui/string_from_utf8_as_bytes.rs new file mode 100644 index 00000000000..670d206d367 --- /dev/null +++ b/tests/ui/string_from_utf8_as_bytes.rs @@ -0,0 +1,6 @@ +// run-rustfix +#![warn(clippy::string_from_utf8_as_bytes)] + +fn main() { + let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); +} diff --git a/tests/ui/string_from_utf8_as_bytes.stderr b/tests/ui/string_from_utf8_as_bytes.stderr new file mode 100644 index 00000000000..bf5e5d33e8f --- /dev/null +++ b/tests/ui/string_from_utf8_as_bytes.stderr @@ -0,0 +1,10 @@ +error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary + --> $DIR/string_from_utf8_as_bytes.rs:5:13 + | +LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&"Hello World!"[6..11])` + | + = note: `-D clippy::string-from-utf8-as-bytes` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index 9e77dcd8731..652b611208b 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -2,6 +2,7 @@ // aux-build:macro_rules.rs #![deny(clippy::try_err)] +#![allow(clippy::unnecessary_wraps)] #[macro_use] extern crate macro_rules; @@ -78,12 +79,46 @@ fn nested_error() -> Result { Ok(1) } +// Bad suggestion when in macro (see #6242) +macro_rules! try_validation { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => return Err(1), + } + }}; +} + +macro_rules! ret_one { + () => { + 1 + }; +} + +macro_rules! try_validation_in_macro { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => return Err(ret_one!()), + } + }}; +} + +fn calling_macro() -> Result { + // macro + try_validation!(Ok::<_, i32>(5)); + // `Err` arg is another macro + try_validation_in_macro!(Ok::<_, i32>(5)); + Ok(5) +} + fn main() { basic_test().unwrap(); into_test().unwrap(); negative_test().unwrap(); closure_matches_test().unwrap(); closure_into_test().unwrap(); + calling_macro().unwrap(); // We don't want to lint in external macros try_err!(); diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index 41bcb0a189e..6bd479657b7 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -2,6 +2,7 @@ // aux-build:macro_rules.rs #![deny(clippy::try_err)] +#![allow(clippy::unnecessary_wraps)] #[macro_use] extern crate macro_rules; @@ -78,12 +79,46 @@ fn nested_error() -> Result { Ok(1) } +// Bad suggestion when in macro (see #6242) +macro_rules! try_validation { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => Err(1)?, + } + }}; +} + +macro_rules! ret_one { + () => { + 1 + }; +} + +macro_rules! try_validation_in_macro { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => Err(ret_one!())?, + } + }}; +} + +fn calling_macro() -> Result { + // macro + try_validation!(Ok::<_, i32>(5)); + // `Err` arg is another macro + try_validation_in_macro!(Ok::<_, i32>(5)); + Ok(5) +} + fn main() { basic_test().unwrap(); into_test().unwrap(); negative_test().unwrap(); closure_matches_test().unwrap(); closure_into_test().unwrap(); + calling_macro().unwrap(); // We don't want to lint in external macros try_err!(); diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 3f1cbc17e72..2c01d37192e 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -1,5 +1,5 @@ error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:18:9 + --> $DIR/try_err.rs:19:9 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err)` @@ -11,46 +11,68 @@ LL | #![deny(clippy::try_err)] | ^^^^^^^^^^^^^^^ error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:28:9 + --> $DIR/try_err.rs:29:9 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:48:17 + --> $DIR/try_err.rs:49:17 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err)` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:67:17 + --> $DIR/try_err.rs:68:17 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:106:9 + --> $DIR/try_err.rs:87:23 + | +LL | Err(_) => Err(1)?, + | ^^^^^^^ help: try this: `return Err(1)` +... +LL | try_validation!(Ok::<_, i32>(5)); + | --------------------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: returning an `Err(_)` with the `?` operator + --> $DIR/try_err.rs:102:23 + | +LL | Err(_) => Err(ret_one!())?, + | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` +... +LL | try_validation_in_macro!(Ok::<_, i32>(5)); + | ------------------------------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: returning an `Err(_)` with the `?` operator + --> $DIR/try_err.rs:141:9 | LL | Err(foo!())?; | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:113:9 + --> $DIR/try_err.rs:148:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:115:9 + --> $DIR/try_err.rs:150:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:123:9 + --> $DIR/try_err.rs:158:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index fec115ff29d..9ad16d36509 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -4,6 +4,7 @@ unused_must_use, unused_variables, clippy::unused_unit, + clippy::unnecessary_wraps, clippy::or_fun_call )] diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 90fee3aab23..c3a839a9bf8 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:29:5 + --> $DIR/unit_arg.rs:30:5 | LL | / foo({ LL | | 1; @@ -20,7 +20,7 @@ LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:32:5 + --> $DIR/unit_arg.rs:33:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:33:5 + --> $DIR/unit_arg.rs:34:5 | LL | / foo({ LL | | foo(1); @@ -54,7 +54,7 @@ LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:38:5 + --> $DIR/unit_arg.rs:39:5 | LL | / b.bar({ LL | | 1; @@ -74,7 +74,7 @@ LL | b.bar(()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:41:5 + --> $DIR/unit_arg.rs:42:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:42:5 + --> $DIR/unit_arg.rs:43:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -110,7 +110,7 @@ LL | taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:46:5 + --> $DIR/unit_arg.rs:47:5 | LL | / taking_multiple_units( LL | | { @@ -140,7 +140,7 @@ LL | foo(2); ... error: passing a unit value to a function - --> $DIR/unit_arg.rs:57:13 + --> $DIR/unit_arg.rs:58:13 | LL | None.or(Some(foo(2))); | ^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | }); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:60:5 + --> $DIR/unit_arg.rs:61:5 | LL | foo(foo(())) | ^^^^^^^^^^^^ @@ -166,7 +166,7 @@ LL | foo(()) | error: passing a unit value to a function - --> $DIR/unit_arg.rs:93:5 + --> $DIR/unit_arg.rs:94:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index e785ac02feb..6770a7fac90 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -1,7 +1,7 @@ // does not test any rustfixable lints #![warn(clippy::clone_on_ref_ptr)] -#![allow(unused, clippy::redundant_clone)] +#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wraps)] use std::cell::RefCell; use std::rc::{self, Rc}; diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.rs b/tests/ui/unnecessary_lazy_eval_unfixable.rs new file mode 100644 index 00000000000..2e923bc97a2 --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -0,0 +1,18 @@ +#![warn(clippy::unnecessary_lazy_evaluations)] + +struct Deep(Option); + +#[derive(Copy, Clone)] +struct SomeStruct { + some_field: usize, +} + +fn main() { + // fix will break type inference + let _ = Ok(1).unwrap_or_else(|()| 2); + mod e { + pub struct E; + } + let _ = Ok(1).unwrap_or_else(|e::E| 2); + let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); +} diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr new file mode 100644 index 00000000000..581d641cbf5 --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -0,0 +1,22 @@ +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:12:13 + | +LL | let _ = Ok(1).unwrap_or_else(|()| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | + = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:16:13 + | +LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:17:13 + | +LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/unnecessary_wraps.rs b/tests/ui/unnecessary_wraps.rs new file mode 100644 index 00000000000..a53dec8f91a --- /dev/null +++ b/tests/ui/unnecessary_wraps.rs @@ -0,0 +1,116 @@ +#![warn(clippy::unnecessary_wraps)] +#![allow(clippy::no_effect)] +#![allow(clippy::needless_return)] +#![allow(clippy::if_same_then_else)] +#![allow(dead_code)] + +// should be linted +fn func1(a: bool, b: bool) -> Option { + if a && b { + return Some(42); + } + if a { + Some(-1); + Some(2) + } else { + return Some(1337); + } +} + +// should be linted +fn func2(a: bool, b: bool) -> Option { + if a && b { + return Some(10); + } + if a { + Some(20) + } else { + Some(30) + } +} + +// public fns should not be linted +pub fn func3(a: bool) -> Option { + if a { + Some(1) + } else { + Some(1) + } +} + +// should not be linted +fn func4(a: bool) -> Option { + if a { + Some(1) + } else { + None + } +} + +// should be linted +fn func5() -> Option { + Some(1) +} + +// should not be linted +fn func6() -> Option { + None +} + +// should be linted +fn func7() -> Result { + Ok(1) +} + +// should not be linted +fn func8(a: bool) -> Result { + if a { + Ok(1) + } else { + Err(()) + } +} + +// should not be linted +fn func9(a: bool) -> Result { + Err(()) +} + +// should not be linted +fn func10() -> Option<()> { + unimplemented!() +} + +struct A; + +impl A { + // should not be linted + pub fn func11() -> Option { + Some(1) + } + + // should be linted + fn func12() -> Option { + Some(1) + } +} + +trait B { + // trait impls are not linted + fn func13() -> Option { + Some(1) + } +} + +impl B for A { + // trait impls are not linted + fn func13() -> Option { + Some(0) + } +} + +fn main() { + // method calls are not linted + func1(true, true); + func2(true, true); +} diff --git a/tests/ui/unnecessary_wraps.stderr b/tests/ui/unnecessary_wraps.stderr new file mode 100644 index 00000000000..410f054b8ef --- /dev/null +++ b/tests/ui/unnecessary_wraps.stderr @@ -0,0 +1,106 @@ +error: this function's return value is unnecessarily wrapped by `Option` + --> $DIR/unnecessary_wraps.rs:8:1 + | +LL | / fn func1(a: bool, b: bool) -> Option { +LL | | if a && b { +LL | | return Some(42); +LL | | } +... | +LL | | } +LL | | } + | |_^ + | + = note: `-D clippy::unnecessary-wraps` implied by `-D warnings` +help: remove `Option` from the return type... + | +LL | fn func1(a: bool, b: bool) -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | return 42; +LL | } +LL | if a { +LL | Some(-1); +LL | 2 +LL | } else { + ... + +error: this function's return value is unnecessarily wrapped by `Option` + --> $DIR/unnecessary_wraps.rs:21:1 + | +LL | / fn func2(a: bool, b: bool) -> Option { +LL | | if a && b { +LL | | return Some(10); +LL | | } +... | +LL | | } +LL | | } + | |_^ + | +help: remove `Option` from the return type... + | +LL | fn func2(a: bool, b: bool) -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | return 10; +LL | } +LL | if a { +LL | 20 +LL | } else { +LL | 30 + | + +error: this function's return value is unnecessarily wrapped by `Option` + --> $DIR/unnecessary_wraps.rs:51:1 + | +LL | / fn func5() -> Option { +LL | | Some(1) +LL | | } + | |_^ + | +help: remove `Option` from the return type... + | +LL | fn func5() -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | 1 + | + +error: this function's return value is unnecessarily wrapped by `Result` + --> $DIR/unnecessary_wraps.rs:61:1 + | +LL | / fn func7() -> Result { +LL | | Ok(1) +LL | | } + | |_^ + | +help: remove `Result` from the return type... + | +LL | fn func7() -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | 1 + | + +error: this function's return value is unnecessarily wrapped by `Option` + --> $DIR/unnecessary_wraps.rs:93:5 + | +LL | / fn func12() -> Option { +LL | | Some(1) +LL | | } + | |_____^ + | +help: remove `Option` from the return type... + | +LL | fn func12() -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | 1 + | + +error: aborting due to 5 previous errors + diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 8a9b0cd3cf0..03977de9455 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::useless_conversion)] +#![allow(clippy::unnecessary_wraps)] fn test_generic(val: T) -> T { let _ = val; diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 4faa1572973..f6e094c1661 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::useless_conversion)] +#![allow(clippy::unnecessary_wraps)] fn test_generic(val: T) -> T { let _ = T::from(val); diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 11c6efb25cc..26a33595031 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> $DIR/useless_conversion.rs:6:13 + --> $DIR/useless_conversion.rs:7:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` @@ -11,61 +11,61 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> $DIR/useless_conversion.rs:7:5 + --> $DIR/useless_conversion.rs:8:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:19:22 + --> $DIR/useless_conversion.rs:20:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:60:21 + --> $DIR/useless_conversion.rs:61:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:61:21 + --> $DIR/useless_conversion.rs:62:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:62:13 + --> $DIR/useless_conversion.rs:63:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:63:13 + --> $DIR/useless_conversion.rs:64:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines` - --> $DIR/useless_conversion.rs:64:13 + --> $DIR/useless_conversion.rs:65:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> $DIR/useless_conversion.rs:65:13 + --> $DIR/useless_conversion.rs:66:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:66:21 + --> $DIR/useless_conversion.rs:67:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:71:13 + --> $DIR/useless_conversion.rs:72:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` diff --git a/tests/ui/vec_box_sized.fixed b/tests/ui/vec_box_sized.fixed index d0bee2460dd..4fa28b525c3 100644 --- a/tests/ui/vec_box_sized.fixed +++ b/tests/ui/vec_box_sized.fixed @@ -35,4 +35,18 @@ mod should_not_trigger { } } +mod inner_mod { + mod inner { + pub struct S; + } + + mod inner2 { + use super::inner::S; + + pub fn f() -> Vec { + vec![] + } + } +} + fn main() {} diff --git a/tests/ui/vec_box_sized.rs b/tests/ui/vec_box_sized.rs index 500a0ae263e..7dc735cd90b 100644 --- a/tests/ui/vec_box_sized.rs +++ b/tests/ui/vec_box_sized.rs @@ -35,4 +35,18 @@ mod should_not_trigger { } } +mod inner_mod { + mod inner { + pub struct S; + } + + mod inner2 { + use super::inner::S; + + pub fn f() -> Vec> { + vec![] + } + } +} + fn main() {} diff --git a/tests/ui/vec_box_sized.stderr b/tests/ui/vec_box_sized.stderr index 29bf7069e8a..57e2f1fdf9a 100644 --- a/tests/ui/vec_box_sized.stderr +++ b/tests/ui/vec_box_sized.stderr @@ -18,5 +18,11 @@ error: `Vec` is already on the heap, the boxing is unnecessary. LL | struct B(Vec>>); | ^^^^^^^^^^^^^^^ help: try: `Vec` -error: aborting due to 3 previous errors +error: `Vec` is already on the heap, the boxing is unnecessary. + --> $DIR/vec_box_sized.rs:46:23 + | +LL | pub fn f() -> Vec> { + | ^^^^^^^^^^^ help: try: `Vec` + +error: aborting due to 4 previous errors diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 287f8935327..ee9c9045fff 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -4,6 +4,7 @@ #![warn(clippy::wildcard_imports)] //#![allow(clippy::redundant_pub_crate)] #![allow(unused)] +#![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] extern crate wildcard_imports_helper; diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 1f261159f4a..efaa8f9ef66 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -4,6 +4,7 @@ #![warn(clippy::wildcard_imports)] //#![allow(clippy::redundant_pub_crate)] #![allow(unused)] +#![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] extern crate wildcard_imports_helper; diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 351988f31ea..66267dd27b8 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -1,5 +1,5 @@ error: usage of wildcard import - --> $DIR/wildcard_imports.rs:11:5 + --> $DIR/wildcard_imports.rs:12:5 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` @@ -7,85 +7,85 @@ LL | use crate::fn_mod::*; = note: `-D clippy::wildcard-imports` implied by `-D warnings` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:12:5 + --> $DIR/wildcard_imports.rs:13:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:13:5 + --> $DIR/wildcard_imports.rs:14:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:15:5 + --> $DIR/wildcard_imports.rs:16:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:19:5 + --> $DIR/wildcard_imports.rs:20:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:20:5 + --> $DIR/wildcard_imports.rs:21:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:91:13 + --> $DIR/wildcard_imports.rs:92:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:97:75 + --> $DIR/wildcard_imports.rs:98:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:98:13 + --> $DIR/wildcard_imports.rs:99:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:109:20 + --> $DIR/wildcard_imports.rs:110:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:109:30 + --> $DIR/wildcard_imports.rs:110:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:116:13 + --> $DIR/wildcard_imports.rs:117:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:145:9 + --> $DIR/wildcard_imports.rs:146:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:154:9 + --> $DIR/wildcard_imports.rs:155:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:155:9 + --> $DIR/wildcard_imports.rs:156:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,31 +93,31 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:166:13 + --> $DIR/wildcard_imports.rs:167:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:201:17 + --> $DIR/wildcard_imports.rs:202:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:209:13 + --> $DIR/wildcard_imports.rs:210:13 | LL | use super_imports::*; | ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:218:17 + --> $DIR/wildcard_imports.rs:219:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:227:13 + --> $DIR/wildcard_imports.rs:228:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` From 284c359c6141404c186a37e5537ffa849b2dcc23 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 23 Nov 2020 13:52:27 +0100 Subject: [PATCH 061/274] Fix ICE in utils::implements_trait This only happend when debug_assertions were enabled in rustc --- clippy_lints/src/utils/mod.rs | 3 +++ tests/ui/crashes/implements-trait.rs | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 tests/ui/crashes/implements-trait.rs diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 5bd64dcb541..e9c71e23a67 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -365,6 +365,9 @@ pub fn implements_trait<'tcx>( return false; } let ty = cx.tcx.erase_regions(ty); + if ty.has_escaping_bound_vars() { + return false; + } let ty_params = cx.tcx.mk_substs(ty_params.iter()); cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) } diff --git a/tests/ui/crashes/implements-trait.rs b/tests/ui/crashes/implements-trait.rs new file mode 100644 index 00000000000..4502b0147a8 --- /dev/null +++ b/tests/ui/crashes/implements-trait.rs @@ -0,0 +1,5 @@ +#[allow(clippy::needless_borrowed_reference)] +fn main() { + let mut v = Vec::::new(); + let _ = v.iter_mut().filter(|&ref a| a.is_empty()); +} From d708b444e4dc324369ba7ee2235451399f828321 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 24 Oct 2020 18:35:46 -0700 Subject: [PATCH 062/274] Qualify `panic!` as `core::panic!` in non-built-in `core` macros Otherwise code like this #![no_implicit_prelude] fn main() { ::std::todo!(); ::std::unimplemented!(); } will fail to compile, which is unfortunate and presumably unintended. This changes many invocations of `panic!` in a `macro_rules!` definition to invocations of `$crate::panic!`, which makes the invocations hygienic. Note that this does not make the built-in macro `assert!` hygienic. --- tests/ui/logic_bug.rs | 2 +- tests/ui/nonminimal_bool.rs | 2 +- tests/ui/nonminimal_bool_methods.rs | 2 +- tests/ui/wildcard_enum_match_arm.fixed | 2 +- tests/ui/wildcard_enum_match_arm.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ui/logic_bug.rs b/tests/ui/logic_bug.rs index b4163d776e7..a01c6ef99db 100644 --- a/tests/ui/logic_bug.rs +++ b/tests/ui/logic_bug.rs @@ -1,4 +1,4 @@ -#![allow(unused, clippy::many_single_char_names)] +#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)] #![warn(clippy::logic_bug)] fn main() { diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index 7ea154cb9b0..971be26278f 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -1,4 +1,4 @@ -#![allow(unused, clippy::many_single_char_names)] +#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] fn main() { diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs index 4de48cd0879..90758740290 100644 --- a/tests/ui/nonminimal_bool_methods.rs +++ b/tests/ui/nonminimal_bool_methods.rs @@ -1,4 +1,4 @@ -#![allow(unused, clippy::many_single_char_names)] +#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] fn methods_with_negation() { diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed index 4f8754a9301..b1e5742b785 100644 --- a/tests/ui/wildcard_enum_match_arm.fixed +++ b/tests/ui/wildcard_enum_match_arm.fixed @@ -7,7 +7,7 @@ dead_code, clippy::single_match, clippy::wildcard_in_or_patterns, - clippy::unnested_or_patterns + clippy::unnested_or_patterns, clippy::diverging_sub_expression )] use std::io::ErrorKind; diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs index 5e66644ceca..cd3ec3ea8d2 100644 --- a/tests/ui/wildcard_enum_match_arm.rs +++ b/tests/ui/wildcard_enum_match_arm.rs @@ -7,7 +7,7 @@ dead_code, clippy::single_match, clippy::wildcard_in_or_patterns, - clippy::unnested_or_patterns + clippy::unnested_or_patterns, clippy::diverging_sub_expression )] use std::io::ErrorKind; From 9f1505ce9fcadba36a729431ecff1bb6b4e1c228 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 7 Oct 2020 16:04:22 +0200 Subject: [PATCH 063/274] clippy: Let rustc handle describing lints --- src/driver.rs | 121 -------------------------------------------------- 1 file changed, 121 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index cc71cc66b92..ef31c72481a 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -8,7 +8,6 @@ // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) -extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_interface; @@ -26,8 +25,6 @@ use std::panic; use std::path::{Path, PathBuf}; use std::process::{exit, Command}; -mod lintlist; - /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. fn arg_value<'a, T: Deref>( @@ -92,113 +89,6 @@ impl rustc_driver::Callbacks for ClippyCallbacks { } } -#[allow(clippy::find_map, clippy::filter_map)] -fn describe_lints() { - use lintlist::{Level, Lint, ALL_LINTS, LINT_LEVELS}; - use rustc_data_structures::fx::FxHashSet; - - println!( - " -Available lint options: - -W Warn about - -A Allow - -D Deny - -F Forbid (deny and all attempts to override) - -" - ); - - let lint_level = |lint: &Lint| { - LINT_LEVELS - .iter() - .find(|level_mapping| level_mapping.0 == lint.group) - .map(|(_, level)| match level { - Level::Allow => "allow", - Level::Warn => "warn", - Level::Deny => "deny", - }) - .unwrap() - }; - - let mut lints: Vec<_> = ALL_LINTS.iter().collect(); - // The sort doesn't case-fold but it's doubtful we care. - lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name)); - - let max_lint_name_len = lints - .iter() - .map(|lint| lint.name.len()) - .map(|len| len + "clippy::".len()) - .max() - .unwrap_or(0); - - let padded = |x: &str| { - let mut s = " ".repeat(max_lint_name_len - x.chars().count()); - s.push_str(x); - s - }; - - let scoped = |x: &str| format!("clippy::{}", x); - - let lint_groups: FxHashSet<_> = lints.iter().map(|lint| lint.group).collect(); - - println!("Lint checks provided by clippy:\n"); - println!(" {} {:7.7} meaning", padded("name"), "default"); - println!(" {} {:7.7} -------", padded("----"), "-------"); - - let print_lints = |lints: &[&Lint]| { - for lint in lints { - let name = lint.name.replace("_", "-"); - println!( - " {} {:7.7} {}", - padded(&scoped(&name)), - lint_level(lint), - lint.desc - ); - } - println!("\n"); - }; - - print_lints(&lints); - - let max_group_name_len = std::cmp::max( - "clippy::all".len(), - lint_groups - .iter() - .map(|group| group.len()) - .map(|len| len + "clippy::".len()) - .max() - .unwrap_or(0), - ); - - let padded_group = |x: &str| { - let mut s = " ".repeat(max_group_name_len - x.chars().count()); - s.push_str(x); - s - }; - - println!("Lint groups provided by clippy:\n"); - println!(" {} sub-lints", padded_group("name")); - println!(" {} ---------", padded_group("----")); - println!(" {} the set of all clippy lints", padded_group("clippy::all")); - - let print_lint_groups = || { - for group in lint_groups { - let name = group.to_lowercase().replace("_", "-"); - let desc = lints - .iter() - .filter(|&lint| lint.group == group) - .map(|lint| lint.name) - .map(|name| name.replace("_", "-")) - .collect::>() - .join(", "); - println!(" {} {}", padded_group(&scoped(&name)), desc); - } - println!("\n"); - }; - - print_lint_groups(); -} - fn display_help() { println!( "\ @@ -379,17 +269,6 @@ pub fn main() { exit(0); } - let should_describe_lints = || { - let args: Vec<_> = env::args().collect(); - args.windows(2) - .any(|args| args[1] == "help" && matches!(args[0].as_str(), "-W" | "-A" | "-D" | "-F")) - }; - - if !wrapper_mode && should_describe_lints() { - describe_lints(); - exit(0); - } - // this conditional check for the --sysroot flag is there so users can call // `clippy_driver` directly // without having to pass --sysroot or anything From 03f04314dd715db631214ed4c5fa8243dc17eb1c Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 7 Oct 2020 16:05:13 +0200 Subject: [PATCH 064/274] clippy: Remove now obsolete lintlist module Also stop updating the lintlist module in clippy_dev update_lints --- clippy_dev/src/update_lints.rs | 15 +- src/lintlist/lint.rs | 27 - src/lintlist/mod.rs | 2942 -------------------------------- 3 files changed, 1 insertion(+), 2983 deletions(-) delete mode 100644 src/lintlist/lint.rs delete mode 100644 src/lintlist/mod.rs diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 556b67e0b37..fcf093f8835 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -22,20 +22,7 @@ pub fn run(update_mode: UpdateMode) { let usable_lint_count = round_to_fifty(usable_lints.len()); - let mut file_change = replace_region_in_file( - Path::new("src/lintlist/mod.rs"), - "begin lint list", - "end lint list", - false, - update_mode == UpdateMode::Change, - || { - format!("vec!{:#?}", sorted_usable_lints) - .lines() - .map(ToString::to_string) - .collect::>() - }, - ) - .changed; + let mut file_change = false; file_change |= replace_region_in_file( Path::new("README.md"), diff --git a/src/lintlist/lint.rs b/src/lintlist/lint.rs deleted file mode 100644 index c817d83b33a..00000000000 --- a/src/lintlist/lint.rs +++ /dev/null @@ -1,27 +0,0 @@ -/// Lint data parsed from the Clippy source code. -#[derive(Clone, PartialEq, Debug)] -pub struct Lint { - pub name: &'static str, - pub group: &'static str, - pub desc: &'static str, - pub deprecation: Option<&'static str>, - pub module: &'static str, -} - -#[derive(PartialOrd, PartialEq, Ord, Eq)] -pub enum Level { - Allow, - Warn, - Deny, -} - -pub const LINT_LEVELS: [(&str, Level); 8] = [ - ("correctness", Level::Deny), - ("style", Level::Warn), - ("complexity", Level::Warn), - ("perf", Level::Warn), - ("restriction", Level::Allow), - ("pedantic", Level::Allow), - ("nursery", Level::Allow), - ("cargo", Level::Allow), -]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs deleted file mode 100644 index 1d906d20ad4..00000000000 --- a/src/lintlist/mod.rs +++ /dev/null @@ -1,2942 +0,0 @@ -//! This file is managed by `cargo dev update_lints`. Do not edit or format this file. - -use std::lazy::SyncLazy; - -pub mod lint; -pub use lint::Level; -pub use lint::Lint; -pub use lint::LINT_LEVELS; - -#[rustfmt::skip] -pub static ALL_LINTS: SyncLazy> = SyncLazy::new(|| { -// begin lint list, do not remove this comment, it’s used in `update_lints` -vec![ - Lint { - name: "absurd_extreme_comparisons", - group: "correctness", - desc: "a comparison with a maximum or minimum value that is always true or false", - deprecation: None, - module: "types", - }, - Lint { - name: "almost_swapped", - group: "correctness", - desc: "`foo = bar; bar = foo` sequence", - deprecation: None, - module: "swap", - }, - Lint { - name: "approx_constant", - group: "correctness", - desc: "the approximate of a known float constant (in `std::fXX::consts`)", - deprecation: None, - module: "approx_const", - }, - Lint { - name: "as_conversions", - group: "restriction", - desc: "using a potentially dangerous silent `as` conversion", - deprecation: None, - module: "as_conversions", - }, - Lint { - name: "assertions_on_constants", - group: "style", - desc: "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`", - deprecation: None, - module: "assertions_on_constants", - }, - Lint { - name: "assign_op_pattern", - group: "style", - desc: "assigning the result of an operation on a variable to that same variable", - deprecation: None, - module: "assign_ops", - }, - Lint { - name: "async_yields_async", - group: "correctness", - desc: "async blocks that return a type that can be awaited", - deprecation: None, - module: "async_yields_async", - }, - Lint { - name: "await_holding_lock", - group: "pedantic", - desc: "Inside an async function, holding a MutexGuard while calling await", - deprecation: None, - module: "await_holding_invalid", - }, - Lint { - name: "await_holding_refcell_ref", - group: "pedantic", - desc: "Inside an async function, holding a RefCell ref while calling await", - deprecation: None, - module: "await_holding_invalid", - }, - Lint { - name: "bad_bit_mask", - group: "correctness", - desc: "expressions of the form `_ & mask == select` that will only ever return `true` or `false`", - deprecation: None, - module: "bit_mask", - }, - Lint { - name: "bind_instead_of_map", - group: "complexity", - desc: "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "blacklisted_name", - group: "style", - desc: "usage of a blacklisted/placeholder name", - deprecation: None, - module: "blacklisted_name", - }, - Lint { - name: "blanket_clippy_restriction_lints", - group: "style", - desc: "enabling the complete restriction group", - deprecation: None, - module: "attrs", - }, - Lint { - name: "blocks_in_if_conditions", - group: "style", - desc: "useless or complex blocks that can be eliminated in conditions", - deprecation: None, - module: "blocks_in_if_conditions", - }, - Lint { - name: "bool_comparison", - group: "complexity", - desc: "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`", - deprecation: None, - module: "needless_bool", - }, - Lint { - name: "borrow_interior_mutable_const", - group: "style", - desc: "referencing `const` with interior mutability", - deprecation: None, - module: "non_copy_const", - }, - Lint { - name: "borrowed_box", - group: "complexity", - desc: "a borrow of a boxed type", - deprecation: None, - module: "types", - }, - Lint { - name: "box_vec", - group: "perf", - desc: "usage of `Box>`, vector elements are already on the heap", - deprecation: None, - module: "types", - }, - Lint { - name: "boxed_local", - group: "perf", - desc: "using `Box` where unnecessary", - deprecation: None, - module: "escape", - }, - Lint { - name: "builtin_type_shadow", - group: "style", - desc: "shadowing a builtin type", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "cargo_common_metadata", - group: "cargo", - desc: "common metadata is defined in `Cargo.toml`", - deprecation: None, - module: "cargo_common_metadata", - }, - Lint { - name: "cast_lossless", - group: "pedantic", - desc: "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_possible_truncation", - group: "pedantic", - desc: "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_possible_wrap", - group: "pedantic", - desc: "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_precision_loss", - group: "pedantic", - desc: "casts that cause loss of precision, e.g., `x as f32` where `x: u64`", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_ptr_alignment", - group: "pedantic", - desc: "cast from a pointer to a more-strictly-aligned pointer", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_ref_to_mut", - group: "correctness", - desc: "a cast of reference to a mutable pointer", - deprecation: None, - module: "types", - }, - Lint { - name: "cast_sign_loss", - group: "pedantic", - desc: "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`", - deprecation: None, - module: "types", - }, - Lint { - name: "char_lit_as_u8", - group: "complexity", - desc: "casting a character literal to `u8` truncates", - deprecation: None, - module: "types", - }, - Lint { - name: "chars_last_cmp", - group: "style", - desc: "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char", - deprecation: None, - module: "methods", - }, - Lint { - name: "chars_next_cmp", - group: "style", - desc: "using `.chars().next()` to check if a string starts with a char", - deprecation: None, - module: "methods", - }, - Lint { - name: "checked_conversions", - group: "pedantic", - desc: "`try_from` could replace manual bounds checking when casting", - deprecation: None, - module: "checked_conversions", - }, - Lint { - name: "clone_double_ref", - group: "correctness", - desc: "using `clone` on `&&T`", - deprecation: None, - module: "methods", - }, - Lint { - name: "clone_on_copy", - group: "complexity", - desc: "using `clone` on a `Copy` type", - deprecation: None, - module: "methods", - }, - Lint { - name: "clone_on_ref_ptr", - group: "restriction", - desc: "using \'clone\' on a ref-counted pointer", - deprecation: None, - module: "methods", - }, - Lint { - name: "cmp_nan", - group: "correctness", - desc: "comparisons to `NAN`, which will always return false, probably not intended", - deprecation: None, - module: "misc", - }, - Lint { - name: "cmp_null", - group: "style", - desc: "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead.", - deprecation: None, - module: "ptr", - }, - Lint { - name: "cmp_owned", - group: "perf", - desc: "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`", - deprecation: None, - module: "misc", - }, - Lint { - name: "cognitive_complexity", - group: "nursery", - desc: "functions that should be split up into multiple functions", - deprecation: None, - module: "cognitive_complexity", - }, - Lint { - name: "collapsible_if", - group: "style", - desc: "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)", - deprecation: None, - module: "collapsible_if", - }, - Lint { - name: "comparison_chain", - group: "style", - desc: "`if`s that can be rewritten with `match` and `cmp`", - deprecation: None, - module: "comparison_chain", - }, - Lint { - name: "comparison_to_empty", - group: "style", - desc: "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead", - deprecation: None, - module: "len_zero", - }, - Lint { - name: "copy_iterator", - group: "pedantic", - desc: "implementing `Iterator` on a `Copy` type", - deprecation: None, - module: "copy_iterator", - }, - Lint { - name: "create_dir", - group: "restriction", - desc: "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`", - deprecation: None, - module: "create_dir", - }, - Lint { - name: "crosspointer_transmute", - group: "complexity", - desc: "transmutes that have to or from types that are a pointer to the other", - deprecation: None, - module: "transmute", - }, - Lint { - name: "dbg_macro", - group: "restriction", - desc: "`dbg!` macro is intended as a debugging tool", - deprecation: None, - module: "dbg_macro", - }, - Lint { - name: "debug_assert_with_mut_call", - group: "nursery", - desc: "mutable arguments in `debug_assert{,_ne,_eq}!`", - deprecation: None, - module: "mutable_debug_assertion", - }, - Lint { - name: "decimal_literal_representation", - group: "restriction", - desc: "using decimal representation when hexadecimal would be better", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "declare_interior_mutable_const", - group: "style", - desc: "declaring `const` with interior mutability", - deprecation: None, - module: "non_copy_const", - }, - Lint { - name: "default_trait_access", - group: "pedantic", - desc: "checks for literal calls to `Default::default()`", - deprecation: None, - module: "default", - }, - Lint { - name: "deprecated_cfg_attr", - group: "complexity", - desc: "usage of `cfg_attr(rustfmt)` instead of tool attributes", - deprecation: None, - module: "attrs", - }, - Lint { - name: "deprecated_semver", - group: "correctness", - desc: "use of `#[deprecated(since = \"x\")]` where x is not semver", - deprecation: None, - module: "attrs", - }, - Lint { - name: "deref_addrof", - group: "complexity", - desc: "use of `*&` or `*&mut` in an expression", - deprecation: None, - module: "reference", - }, - Lint { - name: "derive_hash_xor_eq", - group: "correctness", - desc: "deriving `Hash` but implementing `PartialEq` explicitly", - deprecation: None, - module: "derive", - }, - Lint { - name: "derive_ord_xor_partial_ord", - group: "correctness", - desc: "deriving `Ord` but implementing `PartialOrd` explicitly", - deprecation: None, - module: "derive", - }, - Lint { - name: "disallowed_method", - group: "nursery", - desc: "use of a disallowed method call", - deprecation: None, - module: "disallowed_method", - }, - Lint { - name: "diverging_sub_expression", - group: "complexity", - desc: "whether an expression contains a diverging sub expression", - deprecation: None, - module: "eval_order_dependence", - }, - Lint { - name: "doc_markdown", - group: "pedantic", - desc: "presence of `_`, `::` or camel-case outside backticks in documentation", - deprecation: None, - module: "doc", - }, - Lint { - name: "double_comparisons", - group: "complexity", - desc: "unnecessary double comparisons that can be simplified", - deprecation: None, - module: "double_comparison", - }, - Lint { - name: "double_must_use", - group: "style", - desc: "`#[must_use]` attribute on a `#[must_use]`-returning function / method", - deprecation: None, - module: "functions", - }, - Lint { - name: "double_neg", - group: "style", - desc: "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "double_parens", - group: "complexity", - desc: "Warn on unnecessary double parentheses", - deprecation: None, - module: "double_parens", - }, - Lint { - name: "drop_copy", - group: "correctness", - desc: "calls to `std::mem::drop` with a value that implements Copy", - deprecation: None, - module: "drop_forget_ref", - }, - Lint { - name: "drop_ref", - group: "correctness", - desc: "calls to `std::mem::drop` with a reference instead of an owned value", - deprecation: None, - module: "drop_forget_ref", - }, - Lint { - name: "duplicate_underscore_argument", - group: "style", - desc: "function arguments having names which only differ by an underscore", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "duration_subsec", - group: "complexity", - desc: "checks for calculation of subsecond microseconds or milliseconds", - deprecation: None, - module: "duration_subsec", - }, - Lint { - name: "else_if_without_else", - group: "restriction", - desc: "`if` expression with an `else if`, but without a final `else` branch", - deprecation: None, - module: "else_if_without_else", - }, - Lint { - name: "empty_enum", - group: "pedantic", - desc: "enum with no variants", - deprecation: None, - module: "empty_enum", - }, - Lint { - name: "empty_line_after_outer_attr", - group: "nursery", - desc: "empty line after outer attribute", - deprecation: None, - module: "attrs", - }, - Lint { - name: "empty_loop", - group: "style", - desc: "empty `loop {}`, which should block or sleep", - deprecation: None, - module: "loops", - }, - Lint { - name: "enum_clike_unportable_variant", - group: "correctness", - desc: "C-like enums that are `repr(isize/usize)` and have values that don\'t fit into an `i32`", - deprecation: None, - module: "enum_clike", - }, - Lint { - name: "enum_glob_use", - group: "pedantic", - desc: "use items that import all variants of an enum", - deprecation: None, - module: "wildcard_imports", - }, - Lint { - name: "enum_variant_names", - group: "style", - desc: "enums where all variants share a prefix/postfix", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "eq_op", - group: "correctness", - desc: "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)", - deprecation: None, - module: "eq_op", - }, - Lint { - name: "erasing_op", - group: "correctness", - desc: "using erasing operations, e.g., `x * 0` or `y & 0`", - deprecation: None, - module: "erasing_op", - }, - Lint { - name: "eval_order_dependence", - group: "complexity", - desc: "whether a variable read occurs before a write depends on sub-expression evaluation order", - deprecation: None, - module: "eval_order_dependence", - }, - Lint { - name: "excessive_precision", - group: "style", - desc: "excessive precision for float literal", - deprecation: None, - module: "float_literal", - }, - Lint { - name: "exit", - group: "restriction", - desc: "`std::process::exit` is called, terminating the program", - deprecation: None, - module: "exit", - }, - Lint { - name: "expect_fun_call", - group: "perf", - desc: "using any `expect` method with a function call", - deprecation: None, - module: "methods", - }, - Lint { - name: "expect_used", - group: "restriction", - desc: "using `.expect()` on `Result` or `Option`, which might be better handled", - deprecation: None, - module: "methods", - }, - Lint { - name: "expl_impl_clone_on_copy", - group: "pedantic", - desc: "implementing `Clone` explicitly on `Copy` types", - deprecation: None, - module: "derive", - }, - Lint { - name: "explicit_counter_loop", - group: "complexity", - desc: "for-looping with an explicit counter when `_.enumerate()` would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "explicit_deref_methods", - group: "pedantic", - desc: "Explicit use of deref or deref_mut method while not in a method chain.", - deprecation: None, - module: "dereference", - }, - Lint { - name: "explicit_into_iter_loop", - group: "pedantic", - desc: "for-looping over `_.into_iter()` when `_` would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "explicit_iter_loop", - group: "pedantic", - desc: "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "explicit_write", - group: "complexity", - desc: "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work", - deprecation: None, - module: "explicit_write", - }, - Lint { - name: "extra_unused_lifetimes", - group: "complexity", - desc: "unused lifetimes in function definitions", - deprecation: None, - module: "lifetimes", - }, - Lint { - name: "fallible_impl_from", - group: "nursery", - desc: "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`", - deprecation: None, - module: "fallible_impl_from", - }, - Lint { - name: "field_reassign_with_default", - group: "style", - desc: "binding initialized with Default should have its fields set in the initializer", - deprecation: None, - module: "default", - }, - Lint { - name: "filetype_is_file", - group: "restriction", - desc: "`FileType::is_file` is not recommended to test for readable file type", - deprecation: None, - module: "methods", - }, - Lint { - name: "filter_map", - group: "pedantic", - desc: "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call", - deprecation: None, - module: "methods", - }, - Lint { - name: "filter_map_next", - group: "pedantic", - desc: "using combination of `filter_map` and `next` which can usually be written as a single method call", - deprecation: None, - module: "methods", - }, - Lint { - name: "filter_next", - group: "complexity", - desc: "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "find_map", - group: "pedantic", - desc: "using a combination of `find` and `map` can usually be written as a single method call", - deprecation: None, - module: "methods", - }, - Lint { - name: "flat_map_identity", - group: "complexity", - desc: "call to `flat_map` where `flatten` is sufficient", - deprecation: None, - module: "methods", - }, - Lint { - name: "float_arithmetic", - group: "restriction", - desc: "any floating-point arithmetic statement", - deprecation: None, - module: "arithmetic", - }, - Lint { - name: "float_cmp", - group: "correctness", - desc: "using `==` or `!=` on float values instead of comparing difference with an epsilon", - deprecation: None, - module: "misc", - }, - Lint { - name: "float_cmp_const", - group: "restriction", - desc: "using `==` or `!=` on float constants instead of comparing difference with an epsilon", - deprecation: None, - module: "misc", - }, - Lint { - name: "float_equality_without_abs", - group: "correctness", - desc: "float equality check without `.abs()`", - deprecation: None, - module: "float_equality_without_abs", - }, - Lint { - name: "fn_address_comparisons", - group: "correctness", - desc: "comparison with an address of a function item", - deprecation: None, - module: "unnamed_address", - }, - Lint { - name: "fn_params_excessive_bools", - group: "pedantic", - desc: "using too many bools in function parameters", - deprecation: None, - module: "excessive_bools", - }, - Lint { - name: "fn_to_numeric_cast", - group: "style", - desc: "casting a function pointer to a numeric type other than usize", - deprecation: None, - module: "types", - }, - Lint { - name: "fn_to_numeric_cast_with_truncation", - group: "style", - desc: "casting a function pointer to a numeric type not wide enough to store the address", - deprecation: None, - module: "types", - }, - Lint { - name: "for_kv_map", - group: "style", - desc: "looping on a map using `iter` when `keys` or `values` would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "for_loops_over_fallibles", - group: "correctness", - desc: "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`", - deprecation: None, - module: "loops", - }, - Lint { - name: "forget_copy", - group: "correctness", - desc: "calls to `std::mem::forget` with a value that implements Copy", - deprecation: None, - module: "drop_forget_ref", - }, - Lint { - name: "forget_ref", - group: "correctness", - desc: "calls to `std::mem::forget` with a reference instead of an owned value", - deprecation: None, - module: "drop_forget_ref", - }, - Lint { - name: "from_iter_instead_of_collect", - group: "style", - desc: "use `.collect()` instead of `::from_iter()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "future_not_send", - group: "nursery", - desc: "public Futures must be Send", - deprecation: None, - module: "future_not_send", - }, - Lint { - name: "get_last_with_len", - group: "complexity", - desc: "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler", - deprecation: None, - module: "get_last_with_len", - }, - Lint { - name: "get_unwrap", - group: "restriction", - desc: "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead", - deprecation: None, - module: "methods", - }, - Lint { - name: "identity_op", - group: "complexity", - desc: "using identity operations, e.g., `x + 0` or `y / 1`", - deprecation: None, - module: "identity_op", - }, - Lint { - name: "if_let_mutex", - group: "correctness", - desc: "locking a `Mutex` in an `if let` block can cause deadlocks", - deprecation: None, - module: "if_let_mutex", - }, - Lint { - name: "if_let_some_result", - group: "style", - desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead", - deprecation: None, - module: "if_let_some_result", - }, - Lint { - name: "if_not_else", - group: "pedantic", - desc: "`if` branches that could be swapped so no negation operation is necessary on the condition", - deprecation: None, - module: "if_not_else", - }, - Lint { - name: "if_same_then_else", - group: "correctness", - desc: "`if` with the same `then` and `else` blocks", - deprecation: None, - module: "copies", - }, - Lint { - name: "ifs_same_cond", - group: "correctness", - desc: "consecutive `if`s with the same condition", - deprecation: None, - module: "copies", - }, - Lint { - name: "implicit_hasher", - group: "pedantic", - desc: "missing generalization over different hashers", - deprecation: None, - module: "types", - }, - Lint { - name: "implicit_return", - group: "restriction", - desc: "use a return statement like `return expr` instead of an expression", - deprecation: None, - module: "implicit_return", - }, - Lint { - name: "implicit_saturating_sub", - group: "pedantic", - desc: "Perform saturating subtraction instead of implicitly checking lower bound of data type", - deprecation: None, - module: "implicit_saturating_sub", - }, - Lint { - name: "imprecise_flops", - group: "nursery", - desc: "usage of imprecise floating point operations", - deprecation: None, - module: "floating_point_arithmetic", - }, - Lint { - name: "inconsistent_digit_grouping", - group: "style", - desc: "integer literals with digits grouped inconsistently", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "indexing_slicing", - group: "restriction", - desc: "indexing/slicing usage", - deprecation: None, - module: "indexing_slicing", - }, - Lint { - name: "ineffective_bit_mask", - group: "correctness", - desc: "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`", - deprecation: None, - module: "bit_mask", - }, - Lint { - name: "inefficient_to_string", - group: "pedantic", - desc: "using `to_string` on `&&T` where `T: ToString`", - deprecation: None, - module: "methods", - }, - Lint { - name: "infallible_destructuring_match", - group: "style", - desc: "a `match` statement with a single infallible arm instead of a `let`", - deprecation: None, - module: "matches", - }, - Lint { - name: "infinite_iter", - group: "correctness", - desc: "infinite iteration", - deprecation: None, - module: "infinite_iter", - }, - Lint { - name: "inherent_to_string", - group: "style", - desc: "type implements inherent method `to_string()`, but should instead implement the `Display` trait", - deprecation: None, - module: "inherent_to_string", - }, - Lint { - name: "inherent_to_string_shadow_display", - group: "correctness", - desc: "type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait", - deprecation: None, - module: "inherent_to_string", - }, - Lint { - name: "inline_always", - group: "pedantic", - desc: "use of `#[inline(always)]`", - deprecation: None, - module: "attrs", - }, - Lint { - name: "inline_asm_x86_att_syntax", - group: "restriction", - desc: "prefer Intel x86 assembly syntax", - deprecation: None, - module: "asm_syntax", - }, - Lint { - name: "inline_asm_x86_intel_syntax", - group: "restriction", - desc: "prefer AT&T x86 assembly syntax", - deprecation: None, - module: "asm_syntax", - }, - Lint { - name: "inline_fn_without_body", - group: "correctness", - desc: "use of `#[inline]` on trait methods without bodies", - deprecation: None, - module: "inline_fn_without_body", - }, - Lint { - name: "int_plus_one", - group: "complexity", - desc: "instead of using `x >= y + 1`, use `x > y`", - deprecation: None, - module: "int_plus_one", - }, - Lint { - name: "integer_arithmetic", - group: "restriction", - desc: "any integer arithmetic expression which could overflow or panic", - deprecation: None, - module: "arithmetic", - }, - Lint { - name: "integer_division", - group: "restriction", - desc: "integer division may cause loss of precision", - deprecation: None, - module: "integer_division", - }, - Lint { - name: "into_iter_on_ref", - group: "style", - desc: "using `.into_iter()` on a reference", - deprecation: None, - module: "methods", - }, - Lint { - name: "invalid_atomic_ordering", - group: "correctness", - desc: "usage of invalid atomic ordering in atomic operations and memory fences", - deprecation: None, - module: "atomic_ordering", - }, - Lint { - name: "invalid_regex", - group: "correctness", - desc: "invalid regular expressions", - deprecation: None, - module: "regex", - }, - Lint { - name: "invalid_upcast_comparisons", - group: "pedantic", - desc: "a comparison involving an upcast which is always true or false", - deprecation: None, - module: "types", - }, - Lint { - name: "invisible_characters", - group: "correctness", - desc: "using an invisible character in a string literal, which is confusing", - deprecation: None, - module: "unicode", - }, - Lint { - name: "items_after_statements", - group: "pedantic", - desc: "blocks where an item comes after a statement", - deprecation: None, - module: "items_after_statements", - }, - Lint { - name: "iter_cloned_collect", - group: "style", - desc: "using `.cloned().collect()` on slice to create a `Vec`", - deprecation: None, - module: "methods", - }, - Lint { - name: "iter_next_loop", - group: "correctness", - desc: "for-looping over `_.next()` which is probably not intended", - deprecation: None, - module: "loops", - }, - Lint { - name: "iter_next_slice", - group: "style", - desc: "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "iter_nth", - group: "perf", - desc: "using `.iter().nth()` on a standard library type with O(1) element access", - deprecation: None, - module: "methods", - }, - Lint { - name: "iter_nth_zero", - group: "style", - desc: "replace `iter.nth(0)` with `iter.next()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "iter_skip_next", - group: "style", - desc: "using `.skip(x).next()` on an iterator", - deprecation: None, - module: "methods", - }, - Lint { - name: "iterator_step_by_zero", - group: "correctness", - desc: "using `Iterator::step_by(0)`, which will panic at runtime", - deprecation: None, - module: "methods", - }, - Lint { - name: "just_underscores_and_digits", - group: "style", - desc: "unclear name", - deprecation: None, - module: "non_expressive_names", - }, - Lint { - name: "large_const_arrays", - group: "perf", - desc: "large non-scalar const array may cause performance overhead", - deprecation: None, - module: "large_const_arrays", - }, - Lint { - name: "large_digit_groups", - group: "pedantic", - desc: "grouping digits into groups that are too large", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "large_enum_variant", - group: "perf", - desc: "large size difference between variants on an enum", - deprecation: None, - module: "large_enum_variant", - }, - Lint { - name: "large_stack_arrays", - group: "pedantic", - desc: "allocating large arrays on stack may cause stack overflow", - deprecation: None, - module: "large_stack_arrays", - }, - Lint { - name: "large_types_passed_by_value", - group: "pedantic", - desc: "functions taking large arguments by value", - deprecation: None, - module: "pass_by_ref_or_value", - }, - Lint { - name: "len_without_is_empty", - group: "style", - desc: "traits or impls with a public `len` method but no corresponding `is_empty` method", - deprecation: None, - module: "len_zero", - }, - Lint { - name: "len_zero", - group: "style", - desc: "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead", - deprecation: None, - module: "len_zero", - }, - Lint { - name: "let_and_return", - group: "style", - desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block", - deprecation: None, - module: "returns", - }, - Lint { - name: "let_underscore_drop", - group: "pedantic", - desc: "non-binding let on a type that implements `Drop`", - deprecation: None, - module: "let_underscore", - }, - Lint { - name: "let_underscore_lock", - group: "correctness", - desc: "non-binding let on a synchronization lock", - deprecation: None, - module: "let_underscore", - }, - Lint { - name: "let_underscore_must_use", - group: "restriction", - desc: "non-binding let on a `#[must_use]` expression", - deprecation: None, - module: "let_underscore", - }, - Lint { - name: "let_unit_value", - group: "pedantic", - desc: "creating a `let` binding to a value of unit type, which usually can\'t be used afterwards", - deprecation: None, - module: "types", - }, - Lint { - name: "linkedlist", - group: "pedantic", - desc: "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a `VecDeque`", - deprecation: None, - module: "types", - }, - Lint { - name: "logic_bug", - group: "correctness", - desc: "boolean expressions that contain terminals which can be eliminated", - deprecation: None, - module: "booleans", - }, - Lint { - name: "lossy_float_literal", - group: "restriction", - desc: "lossy whole number float literals", - deprecation: None, - module: "float_literal", - }, - Lint { - name: "macro_use_imports", - group: "pedantic", - desc: "#[macro_use] is no longer needed", - deprecation: None, - module: "macro_use", - }, - Lint { - name: "main_recursion", - group: "style", - desc: "recursion using the entrypoint", - deprecation: None, - module: "main_recursion", - }, - Lint { - name: "manual_async_fn", - group: "style", - desc: "manual implementations of `async` functions can be simplified using the dedicated syntax", - deprecation: None, - module: "manual_async_fn", - }, - Lint { - name: "manual_memcpy", - group: "perf", - desc: "manually copying items between slices", - deprecation: None, - module: "loops", - }, - Lint { - name: "manual_non_exhaustive", - group: "style", - desc: "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]", - deprecation: None, - module: "manual_non_exhaustive", - }, - Lint { - name: "manual_ok_or", - group: "pedantic", - desc: "finds patterns that can be encoded more concisely with `Option::ok_or`", - deprecation: None, - module: "manual_ok_or", - }, - Lint { - name: "manual_range_contains", - group: "style", - desc: "manually reimplementing {`Range`, `RangeInclusive`}`::contains`", - deprecation: None, - module: "ranges", - }, - Lint { - name: "manual_saturating_arithmetic", - group: "style", - desc: "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "manual_strip", - group: "complexity", - desc: "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing", - deprecation: None, - module: "manual_strip", - }, - Lint { - name: "manual_swap", - group: "complexity", - desc: "manual swap of two variables", - deprecation: None, - module: "swap", - }, - Lint { - name: "manual_unwrap_or", - group: "complexity", - desc: "finds patterns that can be encoded more concisely with `Option::unwrap_or` or `Result::unwrap_or`", - deprecation: None, - module: "manual_unwrap_or", - }, - Lint { - name: "many_single_char_names", - group: "style", - desc: "too many single character bindings", - deprecation: None, - module: "non_expressive_names", - }, - Lint { - name: "map_clone", - group: "style", - desc: "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types", - deprecation: None, - module: "map_clone", - }, - Lint { - name: "map_collect_result_unit", - group: "style", - desc: "using `.map(_).collect::()`, which can be replaced with `try_for_each`", - deprecation: None, - module: "methods", - }, - Lint { - name: "map_entry", - group: "perf", - desc: "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`", - deprecation: None, - module: "entry", - }, - Lint { - name: "map_err_ignore", - group: "pedantic", - desc: "`map_err` should not ignore the original error", - deprecation: None, - module: "map_err_ignore", - }, - Lint { - name: "map_flatten", - group: "pedantic", - desc: "using combinations of `flatten` and `map` which can usually be written as a single method call", - deprecation: None, - module: "methods", - }, - Lint { - name: "map_identity", - group: "complexity", - desc: "using iterator.map(|x| x)", - deprecation: None, - module: "map_identity", - }, - Lint { - name: "map_unwrap_or", - group: "pedantic", - desc: "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "match_as_ref", - group: "complexity", - desc: "a `match` on an Option value instead of using `as_ref()` or `as_mut`", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_bool", - group: "pedantic", - desc: "a `match` on a boolean expression instead of an `if..else` block", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_like_matches_macro", - group: "style", - desc: "a match that could be written with the matches! macro", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_on_vec_items", - group: "pedantic", - desc: "matching on vector elements can panic", - deprecation: None, - module: "match_on_vec_items", - }, - Lint { - name: "match_overlapping_arm", - group: "style", - desc: "a `match` with overlapping arms", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_ref_pats", - group: "style", - desc: "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_same_arms", - group: "pedantic", - desc: "`match` with identical arm bodies", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_single_binding", - group: "complexity", - desc: "a match with a single binding instead of using `let` statement", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_wild_err_arm", - group: "pedantic", - desc: "a `match` with `Err(_)` arm and take drastic actions", - deprecation: None, - module: "matches", - }, - Lint { - name: "match_wildcard_for_single_variants", - group: "pedantic", - desc: "a wildcard enum match for a single variant", - deprecation: None, - module: "matches", - }, - Lint { - name: "maybe_infinite_iter", - group: "pedantic", - desc: "possible infinite iteration", - deprecation: None, - module: "infinite_iter", - }, - Lint { - name: "mem_discriminant_non_enum", - group: "correctness", - desc: "calling `mem::descriminant` on non-enum type", - deprecation: None, - module: "mem_discriminant", - }, - Lint { - name: "mem_forget", - group: "restriction", - desc: "`mem::forget` usage on `Drop` types, likely to cause memory leaks", - deprecation: None, - module: "mem_forget", - }, - Lint { - name: "mem_replace_option_with_none", - group: "style", - desc: "replacing an `Option` with `None` instead of `take()`", - deprecation: None, - module: "mem_replace", - }, - Lint { - name: "mem_replace_with_default", - group: "style", - desc: "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`", - deprecation: None, - module: "mem_replace", - }, - Lint { - name: "mem_replace_with_uninit", - group: "correctness", - desc: "`mem::replace(&mut _, mem::uninitialized())` or `mem::replace(&mut _, mem::zeroed())`", - deprecation: None, - module: "mem_replace", - }, - Lint { - name: "min_max", - group: "correctness", - desc: "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant", - deprecation: None, - module: "minmax", - }, - Lint { - name: "mismatched_target_os", - group: "correctness", - desc: "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`", - deprecation: None, - module: "attrs", - }, - Lint { - name: "misrefactored_assign_op", - group: "complexity", - desc: "having a variable on both sides of an assign op", - deprecation: None, - module: "assign_ops", - }, - Lint { - name: "missing_const_for_fn", - group: "nursery", - desc: "Lint functions definitions that could be made `const fn`", - deprecation: None, - module: "missing_const_for_fn", - }, - Lint { - name: "missing_docs_in_private_items", - group: "restriction", - desc: "detects missing documentation for public and private members", - deprecation: None, - module: "missing_doc", - }, - Lint { - name: "missing_errors_doc", - group: "pedantic", - desc: "`pub fn` returns `Result` without `# Errors` in doc comment", - deprecation: None, - module: "doc", - }, - Lint { - name: "missing_inline_in_public_items", - group: "restriction", - desc: "detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)", - deprecation: None, - module: "missing_inline", - }, - Lint { - name: "missing_safety_doc", - group: "style", - desc: "`pub unsafe fn` without `# Safety` docs", - deprecation: None, - module: "doc", - }, - Lint { - name: "mistyped_literal_suffixes", - group: "correctness", - desc: "mistyped literal suffix", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "mixed_case_hex_literals", - group: "style", - desc: "hex literals whose letter digits are not consistently upper- or lowercased", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "module_inception", - group: "style", - desc: "modules that have the same name as their parent module", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "module_name_repetitions", - group: "pedantic", - desc: "type names prefixed/postfixed with their containing module\'s name", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "modulo_arithmetic", - group: "restriction", - desc: "any modulo arithmetic statement", - deprecation: None, - module: "modulo_arithmetic", - }, - Lint { - name: "modulo_one", - group: "correctness", - desc: "taking a number modulo 1, which always returns 0", - deprecation: None, - module: "misc", - }, - Lint { - name: "multiple_crate_versions", - group: "cargo", - desc: "multiple versions of the same crate being used", - deprecation: None, - module: "multiple_crate_versions", - }, - Lint { - name: "multiple_inherent_impl", - group: "restriction", - desc: "Multiple inherent impl that could be grouped", - deprecation: None, - module: "inherent_impl", - }, - Lint { - name: "must_use_candidate", - group: "pedantic", - desc: "function or method that could take a `#[must_use]` attribute", - deprecation: None, - module: "functions", - }, - Lint { - name: "must_use_unit", - group: "style", - desc: "`#[must_use]` attribute on a unit-returning function / method", - deprecation: None, - module: "functions", - }, - Lint { - name: "mut_from_ref", - group: "correctness", - desc: "fns that create mutable refs from immutable ref args", - deprecation: None, - module: "ptr", - }, - Lint { - name: "mut_mut", - group: "pedantic", - desc: "usage of double-mut refs, e.g., `&mut &mut ...`", - deprecation: None, - module: "mut_mut", - }, - Lint { - name: "mut_mutex_lock", - group: "style", - desc: "`&mut Mutex::lock` does unnecessary locking", - deprecation: None, - module: "mut_mutex_lock", - }, - Lint { - name: "mut_range_bound", - group: "complexity", - desc: "for loop over a range where one of the bounds is a mutable variable", - deprecation: None, - module: "loops", - }, - Lint { - name: "mutable_key_type", - group: "correctness", - desc: "Check for mutable `Map`/`Set` key type", - deprecation: None, - module: "mut_key", - }, - Lint { - name: "mutex_atomic", - group: "perf", - desc: "using a mutex where an atomic value could be used instead", - deprecation: None, - module: "mutex_atomic", - }, - Lint { - name: "mutex_integer", - group: "nursery", - desc: "using a mutex for an integer type", - deprecation: None, - module: "mutex_atomic", - }, - Lint { - name: "naive_bytecount", - group: "perf", - desc: "use of naive `.filter(|&x| x == y).count()` to count byte values", - deprecation: None, - module: "bytecount", - }, - Lint { - name: "needless_arbitrary_self_type", - group: "complexity", - desc: "type of `self` parameter is already by default `Self`", - deprecation: None, - module: "needless_arbitrary_self_type", - }, - Lint { - name: "needless_bool", - group: "complexity", - desc: "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`", - deprecation: None, - module: "needless_bool", - }, - Lint { - name: "needless_borrow", - group: "nursery", - desc: "taking a reference that is going to be automatically dereferenced", - deprecation: None, - module: "needless_borrow", - }, - Lint { - name: "needless_borrowed_reference", - group: "complexity", - desc: "taking a needless borrowed reference", - deprecation: None, - module: "needless_borrowed_ref", - }, - Lint { - name: "needless_collect", - group: "perf", - desc: "collecting an iterator when collect is not needed", - deprecation: None, - module: "loops", - }, - Lint { - name: "needless_continue", - group: "pedantic", - desc: "`continue` statements that can be replaced by a rearrangement of code", - deprecation: None, - module: "needless_continue", - }, - Lint { - name: "needless_doctest_main", - group: "style", - desc: "presence of `fn main() {` in code examples", - deprecation: None, - module: "doc", - }, - Lint { - name: "needless_lifetimes", - group: "complexity", - desc: "using explicit lifetimes for references in function arguments when elision rules would allow omitting them", - deprecation: None, - module: "lifetimes", - }, - Lint { - name: "needless_pass_by_value", - group: "pedantic", - desc: "functions taking arguments by value, but not consuming them in its body", - deprecation: None, - module: "needless_pass_by_value", - }, - Lint { - name: "needless_range_loop", - group: "style", - desc: "for-looping over a range of indices where an iterator over items would do", - deprecation: None, - module: "loops", - }, - Lint { - name: "needless_return", - group: "style", - desc: "using a return statement like `return expr;` where an expression would suffice", - deprecation: None, - module: "returns", - }, - Lint { - name: "needless_update", - group: "complexity", - desc: "using `Foo { ..base }` when there are no missing fields", - deprecation: None, - module: "needless_update", - }, - Lint { - name: "neg_cmp_op_on_partial_ord", - group: "complexity", - desc: "The use of negated comparison operators on partially ordered types may produce confusing code.", - deprecation: None, - module: "neg_cmp_op_on_partial_ord", - }, - Lint { - name: "neg_multiply", - group: "style", - desc: "multiplying integers with `-1`", - deprecation: None, - module: "neg_multiply", - }, - Lint { - name: "never_loop", - group: "correctness", - desc: "any loop that will always `break` or `return`", - deprecation: None, - module: "loops", - }, - Lint { - name: "new_ret_no_self", - group: "style", - desc: "not returning type containing `Self` in a `new` method", - deprecation: None, - module: "methods", - }, - Lint { - name: "new_without_default", - group: "style", - desc: "`fn new() -> Self` method without `Default` implementation", - deprecation: None, - module: "new_without_default", - }, - Lint { - name: "no_effect", - group: "complexity", - desc: "statements with no effect", - deprecation: None, - module: "no_effect", - }, - Lint { - name: "non_ascii_literal", - group: "pedantic", - desc: "using any literal non-ASCII chars in a string literal instead of using the `\\\\u` escape", - deprecation: None, - module: "unicode", - }, - Lint { - name: "nonminimal_bool", - group: "complexity", - desc: "boolean expressions that can be written more concisely", - deprecation: None, - module: "booleans", - }, - Lint { - name: "nonsensical_open_options", - group: "correctness", - desc: "nonsensical combination of options for opening a file", - deprecation: None, - module: "open_options", - }, - Lint { - name: "not_unsafe_ptr_arg_deref", - group: "correctness", - desc: "public functions dereferencing raw pointer arguments but not marked `unsafe`", - deprecation: None, - module: "functions", - }, - Lint { - name: "ok_expect", - group: "style", - desc: "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result", - deprecation: None, - module: "methods", - }, - Lint { - name: "op_ref", - group: "style", - desc: "taking a reference to satisfy the type constraints on `==`", - deprecation: None, - module: "eq_op", - }, - Lint { - name: "option_as_ref_deref", - group: "complexity", - desc: "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "option_env_unwrap", - group: "correctness", - desc: "using `option_env!(...).unwrap()` to get environment variable", - deprecation: None, - module: "option_env_unwrap", - }, - Lint { - name: "option_if_let_else", - group: "pedantic", - desc: "reimplementation of Option::map_or", - deprecation: None, - module: "option_if_let_else", - }, - Lint { - name: "option_map_or_none", - group: "style", - desc: "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "option_map_unit_fn", - group: "complexity", - desc: "using `option.map(f)`, where `f` is a function or closure that returns `()`", - deprecation: None, - module: "map_unit_fn", - }, - Lint { - name: "option_option", - group: "pedantic", - desc: "usage of `Option>`", - deprecation: None, - module: "types", - }, - Lint { - name: "or_fun_call", - group: "perf", - desc: "using any `*or` method with a function call, which suggests `*or_else`", - deprecation: None, - module: "methods", - }, - Lint { - name: "out_of_bounds_indexing", - group: "correctness", - desc: "out of bounds constant indexing", - deprecation: None, - module: "indexing_slicing", - }, - Lint { - name: "overflow_check_conditional", - group: "complexity", - desc: "overflow checks inspired by C which are likely to panic", - deprecation: None, - module: "overflow_check_conditional", - }, - Lint { - name: "panic", - group: "restriction", - desc: "usage of the `panic!` macro", - deprecation: None, - module: "panic_unimplemented", - }, - Lint { - name: "panic_in_result_fn", - group: "restriction", - desc: "functions of type `Result<..>` that contain `panic!()`, `todo!()` or `unreachable()` or `unimplemented()` ", - deprecation: None, - module: "panic_in_result_fn", - }, - Lint { - name: "panicking_unwrap", - group: "correctness", - desc: "checks for calls of `unwrap[_err]()` that will always fail", - deprecation: None, - module: "unwrap", - }, - Lint { - name: "partialeq_ne_impl", - group: "complexity", - desc: "re-implementing `PartialEq::ne`", - deprecation: None, - module: "partialeq_ne_impl", - }, - Lint { - name: "path_buf_push_overwrite", - group: "nursery", - desc: "calling `push` with file system root on `PathBuf` can overwrite it", - deprecation: None, - module: "path_buf_push_overwrite", - }, - Lint { - name: "pattern_type_mismatch", - group: "restriction", - desc: "type of pattern does not match the expression type", - deprecation: None, - module: "pattern_type_mismatch", - }, - Lint { - name: "possible_missing_comma", - group: "correctness", - desc: "possible missing comma in array", - deprecation: None, - module: "formatting", - }, - Lint { - name: "precedence", - group: "complexity", - desc: "operations where precedence may be unclear", - deprecation: None, - module: "precedence", - }, - Lint { - name: "print_literal", - group: "style", - desc: "printing a literal with a format string", - deprecation: None, - module: "write", - }, - Lint { - name: "print_stdout", - group: "restriction", - desc: "printing on stdout", - deprecation: None, - module: "write", - }, - Lint { - name: "print_with_newline", - group: "style", - desc: "using `print!()` with a format string that ends in a single newline", - deprecation: None, - module: "write", - }, - Lint { - name: "println_empty_string", - group: "style", - desc: "using `println!(\"\")` with an empty string", - deprecation: None, - module: "write", - }, - Lint { - name: "ptr_arg", - group: "style", - desc: "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively", - deprecation: None, - module: "ptr", - }, - Lint { - name: "ptr_eq", - group: "style", - desc: "use `std::ptr::eq` when comparing raw pointers", - deprecation: None, - module: "ptr_eq", - }, - Lint { - name: "ptr_offset_with_cast", - group: "complexity", - desc: "unneeded pointer offset cast", - deprecation: None, - module: "ptr_offset_with_cast", - }, - Lint { - name: "pub_enum_variant_names", - group: "pedantic", - desc: "public enums where all variants share a prefix/postfix", - deprecation: None, - module: "enum_variants", - }, - Lint { - name: "question_mark", - group: "style", - desc: "checks for expressions that could be replaced by the question mark operator", - deprecation: None, - module: "question_mark", - }, - Lint { - name: "range_minus_one", - group: "pedantic", - desc: "`x..=(y-1)` reads better as `x..y`", - deprecation: None, - module: "ranges", - }, - Lint { - name: "range_plus_one", - group: "pedantic", - desc: "`x..(y+1)` reads better as `x..=y`", - deprecation: None, - module: "ranges", - }, - Lint { - name: "range_zip_with_len", - group: "complexity", - desc: "zipping iterator with a range when `enumerate()` would do", - deprecation: None, - module: "ranges", - }, - Lint { - name: "rc_buffer", - group: "restriction", - desc: "shared ownership of a buffer type", - deprecation: None, - module: "types", - }, - Lint { - name: "redundant_allocation", - group: "perf", - desc: "redundant allocation", - deprecation: None, - module: "types", - }, - Lint { - name: "redundant_clone", - group: "perf", - desc: "`clone()` of an owned value that is going to be dropped immediately", - deprecation: None, - module: "redundant_clone", - }, - Lint { - name: "redundant_closure", - group: "style", - desc: "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)", - deprecation: None, - module: "eta_reduction", - }, - Lint { - name: "redundant_closure_call", - group: "complexity", - desc: "throwaway closures called in the expression they are defined", - deprecation: None, - module: "redundant_closure_call", - }, - Lint { - name: "redundant_closure_for_method_calls", - group: "pedantic", - desc: "redundant closures for method calls", - deprecation: None, - module: "eta_reduction", - }, - Lint { - name: "redundant_field_names", - group: "style", - desc: "checks for fields in struct literals where shorthands could be used", - deprecation: None, - module: "redundant_field_names", - }, - Lint { - name: "redundant_pattern", - group: "style", - desc: "using `name @ _` in a pattern", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "redundant_pattern_matching", - group: "style", - desc: "use the proper utility function avoiding an `if let`", - deprecation: None, - module: "matches", - }, - Lint { - name: "redundant_pub_crate", - group: "nursery", - desc: "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them.", - deprecation: None, - module: "redundant_pub_crate", - }, - Lint { - name: "redundant_static_lifetimes", - group: "style", - desc: "Using explicit `\'static` lifetime for constants or statics when elision rules would allow omitting them.", - deprecation: None, - module: "redundant_static_lifetimes", - }, - Lint { - name: "ref_in_deref", - group: "complexity", - desc: "Use of reference in auto dereference expression.", - deprecation: None, - module: "reference", - }, - Lint { - name: "ref_option_ref", - group: "pedantic", - desc: "use `Option<&T>` instead of `&Option<&T>`", - deprecation: None, - module: "ref_option_ref", - }, - Lint { - name: "repeat_once", - group: "complexity", - desc: "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` ", - deprecation: None, - module: "repeat_once", - }, - Lint { - name: "rest_pat_in_fully_bound_structs", - group: "restriction", - desc: "a match on a struct that binds all fields but still uses the wildcard pattern", - deprecation: None, - module: "matches", - }, - Lint { - name: "result_map_or_into_option", - group: "style", - desc: "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "result_map_unit_fn", - group: "complexity", - desc: "using `result.map(f)`, where `f` is a function or closure that returns `()`", - deprecation: None, - module: "map_unit_fn", - }, - Lint { - name: "result_unit_err", - group: "style", - desc: "public function returning `Result` with an `Err` type of `()`", - deprecation: None, - module: "functions", - }, - Lint { - name: "reversed_empty_ranges", - group: "correctness", - desc: "reversing the limits of range expressions, resulting in empty ranges", - deprecation: None, - module: "ranges", - }, - Lint { - name: "same_functions_in_if_condition", - group: "pedantic", - desc: "consecutive `if`s with the same function call", - deprecation: None, - module: "copies", - }, - Lint { - name: "same_item_push", - group: "style", - desc: "the same item is pushed inside of a for loop", - deprecation: None, - module: "loops", - }, - Lint { - name: "search_is_some", - group: "complexity", - desc: "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "self_assignment", - group: "correctness", - desc: "explicit self-assignment", - deprecation: None, - module: "self_assignment", - }, - Lint { - name: "serde_api_misuse", - group: "correctness", - desc: "various things that will negatively affect your serde experience", - deprecation: None, - module: "serde_api", - }, - Lint { - name: "shadow_reuse", - group: "restriction", - desc: "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`", - deprecation: None, - module: "shadow", - }, - Lint { - name: "shadow_same", - group: "restriction", - desc: "rebinding a name to itself, e.g., `let mut x = &mut x`", - deprecation: None, - module: "shadow", - }, - Lint { - name: "shadow_unrelated", - group: "pedantic", - desc: "rebinding a name without even using the original value", - deprecation: None, - module: "shadow", - }, - Lint { - name: "short_circuit_statement", - group: "complexity", - desc: "using a short circuit boolean condition as a statement", - deprecation: None, - module: "misc", - }, - Lint { - name: "should_implement_trait", - group: "style", - desc: "defining a method that should be implementing a std trait", - deprecation: None, - module: "methods", - }, - Lint { - name: "similar_names", - group: "pedantic", - desc: "similarly named items and bindings", - deprecation: None, - module: "non_expressive_names", - }, - Lint { - name: "single_char_add_str", - group: "style", - desc: "`push_str()` or `insert_str()` used with a single-character string literal as parameter", - deprecation: None, - module: "methods", - }, - Lint { - name: "single_char_pattern", - group: "perf", - desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", - deprecation: None, - module: "methods", - }, - Lint { - name: "single_component_path_imports", - group: "style", - desc: "imports with single component path are redundant", - deprecation: None, - module: "single_component_path_imports", - }, - Lint { - name: "single_element_loop", - group: "complexity", - desc: "there is no reason to have a single element loop", - deprecation: None, - module: "loops", - }, - Lint { - name: "single_match", - group: "style", - desc: "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`", - deprecation: None, - module: "matches", - }, - Lint { - name: "single_match_else", - group: "pedantic", - desc: "a `match` statement with two arms where the second arm\'s pattern is a placeholder instead of a specific match pattern", - deprecation: None, - module: "matches", - }, - Lint { - name: "skip_while_next", - group: "complexity", - desc: "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "slow_vector_initialization", - group: "perf", - desc: "slow vector initialization", - deprecation: None, - module: "slow_vector_initialization", - }, - Lint { - name: "stable_sort_primitive", - group: "perf", - desc: "use of sort() when sort_unstable() is equivalent", - deprecation: None, - module: "stable_sort_primitive", - }, - Lint { - name: "string_add", - group: "restriction", - desc: "using `x + ..` where x is a `String` instead of `push_str()`", - deprecation: None, - module: "strings", - }, - Lint { - name: "string_add_assign", - group: "pedantic", - desc: "using `x = x + ..` where x is a `String` instead of `push_str()`", - deprecation: None, - module: "strings", - }, - Lint { - name: "string_extend_chars", - group: "style", - desc: "using `x.extend(s.chars())` where s is a `&str` or `String`", - deprecation: None, - module: "methods", - }, - Lint { - name: "string_from_utf8_as_bytes", - group: "complexity", - desc: "casting string slices to byte slices and back", - deprecation: None, - module: "strings", - }, - Lint { - name: "string_lit_as_bytes", - group: "nursery", - desc: "calling `as_bytes` on a string literal instead of using a byte string literal", - deprecation: None, - module: "strings", - }, - Lint { - name: "struct_excessive_bools", - group: "pedantic", - desc: "using too many bools in a struct", - deprecation: None, - module: "excessive_bools", - }, - Lint { - name: "suboptimal_flops", - group: "nursery", - desc: "usage of sub-optimal floating point operations", - deprecation: None, - module: "floating_point_arithmetic", - }, - Lint { - name: "suspicious_arithmetic_impl", - group: "correctness", - desc: "suspicious use of operators in impl of arithmetic trait", - deprecation: None, - module: "suspicious_trait_impl", - }, - Lint { - name: "suspicious_assignment_formatting", - group: "style", - desc: "suspicious formatting of `*=`, `-=` or `!=`", - deprecation: None, - module: "formatting", - }, - Lint { - name: "suspicious_else_formatting", - group: "style", - desc: "suspicious formatting of `else`", - deprecation: None, - module: "formatting", - }, - Lint { - name: "suspicious_map", - group: "complexity", - desc: "suspicious usage of map", - deprecation: None, - module: "methods", - }, - Lint { - name: "suspicious_op_assign_impl", - group: "correctness", - desc: "suspicious use of operators in impl of OpAssign trait", - deprecation: None, - module: "suspicious_trait_impl", - }, - Lint { - name: "suspicious_unary_op_formatting", - group: "style", - desc: "suspicious formatting of unary `-` or `!` on the RHS of a BinOp", - deprecation: None, - module: "formatting", - }, - Lint { - name: "tabs_in_doc_comments", - group: "style", - desc: "using tabs in doc comments is not recommended", - deprecation: None, - module: "tabs_in_doc_comments", - }, - Lint { - name: "temporary_assignment", - group: "complexity", - desc: "assignments to temporaries", - deprecation: None, - module: "temporary_assignment", - }, - Lint { - name: "to_digit_is_some", - group: "style", - desc: "`char.is_digit()` is clearer", - deprecation: None, - module: "to_digit_is_some", - }, - Lint { - name: "to_string_in_display", - group: "correctness", - desc: "`to_string` method used while implementing `Display` trait", - deprecation: None, - module: "to_string_in_display", - }, - Lint { - name: "todo", - group: "restriction", - desc: "`todo!` should not be present in production code", - deprecation: None, - module: "panic_unimplemented", - }, - Lint { - name: "too_many_arguments", - group: "complexity", - desc: "functions with too many arguments", - deprecation: None, - module: "functions", - }, - Lint { - name: "too_many_lines", - group: "pedantic", - desc: "functions with too many lines", - deprecation: None, - module: "functions", - }, - Lint { - name: "toplevel_ref_arg", - group: "style", - desc: "an entire binding declared as `ref`, in a function argument or a `let` statement", - deprecation: None, - module: "misc", - }, - Lint { - name: "trait_duplication_in_bounds", - group: "pedantic", - desc: "Check if the same trait bounds are specified twice during a function declaration", - deprecation: None, - module: "trait_bounds", - }, - Lint { - name: "transmute_bytes_to_str", - group: "complexity", - desc: "transmutes from a `&[u8]` to a `&str`", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_float_to_int", - group: "complexity", - desc: "transmutes from a float to an integer", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_int_to_bool", - group: "complexity", - desc: "transmutes from an integer to a `bool`", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_int_to_char", - group: "complexity", - desc: "transmutes from an integer to a `char`", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_int_to_float", - group: "complexity", - desc: "transmutes from an integer to a float", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_ptr_to_ptr", - group: "complexity", - desc: "transmutes from a pointer to a pointer / a reference to a reference", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmute_ptr_to_ref", - group: "complexity", - desc: "transmutes from a pointer to a reference type", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmutes_expressible_as_ptr_casts", - group: "complexity", - desc: "transmutes that could be a pointer cast", - deprecation: None, - module: "transmute", - }, - Lint { - name: "transmuting_null", - group: "correctness", - desc: "transmutes from a null pointer to a reference, which is undefined behavior", - deprecation: None, - module: "transmuting_null", - }, - Lint { - name: "trivial_regex", - group: "style", - desc: "trivial regular expressions", - deprecation: None, - module: "regex", - }, - Lint { - name: "trivially_copy_pass_by_ref", - group: "pedantic", - desc: "functions taking small copyable arguments by reference", - deprecation: None, - module: "pass_by_ref_or_value", - }, - Lint { - name: "try_err", - group: "style", - desc: "return errors explicitly rather than hiding them behind a `?`", - deprecation: None, - module: "try_err", - }, - Lint { - name: "type_complexity", - group: "complexity", - desc: "usage of very complex types that might be better factored into `type` definitions", - deprecation: None, - module: "types", - }, - Lint { - name: "type_repetition_in_bounds", - group: "pedantic", - desc: "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`", - deprecation: None, - module: "trait_bounds", - }, - Lint { - name: "undropped_manually_drops", - group: "correctness", - desc: "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value", - deprecation: None, - module: "undropped_manually_drops", - }, - Lint { - name: "unicode_not_nfc", - group: "pedantic", - desc: "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)", - deprecation: None, - module: "unicode", - }, - Lint { - name: "unimplemented", - group: "restriction", - desc: "`unimplemented!` should not be present in production code", - deprecation: None, - module: "panic_unimplemented", - }, - Lint { - name: "uninit_assumed_init", - group: "correctness", - desc: "`MaybeUninit::uninit().assume_init()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "unit_arg", - group: "complexity", - desc: "passing unit to a function", - deprecation: None, - module: "types", - }, - Lint { - name: "unit_cmp", - group: "correctness", - desc: "comparing unit values", - deprecation: None, - module: "types", - }, - Lint { - name: "unit_return_expecting_ord", - group: "correctness", - desc: "fn arguments of type Fn(...) -> Ord returning the unit type ().", - deprecation: None, - module: "unit_return_expecting_ord", - }, - Lint { - name: "unknown_clippy_lints", - group: "style", - desc: "unknown_lints for scoped Clippy lints", - deprecation: None, - module: "attrs", - }, - Lint { - name: "unnecessary_cast", - group: "complexity", - desc: "cast to the same type, e.g., `x as i32` where `x: i32`", - deprecation: None, - module: "types", - }, - Lint { - name: "unnecessary_filter_map", - group: "complexity", - desc: "using `filter_map` when a more succinct alternative exists", - deprecation: None, - module: "methods", - }, - Lint { - name: "unnecessary_fold", - group: "style", - desc: "using `fold` when a more succinct alternative exists", - deprecation: None, - module: "methods", - }, - Lint { - name: "unnecessary_lazy_evaluations", - group: "style", - desc: "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation", - deprecation: None, - module: "methods", - }, - Lint { - name: "unnecessary_mut_passed", - group: "style", - desc: "an argument passed as a mutable reference although the callee only demands an immutable reference", - deprecation: None, - module: "mut_reference", - }, - Lint { - name: "unnecessary_operation", - group: "complexity", - desc: "outer expressions with no effect", - deprecation: None, - module: "no_effect", - }, - Lint { - name: "unnecessary_sort_by", - group: "complexity", - desc: "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer", - deprecation: None, - module: "unnecessary_sort_by", - }, - Lint { - name: "unnecessary_unwrap", - group: "complexity", - desc: "checks for calls of `unwrap[_err]()` that cannot fail", - deprecation: None, - module: "unwrap", - }, - Lint { - name: "unnecessary_wraps", - group: "complexity", - desc: "functions that only return `Ok` or `Some`", - deprecation: None, - module: "unnecessary_wraps", - }, - Lint { - name: "unneeded_field_pattern", - group: "restriction", - desc: "struct fields bound to a wildcard instead of using `..`", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "unneeded_wildcard_pattern", - group: "complexity", - desc: "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "unnested_or_patterns", - group: "pedantic", - desc: "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`", - deprecation: None, - module: "unnested_or_patterns", - }, - Lint { - name: "unreachable", - group: "restriction", - desc: "`unreachable!` should not be present in production code", - deprecation: None, - module: "panic_unimplemented", - }, - Lint { - name: "unreadable_literal", - group: "pedantic", - desc: "long integer literal without underscores", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "unsafe_derive_deserialize", - group: "pedantic", - desc: "deriving `serde::Deserialize` on a type that has methods using `unsafe`", - deprecation: None, - module: "derive", - }, - Lint { - name: "unsafe_removed_from_name", - group: "style", - desc: "`unsafe` removed from API names on import", - deprecation: None, - module: "unsafe_removed_from_name", - }, - Lint { - name: "unseparated_literal_suffix", - group: "pedantic", - desc: "literals whose suffix is not separated by an underscore", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "unsound_collection_transmute", - group: "correctness", - desc: "transmute between collections of layout-incompatible types", - deprecation: None, - module: "transmute", - }, - Lint { - name: "unused_io_amount", - group: "correctness", - desc: "unused written/read amount", - deprecation: None, - module: "unused_io_amount", - }, - Lint { - name: "unused_self", - group: "pedantic", - desc: "methods that contain a `self` argument but don\'t use it", - deprecation: None, - module: "unused_self", - }, - Lint { - name: "unused_unit", - group: "style", - desc: "needless unit expression", - deprecation: None, - module: "unused_unit", - }, - Lint { - name: "unusual_byte_groupings", - group: "style", - desc: "binary or hex literals that aren\'t grouped by four", - deprecation: None, - module: "literal_representation", - }, - Lint { - name: "unwrap_in_result", - group: "restriction", - desc: "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`", - deprecation: None, - module: "unwrap_in_result", - }, - Lint { - name: "unwrap_used", - group: "restriction", - desc: "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`", - deprecation: None, - module: "methods", - }, - Lint { - name: "use_debug", - group: "restriction", - desc: "use of `Debug`-based formatting", - deprecation: None, - module: "write", - }, - Lint { - name: "use_self", - group: "nursery", - desc: "unnecessary structure name repetition whereas `Self` is applicable", - deprecation: None, - module: "use_self", - }, - Lint { - name: "used_underscore_binding", - group: "pedantic", - desc: "using a binding which is prefixed with an underscore", - deprecation: None, - module: "misc", - }, - Lint { - name: "useless_asref", - group: "complexity", - desc: "using `as_ref` where the types before and after the call are the same", - deprecation: None, - module: "methods", - }, - Lint { - name: "useless_attribute", - group: "correctness", - desc: "use of lint attributes on `extern crate` items", - deprecation: None, - module: "attrs", - }, - Lint { - name: "useless_conversion", - group: "complexity", - desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type", - deprecation: None, - module: "useless_conversion", - }, - Lint { - name: "useless_format", - group: "complexity", - desc: "useless use of `format!`", - deprecation: None, - module: "format", - }, - Lint { - name: "useless_let_if_seq", - group: "nursery", - desc: "unidiomatic `let mut` declaration followed by initialization in `if`", - deprecation: None, - module: "let_if_seq", - }, - Lint { - name: "useless_transmute", - group: "nursery", - desc: "transmutes that have the same to and from types or could be a cast/coercion", - deprecation: None, - module: "transmute", - }, - Lint { - name: "useless_vec", - group: "perf", - desc: "useless `vec!`", - deprecation: None, - module: "vec", - }, - Lint { - name: "vec_box", - group: "complexity", - desc: "usage of `Vec>` where T: Sized, vector elements are already on the heap", - deprecation: None, - module: "types", - }, - Lint { - name: "vec_resize_to_zero", - group: "correctness", - desc: "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake", - deprecation: None, - module: "vec_resize_to_zero", - }, - Lint { - name: "verbose_bit_mask", - group: "pedantic", - desc: "expressions where a bit mask is less readable than the corresponding method call", - deprecation: None, - module: "bit_mask", - }, - Lint { - name: "verbose_file_reads", - group: "restriction", - desc: "use of `File::read_to_end` or `File::read_to_string`", - deprecation: None, - module: "verbose_file_reads", - }, - Lint { - name: "vtable_address_comparisons", - group: "correctness", - desc: "comparison with an address of a trait vtable", - deprecation: None, - module: "unnamed_address", - }, - Lint { - name: "while_immutable_condition", - group: "correctness", - desc: "variables used within while expression are not mutated in the body", - deprecation: None, - module: "loops", - }, - Lint { - name: "while_let_loop", - group: "complexity", - desc: "`loop { if let { ... } else break }`, which can be written as a `while let` loop", - deprecation: None, - module: "loops", - }, - Lint { - name: "while_let_on_iterator", - group: "style", - desc: "using a while-let loop instead of a for loop on an iterator", - deprecation: None, - module: "loops", - }, - Lint { - name: "wildcard_dependencies", - group: "cargo", - desc: "wildcard dependencies being used", - deprecation: None, - module: "wildcard_dependencies", - }, - Lint { - name: "wildcard_enum_match_arm", - group: "restriction", - desc: "a wildcard enum match arm using `_`", - deprecation: None, - module: "matches", - }, - Lint { - name: "wildcard_imports", - group: "pedantic", - desc: "lint `use _::*` statements", - deprecation: None, - module: "wildcard_imports", - }, - Lint { - name: "wildcard_in_or_patterns", - group: "complexity", - desc: "a wildcard pattern used with others patterns in same match arm", - deprecation: None, - module: "matches", - }, - Lint { - name: "write_literal", - group: "style", - desc: "writing a literal with a format string", - deprecation: None, - module: "write", - }, - Lint { - name: "write_with_newline", - group: "style", - desc: "using `write!()` with a format string that ends in a single newline", - deprecation: None, - module: "write", - }, - Lint { - name: "writeln_empty_string", - group: "style", - desc: "using `writeln!(buf, \"\")` with an empty string", - deprecation: None, - module: "write", - }, - Lint { - name: "wrong_pub_self_convention", - group: "restriction", - desc: "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", - deprecation: None, - module: "methods", - }, - Lint { - name: "wrong_self_convention", - group: "style", - desc: "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention", - deprecation: None, - module: "methods", - }, - Lint { - name: "wrong_transmute", - group: "correctness", - desc: "transmutes that are confusing at best, undefined behaviour at worst and always useless", - deprecation: None, - module: "transmute", - }, - Lint { - name: "zero_divided_by_zero", - group: "complexity", - desc: "usage of `0.0 / 0.0` to obtain NaN instead of `f32::NAN` or `f64::NAN`", - deprecation: None, - module: "zero_div_zero", - }, - Lint { - name: "zero_prefixed_literal", - group: "complexity", - desc: "integer literals starting with `0`", - deprecation: None, - module: "misc_early", - }, - Lint { - name: "zero_ptr", - group: "style", - desc: "using `0 as *{const, mut} T`", - deprecation: None, - module: "misc", - }, - Lint { - name: "zst_offset", - group: "correctness", - desc: "Check for offset calculations on raw pointers to zero-sized types", - deprecation: None, - module: "methods", - }, -] -// end lint list, do not remove this comment, it’s used in `update_lints` -}); From fe0bea2cc191fcdf8ca79a17168d696c664eded3 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 24 Nov 2020 13:46:51 -0500 Subject: [PATCH 065/274] ext/ucred: Support PID in peer creds on macOS --- library/std/src/sys/unix/ext/ucred.rs | 51 +++++++++++++++++++-- library/std/src/sys/unix/ext/ucred/tests.rs | 19 +++++++- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index ed7516c7f28..e2aeb39f995 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -31,12 +31,16 @@ pub use self::impl_linux::peer_cred; #[cfg(any( target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", - target_os = "macos", target_os = "openbsd" ))] pub use self::impl_bsd::peer_cred; +#[cfg(any( + target_os = "macos", + target_os = "ios", +))] +pub use self::impl_mac::peer_cred; + #[cfg(any(target_os = "linux", target_os = "android"))] pub mod impl_linux { use super::UCred; @@ -75,8 +79,6 @@ pub mod impl_linux { #[cfg(any( target_os = "dragonfly", - target_os = "macos", - target_os = "ios", target_os = "freebsd", target_os = "openbsd" ))] @@ -95,3 +97,44 @@ pub mod impl_bsd { } } } + +#[cfg(any( + target_os = "macos", + target_os = "ios", +))] +pub mod impl_mac { + use super::UCred; + use crate::{io, mem}; + use crate::os::unix::io::AsRawFd; + use crate::os::unix::net::UnixStream; + use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, SOL_LOCAL, LOCAL_PEERPID}; + + pub fn peer_cred(socket: &UnixStream) -> io::Result { + let mut cred = UCred { uid: 1, gid: 1, pid: None }; + unsafe { + let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid); + + if ret != 0 { + return Err(io::Error::last_os_error()); + } + + let mut pid: pid_t = 1; + let mut pid_size = mem::size_of::() as socklen_t; + + let ret = getsockopt( + socket.as_raw_fd(), + SOL_LOCAL, + LOCAL_PEERPID, + &mut pid as *mut pid_t as *mut c_void, + &mut pid_size + ); + + if ret == 0 && pid_size as usize == mem::size_of::() { + cred.pid = Some(pid); + Ok(cred) + } else { + Err(io::Error::last_os_error()) + } + } + } +} diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/sys/unix/ext/ucred/tests.rs index 451b534b266..b3e45d3337c 100644 --- a/library/std/src/sys/unix/ext/ucred/tests.rs +++ b/library/std/src/sys/unix/ext/ucred/tests.rs @@ -1,5 +1,5 @@ use crate::os::unix::net::UnixStream; -use libc::{getegid, geteuid}; +use libc::{getegid, geteuid, getpid}; #[test] #[cfg(any( @@ -23,3 +23,20 @@ fn test_socket_pair() { assert_eq!(cred_a.uid, uid); assert_eq!(cred_a.gid, gid); } + +#[test] +#[cfg(any( + target_os = "linux", + target_os = "ios", + target_os = "macos", +))] +fn test_socket_pair_pids(arg: Type) -> RetType { + // Create two connected sockets and get their peer credentials. + let (sock_a, sock_b) = UnixStream::pair().unwrap(); + let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap()); + + // On supported platforms (see the cfg above), the credentials should always include the PID. + let pid = unsafe { getpid() }; + assert_eq!(cred_a.pid, Some(pid)); + assert_eq!(cred_b.pid, Some(pid)); +} From 3d8329f6fc678024fc74754f4e483d6a83fee098 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 24 Nov 2020 14:55:35 -0500 Subject: [PATCH 066/274] ext/ucred: fmt check --- library/std/src/sys/unix/ext/ucred.rs | 28 ++++++--------------- library/std/src/sys/unix/ext/ucred/tests.rs | 6 +---- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs index e2aeb39f995..1b4c18d3d84 100644 --- a/library/std/src/sys/unix/ext/ucred.rs +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -28,17 +28,10 @@ pub struct UCred { #[cfg(any(target_os = "android", target_os = "linux"))] pub use self::impl_linux::peer_cred; -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd" -))] +#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] pub use self::impl_bsd::peer_cred; -#[cfg(any( - target_os = "macos", - target_os = "ios", -))] +#[cfg(any(target_os = "macos", target_os = "ios",))] pub use self::impl_mac::peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -77,11 +70,7 @@ pub mod impl_linux { } } -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd" -))] +#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] pub mod impl_bsd { use super::UCred; use crate::io; @@ -98,16 +87,13 @@ pub mod impl_bsd { } } -#[cfg(any( - target_os = "macos", - target_os = "ios", -))] +#[cfg(any(target_os = "macos", target_os = "ios",))] pub mod impl_mac { use super::UCred; - use crate::{io, mem}; use crate::os::unix::io::AsRawFd; use crate::os::unix::net::UnixStream; - use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, SOL_LOCAL, LOCAL_PEERPID}; + use crate::{io, mem}; + use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL}; pub fn peer_cred(socket: &UnixStream) -> io::Result { let mut cred = UCred { uid: 1, gid: 1, pid: None }; @@ -126,7 +112,7 @@ pub mod impl_mac { SOL_LOCAL, LOCAL_PEERPID, &mut pid as *mut pid_t as *mut c_void, - &mut pid_size + &mut pid_size, ); if ret == 0 && pid_size as usize == mem::size_of::() { diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/sys/unix/ext/ucred/tests.rs index b3e45d3337c..42d79418cf7 100644 --- a/library/std/src/sys/unix/ext/ucred/tests.rs +++ b/library/std/src/sys/unix/ext/ucred/tests.rs @@ -25,11 +25,7 @@ fn test_socket_pair() { } #[test] -#[cfg(any( - target_os = "linux", - target_os = "ios", - target_os = "macos", -))] +#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))] fn test_socket_pair_pids(arg: Type) -> RetType { // Create two connected sockets and get their peer credentials. let (sock_a, sock_b) = UnixStream::pair().unwrap(); From 9b9dd4aeea858fb2249adc9421ab156a78e84b8b Mon Sep 17 00:00:00 2001 From: LinkTed Date: Tue, 24 Nov 2020 19:24:39 +0100 Subject: [PATCH 067/274] Bug fix for android platform, because of the wrong behavior of CMSG_NXTHDR --- library/std/src/sys/unix/ext/net/ancillary.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index a68475ab985..a94456b4e7a 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -5,6 +5,8 @@ use crate::marker::PhantomData; use crate::mem::{size_of, zeroed}; use crate::os::unix::io::RawFd; use crate::path::Path; +#[cfg(target_os = "android")] +use crate::ptr::eq; use crate::ptr::read_unaligned; use crate::slice::from_raw_parts; use crate::sys::net::Socket; @@ -157,6 +159,13 @@ fn add_to_ancillary_data( while !cmsg.is_null() { previous_cmsg = cmsg; cmsg = libc::CMSG_NXTHDR(&msg, cmsg); + cfg_if::cfg_if! { + if #[cfg(target_os = "android")] { + if cmsg == previous_cmsg { + break; + } + } + } } if previous_cmsg.is_null() { @@ -420,6 +429,16 @@ impl<'a> Iterator for Messages<'a> { }; let cmsg = cmsg.as_ref()?; + cfg_if::cfg_if! { + if #[cfg(target_os = "android")] { + if let Some(current) = self.current { + if eq(current, cmsg) { + return None; + } + } + } + } + self.current = Some(cmsg); let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg); Some(ancillary_result) From f6827839c0b3e81f07c522fc28b5a2406025acaf Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Thu, 12 Nov 2020 11:24:10 -0800 Subject: [PATCH 068/274] Move lev_distance to rustc_ast, make non-generic rustc_ast currently has a few dependencies on rustc_lexer. Ideally, an AST would not have any dependency its lexer, for minimizing unnecessarily design-time dependencies. Breaking this dependency would also have practical benefits, since modifying rustc_lexer would not trigger a rebuild of rustc_ast. This commit does not remove the rustc_ast --> rustc_lexer dependency, but it does remove one of the sources of this dependency, which is the code that handles fuzzy matching between symbol names for making suggestions in diagnostics. Since that code depends only on Symbol, it is easy to move it to rustc_span. It might even be best to move it to a separate crate, since other tools such as Cargo use the same algorithm, and have simply contain a duplicate of the code. This changes the signature of find_best_match_for_name so that it is no longer generic over its input. I checked the optimized binaries, and this function was duplicated at nearly every call site, because most call sites used short-lived iterator chains, generic over Map and such. But there's no good reason for a function like this to be generic, since all it does is immediately convert the generic input (the Iterator impl) to a concrete Vec. This has all of the costs of generics (duplicated method bodies) with no benefit. Changing find_best_match_for_name to be non-generic removed about 10KB of code from the optimized binary. I know it's a drop in the bucket, but we have to start reducing binary size, and beginning to tame over-use of generics is part of that. --- clippy_lints/src/attrs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 9a667aa61b4..15505fd79f4 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -5,7 +5,7 @@ use crate::utils::{ span_lint_and_sugg, span_lint_and_then, without_block_comments, }; use if_chain::if_chain; -use rustc_ast::util::lev_distance::find_best_match_for_name; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; use rustc_hir::{ @@ -427,7 +427,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMet .map(|l| Symbol::intern(&l.name_lower())) .collect::>(); let sugg = find_best_match_for_name( - symbols.iter(), + &symbols, Symbol::intern(&format!("clippy::{}", name_lower)), None, ); From dc075b426675e61cc46089046cf41d85edd79aaa Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Wed, 25 Nov 2020 02:01:05 +0100 Subject: [PATCH 069/274] Change `redundant_pattern_matching` to also lint `std::net::IpAddr` Suggest using utility methods `is_ipv4` and `is_ipv6`. --- clippy_lints/src/matches.rs | 25 +++- clippy_lints/src/utils/paths.rs | 2 + .../redundant_pattern_matching_ipaddr.fixed | 73 ++++++++++ tests/ui/redundant_pattern_matching_ipaddr.rs | 91 ++++++++++++ .../redundant_pattern_matching_ipaddr.stderr | 130 ++++++++++++++++++ .../redundant_pattern_matching_option.fixed | 5 +- tests/ui/redundant_pattern_matching_option.rs | 5 +- .../redundant_pattern_matching_option.stderr | 18 +-- .../ui/redundant_pattern_matching_poll.fixed | 5 +- tests/ui/redundant_pattern_matching_poll.rs | 5 +- .../ui/redundant_pattern_matching_poll.stderr | 18 +-- 11 files changed, 341 insertions(+), 36 deletions(-) create mode 100644 tests/ui/redundant_pattern_matching_ipaddr.fixed create mode 100644 tests/ui/redundant_pattern_matching_ipaddr.rs create mode 100644 tests/ui/redundant_pattern_matching_ipaddr.stderr diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index af59917e801..a14b63faf78 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -411,8 +411,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Lint for redundant pattern matching over `Result`, `Option` or - /// `std::task::Poll` + /// **What it does:** Lint for redundant pattern matching over `Result`, `Option`, + /// `std::task::Poll` or `std::net::IpAddr` /// /// **Why is this bad?** It's more concise and clear to just use the proper /// utility function @@ -423,12 +423,15 @@ declare_clippy_lint! { /// /// ```rust /// # use std::task::Poll; + /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if let Ok(_) = Ok::(42) {} /// if let Err(_) = Err::(42) {} /// if let None = None::<()> {} /// if let Some(_) = Some(42) {} /// if let Poll::Pending = Poll::Pending::<()> {} /// if let Poll::Ready(_) = Poll::Ready(42) {} + /// if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {} + /// if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {} /// match Ok::(42) { /// Ok(_) => true, /// Err(_) => false, @@ -439,12 +442,15 @@ declare_clippy_lint! { /// /// ```rust /// # use std::task::Poll; + /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// if Ok::(42).is_ok() {} /// if Err::(42).is_err() {} /// if None::<()>.is_none() {} /// if Some(42).is_some() {} /// if Poll::Pending::<()>.is_pending() {} /// if Poll::Ready(42).is_ready() {} + /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {} /// Ok::(42).is_ok(); /// ``` pub REDUNDANT_PATTERN_MATCHING, @@ -1546,6 +1552,10 @@ mod redundant_pattern_match { "is_some()" } else if match_qpath(path, &paths::POLL_READY) { "is_ready()" + } else if match_qpath(path, &paths::IPADDR_V4) { + "is_ipv4()" + } else if match_qpath(path, &paths::IPADDR_V6) { + "is_ipv6()" } else { return; } @@ -1626,6 +1636,17 @@ mod redundant_pattern_match { "is_ok()", "is_err()", ) + .or_else(|| { + find_good_method_for_match( + arms, + path_left, + path_right, + &paths::IPADDR_V4, + &paths::IPADDR_V6, + "is_ipv4()", + "is_ipv6()", + ) + }) } else { None } diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 829e9a2989c..61aeabb7ba7 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -58,6 +58,8 @@ pub const INTO: [&str; 3] = ["core", "convert", "Into"]; pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; +pub const IPADDR_V4: [&str; 4] = ["std", "net", "IpAddr", "V4"]; +pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"]; pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"]; pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"]; diff --git a/tests/ui/redundant_pattern_matching_ipaddr.fixed b/tests/ui/redundant_pattern_matching_ipaddr.fixed new file mode 100644 index 00000000000..acc8de5f41e --- /dev/null +++ b/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -0,0 +1,73 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] + +use std::net::{ + IpAddr::{self, V4, V6}, + Ipv4Addr, Ipv6Addr, +}; + +fn main() { + let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST); + if ipaddr.is_ipv4() {} + + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + while V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + while V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + if let V4(ipaddr) = V4(Ipv4Addr::LOCALHOST) { + println!("{}", ipaddr); + } + + V4(Ipv4Addr::LOCALHOST).is_ipv4(); + + V4(Ipv4Addr::LOCALHOST).is_ipv6(); + + V6(Ipv6Addr::LOCALHOST).is_ipv6(); + + V6(Ipv6Addr::LOCALHOST).is_ipv4(); + + let _ = if V4(Ipv4Addr::LOCALHOST).is_ipv4() { + true + } else { + false + }; + + ipaddr_const(); + + let _ = if gen_ipaddr().is_ipv4() { + 1 + } else if gen_ipaddr().is_ipv6() { + 2 + } else { + 3 + }; +} + +fn gen_ipaddr() -> IpAddr { + V4(Ipv4Addr::LOCALHOST) +} + +const fn ipaddr_const() { + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + while V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + while V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + V4(Ipv4Addr::LOCALHOST).is_ipv4(); + + V6(Ipv6Addr::LOCALHOST).is_ipv6(); +} diff --git a/tests/ui/redundant_pattern_matching_ipaddr.rs b/tests/ui/redundant_pattern_matching_ipaddr.rs new file mode 100644 index 00000000000..678d91ce93a --- /dev/null +++ b/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -0,0 +1,91 @@ +// run-rustfix + +#![warn(clippy::all)] +#![warn(clippy::redundant_pattern_matching)] +#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)] + +use std::net::{ + IpAddr::{self, V4, V6}, + Ipv4Addr, Ipv6Addr, +}; + +fn main() { + let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST); + if let V4(_) = &ipaddr {} + + if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + + if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + + while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + + while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + + if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + + if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + + if let V4(ipaddr) = V4(Ipv4Addr::LOCALHOST) { + println!("{}", ipaddr); + } + + match V4(Ipv4Addr::LOCALHOST) { + V4(_) => true, + V6(_) => false, + }; + + match V4(Ipv4Addr::LOCALHOST) { + V4(_) => false, + V6(_) => true, + }; + + match V6(Ipv6Addr::LOCALHOST) { + V4(_) => false, + V6(_) => true, + }; + + match V6(Ipv6Addr::LOCALHOST) { + V4(_) => true, + V6(_) => false, + }; + + let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { + true + } else { + false + }; + + ipaddr_const(); + + let _ = if let V4(_) = gen_ipaddr() { + 1 + } else if let V6(_) = gen_ipaddr() { + 2 + } else { + 3 + }; +} + +fn gen_ipaddr() -> IpAddr { + V4(Ipv4Addr::LOCALHOST) +} + +const fn ipaddr_const() { + if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + + if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + + while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + + while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + + match V4(Ipv4Addr::LOCALHOST) { + V4(_) => true, + V6(_) => false, + }; + + match V6(Ipv6Addr::LOCALHOST) { + V4(_) => false, + V6(_) => true, + }; +} diff --git a/tests/ui/redundant_pattern_matching_ipaddr.stderr b/tests/ui/redundant_pattern_matching_ipaddr.stderr new file mode 100644 index 00000000000..caf458cd862 --- /dev/null +++ b/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -0,0 +1,130 @@ +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:14:12 + | +LL | if let V4(_) = &ipaddr {} + | -------^^^^^---------- help: try this: `if ipaddr.is_ipv4()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:16:12 + | +LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12 + | +LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:20:15 + | +LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:22:15 + | +LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:32:5 + | +LL | / match V4(Ipv4Addr::LOCALHOST) { +LL | | V4(_) => true, +LL | | V6(_) => false, +LL | | }; + | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:37:5 + | +LL | / match V4(Ipv4Addr::LOCALHOST) { +LL | | V4(_) => false, +LL | | V6(_) => true, +LL | | }; + | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:42:5 + | +LL | / match V6(Ipv6Addr::LOCALHOST) { +LL | | V4(_) => false, +LL | | V6(_) => true, +LL | | }; + | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:47:5 + | +LL | / match V6(Ipv6Addr::LOCALHOST) { +LL | | V4(_) => true, +LL | | V6(_) => false, +LL | | }; + | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:52:20 + | +LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { + | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:60:20 + | +LL | let _ = if let V4(_) = gen_ipaddr() { + | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:62:19 + | +LL | } else if let V6(_) = gen_ipaddr() { + | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:74:12 + | +LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:76:12 + | +LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:78:15 + | +LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:80:15 + | +LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: redundant pattern matching, consider using `is_ipv4()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:82:5 + | +LL | / match V4(Ipv4Addr::LOCALHOST) { +LL | | V4(_) => true, +LL | | V6(_) => false, +LL | | }; + | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + +error: redundant pattern matching, consider using `is_ipv6()` + --> $DIR/redundant_pattern_matching_ipaddr.rs:87:5 + | +LL | / match V6(Ipv6Addr::LOCALHOST) { +LL | | V4(_) => false, +LL | | V6(_) => true, +LL | | }; + | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + +error: aborting due to 18 previous errors + diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index bc369dd2491..66f580a0a68 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -37,8 +37,7 @@ fn main() { let _ = None::<()>.is_none(); let opt = Some(false); - let x = if opt.is_some() { true } else { false }; - takes_bool(x); + let _ = if opt.is_some() { true } else { false }; issue6067(); @@ -55,8 +54,6 @@ fn gen_opt() -> Option<()> { None } -fn takes_bool(_: bool) {} - fn foo() {} fn bar() {} diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index d7616a72913..f18b27b8b95 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -46,8 +46,7 @@ fn main() { }; let opt = Some(false); - let x = if let Some(_) = opt { true } else { false }; - takes_bool(x); + let _ = if let Some(_) = opt { true } else { false }; issue6067(); @@ -64,8 +63,6 @@ fn gen_opt() -> Option<()> { None } -fn takes_bool(_: bool) {} - fn foo() {} fn bar() {} diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 7ddfbe503a2..58482a0ab70 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -73,47 +73,47 @@ LL | | }; error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:49:20 | -LL | let x = if let Some(_) = opt { true } else { false }; +LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:54:20 + --> $DIR/redundant_pattern_matching_option.rs:53:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:56:19 + --> $DIR/redundant_pattern_matching_option.rs:55:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:77:12 + --> $DIR/redundant_pattern_matching_option.rs:74:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:79:12 + --> $DIR/redundant_pattern_matching_option.rs:76:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:81:15 + --> $DIR/redundant_pattern_matching_option.rs:78:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:83:15 + --> $DIR/redundant_pattern_matching_option.rs:80:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:85:5 + --> $DIR/redundant_pattern_matching_option.rs:82:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -122,7 +122,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:90:5 + --> $DIR/redundant_pattern_matching_option.rs:87:5 | LL | / match None::<()> { LL | | Some(_) => false, diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed index 564c427f063..465aa80dac2 100644 --- a/tests/ui/redundant_pattern_matching_poll.fixed +++ b/tests/ui/redundant_pattern_matching_poll.fixed @@ -34,8 +34,7 @@ fn main() { let _ = Pending::<()>.is_pending(); let poll = Ready(false); - let x = if poll.is_ready() { true } else { false }; - takes_poll(x); + let _ = if poll.is_ready() { true } else { false }; poll_const(); @@ -52,8 +51,6 @@ fn gen_poll() -> Poll<()> { Pending } -fn takes_poll(_: bool) {} - fn foo() {} fn bar() {} diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs index d453d4184af..7891ff353b1 100644 --- a/tests/ui/redundant_pattern_matching_poll.rs +++ b/tests/ui/redundant_pattern_matching_poll.rs @@ -43,8 +43,7 @@ fn main() { }; let poll = Ready(false); - let x = if let Ready(_) = poll { true } else { false }; - takes_poll(x); + let _ = if let Ready(_) = poll { true } else { false }; poll_const(); @@ -61,8 +60,6 @@ fn gen_poll() -> Poll<()> { Pending } -fn takes_poll(_: bool) {} - fn foo() {} fn bar() {} diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr index 42e5d6f41fe..5ffc6c47c90 100644 --- a/tests/ui/redundant_pattern_matching_poll.stderr +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -67,47 +67,47 @@ LL | | }; error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:46:20 | -LL | let x = if let Ready(_) = poll { true } else { false }; +LL | let _ = if let Ready(_) = poll { true } else { false }; | -------^^^^^^^^------- help: try this: `if poll.is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:51:20 + --> $DIR/redundant_pattern_matching_poll.rs:50:20 | LL | let _ = if let Ready(_) = gen_poll() { | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:53:19 + --> $DIR/redundant_pattern_matching_poll.rs:52:19 | LL | } else if let Pending = gen_poll() { | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:71:12 + --> $DIR/redundant_pattern_matching_poll.rs:68:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:73:12 + --> $DIR/redundant_pattern_matching_poll.rs:70:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:75:15 + --> $DIR/redundant_pattern_matching_poll.rs:72:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:77:15 + --> $DIR/redundant_pattern_matching_poll.rs:74:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:79:5 + --> $DIR/redundant_pattern_matching_poll.rs:76:5 | LL | / match Ready(42) { LL | | Ready(_) => true, @@ -116,7 +116,7 @@ LL | | }; | |_____^ help: try this: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:84:5 + --> $DIR/redundant_pattern_matching_poll.rs:81:5 | LL | / match Pending::<()> { LL | | Ready(_) => false, From aaa43250455c19ae54c821518c42219f6460038c Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Wed, 21 Oct 2020 18:17:34 +0530 Subject: [PATCH 070/274] add support for minimum supported rust version. add configuration option for minimum supported rust version add msrv attribute to some lints listed in #6097 add tests --- clippy_lints/src/lib.rs | 23 +++++-- clippy_lints/src/manual_non_exhaustive.rs | 33 ++++++++- clippy_lints/src/manual_strip.rs | 37 ++++++++-- clippy_lints/src/matches.rs | 39 +++++++++-- clippy_lints/src/methods/mod.rs | 51 +++++++++++--- clippy_lints/src/utils/attrs.rs | 17 +++++ clippy_lints/src/utils/conf.rs | 2 + clippy_lints/src/utils/mod.rs | 49 +++++++++++++ .../invalid_min_rust_version/clippy.toml | 1 + .../invalid_min_rust_version.rs | 3 + .../invalid_min_rust_version.stderr | 4 ++ tests/ui-toml/min_rust_version/clippy.toml | 1 + .../min_rust_version/min_rust_version.rs | 68 +++++++++++++++++++ .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/min_rust_version_attr.rs | 51 ++++++++++++++ tests/ui/min_rust_version_invalid_attr.rs | 4 ++ tests/ui/min_rust_version_invalid_attr.stderr | 8 +++ tests/ui/min_rust_version_no_patch.rs | 14 ++++ tests/ui/min_rust_version_outer_attr.rs | 4 ++ tests/ui/min_rust_version_outer_attr.stderr | 8 +++ 20 files changed, 390 insertions(+), 29 deletions(-) create mode 100644 tests/ui-toml/invalid_min_rust_version/clippy.toml create mode 100644 tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs create mode 100644 tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr create mode 100644 tests/ui-toml/min_rust_version/clippy.toml create mode 100644 tests/ui-toml/min_rust_version/min_rust_version.rs create mode 100644 tests/ui/min_rust_version_attr.rs create mode 100644 tests/ui/min_rust_version_invalid_attr.rs create mode 100644 tests/ui/min_rust_version_invalid_attr.stderr create mode 100644 tests/ui/min_rust_version_no_patch.rs create mode 100644 tests/ui/min_rust_version_outer_attr.rs create mode 100644 tests/ui/min_rust_version_outer_attr.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7e8cbd00c22..866dae110cc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -44,6 +44,7 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; +use crate::utils::parse_msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::LintId; use rustc_session::Session; @@ -933,7 +934,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); // end register lints, do not remove this comment, it’s used in `update_lints` - store.register_late_pass(|| box await_holding_invalid::AwaitHolding); store.register_late_pass(|| box serde_api::SerdeAPI); store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); @@ -969,7 +969,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box strings::StringAdd); store.register_late_pass(|| box implicit_return::ImplicitReturn); store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); - store.register_late_pass(|| box methods::Methods); + + let parsed_msrv = conf.msrv.as_ref().and_then(|s| { + parse_msrv(s, None, None).or_else(|| { + sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s)); + None + }) + }); + + let msrv = parsed_msrv.clone(); + store.register_late_pass(move || box methods::Methods::new(msrv.clone())); + let msrv = parsed_msrv.clone(); + store.register_late_pass(move || box matches::Matches::new(msrv.clone())); + let msrv = parsed_msrv.clone(); + store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv.clone())); + let msrv = parsed_msrv; + store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv.clone())); + store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); @@ -983,7 +999,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box types::Casts); let type_complexity_threshold = conf.type_complexity_threshold; store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold)); - store.register_late_pass(|| box matches::Matches::default()); store.register_late_pass(|| box minmax::MinMaxPass); store.register_late_pass(|| box open_options::OpenOptions); store.register_late_pass(|| box zero_div_zero::ZeroDiv); @@ -1144,7 +1159,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box if_let_mutex::IfLetMutex); store.register_late_pass(|| box mut_mutex_lock::MutMutexLock); store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); - store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); @@ -1166,7 +1180,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box manual_ok_or::ManualOkOr); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); - store.register_late_pass(|| box manual_strip::ManualStrip); store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::>(); store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index a1450b0d5fe..4762ba16ac7 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,11 +1,20 @@ -use crate::utils::{snippet_opt, span_lint_and_then}; +use crate::utils::{get_inner_attr, meets_msrv, snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind}; use rustc_attr as attr; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; +use semver::{Version, VersionReq}; + +const MANUAL_NON_EXHAUSTIVE_MSRV: Version = Version { + major: 1, + minor: 40, + patch: 0, + pre: Vec::new(), + build: Vec::new(), +}; declare_clippy_lint! { /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. @@ -55,10 +64,26 @@ declare_clippy_lint! { "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]" } -declare_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); +#[derive(Clone)] +pub struct ManualNonExhaustive { + msrv: Option, +} + +impl ManualNonExhaustive { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); impl EarlyLintPass for ManualNonExhaustive { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if !meets_msrv(self.msrv.as_ref(), &MANUAL_NON_EXHAUSTIVE_MSRV) { + return; + } + match &item.kind { ItemKind::Enum(def, _) => { check_manual_non_exhaustive_enum(cx, item, &def.variants); @@ -73,6 +98,8 @@ impl EarlyLintPass for ManualNonExhaustive { _ => {}, } } + + extract_msrv_attr!(EarlyContext); } fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 4afb0ab3bad..446641ca114 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,21 +1,31 @@ use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - eq_expr_value, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then, + eq_expr_value, get_inner_attr, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, + span_lint_and_then, }; use if_chain::if_chain; -use rustc_ast::ast::LitKind; +use rustc_ast::ast::{Attribute, LitKind}; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::BinOpKind; use rustc_hir::{BorrowKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::Span; +use semver::{Version, VersionReq}; + +const MANUAL_STRIP_MSRV: Version = Version { + major: 1, + minor: 45, + patch: 0, + pre: Vec::new(), + build: Vec::new(), +}; declare_clippy_lint! { /// **What it does:** @@ -51,7 +61,18 @@ declare_clippy_lint! { "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing" } -declare_lint_pass!(ManualStrip => [MANUAL_STRIP]); +pub struct ManualStrip { + msrv: Option, +} + +impl ManualStrip { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualStrip => [MANUAL_STRIP]); #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum StripKind { @@ -61,6 +82,10 @@ enum StripKind { impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) { + return; + } + if_chain! { if let Some((cond, then, _)) = higher::if_block(&expr); if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind; @@ -114,6 +139,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { } } } + + extract_msrv_attr!(LateContext); } // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise. diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index af59917e801..5c38abbd9c6 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -2,14 +2,14 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; use crate::utils::usage::is_unused; use crate::utils::{ - expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, - is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet, - snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, + expr_block, get_arg_name, get_inner_attr, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, + is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, + remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, + span_lint_and_sugg, span_lint_and_then, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; +use rustc_ast::ast::{Attribute, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::CtorKind; @@ -23,6 +23,7 @@ use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::{sym, Symbol}; +use semver::{Version, VersionReq}; use std::cmp::Ordering; use std::collections::hash_map::Entry; use std::collections::Bound; @@ -527,9 +528,20 @@ declare_clippy_lint! { #[derive(Default)] pub struct Matches { + msrv: Option, infallible_destructuring_match_linted: bool, } +impl Matches { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { + msrv, + ..Matches::default() + } + } +} + impl_lint_pass!(Matches => [ SINGLE_MATCH, MATCH_REF_PATS, @@ -549,6 +561,14 @@ impl_lint_pass!(Matches => [ MATCH_SAME_ARMS, ]); +const MATCH_LIKE_MATCHES_MACRO_MSRV: Version = Version { + major: 1, + minor: 42, + patch: 0, + pre: Vec::new(), + build: Vec::new(), +}; + impl<'tcx> LateLintPass<'tcx> for Matches { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) { @@ -556,7 +576,12 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } redundant_pattern_match::check(cx, expr); - if !check_match_like_matches(cx, expr) { + + if meets_msrv(self.msrv.as_ref(), &MATCH_LIKE_MATCHES_MACRO_MSRV) { + if !check_match_like_matches(cx, expr) { + lint_match_arms(cx, expr); + } + } else { lint_match_arms(cx, expr); } @@ -640,6 +665,8 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } } + + extract_msrv_attr!(LateContext); } #[rustfmt::skip] diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fa174404365..6b478986067 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -12,6 +12,7 @@ use std::iter; use bind_instead_of_map::BindInsteadOfMap; use if_chain::if_chain; use rustc_ast::ast; +use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; @@ -20,7 +21,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -28,12 +29,14 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, - is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, - match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, - single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, + contains_ty, get_arg_name, get_inner_attr, get_parent_expr, get_trait_def_id, has_iter_method, higher, + implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, + match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls, + method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, + walk_ptrs_ty_depth, SpanlessEq, }; +use semver::{Version, VersionReq}; declare_clippy_lint! { /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. @@ -1404,7 +1407,18 @@ declare_clippy_lint! { "use `.collect()` instead of `::from_iter()`" } -declare_lint_pass!(Methods => [ +pub struct Methods { + msrv: Option, +} + +impl Methods { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, SHOULD_IMPLEMENT_TRAIT, @@ -1531,8 +1545,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods { check_pointer_offset(cx, expr, arg_lists[0]) }, ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), - ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false), - ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true), + ["map", "as_ref"] => { + lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref()) + }, + ["map", "as_mut"] => { + lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref()) + }, ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"), ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"), ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), @@ -1738,6 +1756,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } } + + extract_msrv_attr!(LateContext); } /// Checks for the `OR_FUN_CALL` lint. @@ -3453,6 +3473,14 @@ fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { ); } +const OPTION_AS_REF_DEREF_MSRV: Version = Version { + major: 1, + minor: 40, + patch: 0, + pre: Vec::new(), + build: Vec::new(), +}; + /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s fn lint_option_as_ref_deref<'tcx>( cx: &LateContext<'tcx>, @@ -3460,7 +3488,12 @@ fn lint_option_as_ref_deref<'tcx>( as_ref_args: &[hir::Expr<'_>], map_args: &[hir::Expr<'_>], is_mut: bool, + msrv: Option<&VersionReq>, ) { + if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) { + return; + } + let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]); diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index e6d41341a55..aed6ee5dc57 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -21,6 +21,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[ DeprecationStatus::Replaced("cognitive_complexity"), ), ("dump", DeprecationStatus::None), + ("msrv", DeprecationStatus::None), ]; pub struct LimitStack { @@ -123,6 +124,22 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' } } +pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'static str) -> Option { + let mut unique_attr = None; + for attr in get_attr(sess, attrs, name) { + match attr.style { + ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()), + ast::AttrStyle::Inner => { + sess.span_err(attr.span, &format!("`{}` is defined multiple times", name)); + }, + ast::AttrStyle::Outer => { + sess.span_err(attr.span, &format!("`{}` cannot be an outer attribute", name)); + }, + } + } + unique_attr +} + /// Return true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool { diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 0ac8fff69f0..fc6304118d9 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -106,6 +106,8 @@ macro_rules! define_Conf { pub use self::helpers::Conf; define_Conf! { + /// Lint: MANUAL_NON_EXHAUSTIVE, MANUAL_STRIP, OPTION_AS_REF_DEREF, MATCH_LIKE_MATCHES_MACRO. The minimum rust version that the project supports + (msrv, "msrv": Option, None), /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses (blacklisted_names, "blacklisted_names": Vec, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()), /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index e9c71e23a67..f8e88512048 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -51,6 +51,7 @@ use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; +use rustc_session::Session; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::sym as rustc_sym; @@ -58,10 +59,58 @@ use rustc_span::symbol::{self, kw, Symbol}; use rustc_span::{BytePos, Pos, Span, DUMMY_SP}; use rustc_target::abi::Integer; use rustc_trait_selection::traits::query::normalize::AtExt; +use semver::{Version, VersionReq}; use smallvec::SmallVec; use crate::consts::{constant, Constant}; +pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { + if let Ok(version) = VersionReq::parse(msrv) { + return Some(version); + } else if let Some(sess) = sess { + if let Some(span) = span { + sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv)); + } + } + None +} + +pub fn meets_msrv(msrv: Option<&VersionReq>, lint_msrv: &Version) -> bool { + msrv.map_or(true, |msrv| !msrv.matches(lint_msrv)) +} + +#[macro_export] +macro_rules! extract_msrv_attr { + (LateContext) => { + fn enter_lint_attrs(&mut self, cx: &rustc_lint::LateContext<'tcx>, attrs: &'tcx [Attribute]) { + match get_inner_attr(cx.sess(), attrs, "msrv") { + Some(msrv_attr) => { + if let Some(msrv) = msrv_attr.value_str() { + self.msrv = crate::utils::parse_msrv(&msrv.to_string(), Some(cx.sess()), Some(msrv_attr.span)); + } else { + cx.sess().span_err(msrv_attr.span, "bad clippy attribute"); + } + }, + _ => (), + } + } + }; + (EarlyContext) => { + fn enter_lint_attrs(&mut self, cx: &rustc_lint::EarlyContext<'tcx>, attrs: &'tcx [Attribute]) { + match get_inner_attr(cx.sess, attrs, "msrv") { + Some(msrv_attr) => { + if let Some(msrv) = msrv_attr.value_str() { + self.msrv = crate::utils::parse_msrv(&msrv.to_string(), Some(cx.sess), Some(msrv_attr.span)); + } else { + cx.sess.span_err(msrv_attr.span, "bad clippy attribute"); + } + }, + _ => (), + } + } + }; +} + /// Returns `true` if the two spans come from differing expansions (i.e., one is /// from a macro and one isn't). #[must_use] diff --git a/tests/ui-toml/invalid_min_rust_version/clippy.toml b/tests/ui-toml/invalid_min_rust_version/clippy.toml new file mode 100644 index 00000000000..088b12b2dac --- /dev/null +++ b/tests/ui-toml/invalid_min_rust_version/clippy.toml @@ -0,0 +1 @@ +msrv = "invalid.version" diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs new file mode 100644 index 00000000000..2ebf28645e5 --- /dev/null +++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs @@ -0,0 +1,3 @@ +#![allow(clippy::redundant_clone)] + +fn main() {} diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr new file mode 100644 index 00000000000..e9d8fd2e0f5 --- /dev/null +++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr @@ -0,0 +1,4 @@ +error: error reading Clippy's configuration file. `invalid.version` is not a valid Rust version + +error: aborting due to previous error + diff --git a/tests/ui-toml/min_rust_version/clippy.toml b/tests/ui-toml/min_rust_version/clippy.toml new file mode 100644 index 00000000000..8e17d8074c4 --- /dev/null +++ b/tests/ui-toml/min_rust_version/clippy.toml @@ -0,0 +1 @@ +msrv = "1.0.0" diff --git a/tests/ui-toml/min_rust_version/min_rust_version.rs b/tests/ui-toml/min_rust_version/min_rust_version.rs new file mode 100644 index 00000000000..bc41efa42a1 --- /dev/null +++ b/tests/ui-toml/min_rust_version/min_rust_version.rs @@ -0,0 +1,68 @@ +#![allow(clippy::redundant_clone)] +#![warn(clippy::manual_non_exhaustive)] + +use std::ops::Deref; + +mod enums { + enum E { + A, + B, + #[doc(hidden)] + _C, + } + + // user forgot to remove the marker + #[non_exhaustive] + enum Ep { + A, + B, + #[doc(hidden)] + _C, + } +} + +fn option_as_ref_deref() { + let mut opt = Some(String::from("123")); + + let _ = opt.as_ref().map(String::as_str); + let _ = opt.as_ref().map(|x| x.as_str()); + let _ = opt.as_mut().map(String::as_mut_str); + let _ = opt.as_mut().map(|x| x.as_mut_str()); +} + +fn match_like_matches() { + let _y = match Some(5) { + Some(0) => true, + _ => false, + }; +} + +fn match_same_arms() { + match (1, 2, 3) { + (1, .., 3) => 42, + (.., 3) => 42, //~ ERROR match arms have same body + _ => 0, + }; +} + +fn match_same_arms2() { + let _ = match Some(42) { + Some(_) => 24, + None => 24, //~ ERROR match arms have same body + }; +} + +fn manual_strip_msrv() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } +} + +fn main() { + option_as_ref_deref(); + match_like_matches(); + match_same_arms(); + match_same_arms2(); + manual_strip_msrv(); +} diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index a58e7e918e2..af3d9ecf6e8 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs new file mode 100644 index 00000000000..8ed483a3ac6 --- /dev/null +++ b/tests/ui/min_rust_version_attr.rs @@ -0,0 +1,51 @@ +#![allow(clippy::redundant_clone)] +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.0.0"] + +use std::ops::Deref; + +fn option_as_ref_deref() { + let mut opt = Some(String::from("123")); + + let _ = opt.as_ref().map(String::as_str); + let _ = opt.as_ref().map(|x| x.as_str()); + let _ = opt.as_mut().map(String::as_mut_str); + let _ = opt.as_mut().map(|x| x.as_mut_str()); +} + +fn match_like_matches() { + let _y = match Some(5) { + Some(0) => true, + _ => false, + }; +} + +fn match_same_arms() { + match (1, 2, 3) { + (1, .., 3) => 42, + (.., 3) => 42, //~ ERROR match arms have same body + _ => 0, + }; +} + +fn match_same_arms2() { + let _ = match Some(42) { + Some(_) => 24, + None => 24, //~ ERROR match arms have same body + }; +} + +fn manual_strip_msrv() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } +} + +fn main() { + option_as_ref_deref(); + match_like_matches(); + match_same_arms(); + match_same_arms2(); + manual_strip_msrv(); +} diff --git a/tests/ui/min_rust_version_invalid_attr.rs b/tests/ui/min_rust_version_invalid_attr.rs new file mode 100644 index 00000000000..f20841891a7 --- /dev/null +++ b/tests/ui/min_rust_version_invalid_attr.rs @@ -0,0 +1,4 @@ +#![feature(custom_inner_attributes)] +#![clippy::msrv = "invalid.version"] + +fn main() {} diff --git a/tests/ui/min_rust_version_invalid_attr.stderr b/tests/ui/min_rust_version_invalid_attr.stderr new file mode 100644 index 00000000000..6ff88ca56f8 --- /dev/null +++ b/tests/ui/min_rust_version_invalid_attr.stderr @@ -0,0 +1,8 @@ +error: `invalid.version` is not a valid Rust version + --> $DIR/min_rust_version_invalid_attr.rs:2:1 + | +LL | #![clippy::msrv = "invalid.version"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/min_rust_version_no_patch.rs b/tests/ui/min_rust_version_no_patch.rs new file mode 100644 index 00000000000..515fe8f95e9 --- /dev/null +++ b/tests/ui/min_rust_version_no_patch.rs @@ -0,0 +1,14 @@ +#![allow(clippy::redundant_clone)] +#![feature(custom_inner_attributes)] +#![clippy::msrv = "^1.0"] + +fn manual_strip_msrv() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } +} + +fn main() { + manual_strip_msrv() +} diff --git a/tests/ui/min_rust_version_outer_attr.rs b/tests/ui/min_rust_version_outer_attr.rs new file mode 100644 index 00000000000..551948bd72e --- /dev/null +++ b/tests/ui/min_rust_version_outer_attr.rs @@ -0,0 +1,4 @@ +#![feature(custom_inner_attributes)] + +#[clippy::msrv = "invalid.version"] +fn main() {} diff --git a/tests/ui/min_rust_version_outer_attr.stderr b/tests/ui/min_rust_version_outer_attr.stderr new file mode 100644 index 00000000000..579ee7a87d2 --- /dev/null +++ b/tests/ui/min_rust_version_outer_attr.stderr @@ -0,0 +1,8 @@ +error: `msrv` cannot be an outer attribute + --> $DIR/min_rust_version_outer_attr.rs:3:1 + | +LL | #[clippy::msrv = "invalid.version"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From b2e2c0806ec2296bf7d98e0db5cc9c39a55f23ac Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 25 Nov 2020 11:50:13 +0100 Subject: [PATCH 071/274] Improve extract_msrv_attr! situation --- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_lints/src/manual_strip.rs | 5 ++-- clippy_lints/src/matches.rs | 10 ++++---- clippy_lints/src/methods/mod.rs | 12 ++++----- clippy_lints/src/utils/mod.rs | 30 ++++++++++------------- 5 files changed, 26 insertions(+), 33 deletions(-) diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 4762ba16ac7..703e6feeca5 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_inner_attr, meets_msrv, snippet_opt, span_lint_and_then}; +use crate::utils::{meets_msrv, snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind}; use rustc_attr as attr; diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 446641ca114..e17e3adb94f 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -1,12 +1,11 @@ use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - eq_expr_value, get_inner_attr, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, - span_lint_and_then, + eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then, }; use if_chain::if_chain; -use rustc_ast::ast::{Attribute, LitKind}; +use rustc_ast::ast::LitKind; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::BinOpKind; diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 5c38abbd9c6..d695af4de21 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -2,14 +2,14 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; use crate::utils::usage::is_unused; use crate::utils::{ - expr_block, get_arg_name, get_inner_attr, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, - is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, - remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, - span_lint_and_sugg, span_lint_and_then, + expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, + is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, remove_blocks, + snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, + span_lint_and_then, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; -use rustc_ast::ast::{Attribute, LitKind}; +use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::CtorKind; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6b478986067..50dd760432d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -12,7 +12,6 @@ use std::iter; use bind_instead_of_map::BindInsteadOfMap; use if_chain::if_chain; use rustc_ast::ast; -use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; @@ -29,12 +28,11 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_ty, get_arg_name, get_inner_attr, get_parent_expr, get_trait_def_id, has_iter_method, higher, - implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, - match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls, - method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, - walk_ptrs_ty_depth, SpanlessEq, + contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, + is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, + match_trait_method, match_type, match_var, meets_msrv, method_calls, method_chain_args, paths, remove_blocks, + return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, + span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, }; use semver::{Version, VersionReq}; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index f8e88512048..6f89e51279a 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -79,30 +79,26 @@ pub fn meets_msrv(msrv: Option<&VersionReq>, lint_msrv: &Version) -> bool { msrv.map_or(true, |msrv| !msrv.matches(lint_msrv)) } -#[macro_export] macro_rules! extract_msrv_attr { (LateContext) => { - fn enter_lint_attrs(&mut self, cx: &rustc_lint::LateContext<'tcx>, attrs: &'tcx [Attribute]) { - match get_inner_attr(cx.sess(), attrs, "msrv") { - Some(msrv_attr) => { - if let Some(msrv) = msrv_attr.value_str() { - self.msrv = crate::utils::parse_msrv(&msrv.to_string(), Some(cx.sess()), Some(msrv_attr.span)); - } else { - cx.sess().span_err(msrv_attr.span, "bad clippy attribute"); - } - }, - _ => (), - } - } + extract_msrv_attr!(@LateContext, ()); }; (EarlyContext) => { - fn enter_lint_attrs(&mut self, cx: &rustc_lint::EarlyContext<'tcx>, attrs: &'tcx [Attribute]) { - match get_inner_attr(cx.sess, attrs, "msrv") { + extract_msrv_attr!(@EarlyContext); + }; + (@$context:ident$(, $call:tt)?) => { + fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) { + use $crate::utils::get_unique_inner_attr; + match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") { Some(msrv_attr) => { if let Some(msrv) = msrv_attr.value_str() { - self.msrv = crate::utils::parse_msrv(&msrv.to_string(), Some(cx.sess), Some(msrv_attr.span)); + self.msrv = $crate::utils::parse_msrv( + &msrv.to_string(), + Some(cx.sess$($call)?), + Some(msrv_attr.span), + ); } else { - cx.sess.span_err(msrv_attr.span, "bad clippy attribute"); + cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute"); } }, _ => (), From 93f922a85843b2c04e47ea30c109f0bd305e039e Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 25 Nov 2020 12:19:13 +0100 Subject: [PATCH 072/274] Add note where the first definition of msrv attr is --- clippy_lints/src/utils/attrs.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index aed6ee5dc57..24052a243af 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -130,7 +130,9 @@ pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'s match attr.style { ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()), ast::AttrStyle::Inner => { - sess.span_err(attr.span, &format!("`{}` is defined multiple times", name)); + sess.struct_span_err(attr.span, &format!("`{}` is defined multiple times", name)) + .span_note(unique_attr.as_ref().unwrap().span, "first definition found here") + .emit(); }, ast::AttrStyle::Outer => { sess.span_err(attr.span, &format!("`{}` cannot be an outer attribute", name)); From d06076c0c56a2b254b061d569d421b887a7c6bbe Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 25 Nov 2020 12:19:42 +0100 Subject: [PATCH 073/274] Add test for multiple defined msrv attrs --- .../min_rust_version_multiple_inner_attr.rs | 11 ++++++ ...in_rust_version_multiple_inner_attr.stderr | 38 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tests/ui/min_rust_version_multiple_inner_attr.rs create mode 100644 tests/ui/min_rust_version_multiple_inner_attr.stderr diff --git a/tests/ui/min_rust_version_multiple_inner_attr.rs b/tests/ui/min_rust_version_multiple_inner_attr.rs new file mode 100644 index 00000000000..e882d5ccf91 --- /dev/null +++ b/tests/ui/min_rust_version_multiple_inner_attr.rs @@ -0,0 +1,11 @@ +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.40"] +#![clippy::msrv = "=1.35.0"] +#![clippy::msrv = "1.10.1"] + +mod foo { + #![clippy::msrv = "1"] + #![clippy::msrv = "1.0.0"] +} + +fn main() {} diff --git a/tests/ui/min_rust_version_multiple_inner_attr.stderr b/tests/ui/min_rust_version_multiple_inner_attr.stderr new file mode 100644 index 00000000000..e3ff6605cde --- /dev/null +++ b/tests/ui/min_rust_version_multiple_inner_attr.stderr @@ -0,0 +1,38 @@ +error: `msrv` is defined multiple times + --> $DIR/min_rust_version_multiple_inner_attr.rs:3:1 + | +LL | #![clippy::msrv = "=1.35.0"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first definition found here + --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1 + | +LL | #![clippy::msrv = "1.40"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `msrv` is defined multiple times + --> $DIR/min_rust_version_multiple_inner_attr.rs:4:1 + | +LL | #![clippy::msrv = "1.10.1"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first definition found here + --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1 + | +LL | #![clippy::msrv = "1.40"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `msrv` is defined multiple times + --> $DIR/min_rust_version_multiple_inner_attr.rs:8:5 + | +LL | #![clippy::msrv = "1.0.0"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first definition found here + --> $DIR/min_rust_version_multiple_inner_attr.rs:7:5 + | +LL | #![clippy::msrv = "1"] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + From 2345ef5b1f89d9cac7a6697de08c36bfb771fe12 Mon Sep 17 00:00:00 2001 From: PunitLodha Date: Sat, 14 Nov 2020 19:21:33 +0530 Subject: [PATCH 074/274] added lints str_to_string and string_to_string --- clippy_lints/src/deprecated_lints.rs | 20 ------ clippy_lints/src/lib.rs | 22 ++---- clippy_lints/src/strings.rs | 100 ++++++++++++++++++++++++++- src/lintlist/mod.rs | 14 ++++ tests/ui/deprecated.rs | 2 - tests/ui/deprecated.stderr | 46 +++++------- tests/ui/deprecated_old.rs | 2 - tests/ui/deprecated_old.stderr | 30 +++----- tests/ui/str_to_string.rs | 7 ++ tests/ui/str_to_string.stderr | 19 +++++ tests/ui/string_to_string.rs | 7 ++ tests/ui/string_to_string.stderr | 11 +++ 12 files changed, 189 insertions(+), 91 deletions(-) create mode 100644 tests/ui/str_to_string.rs create mode 100644 tests/ui/str_to_string.stderr create mode 100644 tests/ui/string_to_string.rs create mode 100644 tests/ui/string_to_string.stderr diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 1c3285ed701..bec0c9f93a0 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -51,26 +51,6 @@ declare_deprecated_lint! { "`Vec::as_mut_slice` has been stabilized in 1.7" } -declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. - /// - /// **Deprecation reason:** This used to check for `.to_string()` method calls on values - /// of type `&str`. This is not unidiomatic and with specialization coming, `to_string` could be - /// specialized to be as efficient as `to_owned`. - pub STR_TO_STRING, - "using `str::to_string` is common even today and specialization will likely happen soon" -} - -declare_deprecated_lint! { - /// **What it does:** Nothing. This lint has been deprecated. - /// - /// **Deprecation reason:** This used to check for `.to_string()` method calls on values - /// of type `String`. This is not unidiomatic and with specialization coming, `to_string` could be - /// specialized to be as efficient as `clone`. - pub STRING_TO_STRING, - "using `string::to_string` is common even today and specialization will likely happen soon" -} - declare_deprecated_lint! { /// **What it does:** Nothing. This lint has been deprecated. /// diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 866dae110cc..67a3a3fcf48 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -441,14 +441,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` has been stabilized in 1.7", ); - store.register_removed( - "clippy::str_to_string", - "using `str::to_string` is common even today and specialization will likely happen soon", - ); - store.register_removed( - "clippy::string_to_string", - "using `string::to_string` is common even today and specialization will likely happen soon", - ); store.register_removed( "clippy::misaligned_transmute", "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", @@ -840,6 +832,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &strings::STRING_ADD_ASSIGN, &strings::STRING_FROM_UTF8_AS_BYTES, &strings::STRING_LIT_AS_BYTES, + &strings::STRING_TO_STRING, + &strings::STR_TO_STRING, &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, &swap::ALMOST_SWAPPED, @@ -1186,6 +1180,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax); store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax); store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops); + store.register_late_pass(|| box strings::StrToString); + store.register_late_pass(|| box strings::StringToString); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ @@ -1228,6 +1224,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&shadow::SHADOW_REUSE), LintId::of(&shadow::SHADOW_SAME), LintId::of(&strings::STRING_ADD), + LintId::of(&strings::STRING_TO_STRING), + LintId::of(&strings::STR_TO_STRING), LintId::of(&types::RC_BUFFER), LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT), LintId::of(&verbose_file_reads::VERBOSE_FILE_READS), @@ -1943,14 +1941,6 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) { "unstable_as_mut_slice", "`Vec::as_mut_slice` has been stabilized in 1.7", ); - store.register_removed( - "str_to_string", - "using `str::to_string` is common even today and specialization will likely happen soon", - ); - store.register_removed( - "string_to_string", - "using `string::to_string` is common even today and specialization will likely happen soon", - ); store.register_removed( "misaligned_transmute", "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index ede37624f71..42c45be3b45 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -2,6 +2,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -11,7 +12,7 @@ use if_chain::if_chain; use crate::utils::SpanlessEq; use crate::utils::{ get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint, - span_lint_and_sugg, + span_lint_and_help, span_lint_and_sugg, }; declare_clippy_lint! { @@ -289,3 +290,100 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } } } + +declare_clippy_lint! { + /// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`. + /// + /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string. + /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better + /// expressed with `.to_owned()`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // example code where clippy issues a warning + /// let _ = "str".to_string(); + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// let _ = "str".to_owned(); + /// ``` + pub STR_TO_STRING, + restriction, + "using `to_string()` on a `&str`, which should be `to_owned()`" +} + +declare_lint_pass!(StrToString => [STR_TO_STRING]); + +impl LateLintPass<'_> for StrToString { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; + if path.ident.name == sym!(to_string); + let ty = cx.typeck_results().expr_ty(&args[0]); + if let ty::Ref(_, ty, ..) = ty.kind(); + if *ty.kind() == ty::Str; + then { + span_lint_and_help( + cx, + STR_TO_STRING, + expr.span, + "`to_string()` called on a `&str`", + None, + "consider using `.to_owned()`", + ); + } + } + } +} + +declare_clippy_lint! { + /// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`. + /// + /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string. + /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // example code where clippy issues a warning + /// let msg = String::from("Hello World"); + /// let _ = msg.to_string(); + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// let msg = String::from("Hello World"); + /// let _ = msg.clone(); + /// ``` + pub STRING_TO_STRING, + restriction, + "using `to_string()` on a `String`, which should be `clone()`" +} + +declare_lint_pass!(StringToString => [STRING_TO_STRING]); + +impl LateLintPass<'_> for StringToString { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::MethodCall(path, _, args, _) = &expr.kind; + if path.ident.name == sym!(to_string); + let ty = cx.typeck_results().expr_ty(&args[0]); + if is_type_diagnostic_item(cx, ty, sym!(string_type)); + then { + span_lint_and_help( + cx, + STRING_TO_STRING, + expr.span, + "`to_string()` called on a `String`", + None, + "consider using `.clone()`", + ); + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1d906d20ad4..a104f687bdf 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2237,6 +2237,13 @@ vec![ deprecation: None, module: "stable_sort_primitive", }, + Lint { + name: "str_to_string", + group: "restriction", + desc: "using `to_string()` on a `&str`, which should be `to_owned()`", + deprecation: None, + module: "strings", + }, Lint { name: "string_add", group: "restriction", @@ -2272,6 +2279,13 @@ vec![ deprecation: None, module: "strings", }, + Lint { + name: "string_to_string", + group: "restriction", + desc: "using `to_string()` on a `String`, which should be `clone()`", + deprecation: None, + module: "strings", + }, Lint { name: "struct_excessive_bools", group: "pedantic", diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 4cbc5630d75..e1ee8dbca2c 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -1,5 +1,3 @@ -#[warn(clippy::str_to_string)] -#[warn(clippy::string_to_string)] #[warn(clippy::unstable_as_slice)] #[warn(clippy::unstable_as_mut_slice)] #[warn(clippy::misaligned_transmute)] diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index a348d01d734..edbb891afe0 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -1,88 +1,76 @@ -error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated.rs:1:8 - | -LL | #[warn(clippy::str_to_string)] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` - -error: lint `clippy::string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated.rs:2:8 - | -LL | #[warn(clippy::string_to_string)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` - --> $DIR/deprecated.rs:3:8 + --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::unstable_as_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7` - --> $DIR/deprecated.rs:4:8 + --> $DIR/deprecated.rs:2:8 | LL | #[warn(clippy::unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr` - --> $DIR/deprecated.rs:5:8 + --> $DIR/deprecated.rs:3:8 | LL | #[warn(clippy::misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::unused_collect` has been removed: ``collect` has been marked as #[must_use] in rustc and that covers all cases of this lint` - --> $DIR/deprecated.rs:6:8 + --> $DIR/deprecated.rs:4:8 | LL | #[warn(clippy::unused_collect)] | ^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::invalid_ref` has been removed: `superseded by rustc lint `invalid_value`` - --> $DIR/deprecated.rs:7:8 + --> $DIR/deprecated.rs:5:8 | LL | #[warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ error: lint `clippy::into_iter_on_array` has been removed: `this lint has been uplifted to rustc and is now called `array_into_iter`` - --> $DIR/deprecated.rs:8:8 + --> $DIR/deprecated.rs:6:8 | LL | #[warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::unused_label` has been removed: `this lint has been uplifted to rustc and is now called `unused_labels`` - --> $DIR/deprecated.rs:9:8 + --> $DIR/deprecated.rs:7:8 | LL | #[warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::regex_macro` has been removed: `the regex! macro has been removed from the regex crate in 2018` - --> $DIR/deprecated.rs:10:8 + --> $DIR/deprecated.rs:8:8 | LL | #[warn(clippy::regex_macro)] | ^^^^^^^^^^^^^^^^^^^ error: lint `clippy::drop_bounds` has been removed: `this lint has been uplifted to rustc and is now called `drop_bounds`` - --> $DIR/deprecated.rs:11:8 + --> $DIR/deprecated.rs:9:8 | LL | #[warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ error: lint `clippy::temporary_cstring_as_ptr` has been removed: `this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`` - --> $DIR/deprecated.rs:12:8 + --> $DIR/deprecated.rs:10:8 | LL | #[warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::panic_params` has been removed: `this lint has been uplifted to rustc and is now called `panic_fmt`` - --> $DIR/deprecated.rs:13:8 + --> $DIR/deprecated.rs:11:8 | LL | #[warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` +error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` --> $DIR/deprecated.rs:1:8 | -LL | #[warn(clippy::str_to_string)] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[warn(clippy::unstable_as_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/deprecated_old.rs b/tests/ui/deprecated_old.rs index 2e5c5b7ead1..e89dca4fcfd 100644 --- a/tests/ui/deprecated_old.rs +++ b/tests/ui/deprecated_old.rs @@ -1,5 +1,3 @@ -#[warn(str_to_string)] -#[warn(string_to_string)] #[warn(unstable_as_slice)] #[warn(unstable_as_mut_slice)] #[warn(misaligned_transmute)] diff --git a/tests/ui/deprecated_old.stderr b/tests/ui/deprecated_old.stderr index ff3e9e8fcf3..2fe1facf0c7 100644 --- a/tests/ui/deprecated_old.stderr +++ b/tests/ui/deprecated_old.stderr @@ -1,40 +1,28 @@ -error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated_old.rs:1:8 - | -LL | #[warn(str_to_string)] - | ^^^^^^^^^^^^^ - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` - -error: lint `string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon` - --> $DIR/deprecated_old.rs:2:8 - | -LL | #[warn(string_to_string)] - | ^^^^^^^^^^^^^^^^ - error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` - --> $DIR/deprecated_old.rs:3:8 + --> $DIR/deprecated_old.rs:1:8 | LL | #[warn(unstable_as_slice)] | ^^^^^^^^^^^^^^^^^ + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7` - --> $DIR/deprecated_old.rs:4:8 + --> $DIR/deprecated_old.rs:2:8 | LL | #[warn(unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^ error: lint `misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr` - --> $DIR/deprecated_old.rs:5:8 + --> $DIR/deprecated_old.rs:3:8 | LL | #[warn(misaligned_transmute)] | ^^^^^^^^^^^^^^^^^^^^ -error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` +error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7` --> $DIR/deprecated_old.rs:1:8 | -LL | #[warn(str_to_string)] - | ^^^^^^^^^^^^^ +LL | #[warn(unstable_as_slice)] + | ^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/str_to_string.rs b/tests/ui/str_to_string.rs new file mode 100644 index 00000000000..08f73402518 --- /dev/null +++ b/tests/ui/str_to_string.rs @@ -0,0 +1,7 @@ +#![warn(clippy::str_to_string)] + +fn main() { + let hello = "hello world".to_string(); + let msg = &hello[..]; + msg.to_string(); +} diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr new file mode 100644 index 00000000000..b1f73eda5d2 --- /dev/null +++ b/tests/ui/str_to_string.stderr @@ -0,0 +1,19 @@ +error: `to_string()` called on a `&str` + --> $DIR/str_to_string.rs:4:17 + | +LL | let hello = "hello world".to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::str-to-string` implied by `-D warnings` + = help: consider using `.to_owned()` + +error: `to_string()` called on a `&str` + --> $DIR/str_to_string.rs:6:5 + | +LL | msg.to_string(); + | ^^^^^^^^^^^^^^^ + | + = help: consider using `.to_owned()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/string_to_string.rs b/tests/ui/string_to_string.rs new file mode 100644 index 00000000000..4c66855f709 --- /dev/null +++ b/tests/ui/string_to_string.rs @@ -0,0 +1,7 @@ +#![warn(clippy::string_to_string)] +#![allow(clippy::redundant_clone)] + +fn main() { + let mut message = String::from("Hello"); + let mut v = message.to_string(); +} diff --git a/tests/ui/string_to_string.stderr b/tests/ui/string_to_string.stderr new file mode 100644 index 00000000000..1ebd17999bd --- /dev/null +++ b/tests/ui/string_to_string.stderr @@ -0,0 +1,11 @@ +error: `to_string()` called on a `String` + --> $DIR/string_to_string.rs:6:17 + | +LL | let mut v = message.to_string(); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::string-to-string` implied by `-D warnings` + = help: consider using `.clone()` + +error: aborting due to previous error + From 85a17b53343b27ea1470243e4c01844a2997e860 Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Wed, 25 Nov 2020 21:16:44 +0530 Subject: [PATCH 075/274] update README.md for specifying msrv --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 1da626b505d..080e8874427 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,30 @@ lints can be configured and the meaning of the variables. To deactivate the “for further information visit *lint-link*” message you can define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable. +### Specifying the minimum supported Rust version + +Projects that intend to support old versions of Rust can disable lints pertaining to newer features by +specifying the minimum supported Rust version (msrv) in the clippy configuration file. + +```toml +msrv = "1.30.0" +``` + +The msrv can also be specified as an inner attribute, like below. + +```rust +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.30.0"] + +fn main() { + ... +} +``` + +Tilde/Caret version requirements(like `^1.0` or `~1.2`) can be specified as well. + +Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. + ### Allowing/denying lints You can add options to your code to `allow`/`warn`/`deny` Clippy lints: From 94a6832f0bc6ec2d1de0f71e39332eca408551da Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Wed, 25 Nov 2020 22:09:50 +0530 Subject: [PATCH 076/274] update README.md --- README.md | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 080e8874427..e5cff0cc621 100644 --- a/README.md +++ b/README.md @@ -147,30 +147,6 @@ lints can be configured and the meaning of the variables. To deactivate the “for further information visit *lint-link*” message you can define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable. -### Specifying the minimum supported Rust version - -Projects that intend to support old versions of Rust can disable lints pertaining to newer features by -specifying the minimum supported Rust version (msrv) in the clippy configuration file. - -```toml -msrv = "1.30.0" -``` - -The msrv can also be specified as an inner attribute, like below. - -```rust -#![feature(custom_inner_attributes)] -#![clippy::msrv = "1.30.0"] - -fn main() { - ... -} -``` - -Tilde/Caret version requirements(like `^1.0` or `~1.2`) can be specified as well. - -Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. - ### Allowing/denying lints You can add options to your code to `allow`/`warn`/`deny` Clippy lints: @@ -218,6 +194,32 @@ cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... ``` Note that if you've run clippy before, this may only take effect after you've modified a file or ran `cargo clean`. +### Specifying the minimum supported Rust version + +Projects that intend to support old versions of Rust can disable lints pertaining to newer features by +specifying the minimum supported Rust version (MSRV) in the clippy configuration file. + +```toml +msrv = "1.30.0" +``` + +The MSRV can also be specified as an inner attribute, like below. + +```rust +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.30.0"] + +fn main() { + ... +} +``` + +Tilde/Caret version requirements(like `^1.0` or `~1.2`) can be specified as well. + +Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. + +Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv) + ## Contributing If you want to contribute to Clippy, you can find more information in [CONTRIBUTING.md](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md). From b2eb55b03ecd54595260320f4f08263033f813d1 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 25 Nov 2020 20:37:32 +0100 Subject: [PATCH 077/274] Fix formatting in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e5cff0cc621..35683e87133 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,7 @@ fn main() { } ``` -Tilde/Caret version requirements(like `^1.0` or `~1.2`) can be specified as well. +Tilde/Caret version requirements (like `^1.0` or `~1.2`) can be specified as well. Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. From 3b53de6b36081646315c0721638c4318c28b6982 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 21 Nov 2020 21:08:32 -0300 Subject: [PATCH 078/274] Fix rust-lang/rust#79255 - Incorrect try suggestion for unnecessary float literal cast ending in dot --- clippy_lints/src/types.rs | 2 +- tests/ui/unnecessary_cast_fixable.fixed | 2 ++ tests/ui/unnecessary_cast_fixable.rs | 2 ++ tests/ui/unnecessary_cast_fixable.stderr | 32 ++++++++++++++++-------- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index f0e10e374e1..f3cad66cbf3 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -1711,7 +1711,7 @@ fn show_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &st expr.span, &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to), "try", - format!("{}_{}", literal_str, cast_to), + format!("{}_{}", literal_str.trim_end_matches('.'), cast_to), Applicability::MachineApplicable, ); } diff --git a/tests/ui/unnecessary_cast_fixable.fixed b/tests/ui/unnecessary_cast_fixable.fixed index 350da4965d1..7fbce58a82f 100644 --- a/tests/ui/unnecessary_cast_fixable.fixed +++ b/tests/ui/unnecessary_cast_fixable.fixed @@ -11,6 +11,8 @@ fn main() { let _ = -100_f32; let _ = -100_f64; let _ = -100_f64; + 100_f32; + 100_f64; // Should not trigger #[rustfmt::skip] let v = vec!(1); diff --git a/tests/ui/unnecessary_cast_fixable.rs b/tests/ui/unnecessary_cast_fixable.rs index ad2fb2e6289..a71363ea4d2 100644 --- a/tests/ui/unnecessary_cast_fixable.rs +++ b/tests/ui/unnecessary_cast_fixable.rs @@ -11,6 +11,8 @@ fn main() { let _ = -100 as f32; let _ = -100 as f64; let _ = -100_i32 as f64; + 100. as f32; + 100. as f64; // Should not trigger #[rustfmt::skip] let v = vec!(1); diff --git a/tests/ui/unnecessary_cast_fixable.stderr b/tests/ui/unnecessary_cast_fixable.stderr index 5a210fc8909..3695a8f819c 100644 --- a/tests/ui/unnecessary_cast_fixable.stderr +++ b/tests/ui/unnecessary_cast_fixable.stderr @@ -36,59 +36,71 @@ error: casting integer literal to `f64` is unnecessary LL | let _ = -100_i32 as f64; | ^^^^^^^^^^^^^^^ help: try: `-100_f64` +error: casting float literal to `f32` is unnecessary + --> $DIR/unnecessary_cast_fixable.rs:14:5 + | +LL | 100. as f32; + | ^^^^^^^^^^^ help: try: `100_f32` + +error: casting float literal to `f64` is unnecessary + --> $DIR/unnecessary_cast_fixable.rs:15:5 + | +LL | 100. as f64; + | ^^^^^^^^^^^ help: try: `100_f64` + error: casting integer literal to `u32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:25:5 + --> $DIR/unnecessary_cast_fixable.rs:27:5 | LL | 1 as u32; | ^^^^^^^^ help: try: `1_u32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:26:5 + --> $DIR/unnecessary_cast_fixable.rs:28:5 | LL | 0x10 as i32; | ^^^^^^^^^^^ help: try: `0x10_i32` error: casting integer literal to `usize` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:27:5 + --> $DIR/unnecessary_cast_fixable.rs:29:5 | LL | 0b10 as usize; | ^^^^^^^^^^^^^ help: try: `0b10_usize` error: casting integer literal to `u16` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:28:5 + --> $DIR/unnecessary_cast_fixable.rs:30:5 | LL | 0o73 as u16; | ^^^^^^^^^^^ help: try: `0o73_u16` error: casting integer literal to `u32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:29:5 + --> $DIR/unnecessary_cast_fixable.rs:31:5 | LL | 1_000_000_000 as u32; | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` error: casting float literal to `f64` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:31:5 + --> $DIR/unnecessary_cast_fixable.rs:33:5 | LL | 1.0 as f64; | ^^^^^^^^^^ help: try: `1.0_f64` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:32:5 + --> $DIR/unnecessary_cast_fixable.rs:34:5 | LL | 0.5 as f32; | ^^^^^^^^^^ help: try: `0.5_f32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:36:13 + --> $DIR/unnecessary_cast_fixable.rs:38:13 | LL | let _ = -1 as i32; | ^^^^^^^^^ help: try: `-1_i32` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast_fixable.rs:37:13 + --> $DIR/unnecessary_cast_fixable.rs:39:13 | LL | let _ = -1.0 as f32; | ^^^^^^^^^^^ help: try: `-1.0_f32` -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors From 3bcc75d4462f11ee31260aa45b74a144b83e575f Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 26 Nov 2020 10:01:02 +0100 Subject: [PATCH 079/274] Remove mention of possibility to specify the MSRV with a tilde/caret --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 35683e87133..3d7ad38ea6c 100644 --- a/README.md +++ b/README.md @@ -214,8 +214,6 @@ fn main() { } ``` -Tilde/Caret version requirements (like `^1.0` or `~1.2`) can be specified as well. - Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv) From 6eb2c27bcc8760949280f266a52dcc6bb3ca6955 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 26 Nov 2020 10:15:00 +0100 Subject: [PATCH 080/274] Note that it is possible to omit the patch version --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d7ad38ea6c..fddf0614a0b 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ cargo clippy -- -W clippy::lint_name ``` This also works with lint groups. For example you -can run Clippy with warnings for all lints enabled: +can run Clippy with warnings for all lints enabled: ```terminal cargo clippy -- -W clippy::pedantic ``` @@ -214,6 +214,9 @@ fn main() { } ``` +You can also omit the patch version when specifying the MSRV, so `msrv = 1.30` +is equivalent to `msrv = 1.30.0`. + Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv) From 8983752c12c65e598dff704502ad1b0334d1daaa Mon Sep 17 00:00:00 2001 From: LinkTed Date: Thu, 26 Nov 2020 18:54:13 +0100 Subject: [PATCH 081/274] Add comment for the previous android bug fix --- library/std/src/sys/unix/ext/net/ancillary.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs index a94456b4e7a..2c91ba70dd0 100644 --- a/library/std/src/sys/unix/ext/net/ancillary.rs +++ b/library/std/src/sys/unix/ext/net/ancillary.rs @@ -160,6 +160,8 @@ fn add_to_ancillary_data( previous_cmsg = cmsg; cmsg = libc::CMSG_NXTHDR(&msg, cmsg); cfg_if::cfg_if! { + // Android return the same pointer if it is the last cmsg. + // Therefore, check it if the previous pointer is the same as the current one. if #[cfg(target_os = "android")] { if cmsg == previous_cmsg { break; @@ -430,6 +432,8 @@ impl<'a> Iterator for Messages<'a> { let cmsg = cmsg.as_ref()?; cfg_if::cfg_if! { + // Android return the same pointer if it is the last cmsg. + // Therefore, check it if the previous pointer is the same as the current one. if #[cfg(target_os = "android")] { if let Some(current) = self.current { if eq(current, cmsg) { From cb6a654b75ca095aee9ebbe5cf05fc48df5b9b50 Mon Sep 17 00:00:00 2001 From: pro-grammer1 <1df0d0d3-eed4-45fc-bc60-43a85079f3f9@anonaddy.me> Date: Thu, 26 Nov 2020 20:07:50 +0000 Subject: [PATCH 082/274] Added known problem to comparison_chain docs --- clippy_lints/src/comparison_chain.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 99f161a0510..ae1143b2c50 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -12,7 +12,8 @@ declare_clippy_lint! { /// **Why is this bad?** `if` is not guaranteed to be exhaustive and conditionals can get /// repetitive /// - /// **Known problems:** None. + /// **Known problems:** The match statement may be slower due to the compiler + /// not inlining the call to cmp. See issue #5354 /// /// **Example:** /// ```rust,ignore From d95f11bcd68925eae83c81579bd8cc85e2420594 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 11 Nov 2020 22:40:09 +0100 Subject: [PATCH 083/274] Remove ForeignMod struct. --- clippy_lints/src/missing_doc.rs | 2 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/utils/inspector.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 009e3d8937e..4678f6872f3 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -147,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { hir::ItemKind::Union(..) => "a union", hir::ItemKind::OpaqueTy(..) => "an existential type", hir::ItemKind::ExternCrate(..) - | hir::ItemKind::ForeignMod(..) + | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) | hir::ItemKind::Impl { .. } | hir::ItemKind::Use(..) => return, diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 53abe6086ea..913d9daff46 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { | hir::ItemKind::Union(..) | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::ForeignMod(..) + | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Impl { .. } | hir::ItemKind::Use(..) => {}, }; diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 4fbfb3be32c..8f0ef9150d4 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -395,7 +395,7 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { println!("function of type {:#?}", item_ty); }, hir::ItemKind::Mod(..) => println!("module"), - hir::ItemKind::ForeignMod(ref fm) => println!("foreign module with abi: {}", fm.abi), + hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi), hir::ItemKind::GlobalAsm(ref asm) => println!("global asm: {:?}", asm), hir::ItemKind::TyAlias(..) => { println!("type alias for {:?}", cx.tcx.type_of(did)); From e91d15f42d761c1a2f161a2b65deee06a7f472ab Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Fri, 27 Nov 2020 10:32:44 +0900 Subject: [PATCH 084/274] cargo dev fmt --- clippy_lints/src/attrs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 15505fd79f4..3edbe723922 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -5,7 +5,6 @@ use crate::utils::{ span_lint_and_sugg, span_lint_and_then, without_block_comments, }; use if_chain::if_chain; -use rustc_span::lev_distance::find_best_match_for_name; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; use rustc_hir::{ @@ -15,6 +14,7 @@ use rustc_lint::{CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::Span; use rustc_span::sym; use rustc_span::symbol::{Symbol, SymbolStr}; From 82a7068007a1490b43a2eb4e70e0f70de384a9ae Mon Sep 17 00:00:00 2001 From: Markus Legner Date: Sat, 21 Nov 2020 12:28:53 +0100 Subject: [PATCH 085/274] Trigger modulo_one lint also on -1. --- clippy_lints/src/misc.rs | 30 ++++++++++++++------- tests/ui/modulo_one.rs | 11 +++++++- tests/ui/modulo_one.stderr | 54 ++++++++++++++++++++++++++++++++++---- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 308e92057b7..f16feb9b1ba 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -18,7 +18,7 @@ use crate::utils::sugg::Sugg; use crate::utils::{ get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, span_lint_hir_and_then, SpanlessEq, + span_lint_and_then, span_lint_hir_and_then, SpanlessEq, unsext, }; declare_clippy_lint! { @@ -139,12 +139,14 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for getting the remainder of a division by one. + /// **What it does:** Checks for getting the remainder of a division by one or minus + /// one. /// - /// **Why is this bad?** The result can only ever be zero. No one will write - /// such code deliberately, unless trying to win an Underhanded Rust - /// Contest. Even for that contest, it's probably a bad idea. Use something more - /// underhanded. + /// **Why is this bad?** The result for a divisor of one can only ever be zero; for + /// minus one it can cause panic/overflow (if the left operand is the minimal value of + /// the respective integer type) or results in zero. No one will write such code + /// deliberately, unless trying to win an Underhanded Rust Contest. Even for that + /// contest, it's probably a bad idea. Use something more underhanded. /// /// **Known problems:** None. /// @@ -152,10 +154,11 @@ declare_clippy_lint! { /// ```rust /// # let x = 1; /// let a = x % 1; + /// let a = x % -1; /// ``` pub MODULO_ONE, correctness, - "taking a number modulo 1, which always returns 0" + "taking a number modulo +/-1, which can either panic/overflow or always returns 0" } declare_clippy_lint! { @@ -429,8 +432,17 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { } diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); }); - } else if op == BinOpKind::Rem && is_integer_const(cx, right, 1) { - span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); + } else if op == BinOpKind::Rem { + if is_integer_const(cx, right, 1) { + span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); + } + + if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() { + if is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) { + span_lint(cx, MODULO_ONE, expr.span, + "any number modulo -1 will panic/overflow or result in 0"); + } + }; } }, _ => {}, diff --git a/tests/ui/modulo_one.rs b/tests/ui/modulo_one.rs index cc8c8e7cdae..678a312f66e 100644 --- a/tests/ui/modulo_one.rs +++ b/tests/ui/modulo_one.rs @@ -2,13 +2,22 @@ #![allow(clippy::no_effect, clippy::unnecessary_operation)] static STATIC_ONE: usize = 2 - 1; +static STATIC_NEG_ONE: i64 = 1 - 2; fn main() { 10 % 1; + 10 % -1; 10 % 2; + i32::MIN % (-1); // also caught by rustc const ONE: u32 = 1 * 1; + const NEG_ONE: i64 = 1 - 2; + const INT_MIN: i64 = i64::MIN; 2 % ONE; - 5 % STATIC_ONE; + 5 % STATIC_ONE; // NOT caught by lint + 2 % NEG_ONE; + 5 % STATIC_NEG_ONE; // NOT caught by lint + INT_MIN % NEG_ONE; // also caught by rustc + INT_MIN % STATIC_NEG_ONE; // ONLY caught by rustc } diff --git a/tests/ui/modulo_one.stderr b/tests/ui/modulo_one.stderr index 6bee68360b6..2b2c6997338 100644 --- a/tests/ui/modulo_one.stderr +++ b/tests/ui/modulo_one.stderr @@ -1,13 +1,45 @@ +error: this arithmetic operation will overflow + --> $DIR/modulo_one.rs:11:5 + | +LL | i32::MIN % (-1); // also caught by rustc + | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/modulo_one.rs:21:5 + | +LL | INT_MIN % NEG_ONE; // also caught by rustc + | ^^^^^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/modulo_one.rs:22:5 + | +LL | INT_MIN % STATIC_NEG_ONE; // ONLY caught by rustc + | ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow + error: any number modulo 1 will be 0 - --> $DIR/modulo_one.rs:7:5 + --> $DIR/modulo_one.rs:8:5 | LL | 10 % 1; | ^^^^^^ | = note: `-D clippy::modulo-one` implied by `-D warnings` +error: any number modulo -1 will panic/overflow or result in 0 + --> $DIR/modulo_one.rs:9:5 + | +LL | 10 % -1; + | ^^^^^^^ + +error: any number modulo -1 will panic/overflow or result in 0 + --> $DIR/modulo_one.rs:11:5 + | +LL | i32::MIN % (-1); // also caught by rustc + | ^^^^^^^^^^^^^^^ + error: the operation is ineffective. Consider reducing it to `1` - --> $DIR/modulo_one.rs:10:22 + --> $DIR/modulo_one.rs:13:22 | LL | const ONE: u32 = 1 * 1; | ^^^^^ @@ -15,16 +47,28 @@ LL | const ONE: u32 = 1 * 1; = note: `-D clippy::identity-op` implied by `-D warnings` error: the operation is ineffective. Consider reducing it to `1` - --> $DIR/modulo_one.rs:10:22 + --> $DIR/modulo_one.rs:13:22 | LL | const ONE: u32 = 1 * 1; | ^^^^^ error: any number modulo 1 will be 0 - --> $DIR/modulo_one.rs:12:5 + --> $DIR/modulo_one.rs:17:5 | LL | 2 % ONE; | ^^^^^^^ -error: aborting due to 4 previous errors +error: any number modulo -1 will panic/overflow or result in 0 + --> $DIR/modulo_one.rs:19:5 + | +LL | 2 % NEG_ONE; + | ^^^^^^^^^^^ + +error: any number modulo -1 will panic/overflow or result in 0 + --> $DIR/modulo_one.rs:21:5 + | +LL | INT_MIN % NEG_ONE; // also caught by rustc + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors From e42a18f02a45ffc12016a71bb4a210aa62af9a24 Mon Sep 17 00:00:00 2001 From: Markus Legner Date: Sat, 21 Nov 2020 12:38:21 +0100 Subject: [PATCH 086/274] Run `cargo dev fmt`. --- clippy_lints/src/misc.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index f16feb9b1ba..b527b2cc1cb 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -18,7 +18,7 @@ use crate::utils::sugg::Sugg; use crate::utils::{ get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, span_lint_hir_and_then, SpanlessEq, unsext, + span_lint_and_then, span_lint_hir_and_then, unsext, SpanlessEq, }; declare_clippy_lint! { @@ -439,8 +439,12 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() { if is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) { - span_lint(cx, MODULO_ONE, expr.span, - "any number modulo -1 will panic/overflow or result in 0"); + span_lint( + cx, + MODULO_ONE, + expr.span, + "any number modulo -1 will panic/overflow or result in 0", + ); } }; } From b8226320735bc8e3f699cc177be638433ed396d9 Mon Sep 17 00:00:00 2001 From: Markus Legner Date: Mon, 23 Nov 2020 10:18:27 +0100 Subject: [PATCH 087/274] Factor out `check_binary` from function `check_expr`. --- clippy_lints/src/misc.rs | 140 ++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 67 deletions(-) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index b527b2cc1cb..0512d74c7b1 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -381,73 +381,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { return; }, ExprKind::Binary(ref cmp, ref left, ref right) => { - let op = cmp.node; - if op.is_comparison() { - check_nan(cx, left, expr); - check_nan(cx, right, expr); - check_to_owned(cx, left, right, true); - check_to_owned(cx, right, left, false); - } - if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { - if is_allowed(cx, left) || is_allowed(cx, right) { - return; - } - - // Allow comparing the results of signum() - if is_signum(cx, left) && is_signum(cx, right) { - return; - } - - if let Some(name) = get_item_name(cx, expr) { - let name = name.as_str(); - if name == "eq" - || name == "ne" - || name == "is_nan" - || name.starts_with("eq_") - || name.ends_with("_eq") - { - return; - } - } - let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); - let (lint, msg) = get_lint_and_message( - is_named_constant(cx, left) || is_named_constant(cx, right), - is_comparing_arrays, - ); - span_lint_and_then(cx, lint, expr.span, msg, |diag| { - let lhs = Sugg::hir(cx, left, ".."); - let rhs = Sugg::hir(cx, right, ".."); - - if !is_comparing_arrays { - diag.span_suggestion( - expr.span, - "consider comparing them within some margin of error", - format!( - "({}).abs() {} error_margin", - lhs - rhs, - if op == BinOpKind::Eq { '<' } else { '>' } - ), - Applicability::HasPlaceholders, // snippet - ); - } - diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); - }); - } else if op == BinOpKind::Rem { - if is_integer_const(cx, right, 1) { - span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); - } - - if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() { - if is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) { - span_lint( - cx, - MODULO_ONE, - expr.span, - "any number modulo -1 will panic/overflow or result in 0", - ); - } - }; - } + check_binary(cx, expr, cmp, left, right); + return; }, _ => {}, } @@ -760,3 +695,74 @@ fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) } } } + +fn check_binary( + cx: &LateContext<'a>, + expr: &Expr<'_>, + cmp: &rustc_span::source_map::Spanned, + left: &'a Expr<'_>, + right: &'a Expr<'_>, +) { + let op = cmp.node; + if op.is_comparison() { + check_nan(cx, left, expr); + check_nan(cx, right, expr); + check_to_owned(cx, left, right, true); + check_to_owned(cx, right, left, false); + } + if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { + if is_allowed(cx, left) || is_allowed(cx, right) { + return; + } + + // Allow comparing the results of signum() + if is_signum(cx, left) && is_signum(cx, right) { + return; + } + + if let Some(name) = get_item_name(cx, expr) { + let name = name.as_str(); + if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") { + return; + } + } + let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); + let (lint, msg) = get_lint_and_message( + is_named_constant(cx, left) || is_named_constant(cx, right), + is_comparing_arrays, + ); + span_lint_and_then(cx, lint, expr.span, msg, |diag| { + let lhs = Sugg::hir(cx, left, ".."); + let rhs = Sugg::hir(cx, right, ".."); + + if !is_comparing_arrays { + diag.span_suggestion( + expr.span, + "consider comparing them within some margin of error", + format!( + "({}).abs() {} error_margin", + lhs - rhs, + if op == BinOpKind::Eq { '<' } else { '>' } + ), + Applicability::HasPlaceholders, // snippet + ); + } + diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`"); + }); + } else if op == BinOpKind::Rem { + if is_integer_const(cx, right, 1) { + span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0"); + } + + if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() { + if is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) { + span_lint( + cx, + MODULO_ONE, + expr.span, + "any number modulo -1 will panic/overflow or result in 0", + ); + } + }; + } +} From af1cc5c91131e0ec30f0f34691a5e635350295a1 Mon Sep 17 00:00:00 2001 From: Ryan1729 Date: Sat, 7 Nov 2020 16:00:42 -0700 Subject: [PATCH 088/274] add suspicious_operation_groupings lint run `cargo dev new_lint --category correctness --name suspicious_chained_operators --pass early` add (currently failing) tests for suspicious_chained_operators add some tests to answer a question that came up during implementation write usage code for functions we'll need to find or create Complete left-right tracking TODO get it compiling with several `todo!` invocations. refactor to a set of incomplete functions that don't expect to be able to edit a `Span` create placeholder for `suggestion_with_swapped_ident` function and correct some comments add `inside_larger_boolean_expression` test fill out `get_ident` and `suggestion_with_swapped_ident` Implementi the `IdentIter` start on implementing the `IdentIter` handle the `ExprKind::Path` case in `IdentIter` on second thought, make the iterator type dynamic so we don't need an explicit type for each one we will need handle `ExprKind::MacCall` in `IdentIter` Try handling `box x` expressions restructure `IdentIter` set `self.done` when returning `None` Handle `ExprKind::Array` reduce duplication with a macro that we expect to use several more times handle ExprKind::Call add `new_p` convenience method handle `MethodCall` handle `Tup` and `Binary` handle `Unary` simplify by not returning an additional `Expr` from the `IdentIter` add cross product test against false positives rename suspicious_chained_operators to suspicious_operation_groupings within files For the record, the exact commands run were: find . -type f -name "*.md" -exec sed -i 's/suspicious_chained_operators/suspicious_operation_groupings/g' {} + find . -type f -name "*.rs" -exec sed -i 's/suspicious_chained_operators/suspicious_operation_groupings/g' {} + find . -type f -name "*.rs" -exec sed -i 's/SUSPICIOUS_CHAINED_OPERATORS/SUSPICIOUS_OPERATION_GROUPINGS/g' {} + find . -type f -name "*.rs" -exec sed -i 's/SuspiciousChainedOperators/SuspiciousOperationGroupings/g' {} + Also: rename file to match module name rename test file to match lint name start implementing `IdentDifference` creation add `IdentIter` utility use `ident_iter::IdentIter` fix bug in `suggestion_with_swapped_ident` add `inside_if_statements` test implement `Add` `todo`s register `SuspiciousOperationGroupings` lint pass fill in `chained_binops`, and fill in a stopgap version of `ident_difference_expr`, but then notice that the lint does not seem to ever be run in the tests run `cargo dev update_lints` and not that the `suspicious_operation_groupings` lint still does not seem to be run fix base index incrementing bug fix paired_identifiers bug, and remove ident from `Single` change help prefix and note our first successful lint messages! add odd_number_of_pairs test get the `non_boolean_operators` test passing, with two copies of the error message extract `is_useless_with_eq_exprs` so we can know when `eq_op` will already handle something add `not_caught_by_eq_op` tests since `s1.b * s1.b` was (reasonably) not caught by `eq_op` cover the case where the change should be made on either side of the expression with `not_caught_by_eq_op` tests produce the expected suggestion on the `not_caught_by_eq_op_middle_change_left` test confirm that the previous tests still pass and update references fix early continue bug and get `not_caught_by_eq_op_middle_change_right` passing note that `not_caught_by_eq_op_start` already passes fix bugs based on misunderstanding of what `Iterator::skip` does, and note that `not_caught_by_eq_op_end` now passes add several parens tests and make some of them pass handle parens inside `chained_binops_helper` and note that this makes several tests pass get `inside_larger_boolean_expression_with_unsorted_ops` test passing by extracting out `check_same_op_binops` function also run `cargo dev fmt` note that `inside_function_call` already passes add another `if_statement` test remove the matching op requirement, making `inside_larger_boolean_expression_with_unsorted_ops` pass prevent non-change suggestions from being emitted get the `Nested` tests passing, and remove apparently false note about eq_op add a test to justify comment in `ident_difference_expr_with_base_location` but find that the failure mode seems different than expected complete `todo` making `do_not_give_bad_suggestions_for_this_unusual_expr` pass and add some more tests that already pass add test to `eq_op` note that `inside_fn_with_similar_expression` already passes fix `inside_an_if_statement` and note that it already passes attempt to implement if statement extraction and notice that we don't seem to handle unary ops correctly add `maximum_unary_minus_right_tree` test and make it pass add two tests and note one of them passes filter out unary operations in several places, and find that the issue seems to be that we don't currently recognize the error in `multiple_comparison_types_and_unary_minus` even so. remove filtering that was causing bad suggestions remove tests that were deemed too much for now run `cargo dev fmt` correct eq_op post-merge fill out the description and delete debugging code run `cargo dev update_lints` update eq_op references add parens to work around rustfmt issue #3666 and run rustfmt https://github.com/rust-lang/rustfmt/issues/3666#issuecomment-714612257 update references after formatting fix dogfood issues fix multi-cursor edit fix missed dogfood error fix more dogfood pedantic issues, including function length even more nesting insert hidden definition of Vec3 so docs compile add spaces to second struct def reword test description comment Co-authored-by: llogiq add local `use BinOpKind::*;` Apply suggestions from code review Co-authored-by: llogiq switch `SUSPICIOUS_OPERATION_GROUPINGS` to a style lint run `cargo dev update_lints` put both usages of `op_types` in the same closure to satisfy `borrowck` fix compile error --- CHANGELOG.md | 1 + clippy_lints/src/eq_op.rs | 27 +- clippy_lints/src/lib.rs | 5 + .../src/suspicious_operation_groupings.rs | 693 ++++++++++++++++++ clippy_lints/src/utils/ast_utils.rs | 11 + .../src/utils/ast_utils/ident_iter.rs | 45 ++ tests/ui/eq_op.rs | 9 + tests/ui/eq_op.stderr | 10 +- tests/ui/suspicious_operation_groupings.rs | 207 ++++++ .../ui/suspicious_operation_groupings.stderr | 166 +++++ 10 files changed, 1150 insertions(+), 24 deletions(-) create mode 100644 clippy_lints/src/suspicious_operation_groupings.rs create mode 100644 clippy_lints/src/utils/ast_utils/ident_iter.rs create mode 100644 tests/ui/suspicious_operation_groupings.rs create mode 100644 tests/ui/suspicious_operation_groupings.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e4b0e6704..e76a781f13b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2073,6 +2073,7 @@ Released 2018-09-13 [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl +[`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 3201adbf9a0..6308f6e2e7e 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,10 +1,10 @@ use crate::utils::{ - eq_expr_value, higher, implements_trait, in_macro, is_copy, is_expn_of, multispan_sugg, snippet, span_lint, - span_lint_and_then, + ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, implements_trait, in_macro, is_copy, is_expn_of, + multispan_sugg, snippet, span_lint, span_lint_and_then, }; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) { return; } - if is_valid_operator(op) && eq_expr_value(cx, left, right) { + if is_useless_with_eq_exprs(higher::binop(op.node)) && eq_expr_value(cx, left, right) { span_lint( cx, EQ_OP, @@ -245,22 +245,3 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } } } - -fn is_valid_operator(op: BinOp) -> bool { - matches!( - op.node, - BinOpKind::Sub - | BinOpKind::Div - | BinOpKind::Eq - | BinOpKind::Lt - | BinOpKind::Le - | BinOpKind::Gt - | BinOpKind::Ge - | BinOpKind::Ne - | BinOpKind::And - | BinOpKind::Or - | BinOpKind::BitXor - | BinOpKind::BitAnd - | BinOpKind::BitOr - ) -} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 67a3a3fcf48..6eb5f6a7f48 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -308,6 +308,7 @@ mod single_component_path_imports; mod slow_vector_initialization; mod stable_sort_primitive; mod strings; +mod suspicious_operation_groupings; mod suspicious_trait_impl; mod swap; mod tabs_in_doc_comments; @@ -834,6 +835,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &strings::STRING_LIT_AS_BYTES, &strings::STRING_TO_STRING, &strings::STR_TO_STRING, + &suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS, &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, &swap::ALMOST_SWAPPED, @@ -1066,6 +1068,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box types::UnitArg); store.register_late_pass(|| box double_comparison::DoubleComparisons); store.register_late_pass(|| box question_mark::QuestionMark); + store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings); store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl); store.register_late_pass(|| box map_unit_fn::MapUnit); store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default()); @@ -1547,6 +1550,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), + LintId::of(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), @@ -1698,6 +1702,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(&suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME), LintId::of(&try_err::TRY_ERR), diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs new file mode 100644 index 00000000000..cccd24ccf94 --- /dev/null +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -0,0 +1,693 @@ +use crate::utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter}; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; +use core::ops::{Add, AddAssign}; +use if_chain::if_chain; +use rustc_ast::ast::{BinOpKind, Expr, ExprKind, StmtKind}; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; +use rustc_span::symbol::Ident; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** + /// Checks for unlikely usages of binary operators that are almost + /// certainly typos and/or copy/paste errors, given the other usages + /// of binary operators nearby. + /// **Why is this bad?** + /// They are probably bugs and if they aren't then they look like bugs + /// and you should add a comment explaining why you are doing such an + /// odd set of operations. + /// **Known problems:** + /// There may be some false positives if you are trying to do something + /// unusual that happens to look like a typo. + /// + /// **Example:** + /// + /// ```rust + /// struct Vec3 { + /// x: f64, + /// y: f64, + /// z: f64, + /// } + /// + /// impl Eq for Vec3 {} + /// + /// impl PartialEq for Vec3 { + /// fn eq(&self, other: &Self) -> bool { + /// // This should trigger the lint because `self.x` is compared to `other.y` + /// self.x == other.y && self.y == other.y && self.z == other.z + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// # struct Vec3 { + /// # x: f64, + /// # y: f64, + /// # z: f64, + /// # } + /// // same as above except: + /// impl PartialEq for Vec3 { + /// fn eq(&self, other: &Self) -> bool { + /// // Note we now compare other.x to self.x + /// self.x == other.x && self.y == other.y && self.z == other.z + /// } + /// } + /// ``` + pub SUSPICIOUS_OPERATION_GROUPINGS, + style, + "groupings of binary operations that look suspiciously like typos" +} + +declare_lint_pass!(SuspiciousOperationGroupings => [SUSPICIOUS_OPERATION_GROUPINGS]); + +impl EarlyLintPass for SuspiciousOperationGroupings { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if expr.span.from_expansion() { + return; + } + + if let Some(binops) = extract_related_binops(&expr.kind) { + check_binops(cx, &binops.iter().collect::>()); + + let mut op_types = Vec::with_capacity(binops.len()); + // We could use a hashmap, etc. to avoid being O(n*m) here, but + // we want the lints to be emitted in a consistent order. Besides, + // m, (the number of distinct `BinOpKind`s in `binops`) + // will often be small, and does have an upper limit. + binops.iter().map(|b| b.op).for_each(|op| { + if !op_types.contains(&op) { + op_types.push(op); + } + }); + + for op_type in op_types { + let ops: Vec<_> = binops.iter().filter(|b| b.op == op_type).collect(); + + check_binops(cx, &ops); + } + } + } +} + +fn check_binops(cx: &EarlyContext<'_>, binops: &[&BinaryOp<'_>]) { + let binop_count = binops.len(); + if binop_count < 2 { + // Single binary operation expressions would likely be false + // positives. + return; + } + + let mut one_ident_difference_count = 0; + let mut no_difference_info = None; + let mut double_difference_info = None; + let mut expected_ident_loc = None; + + let mut paired_identifiers = FxHashSet::default(); + + for (i, BinaryOp { left, right, op, .. }) in binops.iter().enumerate() { + match ident_difference_expr(left, right) { + IdentDifference::NoDifference => { + if is_useless_with_eq_exprs(*op) { + // The `eq_op` lint should catch this in this case. + return; + } + + no_difference_info = Some(i); + }, + IdentDifference::Single(ident_loc) => { + one_ident_difference_count += 1; + if let Some(previous_expected) = expected_ident_loc { + if previous_expected != ident_loc { + // This expression doesn't match the form we're + // looking for. + return; + } + } else { + expected_ident_loc = Some(ident_loc); + } + + // If there was only a single difference, all other idents + // must have been the same, and thus were paired. + for id in skip_index(IdentIter::from(*left), ident_loc.index) { + paired_identifiers.insert(id); + } + }, + IdentDifference::Double(ident_loc1, ident_loc2) => { + double_difference_info = Some((i, ident_loc1, ident_loc2)); + }, + IdentDifference::Multiple | IdentDifference::NonIdent => { + // It's too hard to know whether this is a bug or not. + return; + }, + } + } + + let mut applicability = Applicability::MachineApplicable; + + if let Some(expected_loc) = expected_ident_loc { + match (no_difference_info, double_difference_info) { + (Some(i), None) => attempt_to_emit_no_difference_lint(cx, binops, i, expected_loc), + (None, Some((double_difference_index, ident_loc1, ident_loc2))) => { + if_chain! { + if one_ident_difference_count == binop_count - 1; + if let Some(binop) = binops.get(double_difference_index); + then { + let changed_loc = if ident_loc1 == expected_loc { + ident_loc2 + } else if ident_loc2 == expected_loc { + ident_loc1 + } else { + // This expression doesn't match the form we're + // looking for. + return; + }; + + if let Some(sugg) = ident_swap_sugg( + cx, + &paired_identifiers, + binop, + changed_loc, + &mut applicability, + ) { + emit_suggestion( + cx, + binop.span, + sugg, + applicability, + ); + } + } + } + }, + _ => {}, + } + } +} + +fn attempt_to_emit_no_difference_lint( + cx: &EarlyContext<'_>, + binops: &[&BinaryOp<'_>], + i: usize, + expected_loc: IdentLocation, +) { + if let Some(binop) = binops.get(i).cloned() { + // We need to try and figure out which identifier we should + // suggest using instead. Since there could be multiple + // replacement candidates in a given expression, and we're + // just taking the first one, we may get some bad lint + // messages. + let mut applicability = Applicability::MaybeIncorrect; + + // We assume that the correct ident is one used elsewhere in + // the other binops, in a place that there was a single + // difference between idents before. + let old_left_ident = get_ident(binop.left, expected_loc); + let old_right_ident = get_ident(binop.right, expected_loc); + + for b in skip_index(binops.iter(), i) { + if_chain! { + if let (Some(old_ident), Some(new_ident)) = + (old_left_ident, get_ident(b.left, expected_loc)); + if old_ident != new_ident; + if let Some(sugg) = suggestion_with_swapped_ident( + cx, + binop.left, + expected_loc, + new_ident, + &mut applicability, + ); + then { + emit_suggestion( + cx, + binop.span, + replace_left_sugg(cx, &binop, &sugg, &mut applicability), + applicability, + ); + return; + } + } + + if_chain! { + if let (Some(old_ident), Some(new_ident)) = + (old_right_ident, get_ident(b.right, expected_loc)); + if old_ident != new_ident; + if let Some(sugg) = suggestion_with_swapped_ident( + cx, + binop.right, + expected_loc, + new_ident, + &mut applicability, + ); + then { + emit_suggestion( + cx, + binop.span, + replace_right_sugg(cx, &binop, &sugg, &mut applicability), + applicability, + ); + return; + } + } + } + } +} + +fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicability: Applicability) { + span_lint_and_sugg( + cx, + SUSPICIOUS_OPERATION_GROUPINGS, + span, + "This sequence of operators looks suspiciously like a bug.", + "I think you meant", + sugg, + applicability, + ) +} + +fn ident_swap_sugg( + cx: &EarlyContext<'_>, + paired_identifiers: &FxHashSet, + binop: &BinaryOp<'_>, + location: IdentLocation, + applicability: &mut Applicability, +) -> Option { + let left_ident = get_ident(&binop.left, location)?; + let right_ident = get_ident(&binop.right, location)?; + + let sugg = match ( + paired_identifiers.contains(&left_ident), + paired_identifiers.contains(&right_ident), + ) { + (true, true) | (false, false) => { + // We don't have a good guess of what ident should be + // used instead, in these cases. + *applicability = Applicability::MaybeIncorrect; + + // We arbitraily choose one side to suggest changing, + // since we don't have a better guess. If the user + // ends up duplicating a clause, the `logic_bug` lint + // should catch it. + + let right_suggestion = + suggestion_with_swapped_ident(cx, &binop.right, location, left_ident, applicability)?; + + replace_right_sugg(cx, binop, &right_suggestion, applicability) + }, + (false, true) => { + // We haven't seen a pair involving the left one, so + // it's probably what is wanted. + + let right_suggestion = + suggestion_with_swapped_ident(cx, &binop.right, location, left_ident, applicability)?; + + replace_right_sugg(cx, binop, &right_suggestion, applicability) + }, + (true, false) => { + // We haven't seen a pair involving the right one, so + // it's probably what is wanted. + let left_suggestion = suggestion_with_swapped_ident(cx, &binop.left, location, right_ident, applicability)?; + + replace_left_sugg(cx, binop, &left_suggestion, applicability) + }, + }; + + Some(sugg) +} + +fn replace_left_sugg( + cx: &EarlyContext<'_>, + binop: &BinaryOp<'_>, + left_suggestion: &str, + applicability: &mut Applicability, +) -> String { + format!( + "{} {} {}", + left_suggestion, + binop.op.to_string(), + snippet_with_applicability(cx, binop.right.span, "..", applicability), + ) +} + +fn replace_right_sugg( + cx: &EarlyContext<'_>, + binop: &BinaryOp<'_>, + right_suggestion: &str, + applicability: &mut Applicability, +) -> String { + format!( + "{} {} {}", + snippet_with_applicability(cx, binop.left.span, "..", applicability), + binop.op.to_string(), + right_suggestion, + ) +} + +#[derive(Clone, Debug)] +struct BinaryOp<'exprs> { + op: BinOpKind, + span: Span, + left: &'exprs Expr, + right: &'exprs Expr, +} + +impl BinaryOp<'exprs> { + fn new(op: BinOpKind, span: Span, (left, right): (&'exprs Expr, &'exprs Expr)) -> Self { + Self { op, span, left, right } + } +} + +fn strip_non_ident_wrappers(expr: &Expr) -> &Expr { + let mut output = expr; + loop { + output = match &output.kind { + ExprKind::Paren(ref inner) | ExprKind::Unary(_, ref inner) => inner, + _ => { + return output; + }, + }; + } +} + +fn extract_related_binops(kind: &ExprKind) -> Option>> { + append_opt_vecs(chained_binops(kind), if_statment_binops(kind)) +} + +fn if_statment_binops(kind: &ExprKind) -> Option>> { + match kind { + ExprKind::If(ref condition, _, _) => chained_binops(&condition.kind), + ExprKind::Paren(ref e) => if_statment_binops(&e.kind), + ExprKind::Block(ref block, _) => { + let mut output = None; + for stmt in &block.stmts { + match stmt.kind { + StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => { + output = append_opt_vecs(output, if_statment_binops(&e.kind)); + }, + _ => {}, + } + } + output + }, + _ => None, + } +} + +fn append_opt_vecs(target_opt: Option>, source_opt: Option>) -> Option> { + match (target_opt, source_opt) { + (Some(mut target), Some(mut source)) => { + target.reserve(source.len()); + for op in source.drain(..) { + target.push(op); + } + Some(target) + }, + (Some(v), None) | (None, Some(v)) => Some(v), + (None, None) => None, + } +} + +fn chained_binops(kind: &ExprKind) -> Option>> { + match kind { + ExprKind::Binary(_, left_outer, right_outer) => chained_binops_helper(left_outer, right_outer), + ExprKind::Paren(ref e) | ExprKind::Unary(_, ref e) => chained_binops(&e.kind), + _ => None, + } +} + +fn chained_binops_helper(left_outer: &'expr Expr, right_outer: &'expr Expr) -> Option>> { + match (&left_outer.kind, &right_outer.kind) { + ( + ExprKind::Paren(ref left_e) | ExprKind::Unary(_, ref left_e), + ExprKind::Paren(ref right_e) | ExprKind::Unary(_, ref right_e), + ) => chained_binops_helper(left_e, right_e), + (ExprKind::Paren(ref left_e) | ExprKind::Unary(_, ref left_e), _) => chained_binops_helper(left_e, right_outer), + (_, ExprKind::Paren(ref right_e) | ExprKind::Unary(_, ref right_e)) => { + chained_binops_helper(left_outer, right_e) + }, + ( + ExprKind::Binary(Spanned { node: left_op, .. }, ref left_left, ref left_right), + ExprKind::Binary(Spanned { node: right_op, .. }, ref right_left, ref right_right), + ) => match ( + chained_binops_helper(left_left, left_right), + chained_binops_helper(right_left, right_right), + ) { + (Some(mut left_ops), Some(mut right_ops)) => { + left_ops.reserve(right_ops.len()); + for op in right_ops.drain(..) { + left_ops.push(op); + } + Some(left_ops) + }, + (Some(mut left_ops), _) => { + left_ops.push(BinaryOp::new(*right_op, right_outer.span, (right_left, right_right))); + Some(left_ops) + }, + (_, Some(mut right_ops)) => { + right_ops.insert(0, BinaryOp::new(*left_op, left_outer.span, (left_left, left_right))); + Some(right_ops) + }, + (None, None) => Some(vec![ + BinaryOp::new(*left_op, left_outer.span, (left_left, left_right)), + BinaryOp::new(*right_op, right_outer.span, (right_left, right_right)), + ]), + }, + _ => None, + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] +struct IdentLocation { + index: usize, +} + +impl Add for IdentLocation { + type Output = IdentLocation; + + fn add(self, other: Self) -> Self::Output { + Self { + index: self.index + other.index, + } + } +} + +impl AddAssign for IdentLocation { + fn add_assign(&mut self, other: Self) { + *self = *self + other + } +} + +#[derive(Clone, Copy, Debug)] +enum IdentDifference { + NoDifference, + Single(IdentLocation), + Double(IdentLocation, IdentLocation), + Multiple, + NonIdent, +} + +impl Add for IdentDifference { + type Output = IdentDifference; + + fn add(self, other: Self) -> Self::Output { + match (self, other) { + (Self::NoDifference, output) | (output, Self::NoDifference) => output, + (Self::Multiple, _) + | (_, Self::Multiple) + | (Self::Double(_, _), Self::Single(_)) + | (Self::Single(_) | Self::Double(_, _), Self::Double(_, _)) => Self::Multiple, + (Self::NonIdent, _) | (_, Self::NonIdent) => Self::NonIdent, + (Self::Single(il1), Self::Single(il2)) => Self::Double(il1, il2), + } + } +} + +impl AddAssign for IdentDifference { + fn add_assign(&mut self, other: Self) { + *self = *self + other + } +} + +impl IdentDifference { + /// Returns true if learning about more differences will not change the value + /// of this `IdentDifference`, and false otherwise. + fn is_complete(&self) -> bool { + match self { + Self::NoDifference | Self::Single(_) | Self::Double(_, _) => false, + Self::Multiple | Self::NonIdent => true, + } + } +} + +fn ident_difference_expr(left: &Expr, right: &Expr) -> IdentDifference { + ident_difference_expr_with_base_location(left, right, IdentLocation::default()).0 +} + +fn ident_difference_expr_with_base_location( + left: &Expr, + right: &Expr, + mut base: IdentLocation, +) -> (IdentDifference, IdentLocation) { + // Ideally, this function should not use IdentIter because it should return + // early if the expressions have any non-ident differences. We want that early + // return because if without that restriction the lint would lead to false + // positives. + // + // But, we cannot (easily?) use a `rustc_ast::visit::Visitor`, since we need + // the two expressions to be walked in lockstep. And without a `Visitor`, we'd + // have to do all the AST traversal ourselves, which is a lot of work, since to + // do it properly we'd need to be able to handle more or less every possible + // AST node since `Item`s can be written inside `Expr`s. + // + // In practice, it seems likely that expressions, above a certain size, that + // happen to use the exact same idents in the exact same order, and which are + // not structured the same, would be rare. Therefore it seems likely that if + // we do only the first layer of matching ourselves and eventually fallback on + // IdentIter, then the output of this function will be almost always be correct + // in practice. + // + // If it turns out that problematic cases are more prelavent than we assume, + // then we should be able to change this function to do the correct traversal, + // without needing to change the rest of the code. + + #![allow(clippy::enum_glob_use)] + use ExprKind::*; + + match ( + &strip_non_ident_wrappers(left).kind, + &strip_non_ident_wrappers(right).kind, + ) { + (Yield(_), Yield(_)) + | (Try(_), Try(_)) + | (Paren(_), Paren(_)) + | (Repeat(_, _), Repeat(_, _)) + | (Struct(_, _, _), Struct(_, _, _)) + | (MacCall(_), MacCall(_)) + | (LlvmInlineAsm(_), LlvmInlineAsm(_)) + | (InlineAsm(_), InlineAsm(_)) + | (Ret(_), Ret(_)) + | (Continue(_), Continue(_)) + | (Break(_, _), Break(_, _)) + | (AddrOf(_, _, _), AddrOf(_, _, _)) + | (Path(_, _), Path(_, _)) + | (Range(_, _, _), Range(_, _, _)) + | (Index(_, _), Index(_, _)) + | (Field(_, _), Field(_, _)) + | (AssignOp(_, _, _), AssignOp(_, _, _)) + | (Assign(_, _, _), Assign(_, _, _)) + | (TryBlock(_), TryBlock(_)) + | (Await(_), Await(_)) + | (Async(_, _, _), Async(_, _, _)) + | (Block(_, _), Block(_, _)) + | (Closure(_, _, _, _, _, _), Closure(_, _, _, _, _, _)) + | (Match(_, _), Match(_, _)) + | (Loop(_, _), Loop(_, _)) + | (ForLoop(_, _, _, _), ForLoop(_, _, _, _)) + | (While(_, _, _), While(_, _, _)) + | (If(_, _, _), If(_, _, _)) + | (Let(_, _), Let(_, _)) + | (Type(_, _), Type(_, _)) + | (Cast(_, _), Cast(_, _)) + | (Lit(_), Lit(_)) + | (Unary(_, _), Unary(_, _)) + | (Binary(_, _, _), Binary(_, _, _)) + | (Tup(_), Tup(_)) + | (MethodCall(_, _, _), MethodCall(_, _, _)) + | (Call(_, _), Call(_, _)) + | (ConstBlock(_), ConstBlock(_)) + | (Array(_), Array(_)) + | (Box(_), Box(_)) => { + // keep going + }, + _ => { + return (IdentDifference::NonIdent, base); + }, + } + + let mut difference = IdentDifference::NoDifference; + + for (left_attr, right_attr) in left.attrs.iter().zip(right.attrs.iter()) { + let (new_difference, new_base) = + ident_difference_via_ident_iter_with_base_location(left_attr, right_attr, base); + base = new_base; + difference += new_difference; + if difference.is_complete() { + return (difference, base); + } + } + + let (new_difference, new_base) = ident_difference_via_ident_iter_with_base_location(left, right, base); + base = new_base; + difference += new_difference; + + (difference, base) +} + +fn ident_difference_via_ident_iter_with_base_location>( + left: Iterable, + right: Iterable, + mut base: IdentLocation, +) -> (IdentDifference, IdentLocation) { + // See the note in `ident_difference_expr_with_base_location` about `IdentIter` + let mut difference = IdentDifference::NoDifference; + + let mut left_iterator = left.into(); + let mut right_iterator = right.into(); + + loop { + match (left_iterator.next(), right_iterator.next()) { + (Some(left_ident), Some(right_ident)) => { + if !eq_id(left_ident, right_ident) { + difference += IdentDifference::Single(base); + if difference.is_complete() { + return (difference, base); + } + } + }, + (Some(_), None) | (None, Some(_)) => { + return (IdentDifference::NonIdent, base); + }, + (None, None) => { + return (difference, base); + }, + } + base += IdentLocation { index: 1 }; + } +} + +fn get_ident(expr: &Expr, location: IdentLocation) -> Option { + IdentIter::from(expr).nth(location.index) +} + +fn suggestion_with_swapped_ident( + cx: &EarlyContext<'_>, + expr: &Expr, + location: IdentLocation, + new_ident: Ident, + applicability: &mut Applicability, +) -> Option { + get_ident(expr, location).and_then(|current_ident| { + if eq_id(current_ident, new_ident) { + // We never want to suggest a non-change + return None; + } + + Some(format!( + "{}{}{}", + snippet_with_applicability(cx, expr.span.with_hi(current_ident.span.lo()), "..", applicability), + new_ident.to_string(), + snippet_with_applicability(cx, expr.span.with_lo(current_ident.span.hi()), "..", applicability), + )) + }) +} + +fn skip_index(iter: Iter, index: usize) -> impl Iterator +where + Iter: Iterator, +{ + iter.enumerate() + .filter_map(move |(i, a)| if i == index { None } else { Some(a) }) +} diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index fcf7a4b1367..31b4e25411b 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -10,6 +10,17 @@ use rustc_ast::{self as ast, *}; use rustc_span::symbol::Ident; use std::mem; +pub mod ident_iter; +pub use ident_iter::IdentIter; + +pub fn is_useless_with_eq_exprs(kind: BinOpKind) -> bool { + use BinOpKind::*; + matches!( + kind, + Sub | Div | Eq | Lt | Le | Gt | Ge | Ne | And | Or | BitXor | BitAnd | BitOr + ) +} + /// Checks if each element in the first slice is contained within the latter as per `eq_fn`. pub fn unordered_over(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { left.len() == right.len() && left.iter().all(|l| right.iter().any(|r| eq_fn(l, r))) diff --git a/clippy_lints/src/utils/ast_utils/ident_iter.rs b/clippy_lints/src/utils/ast_utils/ident_iter.rs new file mode 100644 index 00000000000..eefcbabd835 --- /dev/null +++ b/clippy_lints/src/utils/ast_utils/ident_iter.rs @@ -0,0 +1,45 @@ +use core::iter::FusedIterator; +use rustc_ast::visit::{walk_attribute, walk_expr, Visitor}; +use rustc_ast::{Attribute, Expr}; +use rustc_span::symbol::Ident; + +pub struct IdentIter(std::vec::IntoIter); + +impl Iterator for IdentIter { + type Item = Ident; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +impl FusedIterator for IdentIter {} + +impl From<&Expr> for IdentIter { + fn from(expr: &Expr) -> Self { + let mut visitor = IdentCollector::default(); + + walk_expr(&mut visitor, expr); + + IdentIter(visitor.0.into_iter()) + } +} + +impl From<&Attribute> for IdentIter { + fn from(attr: &Attribute) -> Self { + let mut visitor = IdentCollector::default(); + + walk_attribute(&mut visitor, attr); + + IdentIter(visitor.0.into_iter()) + } +} + +#[derive(Default)] +struct IdentCollector(Vec); + +impl Visitor<'_> for IdentCollector { + fn visit_ident(&mut self, ident: Ident) { + self.0.push(ident); + } +} diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index 4e09d19ea21..7ab23320db6 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -86,3 +86,12 @@ fn check_ignore_macro() { // checks if the lint ignores macros with `!` operator !bool_macro!(1) && !bool_macro!(""); } + +struct Nested { + inner: ((i32,), (i32,), (i32,)), +} + +fn check_nested(n1: &Nested, n2: &Nested) -> bool { + // `n2.inner.0.0` mistyped as `n1.inner.0.0` + (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 +} diff --git a/tests/ui/eq_op.stderr b/tests/ui/eq_op.stderr index ad81b35a766..8ef658af8df 100644 --- a/tests/ui/eq_op.stderr +++ b/tests/ui/eq_op.stderr @@ -162,5 +162,13 @@ error: equal expressions as operands to `/` LL | const D: u32 = A / A; | ^^^^^ -error: aborting due to 27 previous errors +error: equal expressions as operands to `==` + --> $DIR/eq_op.rs:96:5 + | +LL | (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::eq_op)]` on by default + +error: aborting due to 28 previous errors diff --git a/tests/ui/suspicious_operation_groupings.rs b/tests/ui/suspicious_operation_groupings.rs new file mode 100644 index 00000000000..dd6f4ec7bd9 --- /dev/null +++ b/tests/ui/suspicious_operation_groupings.rs @@ -0,0 +1,207 @@ +#![warn(clippy::suspicious_operation_groupings)] + +struct Vec3 { + x: f64, + y: f64, + z: f64, +} + +impl Eq for Vec3 {} + +impl PartialEq for Vec3 { + fn eq(&self, other: &Self) -> bool { + // This should trigger the lint because `self.x` is compared to `other.y` + self.x == other.y && self.y == other.y && self.z == other.z + } +} + +struct S { + a: i32, + b: i32, + c: i32, + d: i32, +} + +fn buggy_ab_cmp(s1: &S, s2: &S) -> bool { + // There's no `s1.b` + s1.a < s2.a && s1.a < s2.b +} + +struct SAOnly { + a: i32, +} + +impl S { + fn a(&self) -> i32 { + 0 + } +} + +fn do_not_give_bad_suggestions_for_this_unusual_expr(s1: &S, s2: &SAOnly) -> bool { + // This is superficially similar to `buggy_ab_cmp`, but we should not suggest + // `s2.b` since that is invalid. + s1.a < s2.a && s1.a() < s1.b +} + +fn do_not_give_bad_suggestions_for_this_macro_expr(s1: &S, s2: &SAOnly) -> bool { + macro_rules! s1 { + () => { + S { + a: 1, + b: 1, + c: 1, + d: 1, + } + }; + } + + // This is superficially similar to `buggy_ab_cmp`, but we should not suggest + // `s2.b` since that is invalid. + s1.a < s2.a && s1!().a < s1.b +} + +fn do_not_give_bad_suggestions_for_this_incorrect_expr(s1: &S, s2: &SAOnly) -> bool { + // There's two `s1.b`, but we should not suggest `s2.b` since that is invalid + s1.a < s2.a && s1.b < s1.b +} + +fn permissable(s1: &S, s2: &S) -> bool { + // Something like this seems like it might actually be what is desired. + s1.a == s2.b +} + +fn non_boolean_operators(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d +} + +fn odd_number_of_pairs(s1: &S, s2: &S) -> i32 { + // There's no `s2.b` + s1.a * s2.a + s1.b * s2.c + s1.c * s2.c +} + +fn not_caught_by_eq_op_middle_change_left(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + s1.a * s2.a + s2.b * s2.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_middle_change_right(s1: &S, s2: &S) -> i32 { + // There's no `s2.b` + s1.a * s2.a + s1.b * s1.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_start(s1: &S, s2: &S) -> i32 { + // There's no `s2.a` + s1.a * s1.a + s1.b * s2.b + s1.c * s2.c +} + +fn not_caught_by_eq_op_end(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + s1.a * s2.a + s1.b * s2.b + s1.c * s1.c +} + +fn the_cross_product_should_not_lint(s1: &S, s2: &S) -> (i32, i32, i32) { + ( + s1.b * s2.c - s1.c * s2.b, + s1.c * s2.a - s1.a * s2.c, + s1.a * s2.b - s1.b * s2.a, + ) +} + +fn outer_parens_simple(s1: &S, s2: &S) -> i32 { + // There's no `s2.b` + (s1.a * s2.a + s1.b * s1.b) +} + +fn outer_parens(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) +} + +fn inner_parens(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) +} + +fn outer_and_some_inner_parens(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) +} + +fn all_parens_balanced_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) +} + +fn all_parens_left_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) +} + +fn all_parens_right_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) +} + +fn inside_other_binop_expression(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + (s1.a * s2.a + s2.b * s2.b) / 2 +} + +fn inside_function_call(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) +} + +fn inside_larger_boolean_expression(s1: &S, s2: &S) -> bool { + // There's no `s1.c` + s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d +} + +fn inside_larger_boolean_expression_with_unsorted_ops(s1: &S, s2: &S) -> bool { + // There's no `s1.c` + s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d +} + +struct Nested { + inner: ((i32,), (i32,), (i32,)), +} + +fn changed_middle_ident(n1: &Nested, n2: &Nested) -> bool { + // There's no `n2.inner.2.0` + (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 +} + +// `eq_op` should catch this one. +fn changed_initial_ident(n1: &Nested, n2: &Nested) -> bool { + // There's no `n2.inner.0.0` + (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 +} + +fn inside_fn_with_similar_expression(s1: &S, s2: &S, strict: bool) -> bool { + if strict { + s1.a < s2.a && s1.b < s2.b + } else { + // There's no `s1.b` in this subexpression + s1.a <= s2.a && s1.a <= s2.b + } +} + +fn inside_an_if_statement(s1: &S, s2: &S) { + // There's no `s1.b` + if s1.a < s2.a && s1.a < s2.b { + s1.c = s2.c; + } +} + +fn maximum_unary_minus_right_tree(s1: &S, s2: &S) -> i32 { + // There's no `s2.c` + -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) +} + +fn unary_minus_and_an_if_expression(s1: &S, s2: &S) -> i32 { + // There's no `s1.b` + -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) +} + +fn main() {} diff --git a/tests/ui/suspicious_operation_groupings.stderr b/tests/ui/suspicious_operation_groupings.stderr new file mode 100644 index 00000000000..ce7108217f1 --- /dev/null +++ b/tests/ui/suspicious_operation_groupings.stderr @@ -0,0 +1,166 @@ +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:14:9 + | +LL | self.x == other.y && self.y == other.y && self.z == other.z + | ^^^^^^^^^^^^^^^^^ help: I think you meant: `self.x == other.x` + | + = note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:14:9 + | +LL | self.x == other.y && self.y == other.y && self.z == other.z + | ^^^^^^^^^^^^^^^^^ help: I think you meant: `self.x == other.x` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:27:20 + | +LL | s1.a < s2.a && s1.a < s2.b + | ^^^^^^^^^^^ help: I think you meant: `s1.b < s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:75:33 + | +LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:80:19 + | +LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:80:19 + | +LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:85:19 + | +LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:90:19 + | +LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:95:5 + | +LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c + | ^^^^^^^^^^^ help: I think you meant: `s1.a * s2.a` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:100:33 + | +LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:113:20 + | +LL | (s1.a * s2.a + s1.b * s1.b) + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:118:34 + | +LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:123:38 + | +LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:128:39 + | +LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:133:42 + | +LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:133:42 + | +LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:138:40 + | +LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:143:40 + | +LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) + | ^^^^^^^^^^^ help: I think you meant: `s1.c * s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:148:20 + | +LL | (s1.a * s2.a + s2.b * s2.b) / 2 + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:153:35 + | +LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) + | ^^^^^^^^^^^ help: I think you meant: `s1.b * s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:158:29 + | +LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d + | ^^^^^^^^^^^^ help: I think you meant: `s1.c == s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:163:17 + | +LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d + | ^^^^^^^^^^^^ help: I think you meant: `s1.c == s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:172:77 + | +LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: I think you meant: `(n1.inner.2).0 == (n2.inner.2).0` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:186:25 + | +LL | s1.a <= s2.a && s1.a <= s2.b + | ^^^^^^^^^^^^ help: I think you meant: `s1.b <= s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:192:23 + | +LL | if s1.a < s2.a && s1.a < s2.b { + | ^^^^^^^^^^^ help: I think you meant: `s1.b < s2.b` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:199:48 + | +LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) + | ^^^^^^^^^^^^^ help: I think you meant: `-s1.c * -s2.c` + +error: This sequence of operators looks suspiciously like a bug. + --> $DIR/suspicious_operation_groupings.rs:204:27 + | +LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) + | ^^^^^^^^^^^^^ help: I think you meant: `-s1.b < -s2.b` + +error: aborting due to 27 previous errors + From 2347eac4ccf62457994901501f64c84535a20f9b Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 22 Nov 2020 14:29:46 -0800 Subject: [PATCH 089/274] Update error to reflect that integer literals can have float suffixes For example, `1` is parsed as an integer literal, but it can be turned into a float with the suffix `f32`. Now the error calls them "numeric literals" and notes that you can add a float suffix since they can be either integers or floats. --- tests/ui/crashes/ice-3891.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/crashes/ice-3891.stderr b/tests/ui/crashes/ice-3891.stderr index 5a285b0e714..59469ec5891 100644 --- a/tests/ui/crashes/ice-3891.stderr +++ b/tests/ui/crashes/ice-3891.stderr @@ -1,10 +1,10 @@ -error: invalid suffix `x` for integer literal +error: invalid suffix `x` for number literal --> $DIR/ice-3891.rs:2:5 | LL | 1x; | ^^ invalid suffix `x` | - = help: the suffix must be one of the integral types (`u32`, `isize`, etc) + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) error: aborting due to previous error From c1b991588f3b2945bddfded808bdab45e250a8dd Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sat, 28 Nov 2020 17:03:20 +0100 Subject: [PATCH 090/274] Fix weird dogfood error --- clippy_lints/src/redundant_closure_call.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 49cb2ffc4e3..f398b3fff25 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { cx: &'a LateContext<'tcx>, path: &'tcx hir::Path<'tcx>, count: usize, - }; + } impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { type Map = Map<'tcx>; @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap { hir_visit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) } - }; + } let mut closure_usage_count = ClosureUsageCount { cx, path, count: 0 }; closure_usage_count.visit_block(block); closure_usage_count.count From 0e5aee1fc1251493c35a4344700798e9a586ef16 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sat, 28 Nov 2020 17:18:15 +0100 Subject: [PATCH 091/274] items_after_statements: don't lint when they a separated by trailing semicolons --- clippy_lints/src/items_after_statements.rs | 4 ++-- tests/ui/item_after_statement.rs | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 8998fae09de..0927d218446 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -58,12 +58,12 @@ impl EarlyLintPass for ItemsAfterStatements { return; } - // skip initial items + // skip initial items and trailing semicolons let stmts = item .stmts .iter() .map(|stmt| &stmt.kind) - .skip_while(|s| matches!(**s, StmtKind::Item(..))); + .skip_while(|s| matches!(**s, StmtKind::Item(..) | StmtKind::Empty)); // lint on all further items for stmt in stmts { diff --git a/tests/ui/item_after_statement.rs b/tests/ui/item_after_statement.rs index 377e58e4417..d439ca1e4e1 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/item_after_statement.rs @@ -37,3 +37,16 @@ fn mac() { b!(); println!("{}", a); } + +fn semicolon() { + struct S { + a: u32, + }; + impl S { + fn new(a: u32) -> Self { + Self { a } + } + } + + let _ = S::new(3); +} From f7b2098e1c4f8e13ec2194f7f094f471b4056f97 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 29 Nov 2020 01:55:15 +0900 Subject: [PATCH 092/274] Fix a false positive in `unnecessary_wraps` --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 2 ++ tests/ui/unnecessary_wraps.rs | 7 +++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 50dd760432d..004b8416fc1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3878,7 +3878,7 @@ fn is_bool(ty: &hir::Ty<'_>) -> bool { } // Returns `true` if `expr` contains a return expression -fn contains_return(expr: &hir::Expr<'_>) -> bool { +pub(crate) fn contains_return(expr: &hir::Expr<'_>) -> bool { struct RetCallFinder { found: bool, } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 25ecc7a82f1..7b550c702cd 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,3 +1,4 @@ +use crate::methods::contains_return; use crate::utils::{ in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, visitors::find_all_ret_expressions, @@ -95,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if let ExprKind::Path(ref qpath) = func.kind; if match_qpath(qpath, path); if args.len() == 1; + if !contains_return(&args[0]); then { suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string())); true diff --git a/tests/ui/unnecessary_wraps.rs b/tests/ui/unnecessary_wraps.rs index a53dec8f91a..a4570098d71 100644 --- a/tests/ui/unnecessary_wraps.rs +++ b/tests/ui/unnecessary_wraps.rs @@ -109,6 +109,13 @@ impl B for A { } } +fn issue_6384(s: &str) -> Option<&str> { + Some(match s { + "a" => "A", + _ => return None, + }) +} + fn main() { // method calls are not linted func1(true, true); From aabe70f90e30c45f13dbdaaed1ea05776e541b8d Mon Sep 17 00:00:00 2001 From: oli Date: Tue, 6 Oct 2020 10:03:52 +0000 Subject: [PATCH 093/274] Directly use raw pointers in `AtomicPtr` store/load --- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 6 ++-- library/core/src/sync/atomic.rs | 28 ++++++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 94340e92048..3026eadefe3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -437,7 +437,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match split[1] { "cxchg" | "cxchgweak" => { let ty = substs.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { let weak = split[1] == "cxchgweak"; let pair = bx.atomic_cmpxchg( args[0].immediate(), @@ -464,7 +464,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "load" => { let ty = substs.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { let size = bx.layout_of(ty).size; bx.atomic_load(args[0].immediate(), order, size) } else { @@ -474,7 +474,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "store" => { let ty = substs.type_at(0); - if int_type_width_signed(ty, bx.tcx()).is_some() { + if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { let size = bx.layout_of(ty).size; bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size); return; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 9d204599057..c167a9d8e5b 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -966,8 +966,16 @@ impl AtomicPtr { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn load(&self, order: Ordering) -> *mut T { + #[cfg(not(bootstrap))] // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_load(self.p.get() as *mut usize, order) as *mut T } + unsafe { + atomic_load(self.p.get(), order) + } + #[cfg(bootstrap)] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_load(self.p.get() as *mut usize, order) as *mut T + } } /// Stores a value into the pointer. @@ -994,6 +1002,12 @@ impl AtomicPtr { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, ptr: *mut T, order: Ordering) { + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_store(self.p.get(), ptr, order); + } + #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. unsafe { atomic_store(self.p.get() as *mut usize, ptr as usize, order); @@ -1105,6 +1119,7 @@ impl AtomicPtr { success: Ordering, failure: Ordering, ) -> Result<*mut T, *mut T> { + #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. unsafe { let res = atomic_compare_exchange( @@ -1119,6 +1134,11 @@ impl AtomicPtr { Err(x) => Err(x as *mut T), } } + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_compare_exchange(self.p.get(), current, new, success, failure) + } } /// Stores a value into the pointer if the current value is the same as the `current` value. @@ -1165,6 +1185,7 @@ impl AtomicPtr { success: Ordering, failure: Ordering, ) -> Result<*mut T, *mut T> { + #[cfg(bootstrap)] // SAFETY: data races are prevented by atomic intrinsics. unsafe { let res = atomic_compare_exchange_weak( @@ -1179,6 +1200,11 @@ impl AtomicPtr { Err(x) => Err(x as *mut T), } } + #[cfg(not(bootstrap))] + // SAFETY: data races are prevented by atomic intrinsics. + unsafe { + atomic_compare_exchange_weak(self.p.get(), current, new, success, failure) + } } /// Fetches the value, and applies a function to it that returns an optional From 79fb037cc5f34368de069e8958ffc3a21036d091 Mon Sep 17 00:00:00 2001 From: oli Date: Tue, 6 Oct 2020 12:25:08 +0000 Subject: [PATCH 094/274] Remove now-unnecessary `miri_static_root` invocation --- library/std/src/sys/windows/thread_local_key.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/library/std/src/sys/windows/thread_local_key.rs b/library/std/src/sys/windows/thread_local_key.rs index 82901871e78..fb2bb0613ee 100644 --- a/library/std/src/sys/windows/thread_local_key.rs +++ b/library/std/src/sys/windows/thread_local_key.rs @@ -110,16 +110,6 @@ struct Node { next: *mut Node, } -#[cfg(miri)] -extern "Rust" { - /// Miri-provided extern function to mark the block `ptr` points to as a "root" - /// for some static memory. This memory and everything reachable by it is not - /// considered leaking even if it still exists when the program terminates. - /// - /// `ptr` has to point to the beginning of an allocated block. - fn miri_static_root(ptr: *const u8); -} - unsafe fn register_dtor(key: Key, dtor: Dtor) { let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() }); @@ -128,9 +118,6 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) { node.next = head; match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) { Ok(_) => { - #[cfg(miri)] - miri_static_root(&*node as *const _ as *const u8); - mem::forget(node); return; } From 2c26cb14db4d3a86aea0a897f9b727cef4e72e27 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 29 Nov 2020 02:18:05 +0900 Subject: [PATCH 095/274] Move `contains_return` to utils/mod.rs --- clippy_lints/src/methods/mod.rs | 43 ++++----------------------- clippy_lints/src/unnecessary_wraps.rs | 3 +- clippy_lints/src/utils/mod.rs | 30 +++++++++++++++++++ 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 004b8416fc1..1476408e0fb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -14,10 +14,8 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; -use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -28,11 +26,12 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, - is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, - match_trait_method, match_type, match_var, meets_msrv, method_calls, method_chain_args, paths, remove_blocks, - return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, + contains_return, contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, + implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, + match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls, + method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, + walk_ptrs_ty_depth, SpanlessEq, }; use semver::{Version, VersionReq}; @@ -3877,36 +3876,6 @@ fn is_bool(ty: &hir::Ty<'_>) -> bool { } } -// Returns `true` if `expr` contains a return expression -pub(crate) fn contains_return(expr: &hir::Expr<'_>) -> bool { - struct RetCallFinder { - found: bool, - } - - impl<'tcx> intravisit::Visitor<'tcx> for RetCallFinder { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if self.found { - return; - } - if let hir::ExprKind::Ret(..) = &expr.kind { - self.found = true; - } else { - intravisit::walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - } - - let mut visitor = RetCallFinder { found: false }; - visitor.visit_expr(expr); - visitor.found -} - fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { if_chain! { if args.len() == 2; diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 7b550c702cd..360df2a6752 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,6 +1,5 @@ -use crate::methods::contains_return; use crate::utils::{ - in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, + contains_return, in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, visitors::find_all_ret_expressions, }; use if_chain::if_chain; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 6f89e51279a..850abc3bae7 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -572,6 +572,36 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool { cn.result } +/// Returns `true` if `expr` contains a return expression +pub fn contains_return(expr: &hir::Expr<'_>) -> bool { + struct RetCallFinder { + found: bool, + } + + impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { + if self.found { + return; + } + if let hir::ExprKind::Ret(..) = &expr.kind { + self.found = true; + } else { + hir::intravisit::walk_expr(self, expr); + } + } + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::None + } + } + + let mut visitor = RetCallFinder { found: false }; + visitor.visit_expr(expr); + visitor.found +} + /// Converts a span to a code snippet if available, otherwise use default. /// /// This is useful if you want to provide suggestions for your lint or more generally, if you want From e266708c42dd3d9489586e65b9c6cd1bee0046d5 Mon Sep 17 00:00:00 2001 From: Aleksei Latyshev Date: Wed, 4 Nov 2020 21:16:25 +0300 Subject: [PATCH 096/274] do not trigger MATCH_LIKE_MATCHES_MACRO lint with attrs - it can't be solved completely for attrs evaluated into `false` - change applicability to MaybeIncorrect and mention it in docs --- clippy_lints/src/matches.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index d695af4de21..c49abbf781e 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -459,7 +459,8 @@ declare_clippy_lint! { /// /// **Why is this bad?** Readability and needless complexity. /// - /// **Known problems:** None + /// **Known problems:** It can be FP triggered, when some arms have `cfg` + /// attributes, which evaluate into `false`. /// /// **Example:** /// ```rust @@ -1167,13 +1168,16 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr if b0 != b1; let if_guard = &b0_arms[0].guard; if if_guard.is_none() || b0_arms.len() == 1; + if b0_arms[0].attrs.is_empty(); if b0_arms[1..].iter() .all(|arm| { find_bool_lit(&arm.body.kind, desugared).map_or(false, |b| b == b0) && - arm.guard.is_none() + arm.guard.is_none() && arm.attrs.is_empty() }); then { - let mut applicability = Applicability::MachineApplicable; + // The suggestion may be incorrect, because some arms can have `cfg` attributes + // evaluated into `false` and so such arms will be stripped before. + let mut applicability = Applicability::MaybeIncorrect; let pat = { use itertools::Itertools as _; b0_arms.iter() From 22e7775aa798c1e4688089c150c0a077b9875bf0 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sat, 28 Nov 2020 18:58:53 +0100 Subject: [PATCH 097/274] Change formulation of known problems section --- clippy_lints/src/matches.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index c49abbf781e..52da580b521 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -459,8 +459,8 @@ declare_clippy_lint! { /// /// **Why is this bad?** Readability and needless complexity. /// - /// **Known problems:** It can be FP triggered, when some arms have `cfg` - /// attributes, which evaluate into `false`. + /// **Known problems:** This lint falsely triggers, if there are arms with + /// `cfg` attributes that remove an arm evaluating to `false`. /// /// **Example:** /// ```rust From 76f2c10fb6afb9071c56e8b6e410671573648ef4 Mon Sep 17 00:00:00 2001 From: Rajkumar Natarajan Date: Sat, 28 Nov 2020 12:19:57 -0500 Subject: [PATCH 098/274] issue_6357 update unreachable macro usage --- clippy_lints/src/panic_unimplemented.rs | 9 ++------- tests/ui/panicking_macros.stderr | 8 ++++---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 31b03ecd101..359620cc079 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -66,7 +66,7 @@ declare_clippy_lint! { /// ``` pub UNREACHABLE, restriction, - "`unreachable!` should not be present in production code" + "usage of the `unreachable!` macro" } declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]); @@ -85,12 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { } else if is_expn_of(expr.span, "todo").is_some() { span_lint(cx, TODO, span, "`todo` should not be present in production code"); } else if is_expn_of(expr.span, "unreachable").is_some() { - span_lint( - cx, - UNREACHABLE, - span, - "`unreachable` should not be present in production code", - ); + span_lint(cx, UNREACHABLE, span, "usage of the `unreachable!` macro"); } else if is_expn_of(expr.span, "panic").is_some() { span_lint(cx, PANIC, span, "`panic` should not be present in production code"); } diff --git a/tests/ui/panicking_macros.stderr b/tests/ui/panicking_macros.stderr index 83234c0ed92..6028323a3c8 100644 --- a/tests/ui/panicking_macros.stderr +++ b/tests/ui/panicking_macros.stderr @@ -62,7 +62,7 @@ error: `unimplemented` should not be present in production code LL | unimplemented!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `unreachable` should not be present in production code +error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:32:5 | LL | unreachable!(); @@ -70,7 +70,7 @@ LL | unreachable!(); | = note: `-D clippy::unreachable` implied by `-D warnings` -error: `unreachable` should not be present in production code +error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:33:5 | LL | unreachable!("message"); @@ -78,7 +78,7 @@ LL | unreachable!("message"); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: `unreachable` should not be present in production code +error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:34:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); @@ -102,7 +102,7 @@ error: `unimplemented` should not be present in production code LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ -error: `unreachable` should not be present in production code +error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:43:5 | LL | unreachable!(); From 84cdb0a939cec1e13d6f464bb7b036ff3b92dfb0 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sat, 28 Nov 2020 22:40:46 +0100 Subject: [PATCH 099/274] Fix formatting --- clippy_lints/src/matches.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 52da580b521..665c59d7093 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -460,7 +460,7 @@ declare_clippy_lint! { /// **Why is this bad?** Readability and needless complexity. /// /// **Known problems:** This lint falsely triggers, if there are arms with - /// `cfg` attributes that remove an arm evaluating to `false`. + /// `cfg` attributes that remove an arm evaluating to `false`. /// /// **Example:** /// ```rust From cd087e5c5e65fa61c0562ceb2d2488f8f5660454 Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Sat, 28 Nov 2020 19:41:27 +0530 Subject: [PATCH 100/274] add rustc-semver to dependencies switch Version/VersionReq usages to RustcVersion --- clippy_lints/Cargo.toml | 1 + clippy_lints/src/manual_non_exhaustive.rs | 14 ++++---------- clippy_lints/src/manual_strip.rs | 14 ++++---------- clippy_lints/src/matches.rs | 14 ++++---------- clippy_lints/src/methods/mod.rs | 16 +++++----------- clippy_lints/src/utils/mod.rs | 10 +++++----- 6 files changed, 23 insertions(+), 46 deletions(-) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index d9471d25197..45fd87b169f 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -28,6 +28,7 @@ smallvec = { version = "1", features = ["union"] } toml = "0.5.3" unicode-normalization = "0.1" semver = "0.11" +rustc-semver="1.0.0" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 703e6feeca5..91849e74887 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -4,17 +4,11 @@ use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantDat use rustc_attr as attr; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; -use semver::{Version, VersionReq}; -const MANUAL_NON_EXHAUSTIVE_MSRV: Version = Version { - major: 1, - minor: 40, - patch: 0, - pre: Vec::new(), - build: Vec::new(), -}; +const MANUAL_NON_EXHAUSTIVE_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); declare_clippy_lint! { /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. @@ -66,12 +60,12 @@ declare_clippy_lint! { #[derive(Clone)] pub struct ManualNonExhaustive { - msrv: Option, + msrv: Option, } impl ManualNonExhaustive { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Option) -> Self { Self { msrv } } } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index e17e3adb94f..f593abdb104 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -13,18 +13,12 @@ use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Spanned; use rustc_span::Span; -use semver::{Version, VersionReq}; -const MANUAL_STRIP_MSRV: Version = Version { - major: 1, - minor: 45, - patch: 0, - pre: Vec::new(), - build: Vec::new(), -}; +const MANUAL_STRIP_MSRV: RustcVersion = RustcVersion::new(1, 45, 0); declare_clippy_lint! { /// **What it does:** @@ -61,12 +55,12 @@ declare_clippy_lint! { } pub struct ManualStrip { - msrv: Option, + msrv: Option, } impl ManualStrip { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Option) -> Self { Self { msrv } } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 7d64fa6c262..86e3e2f637e 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -20,10 +20,10 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty, TyS}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::{sym, Symbol}; -use semver::{Version, VersionReq}; use std::cmp::Ordering; use std::collections::hash_map::Entry; use std::collections::Bound; @@ -535,13 +535,13 @@ declare_clippy_lint! { #[derive(Default)] pub struct Matches { - msrv: Option, + msrv: Option, infallible_destructuring_match_linted: bool, } impl Matches { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Option) -> Self { Self { msrv, ..Matches::default() @@ -568,13 +568,7 @@ impl_lint_pass!(Matches => [ MATCH_SAME_ARMS, ]); -const MATCH_LIKE_MATCHES_MACRO_MSRV: Version = Version { - major: 1, - minor: 42, - patch: 0, - pre: Vec::new(), - build: Vec::new(), -}; +const MATCH_LIKE_MATCHES_MACRO_MSRV: RustcVersion = RustcVersion::new(1, 42, 0); impl<'tcx> LateLintPass<'tcx> for Matches { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1476408e0fb..8002c27a5e9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -18,6 +18,7 @@ use rustc_hir::{TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty, TyS}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -33,7 +34,6 @@ use crate::utils::{ snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, }; -use semver::{Version, VersionReq}; declare_clippy_lint! { /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. @@ -1405,12 +1405,12 @@ declare_clippy_lint! { } pub struct Methods { - msrv: Option, + msrv: Option, } impl Methods { #[must_use] - pub fn new(msrv: Option) -> Self { + pub fn new(msrv: Option) -> Self { Self { msrv } } } @@ -3470,13 +3470,7 @@ fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) { ); } -const OPTION_AS_REF_DEREF_MSRV: Version = Version { - major: 1, - minor: 40, - patch: 0, - pre: Vec::new(), - build: Vec::new(), -}; +const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0); /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s fn lint_option_as_ref_deref<'tcx>( @@ -3485,7 +3479,7 @@ fn lint_option_as_ref_deref<'tcx>( as_ref_args: &[hir::Expr<'_>], map_args: &[hir::Expr<'_>], is_mut: bool, - msrv: Option<&VersionReq>, + msrv: Option<&RustcVersion>, ) { if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) { return; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 850abc3bae7..d68f0698153 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -51,6 +51,7 @@ use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; +use rustc_semver::RustcVersion; use rustc_session::Session; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; @@ -59,13 +60,12 @@ use rustc_span::symbol::{self, kw, Symbol}; use rustc_span::{BytePos, Pos, Span, DUMMY_SP}; use rustc_target::abi::Integer; use rustc_trait_selection::traits::query::normalize::AtExt; -use semver::{Version, VersionReq}; use smallvec::SmallVec; use crate::consts::{constant, Constant}; -pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { - if let Ok(version) = VersionReq::parse(msrv) { +pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { + if let Ok(version) = RustcVersion::parse(msrv) { return Some(version); } else if let Some(sess) = sess { if let Some(span) = span { @@ -75,8 +75,8 @@ pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Opt None } -pub fn meets_msrv(msrv: Option<&VersionReq>, lint_msrv: &Version) -> bool { - msrv.map_or(true, |msrv| !msrv.matches(lint_msrv)) +pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool { + msrv.map_or(true, |msrv| msrv > lint_msrv) } macro_rules! extract_msrv_attr { From 4e4b8319e83d1ec52253dd33c3d108b96fca9024 Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Sat, 28 Nov 2020 19:54:28 +0530 Subject: [PATCH 101/274] fix msrv in test --- tests/ui/min_rust_version_no_patch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/min_rust_version_no_patch.rs b/tests/ui/min_rust_version_no_patch.rs index 515fe8f95e9..98fffe1e351 100644 --- a/tests/ui/min_rust_version_no_patch.rs +++ b/tests/ui/min_rust_version_no_patch.rs @@ -1,6 +1,6 @@ #![allow(clippy::redundant_clone)] #![feature(custom_inner_attributes)] -#![clippy::msrv = "^1.0"] +#![clippy::msrv = "1.0"] fn manual_strip_msrv() { let s = "hello, world!"; From d55d791a3a5b1fb67966099ccb4a961d546e4ad6 Mon Sep 17 00:00:00 2001 From: bstrie Date: Sat, 24 Oct 2020 19:21:40 -0400 Subject: [PATCH 102/274] Update tests to remove old numeric constants Part of #68490. Care has been taken to leave the old consts where appropriate, for testing backcompat regressions, module shadowing, etc. The intrinsics docs were accidentally referring to some methods on f64 as std::f64, which I changed due to being contrary with how we normally disambiguate the shadow module from the primitive. In one other place I changed std::u8 to std::ops since it was just testing path handling in macros. For places which have legitimate uses of the old consts, deprecated attributes have been optimistically inserted. Although currently unnecessary, they exist to emphasize to any future deprecation effort the necessity of these specific symbols and prevent them from being accidentally removed. --- tests/ui/float_cmp_const.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/float_cmp_const.rs b/tests/ui/float_cmp_const.rs index dfc025558a2..263d9a7b92d 100644 --- a/tests/ui/float_cmp_const.rs +++ b/tests/ui/float_cmp_const.rs @@ -48,7 +48,7 @@ fn main() { v != 1.0; const ZERO_ARRAY: [f32; 3] = [0.0, 0.0, 0.0]; - const ZERO_INF_ARRAY: [f32; 3] = [0.0, ::std::f32::INFINITY, ::std::f32::NEG_INFINITY]; + const ZERO_INF_ARRAY: [f32; 3] = [0.0, f32::INFINITY, f32::NEG_INFINITY]; const NON_ZERO_ARRAY: [f32; 3] = [0.0, 0.1, 0.2]; const NON_ZERO_ARRAY2: [f32; 3] = [0.2, 0.1, 0.0]; From a75ab302d28b6751fa1d1d5e47f8a75cebbaaf79 Mon Sep 17 00:00:00 2001 From: suyash458 Date: Sat, 28 Nov 2020 23:17:43 -0800 Subject: [PATCH 103/274] fix dogfood tests --- clippy_lints/src/lib.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6eb5f6a7f48..52237b76c35 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -966,22 +966,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box implicit_return::ImplicitReturn); store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); - let parsed_msrv = conf.msrv.as_ref().and_then(|s| { + let msrv = conf.msrv.as_ref().and_then(|s| { parse_msrv(s, None, None).or_else(|| { sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s)); None }) }); - let msrv = parsed_msrv.clone(); - store.register_late_pass(move || box methods::Methods::new(msrv.clone())); - let msrv = parsed_msrv.clone(); - store.register_late_pass(move || box matches::Matches::new(msrv.clone())); - let msrv = parsed_msrv.clone(); - store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv.clone())); - let msrv = parsed_msrv; - store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv.clone())); - + store.register_late_pass(move || box methods::Methods::new(msrv)); + store.register_late_pass(move || box matches::Matches::new(msrv)); + store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); + store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); From af095db64c48caa73211f40e1648dadd6a23a2ca Mon Sep 17 00:00:00 2001 From: suyash458 Date: Sun, 29 Nov 2020 00:33:07 -0800 Subject: [PATCH 104/274] fix msrv check --- clippy_lints/src/utils/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index d68f0698153..9c5e55b1ed5 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -76,7 +76,7 @@ pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Opt } pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool { - msrv.map_or(true, |msrv| msrv > lint_msrv) + msrv.map_or(true, |msrv| msrv >= lint_msrv) } macro_rules! extract_msrv_attr { From 61b29281e744b6af410e9256cc2e9369a3dc173a Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Sun, 29 Nov 2020 17:08:56 +0530 Subject: [PATCH 105/274] add more tests for msrv --- tests/ui/min_rust_version_attr.rs | 38 ++++++++++++++++++++++++++- tests/ui/min_rust_version_attr.stderr | 37 ++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 tests/ui/min_rust_version_attr.stderr diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs index 8ed483a3ac6..1026cc40d3b 100644 --- a/tests/ui/min_rust_version_attr.rs +++ b/tests/ui/min_rust_version_attr.rs @@ -35,7 +35,7 @@ fn match_same_arms2() { }; } -fn manual_strip_msrv() { +pub fn manual_strip_msrv() { let s = "hello, world!"; if s.starts_with("hello, ") { assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); @@ -49,3 +49,39 @@ fn main() { match_same_arms2(); manual_strip_msrv(); } + +mod meets_msrv { + #![feature(custom_inner_attributes)] + #![clippy::msrv = "1.45.0"] + + fn main() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } + } +} + +mod just_under_msrv { + #![feature(custom_inner_attributes)] + #![clippy::msrv = "1.46.0"] + + fn main() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } + } +} + +mod just_above_msrv { + #![feature(custom_inner_attributes)] + #![clippy::msrv = "1.44.0"] + + fn main() { + let s = "hello, world!"; + if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + } + } +} diff --git a/tests/ui/min_rust_version_attr.stderr b/tests/ui/min_rust_version_attr.stderr new file mode 100644 index 00000000000..3e1af046e7a --- /dev/null +++ b/tests/ui/min_rust_version_attr.stderr @@ -0,0 +1,37 @@ +error: stripping a prefix manually + --> $DIR/min_rust_version_attr.rs:60:24 + | +LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::manual-strip` implied by `-D warnings` +note: the prefix was tested here + --> $DIR/min_rust_version_attr.rs:59:9 + | +LL | if s.starts_with("hello, ") { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix("hello, ") { +LL | assert_eq!(.to_uppercase(), "WORLD!"); + | + +error: stripping a prefix manually + --> $DIR/min_rust_version_attr.rs:72:24 + | +LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the prefix was tested here + --> $DIR/min_rust_version_attr.rs:71:9 + | +LL | if s.starts_with("hello, ") { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL | if let Some() = s.strip_prefix("hello, ") { +LL | assert_eq!(.to_uppercase(), "WORLD!"); + | + +error: aborting due to 2 previous errors + From 392ea297573dab95cc819cecd3a7f7e8e820316b Mon Sep 17 00:00:00 2001 From: oli Date: Sat, 28 Nov 2020 18:12:45 +0000 Subject: [PATCH 106/274] Cast pointers to usize before passing them to atomic operations as some platforms do not support atomic operations on pointers. --- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 49 ++++++++++++++----- library/core/src/sync/atomic.rs | 5 +- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 3026eadefe3..72a64a8c510 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -439,14 +439,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = substs.type_at(0); if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { let weak = split[1] == "cxchgweak"; - let pair = bx.atomic_cmpxchg( - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - order, - failorder, - weak, - ); + let mut dst = args[0].immediate(); + let mut cmp = args[1].immediate(); + let mut src = args[2].immediate(); + if ty.is_unsafe_ptr() { + // Some platforms do not support atomic operations on pointers, + // so we cast to integer first. + let ptr_llty = bx.type_ptr_to(bx.type_isize()); + dst = bx.pointercast(dst, ptr_llty); + cmp = bx.ptrtoint(cmp, bx.type_isize()); + src = bx.ptrtoint(src, bx.type_isize()); + } + let pair = bx.atomic_cmpxchg(dst, cmp, src, order, failorder, weak); let val = bx.extract_value(pair, 0); let success = bx.extract_value(pair, 1); let val = bx.from_immediate(val); @@ -465,8 +469,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "load" => { let ty = substs.type_at(0); if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { - let size = bx.layout_of(ty).size; - bx.atomic_load(args[0].immediate(), order, size) + let layout = bx.layout_of(ty); + let size = layout.size; + let mut source = args[0].immediate(); + if ty.is_unsafe_ptr() { + // Some platforms do not support atomic operations on pointers, + // so we cast to integer first... + let ptr_llty = bx.type_ptr_to(bx.type_isize()); + source = bx.pointercast(source, ptr_llty); + } + let result = bx.atomic_load(source, order, size); + if ty.is_unsafe_ptr() { + // ... and then cast the result back to a pointer + bx.inttoptr(result, bx.backend_type(layout)) + } else { + result + } } else { return invalid_monomorphization(ty); } @@ -476,7 +494,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = substs.type_at(0); if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { let size = bx.layout_of(ty).size; - bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size); + let mut val = args[1].immediate(); + let mut ptr = args[0].immediate(); + if ty.is_unsafe_ptr() { + // Some platforms do not support atomic operations on pointers, + // so we cast to integer first. + let ptr_llty = bx.type_ptr_to(bx.type_isize()); + ptr = bx.pointercast(ptr, ptr_llty); + val = bx.ptrtoint(val, bx.type_isize()); + } + bx.atomic_store(val, ptr, order, size); return; } else { return invalid_monomorphization(ty); diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index c167a9d8e5b..be6c86b5176 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1201,7 +1201,10 @@ impl AtomicPtr { } } #[cfg(not(bootstrap))] - // SAFETY: data races are prevented by atomic intrinsics. + // SAFETY: This intrinsic is unsafe because it operates on a raw pointer + // but we know for sure that the pointer is valid (we just got it from + // an `UnsafeCell` that we have by reference) and the atomic operation + // itself allows us to safely mutate the `UnsafeCell` contents. unsafe { atomic_compare_exchange_weak(self.p.get(), current, new, success, failure) } From 41f988e6ae5b44a2ca742c39fe5551b700379762 Mon Sep 17 00:00:00 2001 From: oli Date: Sun, 29 Nov 2020 14:56:19 +0000 Subject: [PATCH 107/274] Allow cranelift to handle atomic pointers --- compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index ab16fabd348..e5482187a73 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -146,12 +146,12 @@ macro atomic_minmax($fx:expr, $cc:expr, <$T:ident> ($ptr:ident, $src:ident) -> $ macro validate_atomic_type($fx:ident, $intrinsic:ident, $span:ident, $ty:expr) { match $ty.kind() { - ty::Uint(_) | ty::Int(_) => {} + ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} _ => { $fx.tcx.sess.span_err( $span, &format!( - "`{}` intrinsic: expected basic integer type, found `{:?}`", + "`{}` intrinsic: expected basic integer or raw pointer type, found `{:?}`", $intrinsic, $ty ), ); From de3a0bdf0503b22a8e4507c7b2d4cb84c335d272 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 23 Nov 2020 18:53:47 -0300 Subject: [PATCH 108/274] Fixes #79357 unstable or-pat suggestions --- compiler/rustc_parse/src/parser/pat.rs | 33 ++++++++++++------- ...92-tuple-destructure-missing-parens.stderr | 33 ++----------------- 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index ee9a6dca5ad..b62c7373800 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -18,7 +18,7 @@ pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"; /// Whether or not an or-pattern should be gated when occurring in the current context. -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub(super) enum GateOr { Yes, No, @@ -94,7 +94,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { // Parse the first pattern (`p_0`). let first_pat = self.parse_pat(expected)?; - self.maybe_recover_unexpected_comma(first_pat.span, rc)?; + self.maybe_recover_unexpected_comma(first_pat.span, rc, gate_or)?; // If the next token is not a `|`, // this is not an or-pattern and we should exit here. @@ -110,7 +110,7 @@ impl<'a> Parser<'a> { err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; - self.maybe_recover_unexpected_comma(pat.span, rc)?; + self.maybe_recover_unexpected_comma(pat.span, rc, gate_or)?; pats.push(pat); } let or_pattern_span = lo.to(self.prev_token.span); @@ -190,7 +190,12 @@ impl<'a> Parser<'a> { /// Some special error handling for the "top-level" patterns in a match arm, /// `for` loop, `let`, &c. (in contrast to subpatterns within such). - fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> { + fn maybe_recover_unexpected_comma( + &mut self, + lo: Span, + rc: RecoverComma, + gate_or: GateOr, + ) -> PResult<'a, ()> { if rc == RecoverComma::No || self.token != token::Comma { return Ok(()); } @@ -209,18 +214,24 @@ impl<'a> Parser<'a> { let seq_span = lo.to(self.prev_token.span); let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + const MSG: &str = "try adding parentheses to match on a tuple..."; + + let or_suggestion = + gate_or == GateOr::No || !self.sess.gated_spans.is_ungated(sym::or_patterns); err.span_suggestion( seq_span, - "try adding parentheses to match on a tuple...", + if or_suggestion { MSG } else { MSG.trim_end_matches('.') }, format!("({})", seq_snippet), Applicability::MachineApplicable, - ) - .span_suggestion( - seq_span, - "...or a vertical bar to match on multiple alternatives", - seq_snippet.replace(",", " |"), - Applicability::MachineApplicable, ); + if or_suggestion { + err.span_suggestion( + seq_span, + "...or a vertical bar to match on multiple alternatives", + seq_snippet.replace(",", " |"), + Applicability::MachineApplicable, + ); + } } Err(err) } diff --git a/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr index d05d6d120b0..26c24d7432c 100644 --- a/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr +++ b/src/test/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr @@ -47,46 +47,19 @@ error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:67:10 | LL | for x, _barr_body in women.iter().map(|woman| woman.allosomes.clone()) { - | ^ - | -help: try adding parentheses to match on a tuple... - | -LL | for (x, _barr_body) in women.iter().map(|woman| woman.allosomes.clone()) { - | ^^^^^^^^^^^^^^^ -help: ...or a vertical bar to match on multiple alternatives - | -LL | for x | _barr_body in women.iter().map(|woman| woman.allosomes.clone()) { - | ^^^^^^^^^^^^^^ + | -^----------- help: try adding parentheses to match on a tuple: `(x, _barr_body)` error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:75:10 | LL | for x, y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) { - | ^ - | -help: try adding parentheses to match on a tuple... - | -LL | for (x, y @ Allosome::Y(_)) in men.iter().map(|man| man.allosomes.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ -help: ...or a vertical bar to match on multiple alternatives - | -LL | for x | y @ Allosome::Y(_) in men.iter().map(|man| man.allosomes.clone()) { - | ^^^^^^^^^^^^^^^^^^^^^^ + | -^------------------- help: try adding parentheses to match on a tuple: `(x, y @ Allosome::Y(_))` error: unexpected `,` in pattern --> $DIR/issue-48492-tuple-destructure-missing-parens.rs:84:14 | LL | let women, men: (Vec, Vec) = genomes.iter().cloned() - | ^ - | -help: try adding parentheses to match on a tuple... - | -LL | let (women, men): (Vec, Vec) = genomes.iter().cloned() - | ^^^^^^^^^^^^ -help: ...or a vertical bar to match on multiple alternatives - | -LL | let women | men: (Vec, Vec) = genomes.iter().cloned() - | ^^^^^^^^^^^ + | -----^---- help: try adding parentheses to match on a tuple: `(women, men)` error: aborting due to 6 previous errors From 2838b044875b84bb9dc515ba3aa0c1b9772d870b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 8 Nov 2020 13:39:46 +0100 Subject: [PATCH 109/274] add internal-lints feature to enable clippys internal lints (off by default) --- .github/workflows/clippy_bors.yml | 4 +- Cargo.toml | 5 +- clippy_lints/Cargo.toml | 2 + clippy_lints/src/lib.rs | 28 ++++++++--- clippy_lints/src/utils/diagnostics.rs | 4 +- clippy_lints/src/utils/mod.rs | 1 + clippy_lints/src/utils/paths.rs | 4 ++ tests/compile-test.rs | 15 +++++- tests/dogfood.rs | 47 +++++++++++++------ .../collapsible_span_lint_calls.fixed | 0 .../collapsible_span_lint_calls.rs | 0 .../collapsible_span_lint_calls.stderr | 0 .../{ui => ui-internal}/custom_ice_message.rs | 0 .../custom_ice_message.stderr | 0 tests/{ui => ui-internal}/default_lint.rs | 0 tests/{ui => ui-internal}/default_lint.stderr | 0 tests/{ui => ui-internal}/invalid_paths.rs | 0 .../{ui => ui-internal}/invalid_paths.stderr | 0 .../lint_without_lint_pass.rs | 0 .../lint_without_lint_pass.stderr | 0 .../match_type_on_diag_item.rs | 0 .../match_type_on_diag_item.stderr | 0 .../{ui => ui-internal}/outer_expn_data.fixed | 0 tests/{ui => ui-internal}/outer_expn_data.rs | 0 .../outer_expn_data.stderr | 0 25 files changed, 84 insertions(+), 26 deletions(-) rename tests/{ui => ui-internal}/collapsible_span_lint_calls.fixed (100%) rename tests/{ui => ui-internal}/collapsible_span_lint_calls.rs (100%) rename tests/{ui => ui-internal}/collapsible_span_lint_calls.stderr (100%) rename tests/{ui => ui-internal}/custom_ice_message.rs (100%) rename tests/{ui => ui-internal}/custom_ice_message.stderr (100%) rename tests/{ui => ui-internal}/default_lint.rs (100%) rename tests/{ui => ui-internal}/default_lint.stderr (100%) rename tests/{ui => ui-internal}/invalid_paths.rs (100%) rename tests/{ui => ui-internal}/invalid_paths.stderr (100%) rename tests/{ui => ui-internal}/lint_without_lint_pass.rs (100%) rename tests/{ui => ui-internal}/lint_without_lint_pass.stderr (100%) rename tests/{ui => ui-internal}/match_type_on_diag_item.rs (100%) rename tests/{ui => ui-internal}/match_type_on_diag_item.stderr (100%) rename tests/{ui => ui-internal}/outer_expn_data.fixed (100%) rename tests/{ui => ui-internal}/outer_expn_data.rs (100%) rename tests/{ui => ui-internal}/outer_expn_data.stderr (100%) diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 7509d90c6c2..11c1eeac1cf 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -132,10 +132,10 @@ jobs: run: cargo build --features deny-warnings - name: Test - run: cargo test --features deny-warnings + run: cargo test --features deny-warnings --features internal-lints - name: Test clippy_lints - run: cargo test --features deny-warnings + run: cargo test --features deny-warnings --features internal-lints working-directory: clippy_lints - name: Test rustc_tools_util diff --git a/Cargo.toml b/Cargo.toml index 1ddcd18598d..a765390c603 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ path = "src/driver.rs" clippy_lints = { version = "0.0.212", path = "clippy_lints" } # end automatic update semver = "0.11" -rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"} +rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" } tempfile = { version = "3.1.0", optional = true } [dev-dependencies] @@ -49,8 +49,9 @@ derive-new = "0.5" rustc-workspace-hack = "1.0.0" [build-dependencies] -rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"} +rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" } [features] deny-warnings = [] integration = ["tempfile"] +internal-lints = ["clippy_lints/internal-lints"] diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index d9471d25197..969249cc446 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -36,3 +36,5 @@ syn = { version = "1", features = ["full"] } [features] deny-warnings = [] +# build clippy with internal lints enabled, off by default +internal-lints = [] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6eb5f6a7f48..a58f7eb3666 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -904,14 +904,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unwrap_in_result::UNWRAP_IN_RESULT, &use_self::USE_SELF, &useless_conversion::USELESS_CONVERSION, + #[cfg(feature = "internal-lints")] &utils::internal_lints::CLIPPY_LINTS_INTERNAL, + #[cfg(feature = "internal-lints")] &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, + #[cfg(feature = "internal-lints")] &utils::internal_lints::COMPILER_LINT_FUNCTIONS, + #[cfg(feature = "internal-lints")] &utils::internal_lints::DEFAULT_LINT, + #[cfg(feature = "internal-lints")] &utils::internal_lints::INVALID_PATHS, + #[cfg(feature = "internal-lints")] &utils::internal_lints::LINT_WITHOUT_LINT_PASS, + #[cfg(feature = "internal-lints")] &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + #[cfg(feature = "internal-lints")] &utils::internal_lints::OUTER_EXPN_EXPN_DATA, + #[cfg(feature = "internal-lints")] &utils::internal_lints::PRODUCE_ICE, &vec::USELESS_VEC, &vec_resize_to_zero::VEC_RESIZE_TO_ZERO, @@ -932,11 +941,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: // end register lints, do not remove this comment, it’s used in `update_lints` store.register_late_pass(|| box await_holding_invalid::AwaitHolding); store.register_late_pass(|| box serde_api::SerdeAPI); - store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); - store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); - store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass); - store.register_late_pass(|| box utils::internal_lints::InvalidPaths); - store.register_late_pass(|| box utils::inspector::DeepCodeInspector); + #[cfg(feature = "internal-lints")] + { + store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); + store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); + store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass); + store.register_late_pass(|| box utils::internal_lints::InvalidPaths); + store.register_late_pass(|| box utils::inspector::DeepCodeInspector); + } store.register_late_pass(|| box utils::author::Author); let vec_box_size_threshold = conf.vec_box_size_threshold; store.register_late_pass(move || box types::Types::new(vec_box_size_threshold)); @@ -1122,6 +1134,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box literal_representation::LiteralDigitGrouping); let literal_representation_threshold = conf.literal_representation_threshold; store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)); + #[cfg(feature = "internal-lints")] store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal); let enum_variant_name_threshold = conf.enum_variant_name_threshold; store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold)); @@ -1136,6 +1149,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold)); store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic); store.register_early_pass(|| box as_conversions::AsConversions); + #[cfg(feature = "internal-lints")] store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_late_pass(|| box let_underscore::LetUnderscore); store.register_late_pass(|| box atomic_ordering::AtomicOrdering); @@ -1152,6 +1166,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box dereference::Dereferencing); store.register_late_pass(|| box option_if_let_else::OptionIfLetElse); store.register_late_pass(|| box future_not_send::FutureNotSend); + #[cfg(feature = "internal-lints")] store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_late_pass(|| box if_let_mutex::IfLetMutex); store.register_late_pass(|| box mut_mutex_lock::MutMutexLock); @@ -1177,6 +1192,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box manual_ok_or::ManualOkOr); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); + #[cfg(feature = "internal-lints")] store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::>(); store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); @@ -1317,7 +1333,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&wildcard_imports::ENUM_GLOB_USE), LintId::of(&wildcard_imports::WILDCARD_IMPORTS), ]); - + #[cfg(feature = "internal-lints")] store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL), LintId::of(&utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index 0a58231558e..a7a6b5855b7 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -186,7 +186,9 @@ pub fn span_lint_hir_and_then( /// | /// = note: `-D fold-any` implied by `-D warnings` /// ``` -#[allow(clippy::collapsible_span_lint_calls)] + +#[allow(clippy::unknown_clippy_lints)] +#[cfg_attr(feature = "internal-lints", allow(clippy::collapsible_span_lint_calls))] pub fn span_lint_and_sugg<'a, T: LintContext>( cx: &'a T, lint: &'static Lint, diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 850abc3bae7..63f14c592bd 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -14,6 +14,7 @@ pub mod eager_or_lazy; pub mod higher; mod hir_utils; pub mod inspector; +#[cfg(feature = "internal-lints")] pub mod internal_lints; pub mod numeric_literal; pub mod paths; diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 61aeabb7ba7..16e6a016c9e 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -31,6 +31,7 @@ pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"]; pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"]; pub const DROP: [&str; 3] = ["core", "mem", "drop"]; pub const DURATION: [&str; 3] = ["core", "time", "Duration"]; +#[cfg(feature = "internal-lints")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; pub const EXIT: [&str; 3] = ["std", "process", "exit"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; @@ -61,8 +62,10 @@ pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const IPADDR_V4: [&str; 4] = ["std", "net", "IpAddr", "V4"]; pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"]; pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"]; +#[cfg(feature = "internal-lints")] pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"]; +#[cfg(feature = "internal-lints")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"]; pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"]; @@ -133,6 +136,7 @@ pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "", "starts_with"]; +#[cfg(feature = "internal-lints")] pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"]; pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"]; diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 0e8f7683103..ec3af94b9ca 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -12,6 +12,9 @@ use std::path::{Path, PathBuf}; mod cargo; +// whether to run internal tests or not +const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints"); + fn host_lib() -> PathBuf { option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from) } @@ -96,6 +99,16 @@ fn run_mode(cfg: &mut compiletest::Config) { compiletest::run_tests(&cfg); } +fn run_internal_tests(cfg: &mut compiletest::Config) { + // only run internal tests with the internal-tests feature + if !RUN_INTERNAL_TESTS { + return; + } + cfg.mode = TestMode::Ui; + cfg.src_base = Path::new("tests").join("ui-internal"); + compiletest::run_tests(&cfg); +} + fn run_ui_toml(config: &mut compiletest::Config) { fn run_tests(config: &compiletest::Config, mut tests: Vec) -> Result { let mut result = true; @@ -199,7 +212,6 @@ fn run_ui_cargo(config: &mut compiletest::Config) { Some("main.rs") => {}, _ => continue, } - let paths = compiletest::common::TestPaths { file: file_path, base: config.src_base.clone(), @@ -253,4 +265,5 @@ fn compile_test() { run_mode(&mut config); run_ui_toml(&mut config); run_ui_cargo(&mut config); + run_internal_tests(&mut config); } diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 48e0478f169..eae25adf839 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -18,20 +18,39 @@ fn dogfood_clippy() { } let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let output = Command::new(&*CLIPPY_PATH) - .current_dir(root_dir) - .env("CLIPPY_DOGFOOD", "1") - .env("CARGO_INCREMENTAL", "0") - .arg("clippy-preview") - .arg("--all-targets") - .arg("--all-features") - .arg("--") - .args(&["-D", "clippy::all"]) - .args(&["-D", "clippy::internal"]) - .args(&["-D", "clippy::pedantic"]) - .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir - .output() - .unwrap(); + let output = if cfg!(feature = "internal-lints") { + // with internal lints and internal warnings + Command::new(&*CLIPPY_PATH) + .current_dir(root_dir) + .env("CLIPPY_DOGFOOD", "1") + .env("CARGO_INCREMENTAL", "0") + .arg("clippy-preview") + .arg("--all-targets") + .arg("--all-features") + .args(&["--features", "internal-lints"]) + .arg("--") + .args(&["-D", "clippy::all"]) + .args(&["-D", "clippy::pedantic"]) + .args(&["-D", "clippy::internal"]) + .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir + .output() + .unwrap() + } else { + // without internal lints or warnings + Command::new(&*CLIPPY_PATH) + .current_dir(root_dir) + .env("CLIPPY_DOGFOOD", "1") + .env("CARGO_INCREMENTAL", "0") + .arg("clippy-preview") + .arg("--all-targets") + .arg("--all-features") + .arg("--") + .args(&["-D", "clippy::all"]) + .args(&["-D", "clippy::pedantic"]) + .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir + .output() + .unwrap() + }; println!("status: {}", output.status); println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); diff --git a/tests/ui/collapsible_span_lint_calls.fixed b/tests/ui-internal/collapsible_span_lint_calls.fixed similarity index 100% rename from tests/ui/collapsible_span_lint_calls.fixed rename to tests/ui-internal/collapsible_span_lint_calls.fixed diff --git a/tests/ui/collapsible_span_lint_calls.rs b/tests/ui-internal/collapsible_span_lint_calls.rs similarity index 100% rename from tests/ui/collapsible_span_lint_calls.rs rename to tests/ui-internal/collapsible_span_lint_calls.rs diff --git a/tests/ui/collapsible_span_lint_calls.stderr b/tests/ui-internal/collapsible_span_lint_calls.stderr similarity index 100% rename from tests/ui/collapsible_span_lint_calls.stderr rename to tests/ui-internal/collapsible_span_lint_calls.stderr diff --git a/tests/ui/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs similarity index 100% rename from tests/ui/custom_ice_message.rs rename to tests/ui-internal/custom_ice_message.rs diff --git a/tests/ui/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr similarity index 100% rename from tests/ui/custom_ice_message.stderr rename to tests/ui-internal/custom_ice_message.stderr diff --git a/tests/ui/default_lint.rs b/tests/ui-internal/default_lint.rs similarity index 100% rename from tests/ui/default_lint.rs rename to tests/ui-internal/default_lint.rs diff --git a/tests/ui/default_lint.stderr b/tests/ui-internal/default_lint.stderr similarity index 100% rename from tests/ui/default_lint.stderr rename to tests/ui-internal/default_lint.stderr diff --git a/tests/ui/invalid_paths.rs b/tests/ui-internal/invalid_paths.rs similarity index 100% rename from tests/ui/invalid_paths.rs rename to tests/ui-internal/invalid_paths.rs diff --git a/tests/ui/invalid_paths.stderr b/tests/ui-internal/invalid_paths.stderr similarity index 100% rename from tests/ui/invalid_paths.stderr rename to tests/ui-internal/invalid_paths.stderr diff --git a/tests/ui/lint_without_lint_pass.rs b/tests/ui-internal/lint_without_lint_pass.rs similarity index 100% rename from tests/ui/lint_without_lint_pass.rs rename to tests/ui-internal/lint_without_lint_pass.rs diff --git a/tests/ui/lint_without_lint_pass.stderr b/tests/ui-internal/lint_without_lint_pass.stderr similarity index 100% rename from tests/ui/lint_without_lint_pass.stderr rename to tests/ui-internal/lint_without_lint_pass.stderr diff --git a/tests/ui/match_type_on_diag_item.rs b/tests/ui-internal/match_type_on_diag_item.rs similarity index 100% rename from tests/ui/match_type_on_diag_item.rs rename to tests/ui-internal/match_type_on_diag_item.rs diff --git a/tests/ui/match_type_on_diag_item.stderr b/tests/ui-internal/match_type_on_diag_item.stderr similarity index 100% rename from tests/ui/match_type_on_diag_item.stderr rename to tests/ui-internal/match_type_on_diag_item.stderr diff --git a/tests/ui/outer_expn_data.fixed b/tests/ui-internal/outer_expn_data.fixed similarity index 100% rename from tests/ui/outer_expn_data.fixed rename to tests/ui-internal/outer_expn_data.fixed diff --git a/tests/ui/outer_expn_data.rs b/tests/ui-internal/outer_expn_data.rs similarity index 100% rename from tests/ui/outer_expn_data.rs rename to tests/ui-internal/outer_expn_data.rs diff --git a/tests/ui/outer_expn_data.stderr b/tests/ui-internal/outer_expn_data.stderr similarity index 100% rename from tests/ui/outer_expn_data.stderr rename to tests/ui-internal/outer_expn_data.stderr From 958e2e20de762fa45f50e41a58c97548f79f8100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 13 Nov 2020 02:12:48 +0100 Subject: [PATCH 110/274] fix clippy-dev update_lints --- clippy_dev/src/lib.rs | 30 +++++++++++++++++++++------- clippy_dev/src/update_lints.rs | 2 +- clippy_lints/src/lib.rs | 36 +++++++++++++++++----------------- 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 43cb2954b74..1453ac7efa3 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -146,16 +146,32 @@ pub fn gen_deprecated<'a>(lints: impl Iterator) -> Vec } #[must_use] -pub fn gen_register_lint_list<'a>(lints: impl Iterator) -> Vec { - let pre = " store.register_lints(&[".to_string(); - let post = " ]);".to_string(); - let mut inner = lints +pub fn gen_register_lint_list<'a>( + internal_lints: impl Iterator, + usable_lints: impl Iterator, +) -> Vec { + let header = " store.register_lints(&[".to_string(); + let footer = " ]);".to_string(); + let internal_lints = internal_lints + .sorted_by_key(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) + .map(|l| { + format!( + " #[cfg(feature = \"internal-lints\")]\n &{}::{},", + l.module, + l.name.to_uppercase() + ) + }) + .collect::>(); + let other_lints = usable_lints + .sorted_by_key(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) .map(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) .sorted() .collect::>(); - inner.insert(0, pre); - inner.push(post); - inner + let mut lint_list = vec![header]; + lint_list.extend(internal_lints); + lint_list.extend(other_lints); + lint_list.push(footer); + lint_list } /// Gathers all files in `src/clippy_lints` and gathers all lints inside diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index fcf093f8835..edf6c5f57a4 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -68,7 +68,7 @@ pub fn run(update_mode: UpdateMode) { "end register lints", false, update_mode == UpdateMode::Change, - || gen_register_lint_list(usable_lints.iter().chain(internal_lints.iter())), + || gen_register_lint_list(internal_lints.iter(), usable_lints.iter()), ) .changed; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a58f7eb3666..fed7da3ee4f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -498,6 +498,24 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: // begin register lints, do not remove this comment, it’s used in `update_lints` store.register_lints(&[ + #[cfg(feature = "internal-lints")] + &utils::internal_lints::CLIPPY_LINTS_INTERNAL, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::COMPILER_LINT_FUNCTIONS, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::DEFAULT_LINT, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::INVALID_PATHS, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::LINT_WITHOUT_LINT_PASS, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::OUTER_EXPN_EXPN_DATA, + #[cfg(feature = "internal-lints")] + &utils::internal_lints::PRODUCE_ICE, &approx_const::APPROX_CONSTANT, &arithmetic::FLOAT_ARITHMETIC, &arithmetic::INTEGER_ARITHMETIC, @@ -904,24 +922,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unwrap_in_result::UNWRAP_IN_RESULT, &use_self::USE_SELF, &useless_conversion::USELESS_CONVERSION, - #[cfg(feature = "internal-lints")] - &utils::internal_lints::CLIPPY_LINTS_INTERNAL, - #[cfg(feature = "internal-lints")] - &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, - #[cfg(feature = "internal-lints")] - &utils::internal_lints::COMPILER_LINT_FUNCTIONS, - #[cfg(feature = "internal-lints")] - &utils::internal_lints::DEFAULT_LINT, - #[cfg(feature = "internal-lints")] - &utils::internal_lints::INVALID_PATHS, - #[cfg(feature = "internal-lints")] - &utils::internal_lints::LINT_WITHOUT_LINT_PASS, - #[cfg(feature = "internal-lints")] - &utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, - #[cfg(feature = "internal-lints")] - &utils::internal_lints::OUTER_EXPN_EXPN_DATA, - #[cfg(feature = "internal-lints")] - &utils::internal_lints::PRODUCE_ICE, &vec::USELESS_VEC, &vec_resize_to_zero::VEC_RESIZE_TO_ZERO, &verbose_file_reads::VERBOSE_FILE_READS, From b25a6df7754ed3de9914f9d03facdfb09728fbaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 13 Nov 2020 11:36:07 +0100 Subject: [PATCH 111/274] ci: partly clean build artifacts to work around "Found multiple rlibs for crate `clippy_lints`" compiletest error --- .github/workflows/clippy_bors.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 11c1eeac1cf..a8b4925176c 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -131,11 +131,18 @@ jobs: - name: Build run: cargo build --features deny-warnings - - name: Test - run: cargo test --features deny-warnings --features internal-lints + # compiletest would panic due to "Found multiple rlibs for crate `clippy_lints`" + - name: clean rlibs + run: rm -f ./target/debug/deps/libclippy_lints* - - name: Test clippy_lints - run: cargo test --features deny-warnings --features internal-lints + - name: Build with internal lints + run: cargo build --features deny-warnings,internal-lints + + - name: Test with internal lints + run: cargo test --features deny-warnings,internal-lints + + - name: Test clippy_lints with internal lints + run: cargo test --features deny-warnings,internal-lints working-directory: clippy_lints - name: Test rustc_tools_util From 5df286b636e0bf71a665599f099da18a2b90936c Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 27 Nov 2020 12:15:05 -0600 Subject: [PATCH 112/274] Improve SpanlessEq for blocks --- clippy_lints/src/utils/hir_utils.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index e4ad105c351..d847d22275e 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -81,7 +81,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { } } - match (&left.kind, &right.kind) { + match (&reduce_exprkind(&left.kind), &reduce_exprkind(&right.kind)) { (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => { lb == rb && l_mut == r_mut && self.eq_expr(le, re) }, @@ -306,6 +306,32 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { } } +/// Some simple reductions like `{ return }` => `return` +fn reduce_exprkind<'hir>(kind: &'hir ExprKind<'hir>) -> &ExprKind<'hir> { + if let ExprKind::Block(block, _) = kind { + match (block.stmts, block.expr) { + // `{}` => `()` + ([], None) => &ExprKind::Tup(&[]), + ([], Some(expr)) => match expr.kind { + // `{ return .. }` => `return ..` + ExprKind::Ret(..) => &expr.kind, + _ => kind, + }, + ([stmt], None) => match stmt.kind { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind { + // `{ return ..; }` => `return ..` + ExprKind::Ret(..) => &expr.kind, + _ => kind, + }, + _ => kind, + }, + _ => kind, + } + } else { + kind + } +} + fn swap_binop<'a>( binop: BinOpKind, lhs: &'a Expr<'a>, From 6e1fbfdb8fe9a6b543fa2b0e688f928d2ee354b8 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 27 Nov 2020 17:13:19 -0600 Subject: [PATCH 113/274] Add LocalUseVisitor --- clippy_lints/src/utils/visitors.rs | 55 +++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs index b0837b6c43e..28b3e79d7a6 100644 --- a/clippy_lints/src/utils/visitors.rs +++ b/clippy_lints/src/utils/visitors.rs @@ -1,5 +1,7 @@ use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::{Arm, Expr, ExprKind, HirId, QPath, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -123,3 +125,54 @@ where !ret_finder.failed } } + +pub struct LocalUsedVisitor { + pub local_hir_id: HirId, + pub used: bool, +} + +impl LocalUsedVisitor { + pub fn new(local_hir_id: HirId) -> Self { + Self { + local_hir_id, + used: false, + } + } + + fn check(&mut self, t: T, visit: fn(&mut Self, T)) -> bool { + visit(self, t); + std::mem::replace(&mut self.used, false) + } + + pub fn check_arm(&mut self, arm: &Arm<'_>) -> bool { + self.check(arm, Self::visit_arm) + } + + pub fn check_expr(&mut self, expr: &Expr<'_>) -> bool { + self.check(expr, Self::visit_expr) + } + + pub fn check_stmt(&mut self, stmt: &Stmt<'_>) -> bool { + self.check(stmt, Self::visit_stmt) + } +} + +impl<'v> Visitor<'v> for LocalUsedVisitor { + type Map = Map<'v>; + + fn visit_expr(&mut self, expr: &'v Expr<'v>) { + if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind { + if let Res::Local(id) = path.res { + if id == self.local_hir_id { + self.used = true; + return; + } + } + } + walk_expr(self, expr); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } +} From 28dec3b708c3e0d5e45b6c70f054860cbd53d624 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 24 Nov 2020 20:37:07 -0600 Subject: [PATCH 114/274] Add collapsible_match lint --- CHANGELOG.md | 1 + clippy_lints/src/collapsible_match.rs | 172 ++++++++++++++++ clippy_lints/src/lib.rs | 5 + tests/ui/collapsible_match.rs | 278 ++++++++++++++++++++++++++ tests/ui/collapsible_match.stderr | 237 ++++++++++++++++++++++ 5 files changed, 693 insertions(+) create mode 100644 clippy_lints/src/collapsible_match.rs create mode 100644 tests/ui/collapsible_match.rs create mode 100644 tests/ui/collapsible_match.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index e76a781f13b..e65e7cc639f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1770,6 +1770,7 @@ Released 2018-09-13 [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned [`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if +[`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs new file mode 100644 index 00000000000..a34ba2d00a8 --- /dev/null +++ b/clippy_lints/src/collapsible_match.rs @@ -0,0 +1,172 @@ +use crate::utils::visitors::LocalUsedVisitor; +use crate::utils::{span_lint_and_then, SpanlessEq}; +use if_chain::if_chain; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{DefIdTree, TyCtxt}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{MultiSpan, Span}; + +declare_clippy_lint! { + /// **What it does:** Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together + /// without adding any branches. + /// + /// Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only + /// cases where merging would most likely make the code more readable. + /// + /// **Why is this bad?** It is unnecessarily verbose and complex. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// fn func(opt: Option>) { + /// let n = match opt { + /// Some(n) => match n { + /// Ok(n) => n, + /// _ => return, + /// } + /// None => return, + /// }; + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn func(opt: Option>) { + /// let n = match opt { + /// Some(Ok(n)) => n, + /// _ => return, + /// }; + /// } + /// ``` + pub COLLAPSIBLE_MATCH, + style, + "Nested `match` or `if let` expressions where the patterns may be \"collapsed\" together." +} + +declare_lint_pass!(CollapsibleMatch => [COLLAPSIBLE_MATCH]); + +impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::Match(_expr, arms, _source) = expr.kind { + if let Some(wild_arm) = arms.iter().rfind(|arm| arm_is_wild_like(arm, cx.tcx)) { + for arm in arms { + check_arm(arm, wild_arm, cx); + } + } + } + } +} + +fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) { + if_chain! { + let expr = strip_singleton_blocks(arm.body); + if let ExprKind::Match(expr_in, arms_inner, _) = expr.kind; + // the outer arm pattern and the inner match + if expr_in.span.ctxt() == arm.pat.span.ctxt(); + // there must be no more than two arms in the inner match for this lint + if arms_inner.len() == 2; + // no if guards on the inner match + if arms_inner.iter().all(|arm| arm.guard.is_none()); + // match expression must be a local binding + // match { .. } + if let ExprKind::Path(QPath::Resolved(None, path)) = expr_in.kind; + if let Res::Local(binding_id) = path.res; + // one of the branches must be "wild-like" + if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(arm_inner, cx.tcx)); + let (wild_inner_arm, non_wild_inner_arm) = + (&arms_inner[wild_inner_arm_idx], &arms_inner[1 - wild_inner_arm_idx]); + if !pat_contains_or(non_wild_inner_arm.pat); + // the binding must come from the pattern of the containing match arm + // .... => match { .. } + if let Some(binding_span) = find_pat_binding(arm.pat, binding_id); + // the "wild-like" branches must be equal + if SpanlessEq::new(cx).eq_expr(wild_inner_arm.body, wild_outer_arm.body); + // the binding must not be used in the if guard + if !matches!(arm.guard, Some(Guard::If(guard)) if LocalUsedVisitor::new(binding_id).check_expr(guard)); + // ...or anywhere in the inner match + if !arms_inner.iter().any(|arm| LocalUsedVisitor::new(binding_id).check_arm(arm)); + then { + span_lint_and_then( + cx, + COLLAPSIBLE_MATCH, + expr.span, + "Unnecessary nested match", + |diag| { + let mut help_span = MultiSpan::from_spans(vec![binding_span, non_wild_inner_arm.pat.span]); + help_span.push_span_label(binding_span, "Replace this binding".into()); + help_span.push_span_label(non_wild_inner_arm.pat.span, "with this pattern".into()); + diag.span_help(help_span, "The outer pattern can be modified to include the inner pattern."); + }, + ); + } + } +} + +fn strip_singleton_blocks<'hir>(mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { + while let ExprKind::Block(block, _) = expr.kind { + match (block.stmts, block.expr) { + ([stmt], None) => match stmt.kind { + StmtKind::Expr(e) | StmtKind::Semi(e) => expr = e, + _ => break, + }, + ([], Some(e)) => expr = e, + _ => break, + } + } + expr +} + +/// A "wild-like" pattern is wild ("_") or `None`. +/// For this lint to apply, both the outer and inner match expressions +/// must have "wild-like" branches that can be combined. +fn arm_is_wild_like(arm: &Arm<'_>, tcx: TyCtxt<'_>) -> bool { + if arm.guard.is_some() { + return false; + } + match arm.pat.kind { + PatKind::Binding(..) | PatKind::Wild => true, + PatKind::Path(QPath::Resolved(None, path)) if is_none_ctor(path.res, tcx) => true, + _ => false, + } +} + +fn find_pat_binding(pat: &Pat<'_>, hir_id: HirId) -> Option { + let mut span = None; + pat.walk_short(|p| match &p.kind { + // ignore OR patterns + PatKind::Or(_) => false, + PatKind::Binding(_bm, _, _ident, _) => { + let found = p.hir_id == hir_id; + if found { + span = Some(p.span); + } + !found + }, + _ => true, + }); + span +} + +fn pat_contains_or(pat: &Pat<'_>) -> bool { + let mut result = false; + pat.walk(|p| { + let is_or = matches!(p.kind, PatKind::Or(_)); + result |= is_or; + !is_or + }); + result +} + +fn is_none_ctor(res: Res, tcx: TyCtxt<'_>) -> bool { + if let Some(none_id) = tcx.lang_items().option_none_variant() { + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = res { + if let Some(variant_id) = tcx.parent(id) { + return variant_id == none_id; + } + } + } + false +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6eb5f6a7f48..ca190986cdb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -172,6 +172,7 @@ mod cargo_common_metadata; mod checked_conversions; mod cognitive_complexity; mod collapsible_if; +mod collapsible_match; mod comparison_chain; mod copies; mod copy_iterator; @@ -531,6 +532,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &checked_conversions::CHECKED_CONVERSIONS, &cognitive_complexity::COGNITIVE_COMPLEXITY, &collapsible_if::COLLAPSIBLE_IF, + &collapsible_match::COLLAPSIBLE_MATCH, &comparison_chain::COMPARISON_CHAIN, &copies::IFS_SAME_COND, &copies::IF_SAME_THEN_ELSE, @@ -960,6 +962,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box len_zero::LenZero); store.register_late_pass(|| box attrs::Attributes); store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions); + store.register_late_pass(|| box collapsible_match::CollapsibleMatch); store.register_late_pass(|| box unicode::Unicode); store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd); store.register_late_pass(|| box strings::StringAdd); @@ -1351,6 +1354,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&booleans::NONMINIMAL_BOOL), LintId::of(&bytecount::NAIVE_BYTECOUNT), LintId::of(&collapsible_if::COLLAPSIBLE_IF), + LintId::of(&collapsible_match::COLLAPSIBLE_MATCH), LintId::of(&comparison_chain::COMPARISON_CHAIN), LintId::of(&copies::IFS_SAME_COND), LintId::of(&copies::IF_SAME_THEN_ELSE), @@ -1617,6 +1621,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&blacklisted_name::BLACKLISTED_NAME), LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(&collapsible_if::COLLAPSIBLE_IF), + LintId::of(&collapsible_match::COLLAPSIBLE_MATCH), LintId::of(&comparison_chain::COMPARISON_CHAIN), LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT), LintId::of(&doc::MISSING_SAFETY_DOC), diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs new file mode 100644 index 00000000000..75640b70ff0 --- /dev/null +++ b/tests/ui/collapsible_match.rs @@ -0,0 +1,278 @@ +#![warn(clippy::collapsible_match)] +#![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)] + +fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { + // match without block + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + + // match with block + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + + // if let, if let + if let Ok(val) = res_opt { + if let Some(n) = val { + take(n); + } + } + + // if let else, if let else + if let Ok(val) = res_opt { + if let Some(n) = val { + take(n); + } else { + return; + } + } else { + return; + } + + // if let, match + if let Ok(val) = res_opt { + match val { + Some(n) => foo(n), + _ => (), + } + } + + // match, if let + match res_opt { + Ok(val) => { + if let Some(n) = val { + take(n); + } + }, + _ => {}, + } + + // if let else, match + if let Ok(val) = res_opt { + match val { + Some(n) => foo(n), + _ => return, + } + } else { + return; + } + + // match, if let else + match res_opt { + Ok(val) => { + if let Some(n) = val { + take(n); + } else { + return; + } + }, + _ => return, + } + + // None in inner match same as outer wild branch + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + None => return, + }, + _ => return, + } + + // None in outer match same as inner wild branch + match opt_opt { + Some(val) => match val { + Some(n) => foo(n), + _ => return, + }, + None => return, + } + + // if guards on outer match + { + match res_opt { + Ok(val) if make() => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => return, + }, + _ if make() => return, + _ => return, + } + } + + // macro + { + macro_rules! mac { + ($outer:expr => $pat:pat, $e:expr => $inner_pat:pat, $then:expr) => { + match $outer { + $pat => match $e { + $inner_pat => $then, + _ => return, + }, + _ => return, + } + }; + } + // Lint this since the patterns are not defined by the macro. + // Allows the lint to work on if_chain! for example. + // Fixing the lint requires knowledge of the specific macro, but we optimistically assume that + // there is still a better way to write this. + mac!(res_opt => Ok(val), val => Some(n), foo(n)); + } +} + +fn negative_cases(res_opt: Result, String>, res_res: Result, String>) { + // no wild pattern in outer match + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => return, + }, + Err(_) => return, + } + + // inner branch is not wild or None + match res_res { + Ok(val) => match val { + Ok(n) => foo(n), + Err(_) => return, + }, + _ => return, + } + + // statement before inner match + match res_opt { + Ok(val) => { + "hi buddy"; + match val { + Some(n) => foo(n), + _ => return, + } + }, + _ => return, + } + + // statement after inner match + match res_opt { + Ok(val) => { + match val { + Some(n) => foo(n), + _ => return, + } + "hi buddy"; + }, + _ => return, + } + + // wild branches do not match + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => { + "sup"; + return; + }, + }, + _ => return, + } + + // binding used in if guard + match res_opt { + Ok(val) if val.is_some() => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + + // binding used in inner match body + match res_opt { + Ok(val) => match val { + Some(_) => take(val), + _ => return, + }, + _ => return, + } + + // if guard on inner match + { + match res_opt { + Ok(val) => match val { + Some(n) if make() => foo(n), + _ => return, + }, + _ => return, + } + match res_opt { + Ok(val) => match val { + _ => make(), + _ if make() => return, + }, + _ => return, + } + } + + // differing macro contexts + { + macro_rules! mac { + ($val:ident) => { + match $val { + Some(n) => foo(n), + _ => return, + } + }; + } + match res_opt { + Ok(val) => mac!(val), + _ => return, + } + } + + // OR pattern + enum E { + A(T), + B(T), + C(T), + }; + match make::>>() { + E::A(val) | E::B(val) => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + match make::>>() { + Some(val) => match val { + E::A(val) | E::B(val) => foo(val), + _ => return, + }, + _ => return, + } +} + +fn make() -> T { + unimplemented!() +} + +fn foo(t: T) -> U { + unimplemented!() +} + +fn take(t: T) {} + +fn main() {} diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr new file mode 100644 index 00000000000..a9e4f911914 --- /dev/null +++ b/tests/ui/collapsible_match.stderr @@ -0,0 +1,237 @@ +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:7:20 + | +LL | Ok(val) => match val { + | ____________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_________^ + | + = note: `-D clippy::collapsible-match` implied by `-D warnings` +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:7:12 + | +LL | Ok(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:16:20 + | +LL | Ok(val) => match val { + | ____________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:16:12 + | +LL | Ok(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:25:9 + | +LL | / if let Some(n) = val { +LL | | take(n); +LL | | } + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:24:15 + | +LL | if let Ok(val) = res_opt { + | ^^^ Replace this binding +LL | if let Some(n) = val { + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:32:9 + | +LL | / if let Some(n) = val { +LL | | take(n); +LL | | } else { +LL | | return; +LL | | } + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:31:15 + | +LL | if let Ok(val) = res_opt { + | ^^^ Replace this binding +LL | if let Some(n) = val { + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:43:9 + | +LL | / match val { +LL | | Some(n) => foo(n), +LL | | _ => (), +LL | | } + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:42:15 + | +LL | if let Ok(val) = res_opt { + | ^^^ Replace this binding +LL | match val { +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:52:13 + | +LL | / if let Some(n) = val { +LL | | take(n); +LL | | } + | |_____________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:51:12 + | +LL | Ok(val) => { + | ^^^ Replace this binding +LL | if let Some(n) = val { + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:61:9 + | +LL | / match val { +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | } + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:60:15 + | +LL | if let Ok(val) = res_opt { + | ^^^ Replace this binding +LL | match val { +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:72:13 + | +LL | / if let Some(n) = val { +LL | | take(n); +LL | | } else { +LL | | return; +LL | | } + | |_____________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:71:12 + | +LL | Ok(val) => { + | ^^^ Replace this binding +LL | if let Some(n) = val { + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:83:20 + | +LL | Ok(val) => match val { + | ____________________^ +LL | | Some(n) => foo(n), +LL | | None => return, +LL | | }, + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:83:12 + | +LL | Ok(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:92:22 + | +LL | Some(val) => match val { + | ______________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:92:14 + | +LL | Some(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:102:34 + | +LL | Ok(val) if make() => match val { + | __________________________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_____________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:102:16 + | +LL | Ok(val) if make() => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:109:24 + | +LL | Ok(val) => match val { + | ________________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_____________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:109:16 + | +LL | Ok(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match.rs:123:29 + | +LL | $pat => match $e { + | _____________________________^ +LL | | $inner_pat => $then, +LL | | _ => return, +LL | | }, + | |_____________________^ +... +LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); + | ------------------------------------------------- in this macro invocation + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match.rs:135:28 + | +LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); + | ^^^ ^^^^^^^ with this pattern + | | + | Replace this binding + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 13 previous errors + From fff5fa65816f482357989f25a58e98688cb7363d Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 24 Nov 2020 20:57:09 -0600 Subject: [PATCH 115/274] Eat collapsible_match dogfood --- clippy_lints/src/default.rs | 3 +-- clippy_lints/src/if_let_some_result.rs | 3 +-- clippy_lints/src/implicit_return.rs | 3 +-- clippy_lints/src/implicit_saturating_sub.rs | 3 +-- clippy_lints/src/large_const_arrays.rs | 3 +-- clippy_lints/src/large_stack_arrays.rs | 3 +-- clippy_lints/src/loops.rs | 6 ++--- clippy_lints/src/manual_strip.rs | 3 +-- clippy_lints/src/matches.rs | 24 ++++++++----------- .../methods/manual_saturating_arithmetic.rs | 3 +-- clippy_lints/src/needless_bool.rs | 11 +++------ clippy_lints/src/question_mark.rs | 3 +-- clippy_lints/src/strings.rs | 3 +-- clippy_lints/src/trait_bounds.rs | 3 +-- clippy_lints/src/transmuting_null.rs | 3 +-- clippy_lints/src/types.rs | 6 ++--- clippy_lints/src/utils/higher.rs | 3 +-- 17 files changed, 30 insertions(+), 56 deletions(-) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 612c5355338..f69f6f1412a 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -280,8 +280,7 @@ fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Op // only take assignments to fields where the left-hand side field is a field of // the same binding as the previous statement if let ExprKind::Field(ref binding, field_ident) = assign_lhs.kind; - if let ExprKind::Path(ref qpath) = binding.kind; - if let QPath::Resolved(_, path) = qpath; + if let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind; if let Some(second_binding_name) = path.segments.last(); if second_binding_name.ident.name == binding_name; then { diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index e0a1f4c5ca4..1194bd7e55e 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -41,8 +41,7 @@ declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]); impl<'tcx> LateLintPass<'tcx> for OkIfLet { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { //begin checking variables - if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match - if let MatchSource::IfLetDesugar { .. } = source; //test if it is an If Let + if let ExprKind::Match(ref op, ref body, MatchSource::IfLetDesugar { .. }) = expr.kind; //test if expr is if let if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index ed7f3b9293d..03e95c9e27f 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -68,8 +68,7 @@ fn expr_match(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let StmtKind::Semi(expr, ..) = &stmt.kind; // make sure it's a break, otherwise we want to skip - if let ExprKind::Break(.., break_expr) = &expr.kind; - if let Some(break_expr) = break_expr; + if let ExprKind::Break(.., Some(break_expr)) = &expr.kind; then { lint(cx, expr.span, break_expr.span, LINT_BREAK); } diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index b57fe8dc426..3a01acd8fdc 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -59,8 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if let Some(target) = subtracts_one(cx, e); // Extracting out the variable name - if let ExprKind::Path(ref assign_path) = target.kind; - if let QPath::Resolved(_, ref ares_path) = assign_path; + if let ExprKind::Path(QPath::Resolved(_, ref ares_path)) = target.kind; then { // Handle symmetric conditions in the if statement diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 025ff86da39..a76595ed089 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -52,8 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { if let ItemKind::Const(hir_ty, _) = &item.kind; let ty = hir_ty_to_ty(cx.tcx, hir_ty); if let ty::Array(element_type, cst) = ty.kind(); - if let ConstKind::Value(val) = cst.val; - if let ConstValue::Scalar(element_count) = val; + if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); if self.maximum_allowed_size < element_count * element_size; diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 9fd3780e14e..9a448ab1256 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -43,8 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { if_chain! { if let ExprKind::Repeat(_, _) = expr.kind; if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind(); - if let ConstKind::Value(val) = cst.val; - if let ConstValue::Scalar(element_count) = val; + if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); if self.maximum_allowed_size < element_count * element_size; diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 143cbea5537..b0de355e242 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1919,8 +1919,7 @@ fn check_for_single_element_loop<'tcx>( if_chain! { if let ExprKind::AddrOf(BorrowKind::Ref, _, ref arg_expr) = arg.kind; if let PatKind::Binding(.., target, _) = pat.kind; - if let ExprKind::Array(ref arg_expr_list) = arg_expr.kind; - if let [arg_expression] = arg_expr_list; + if let ExprKind::Array([arg_expression]) = arg_expr.kind; if let ExprKind::Path(ref list_item) = arg_expression.kind; if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name); if let ExprKind::Block(ref block, _) = body.kind; @@ -2025,8 +2024,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option let node_str = cx.tcx.hir().get(hir_id); if_chain! { if let Node::Binding(pat) = node_str; - if let PatKind::Binding(bind_ann, ..) = pat.kind; - if let BindingAnnotation::Mutable = bind_ann; + if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; then { return Some(hir_id); } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index e17e3adb94f..80f3045415e 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -225,8 +225,7 @@ fn find_stripping<'tcx>( if is_ref_str(self.cx, ex); let unref = peel_ref(ex); if let ExprKind::Index(indexed, index) = &unref.kind; - if let Some(range) = higher::range(index); - if let higher::Range { start, end, .. } = range; + if let Some(higher::Range { start, end, .. }) = higher::range(index); if let ExprKind::Path(path) = &indexed.kind; if qpath_res(self.cx, path, ex.hir_id) == self.target; then { diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 7d64fa6c262..c223462af26 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -652,8 +652,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if_chain! { if !in_external_macro(cx.sess(), pat.span); if !in_macro(pat.span); - if let PatKind::Struct(ref qpath, fields, true) = pat.kind; - if let QPath::Resolved(_, ref path) = qpath; + if let PatKind::Struct(QPath::Resolved(_, ref path), fields, true) = pat.kind; if let Some(def_id) = path.res.opt_def_id(); let ty = cx.tcx.type_of(def_id); if let ty::Adt(def, _) = ty.kind(); @@ -962,16 +961,14 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) if let QPath::Resolved(_, p) = path { missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); } - } else if let PatKind::TupleStruct(ref path, ref patterns, ..) = arm.pat.kind { - if let QPath::Resolved(_, p) = path { - // Some simple checks for exhaustive patterns. - // There is a room for improvements to detect more cases, - // but it can be more expensive to do so. - let is_pattern_exhaustive = - |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None)); - if patterns.iter().all(is_pattern_exhaustive) { - missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); - } + } else if let PatKind::TupleStruct(QPath::Resolved(_, p), ref patterns, ..) = arm.pat.kind { + // Some simple checks for exhaustive patterns. + // There is a room for improvements to detect more cases, + // but it can be more expensive to do so. + let is_pattern_exhaustive = + |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None)); + if patterns.iter().all(is_pattern_exhaustive) { + missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); } } } @@ -1446,8 +1443,7 @@ fn is_ref_some_arm(arm: &Arm<'_>) -> Option { if let ExprKind::Call(ref e, ref args) = remove_blocks(&arm.body).kind; if let ExprKind::Path(ref some_path) = e.kind; if match_qpath(some_path, &paths::OPTION_SOME) && args.len() == 1; - if let ExprKind::Path(ref qpath) = args[0].kind; - if let &QPath::Resolved(_, ref path2) = qpath; + if let ExprKind::Path(QPath::Resolved(_, ref path2)) = args[0].kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { return Some(rb) diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 40a62575861..44c974b9d98 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -90,8 +90,7 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option return Some(MinMax::Max), diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index a799a644e97..42f97b2ac49 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -6,7 +6,6 @@ use crate::utils::sugg::Sugg; use crate::utils::{ higher, is_expn_of, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg, }; -use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; @@ -198,13 +197,9 @@ struct ExpressionInfoWithSpan { } fn is_unary_not(e: &Expr<'_>) -> (bool, Span) { - if_chain! { - if let ExprKind::Unary(unop, operand) = e.kind; - if let UnOp::UnNot = unop; - then { - return (true, operand.span); - } - }; + if let ExprKind::Unary(UnOp::UnNot, operand) = e.kind { + return (true, operand.span); + } (false, e.span) } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index d9b280b7a85..b91233ac582 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -176,8 +176,7 @@ impl QuestionMark { if block.stmts.len() == 1; if let Some(expr) = block.stmts.iter().last(); if let StmtKind::Semi(ref expr) = expr.kind; - if let ExprKind::Ret(ret_expr) = expr.kind; - if let Some(ret_expr) = ret_expr; + if let ExprKind::Ret(Some(ret_expr)) = expr.kind; then { return Some(ret_expr); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 42c45be3b45..77e79073378 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -222,8 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if method_names[0] == sym!(as_bytes); // Check for slicer - if let ExprKind::Struct(ref path, _, _) = right.kind; - if let QPath::LangItem(LangItem::Range, _) = path; + if let ExprKind::Struct(QPath::LangItem(LangItem::Range, _), _, _) = right.kind; then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index d4acf8df46d..daff5f81e8c 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -168,8 +168,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { if_chain! { if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; if !in_macro(bound_predicate.span); - if let TyKind::Path(ref path) = bound_predicate.bounded_ty.kind; - if let QPath::Resolved(_, Path { ref segments, .. }) = path; + if let TyKind::Path(QPath::Resolved(_, Path { ref segments, .. })) = bound_predicate.bounded_ty.kind; if let Some(segment) = segments.first(); if let Some(trait_resolutions_direct) = map.get(&segment.ident); then { diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index d60306336c6..6b171a0fa1a 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -48,8 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { if_chain! { if let ExprKind::Path(ref _qpath) = args[0].kind; let x = const_eval_context.expr(&args[0]); - if let Some(constant) = x; - if let Constant::RawPtr(0) = constant; + if let Some(Constant::RawPtr(0)) = x; then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index c8bdc5a71e6..74ba53e6a9a 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -738,8 +738,7 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool { fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option> { if_chain! { if let Some(did) = qpath_res(cx, qpath, id).opt_def_id(); - if let Some(node) = cx.tcx.hir().get_if_local(did); - if let Node::GenericParam(generic_param) = node; + if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did); if let GenericParamKind::Type { synthetic, .. } = generic_param.kind; if synthetic == Some(SyntheticTyParamKind::ImplTrait); then { @@ -1470,8 +1469,7 @@ fn check_loss_of_sign(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast // don't lint for positive constants let const_val = constant(cx, &cx.typeck_results(), op); if_chain! { - if let Some((const_val, _)) = const_val; - if let Constant::Int(n) = const_val; + if let Some((Constant::Int(n), _)) = const_val; if let ty::Int(ity) = *cast_from.kind(); if sext(cx.tcx, n, ity) >= 0; then { diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 6d7c5058b4f..01ffac5b559 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -162,8 +162,7 @@ pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr< if let hir::Block { expr: Some(expr), .. } = &**block; if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind; if let hir::ExprKind::DropTemps(cond) = &cond.kind; - if let [arm, ..] = &arms[..]; - if let hir::Arm { body, .. } = arm; + if let [hir::Arm { body, .. }, ..] = &arms[..]; then { return Some((cond, body)); } From a5d6855333c55636bc0fc56efcc83eac7c57ffa7 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sat, 28 Nov 2020 20:41:29 -0600 Subject: [PATCH 116/274] Use LocalUsedVisitor in more places --- clippy_lints/src/let_if_seq.rs | 53 ++++------------------------------ clippy_lints/src/loops.rs | 29 ++----------------- 2 files changed, 8 insertions(+), 74 deletions(-) diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 8243b0a29bc..0d2d95324c4 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,12 +1,11 @@ +use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{higher, qpath_res, snippet, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; -use rustc_hir::intravisit; use rustc_hir::BindingAnnotation; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -66,10 +65,10 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; if let hir::StmtKind::Expr(ref if_) = expr.kind; if let Some((ref cond, ref then, ref else_)) = higher::if_block(&if_); - if !used_in_expr(cx, canonical_id, cond); + if !LocalUsedVisitor::new(canonical_id).check_expr(cond); if let hir::ExprKind::Block(ref then, _) = then.kind; if let Some(value) = check_assign(cx, canonical_id, &*then); - if !used_in_expr(cx, canonical_id, value); + if !LocalUsedVisitor::new(canonical_id).check_expr(value); then { let span = stmt.span.to(if_.span); @@ -136,32 +135,6 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { } } -struct UsedVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - id: hir::HirId, - used: bool, -} - -impl<'a, 'tcx> intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::Path(ref qpath) = expr.kind; - if let Res::Local(local_id) = qpath_res(self.cx, qpath, expr.hir_id); - if self.id == local_id; - then { - self.used = true; - return; - } - } - intravisit::walk_expr(self, expr); - } - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } -} - fn check_assign<'tcx>( cx: &LateContext<'tcx>, decl: hir::HirId, @@ -176,18 +149,10 @@ fn check_assign<'tcx>( if let Res::Local(local_id) = qpath_res(cx, qpath, var.hir_id); if decl == local_id; then { - let mut v = UsedVisitor { - cx, - id: decl, - used: false, - }; - - for s in block.stmts.iter().take(block.stmts.len()-1) { - intravisit::walk_stmt(&mut v, s); + let mut v = LocalUsedVisitor::new(decl); - if v.used { - return None; - } + if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| v.check_stmt(stmt)) { + return None; } return Some(value); @@ -196,9 +161,3 @@ fn check_assign<'tcx>( None } - -fn used_in_expr<'tcx>(cx: &LateContext<'tcx>, id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> bool { - let mut v = UsedVisitor { cx, id, used: false }; - intravisit::walk_expr(&mut v, expr); - v.used -} diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index b0de355e242..400148ab81d 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2,6 +2,7 @@ use crate::consts::constant; use crate::utils::paths; use crate::utils::sugg::Sugg; use crate::utils::usage::{is_unused, mutated_variables}; +use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, @@ -2069,28 +2070,6 @@ fn pat_is_wild<'tcx>(pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { } } -struct LocalUsedVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - local: HirId, - used: bool, -} - -impl<'a, 'tcx> Visitor<'tcx> for LocalUsedVisitor<'a, 'tcx> { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if same_var(self.cx, expr, self.local) { - self.used = true; - } else { - walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } -} - struct VarVisitor<'a, 'tcx> { /// context reference cx: &'a LateContext<'tcx>, @@ -2124,11 +2103,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { then { let index_used_directly = same_var(self.cx, idx, self.var); let indexed_indirectly = { - let mut used_visitor = LocalUsedVisitor { - cx: self.cx, - local: self.var, - used: false, - }; + let mut used_visitor = LocalUsedVisitor::new(self.var); walk_expr(&mut used_visitor, idx); used_visitor.used }; From 252083f7e02a3a9174bb39821fd20356ada3dd4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Mon, 16 Nov 2020 12:44:05 +0100 Subject: [PATCH 117/274] address review comments and rebase ci: always build with internal lints group up internal lints in lib.rs dogfood: we already pass --all-features, no need to enable internal-lints again --- .github/workflows/clippy_bors.yml | 7 ---- clippy_dev/src/lib.rs | 6 ++-- clippy_lints/src/lib.rs | 25 +++++++-------- tests/dogfood.rs | 53 ++++++++++++------------------- 4 files changed, 33 insertions(+), 58 deletions(-) diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index a8b4925176c..784463fe0df 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -128,13 +128,6 @@ jobs: SYSROOT=$(rustc --print sysroot) echo "$SYSROOT/bin" >> $GITHUB_PATH - - name: Build - run: cargo build --features deny-warnings - - # compiletest would panic due to "Found multiple rlibs for crate `clippy_lints`" - - name: clean rlibs - run: rm -f ./target/debug/deps/libclippy_lints* - - name: Build with internal lints run: cargo build --features deny-warnings,internal-lints diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 1453ac7efa3..f51c45e9eb5 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -160,13 +160,11 @@ pub fn gen_register_lint_list<'a>( l.module, l.name.to_uppercase() ) - }) - .collect::>(); + }); let other_lints = usable_lints .sorted_by_key(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) .map(|l| format!(" &{}::{},", l.module, l.name.to_uppercase())) - .sorted() - .collect::>(); + .sorted(); let mut lint_list = vec![header]; lint_list.extend(internal_lints); lint_list.extend(other_lints); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fed7da3ee4f..8fbd44528b1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -939,17 +939,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); // end register lints, do not remove this comment, it’s used in `update_lints` - store.register_late_pass(|| box await_holding_invalid::AwaitHolding); - store.register_late_pass(|| box serde_api::SerdeAPI); + + // all the internal lints #[cfg(feature = "internal-lints")] { + store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal); + store.register_early_pass(|| box utils::internal_lints::ProduceIce); + store.register_late_pass(|| box utils::inspector::DeepCodeInspector); + store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); + store.register_late_pass(|| box utils::internal_lints::InvalidPaths); store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); + store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass); - store.register_late_pass(|| box utils::internal_lints::InvalidPaths); - store.register_late_pass(|| box utils::inspector::DeepCodeInspector); } store.register_late_pass(|| box utils::author::Author); + store.register_late_pass(|| box await_holding_invalid::AwaitHolding); + store.register_late_pass(|| box serde_api::SerdeAPI); let vec_box_size_threshold = conf.vec_box_size_threshold; store.register_late_pass(move || box types::Types::new(vec_box_size_threshold)); store.register_late_pass(|| box booleans::NonminimalBool); @@ -1134,8 +1140,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box literal_representation::LiteralDigitGrouping); let literal_representation_threshold = conf.literal_representation_threshold; store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)); - #[cfg(feature = "internal-lints")] - store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal); let enum_variant_name_threshold = conf.enum_variant_name_threshold; store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold)); store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments); @@ -1149,8 +1153,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold)); store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic); store.register_early_pass(|| box as_conversions::AsConversions); - #[cfg(feature = "internal-lints")] - store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_late_pass(|| box let_underscore::LetUnderscore); store.register_late_pass(|| box atomic_ordering::AtomicOrdering); store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports); @@ -1166,8 +1168,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box dereference::Dereferencing); store.register_late_pass(|| box option_if_let_else::OptionIfLetElse); store.register_late_pass(|| box future_not_send::FutureNotSend); - #[cfg(feature = "internal-lints")] - store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_late_pass(|| box if_let_mutex::IfLetMutex); store.register_late_pass(|| box mut_mutex_lock::MutMutexLock); store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); @@ -1175,7 +1175,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn); - let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { single_char_binding_names_threshold, @@ -1192,8 +1191,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box manual_ok_or::ManualOkOr); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); - #[cfg(feature = "internal-lints")] - store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::>(); store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax); @@ -1202,7 +1199,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box strings::StrToString); store.register_late_pass(|| box strings::StringToString); - store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::INTEGER_ARITHMETIC), @@ -1333,6 +1329,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&wildcard_imports::ENUM_GLOB_USE), LintId::of(&wildcard_imports::WILDCARD_IMPORTS), ]); + #[cfg(feature = "internal-lints")] store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ LintId::of(&utils::internal_lints::CLIPPY_LINTS_INTERNAL), diff --git a/tests/dogfood.rs b/tests/dogfood.rs index eae25adf839..a6163a83d76 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -18,39 +18,26 @@ fn dogfood_clippy() { } let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let output = if cfg!(feature = "internal-lints") { - // with internal lints and internal warnings - Command::new(&*CLIPPY_PATH) - .current_dir(root_dir) - .env("CLIPPY_DOGFOOD", "1") - .env("CARGO_INCREMENTAL", "0") - .arg("clippy-preview") - .arg("--all-targets") - .arg("--all-features") - .args(&["--features", "internal-lints"]) - .arg("--") - .args(&["-D", "clippy::all"]) - .args(&["-D", "clippy::pedantic"]) - .args(&["-D", "clippy::internal"]) - .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir - .output() - .unwrap() - } else { - // without internal lints or warnings - Command::new(&*CLIPPY_PATH) - .current_dir(root_dir) - .env("CLIPPY_DOGFOOD", "1") - .env("CARGO_INCREMENTAL", "0") - .arg("clippy-preview") - .arg("--all-targets") - .arg("--all-features") - .arg("--") - .args(&["-D", "clippy::all"]) - .args(&["-D", "clippy::pedantic"]) - .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir - .output() - .unwrap() - }; + let mut command = Command::new(&*CLIPPY_PATH); + command + .current_dir(root_dir) + .env("CLIPPY_DOGFOOD", "1") + .env("CARGO_INCREMENTAL", "0") + .arg("clippy-preview") + .arg("--all-targets") + .arg("--all-features") + .arg("--") + .args(&["-D", "clippy::all"]) + .args(&["-D", "clippy::pedantic"]) + .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir + + // internal lints only exist if we build with the internal-lints feature + if cfg!(feature = "internal-lints") { + command.args(&["-D", "clippy::internal"]); + } + + let output = command.output().unwrap(); + println!("status: {}", output.status); println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); From 0e207888391fb8b55fa75d19259812b6cb97a75c Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 29 Nov 2020 18:21:21 -0600 Subject: [PATCH 118/274] Split tests --- tests/ui/collapsible_match.rs | 39 ------------------- tests/ui/collapsible_match.stderr | 60 +---------------------------- tests/ui/collapsible_match2.rs | 53 ++++++++++++++++++++++++++ tests/ui/collapsible_match2.stderr | 61 ++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 98 deletions(-) create mode 100644 tests/ui/collapsible_match2.rs create mode 100644 tests/ui/collapsible_match2.stderr diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs index 75640b70ff0..a83e6c77b12 100644 --- a/tests/ui/collapsible_match.rs +++ b/tests/ui/collapsible_match.rs @@ -95,45 +95,6 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> }, None => return, } - - // if guards on outer match - { - match res_opt { - Ok(val) if make() => match val { - Some(n) => foo(n), - _ => return, - }, - _ => return, - } - match res_opt { - Ok(val) => match val { - Some(n) => foo(n), - _ => return, - }, - _ if make() => return, - _ => return, - } - } - - // macro - { - macro_rules! mac { - ($outer:expr => $pat:pat, $e:expr => $inner_pat:pat, $then:expr) => { - match $outer { - $pat => match $e { - $inner_pat => $then, - _ => return, - }, - _ => return, - } - }; - } - // Lint this since the patterns are not defined by the macro. - // Allows the lint to work on if_chain! for example. - // Fixing the lint requires knowledge of the specific macro, but we optimistically assume that - // there is still a better way to write this. - mac!(res_opt => Ok(val), val => Some(n), foo(n)); - } } fn negative_cases(res_opt: Result, String>, res_res: Result, String>) { diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr index a9e4f911914..63ac6a1613d 100644 --- a/tests/ui/collapsible_match.stderr +++ b/tests/ui/collapsible_match.stderr @@ -175,63 +175,5 @@ LL | Some(val) => match val { LL | Some(n) => foo(n), | ^^^^^^^ with this pattern -error: Unnecessary nested match - --> $DIR/collapsible_match.rs:102:34 - | -LL | Ok(val) if make() => match val { - | __________________________________^ -LL | | Some(n) => foo(n), -LL | | _ => return, -LL | | }, - | |_____________^ - | -help: The outer pattern can be modified to include the inner pattern. - --> $DIR/collapsible_match.rs:102:16 - | -LL | Ok(val) if make() => match val { - | ^^^ Replace this binding -LL | Some(n) => foo(n), - | ^^^^^^^ with this pattern - -error: Unnecessary nested match - --> $DIR/collapsible_match.rs:109:24 - | -LL | Ok(val) => match val { - | ________________________^ -LL | | Some(n) => foo(n), -LL | | _ => return, -LL | | }, - | |_____________^ - | -help: The outer pattern can be modified to include the inner pattern. - --> $DIR/collapsible_match.rs:109:16 - | -LL | Ok(val) => match val { - | ^^^ Replace this binding -LL | Some(n) => foo(n), - | ^^^^^^^ with this pattern - -error: Unnecessary nested match - --> $DIR/collapsible_match.rs:123:29 - | -LL | $pat => match $e { - | _____________________________^ -LL | | $inner_pat => $then, -LL | | _ => return, -LL | | }, - | |_____________________^ -... -LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); - | ------------------------------------------------- in this macro invocation - | -help: The outer pattern can be modified to include the inner pattern. - --> $DIR/collapsible_match.rs:135:28 - | -LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); - | ^^^ ^^^^^^^ with this pattern - | | - | Replace this binding - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 13 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/collapsible_match2.rs b/tests/ui/collapsible_match2.rs new file mode 100644 index 00000000000..d571ac4ab69 --- /dev/null +++ b/tests/ui/collapsible_match2.rs @@ -0,0 +1,53 @@ +#![warn(clippy::collapsible_match)] +#![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)] + +fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { + // if guards on outer match + { + match res_opt { + Ok(val) if make() => match val { + Some(n) => foo(n), + _ => return, + }, + _ => return, + } + match res_opt { + Ok(val) => match val { + Some(n) => foo(n), + _ => return, + }, + _ if make() => return, + _ => return, + } + } + + // macro + { + macro_rules! mac { + ($outer:expr => $pat:pat, $e:expr => $inner_pat:pat, $then:expr) => { + match $outer { + $pat => match $e { + $inner_pat => $then, + _ => return, + }, + _ => return, + } + }; + } + // Lint this since the patterns are not defined by the macro. + // Allows the lint to work on if_chain! for example. + // Fixing the lint requires knowledge of the specific macro, but we optimistically assume that + // there is still a better way to write this. + mac!(res_opt => Ok(val), val => Some(n), foo(n)); + } +} + +fn make() -> T { + unimplemented!() +} + +fn foo(t: T) -> U { + unimplemented!() +} + +fn main() {} diff --git a/tests/ui/collapsible_match2.stderr b/tests/ui/collapsible_match2.stderr new file mode 100644 index 00000000000..490d82d12cd --- /dev/null +++ b/tests/ui/collapsible_match2.stderr @@ -0,0 +1,61 @@ +error: Unnecessary nested match + --> $DIR/collapsible_match2.rs:8:34 + | +LL | Ok(val) if make() => match val { + | __________________________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_____________^ + | + = note: `-D clippy::collapsible-match` implied by `-D warnings` +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match2.rs:8:16 + | +LL | Ok(val) if make() => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match2.rs:15:24 + | +LL | Ok(val) => match val { + | ________________________^ +LL | | Some(n) => foo(n), +LL | | _ => return, +LL | | }, + | |_____________^ + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match2.rs:15:16 + | +LL | Ok(val) => match val { + | ^^^ Replace this binding +LL | Some(n) => foo(n), + | ^^^^^^^ with this pattern + +error: Unnecessary nested match + --> $DIR/collapsible_match2.rs:29:29 + | +LL | $pat => match $e { + | _____________________________^ +LL | | $inner_pat => $then, +LL | | _ => return, +LL | | }, + | |_____________________^ +... +LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); + | ------------------------------------------------- in this macro invocation + | +help: The outer pattern can be modified to include the inner pattern. + --> $DIR/collapsible_match2.rs:41:28 + | +LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); + | ^^^ ^^^^^^^ with this pattern + | | + | Replace this binding + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + From 0183b4109a04ad78722b919366005df84878cf5d Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 29 Nov 2020 19:49:41 -0500 Subject: [PATCH 119/274] Pass arguments up to 2*usize by value --- compiler/rustc_middle/src/ty/layout.rs | 12 ++++++------ ...rn-value-in-reg.rs => arg-return-value-in-reg.rs} | 4 ++-- src/test/codegen/union-abi.rs | 11 ++++++++--- 3 files changed, 16 insertions(+), 11 deletions(-) rename src/test/codegen/{return-value-in-reg.rs => arg-return-value-in-reg.rs} (74%) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8bdc7efa0bb..ffc24aef579 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2818,7 +2818,7 @@ where || abi == SpecAbi::RustIntrinsic || abi == SpecAbi::PlatformIntrinsic { - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, is_ret: bool| { + let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| { if arg.is_ignore() { return; } @@ -2856,9 +2856,9 @@ where _ => return, } - // Return structures up to 2 pointers in size by value, matching `ScalarPair`. LLVM - // will usually return these in 2 registers, which is more efficient than by-ref. - let max_by_val_size = if is_ret { Pointer.size(cx) * 2 } else { Pointer.size(cx) }; + // Pass and return structures up to 2 pointers in size by value, matching `ScalarPair`. + // LLVM will usually pass these in 2 registers, which is more efficient than by-ref. + let max_by_val_size = Pointer.size(cx) * 2; let size = arg.layout.size; if arg.layout.is_unsized() || size > max_by_val_size { @@ -2870,9 +2870,9 @@ where arg.cast_to(Reg { kind: RegKind::Integer, size }); } }; - fixup(&mut self.ret, true); + fixup(&mut self.ret); for arg in &mut self.args { - fixup(arg, false); + fixup(arg); } return; } diff --git a/src/test/codegen/return-value-in-reg.rs b/src/test/codegen/arg-return-value-in-reg.rs similarity index 74% rename from src/test/codegen/return-value-in-reg.rs rename to src/test/codegen/arg-return-value-in-reg.rs index 4bc0136c5e3..a1815e37cf2 100644 --- a/src/test/codegen/return-value-in-reg.rs +++ b/src/test/codegen/arg-return-value-in-reg.rs @@ -1,4 +1,4 @@ -//! This test checks that types of up to 128 bits are returned by-value instead of via out-pointer. +//! Check that types of up to 128 bits are passed and returned by-value instead of via pointer. // compile-flags: -C no-prepopulate-passes -O // only-x86_64 @@ -11,7 +11,7 @@ pub struct S { c: u32, } -// CHECK: define i128 @modify(%S* noalias nocapture dereferenceable(16) %s) +// CHECK: define i128 @modify(i128 %0) #[no_mangle] pub fn modify(s: S) -> S { S { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c } diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs index afea01e9a2d..f282fd23705 100644 --- a/src/test/codegen/union-abi.rs +++ b/src/test/codegen/union-abi.rs @@ -63,11 +63,16 @@ pub union UnionU128{a:u128} #[no_mangle] pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} } +pub union UnionU128x2{a:(u128, u128)} +// CHECK: define void @test_UnionU128x2(i128 %_1.0, i128 %_1.1) +#[no_mangle] +pub fn test_UnionU128x2(_: UnionU128x2) { loop {} } + #[repr(C)] -pub union CUnionU128{a:u128} -// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %_1) +pub union CUnionU128x2{a:(u128, u128)} +// CHECK: define void @test_CUnionU128x2(%CUnionU128x2* {{.*}} %_1) #[no_mangle] -pub fn test_CUnionU128(_: CUnionU128) { loop {} } +pub fn test_CUnionU128x2(_: CUnionU128x2) { loop {} } pub union UnionBool { b:bool } // CHECK: define zeroext i1 @test_UnionBool(i8 %b) From e7258ac714941ed5534ae31cddac7164ce1f50c1 Mon Sep 17 00:00:00 2001 From: Suyash458 Date: Mon, 30 Nov 2020 11:24:10 +0530 Subject: [PATCH 120/274] bump rustc-semver version. use in built method to compare versions --- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/utils/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 45fd87b169f..9b8ff266f5c 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -28,7 +28,7 @@ smallvec = { version = "1", features = ["union"] } toml = "0.5.3" unicode-normalization = "0.1" semver = "0.11" -rustc-semver="1.0.0" +rustc-semver="1.1.0" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 9c5e55b1ed5..b2f16007e35 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -76,7 +76,7 @@ pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Opt } pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool { - msrv.map_or(true, |msrv| msrv >= lint_msrv) + msrv.map_or(true, |msrv| msrv.meets(*lint_msrv)) } macro_rules! extract_msrv_attr { From 53943d6debc78efafa037744774d3216d22a10ad Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Mon, 30 Nov 2020 01:21:47 -0500 Subject: [PATCH 121/274] make test work in llvm 9 --- src/test/codegen/arg-return-value-in-reg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/codegen/arg-return-value-in-reg.rs b/src/test/codegen/arg-return-value-in-reg.rs index a1815e37cf2..a69291d4782 100644 --- a/src/test/codegen/arg-return-value-in-reg.rs +++ b/src/test/codegen/arg-return-value-in-reg.rs @@ -11,7 +11,7 @@ pub struct S { c: u32, } -// CHECK: define i128 @modify(i128 %0) +// CHECK: define i128 @modify(i128{{( %0)?}}) #[no_mangle] pub fn modify(s: S) -> S { S { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c } From db7373da14ddeb4c21f0d2c32139364d0ff530ee Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 30 Nov 2020 14:39:00 -0500 Subject: [PATCH 122/274] Don't time `emit_ignored_resolution_errors` This printed several hundred lines each time rustdoc was run, almost all of which rounded to 0.000. Since this isn't useful info, don't print it everywhere, so other perf info is easier to read. --- src/librustdoc/core.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b63acdc114e..5a1c0aa7662 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -412,9 +412,7 @@ crate fn run_core( let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(def_id))); debug!("visiting body for {:?}", def_id); - tcx.sess.time("emit_ignored_resolution_errors", || { - EmitIgnoredResolutionErrors::new(tcx).visit_body(body); - }); + EmitIgnoredResolutionErrors::new(tcx).visit_body(body); (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id) }; }), From 292a54eede3da9fc9b8f8148546ea20ae76755a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 1 Dec 2020 01:26:02 +0100 Subject: [PATCH 123/274] CONTRIBUTING: update bors queue url from buildbot2.rlo to bors.rlo --- CONTRIBUTING.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a8e2123656e..f8c26e2d456 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,11 +14,16 @@ All contributors are expected to follow the [Rust Code of Conduct]. - [Contributing to Clippy](#contributing-to-clippy) - [Getting started](#getting-started) + - [High level approach](#high-level-approach) - [Finding something to fix/improve](#finding-something-to-fiximprove) - [Writing code](#writing-code) - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work) - [How Clippy works](#how-clippy-works) - [Fixing build failures caused by Rust](#fixing-build-failures-caused-by-rust) + - [Patching git-subtree to work with big repos](#patching-git-subtree-to-work-with-big-repos) + - [Performing the sync](#performing-the-sync) + - [Syncing back changes in Clippy to [`rust-lang/rust`]](#syncing-back-changes-in-clippy-to-rust-langrust) + - [Defining remotes](#defining-remotes) - [Issue and PR triage](#issue-and-pr-triage) - [Bors and Homu](#bors-and-homu) - [Contributions](#contributions) @@ -320,8 +325,8 @@ commands [here][homu_instructions]. [l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash [l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug [homu]: https://github.com/rust-lang/homu -[homu_instructions]: https://buildbot2.rust-lang.org/homu/ -[homu_queue]: https://buildbot2.rust-lang.org/homu/queue/clippy +[homu_instructions]: https://bors.rust-lang.org/ +[homu_queue]: https://bors.rust-lang.org/queue/clippy ## Contributions From 528355c541b2f5d54d91a642355e39e01d93c75f Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Tue, 1 Dec 2020 15:39:25 +0530 Subject: [PATCH 124/274] add const_allocate intrisic --- compiler/rustc_mir/src/interpret/intern.rs | 2 +- .../rustc_mir/src/interpret/intrinsics.rs | 18 +++++++++++++++-- compiler/rustc_mir/src/interpret/memory.rs | 4 ++++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/intrinsic.rs | 4 ++++ library/core/src/intrinsics.rs | 5 +++++ library/core/src/lib.rs | 1 + .../heap/alloc_intrinsic_nontransient.rs | 20 +++++++++++++++++++ .../heap/alloc_intrinsic_transient.rs | 20 +++++++++++++++++++ .../const-eval/heap/alloc_intrinsic_uninit.rs | 10 ++++++++++ .../heap/alloc_intrinsic_uninit.stderr | 11 ++++++++++ .../heap/alloc_intrinsic_untyped.rs | 10 ++++++++++ .../heap/alloc_intrinsic_untyped.stderr | 8 ++++++++ 13 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 413be427339..443ef072647 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -104,7 +104,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( // This match is just a canary for future changes to `MemoryKind`, which most likely need // changes in this function. match kind { - MemoryKind::Stack | MemoryKind::Vtable | MemoryKind::CallerLocation => {} + MemoryKind::Stack | MemoryKind::Heap | MemoryKind::Vtable | MemoryKind::CallerLocation => {} } // Set allocation mutability as appropriate. This is used by LLVM to put things into // read-only memory, and also by Miri when evaluating other globals that diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index f666a89ca56..953c04a1007 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -14,10 +14,11 @@ use rustc_middle::ty; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size}; +use rustc_target::abi::{Abi, Align, LayoutOf as _, Primitive, Size}; use super::{ - util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy, + util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, MemoryKind, OpTy, + PlaceTy, }; mod caller_location; @@ -337,6 +338,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = Scalar::from_uint(truncated_bits, layout.size); self.write_scalar(result, dest)?; } + sym::const_allocate => { + let size = self.read_scalar(args[0])?.to_machine_usize(self)?; + let align = self.read_scalar(args[1])?.to_machine_usize(self)?; + + let align = match Align::from_bytes(align) { + Ok(a) => a, + Err(err) => bug!("align has to power of 2, {}", err), + }; + + let ptr = + self.memory.allocate(Size::from_bytes(size as u64), align, MemoryKind::Heap); + self.write_scalar(Scalar::Ptr(ptr), dest)?; + } sym::offset => { let ptr = self.read_scalar(args[0])?.check_init()?; let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?; diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index f3e373813ca..ce64923727c 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -27,6 +27,8 @@ use crate::util::pretty; pub enum MemoryKind { /// Stack memory. Error if deallocated except during a stack pop. Stack, + /// Heap memory. + Heap, /// Memory backing vtables. Error if ever deallocated. Vtable, /// Memory allocated by `caller_location` intrinsic. Error if ever deallocated. @@ -40,6 +42,7 @@ impl MayLeak for MemoryKind { fn may_leak(self) -> bool { match self { MemoryKind::Stack => false, + MemoryKind::Heap => true, MemoryKind::Vtable => true, MemoryKind::CallerLocation => true, MemoryKind::Machine(k) => k.may_leak(), @@ -51,6 +54,7 @@ impl fmt::Display for MemoryKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { MemoryKind::Stack => write!(f, "stack variable"), + MemoryKind::Heap => write!(f, "heap variable"), MemoryKind::Vtable => write!(f, "vtable"), MemoryKind::CallerLocation => write!(f, "caller location"), MemoryKind::Machine(m) => write!(f, "{}", m), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 523628b7058..91b87fdc482 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -356,6 +356,7 @@ symbols! { concat_idents, conservative_impl_trait, console, + const_allocate, const_compare_raw_pointers, const_constructor, const_eval_limit, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index f40a250200e..e2712a30339 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -286,6 +286,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool) } + sym::const_allocate => { + (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8)) + } + sym::ptr_offset_from => { (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize) } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 1a588b314c4..72282a93b70 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1732,6 +1732,11 @@ extern "rust-intrinsic" { /// See documentation of `<*const T>::guaranteed_ne` for details. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool; + + /// Allocate at compile time. Should not be called at runtime. + #[rustc_const_unstable(feature = "const_heap", issue = "none")] + #[cfg(not(bootstrap))] + pub fn const_allocate(size: usize, align: usize) -> *mut u8; } // Some functions are defined here because they accidentally got made diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e3b004be39a..bb76683e0fe 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -68,6 +68,7 @@ #![feature(arbitrary_self_types)] #![feature(asm)] #![feature(cfg_target_has_atomic)] +#![cfg_attr(not(bootstrap), feature(const_heap))] #![feature(const_alloc_layout)] #![feature(const_discriminant)] #![feature(const_cell_into_inner)] diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs new file mode 100644 index 00000000000..db650f8817f --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -0,0 +1,20 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: *const i32 = foo(); + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { &*t } +} +fn main() { + assert_eq!(unsafe { *FOO }, 20) +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs new file mode 100644 index 00000000000..c55cd32d264 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs @@ -0,0 +1,20 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: i32 = foo(); + +const fn foo() -> i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { *t } +} +fn main() { + assert_eq!(FOO, 20); +} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs new file mode 100644 index 00000000000..998b6cef84a --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -0,0 +1,10 @@ +// compile-test +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +//~^ error: it is undefined behavior to use this value +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr new file mode 100644 index 00000000000..866f877f54d --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.stderr @@ -0,0 +1,11 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/alloc_intrinsic_uninit.rs:8:1 + | +LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at ., but expected initialized plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs new file mode 100644 index 00000000000..625f7670bcd --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs @@ -0,0 +1,10 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32}; +//~^ error: untyped pointers are not allowed in constant + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr new file mode 100644 index 00000000000..ee84f8e54f3 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/alloc_intrinsic_untyped.rs:7:1 + | +LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From b5b811aab49837e5fca93f41c9ac9fe9354f746f Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Tue, 1 Dec 2020 19:48:09 +0530 Subject: [PATCH 125/274] review comments --- compiler/rustc_mir/src/const_eval/machine.rs | 10 ++++++++-- compiler/rustc_mir/src/interpret/intrinsics.rs | 2 +- compiler/rustc_mir/src/interpret/memory.rs | 4 ++-- library/core/src/intrinsics.rs | 2 +- .../const-eval/heap/alloc_intrinsic_errors.rs | 17 +++++++++++++++++ .../heap/alloc_intrinsic_errors.stderr | 17 +++++++++++++++++ .../heap/alloc_intrinsic_nontransient.rs | 2 +- .../heap/alloc_intrinsic_nontransient.stderr | 8 ++++++++ 8 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.stderr diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index c72089ec55a..ada9a0f887a 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -1,5 +1,6 @@ use rustc_middle::mir; use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::InstanceDef; use rustc_middle::ty::{self, Ty}; use std::borrow::Borrow; use std::collections::hash_map::Entry; @@ -231,8 +232,13 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, if ecx.tcx.is_const_fn_raw(def.did) { // If this function is a `const fn` then under certain circumstances we // can evaluate call via the query system, thus memoizing all future calls. - if ecx.try_eval_const_fn_call(instance, ret, args)? { - return Ok(None); + match instance.def { + InstanceDef::Intrinsic(_) => { + if ecx.try_eval_const_fn_call(instance, ret, args)? { + return Ok(None); + } + } + _ => {} } } else { // Some functions we support even if they are non-const -- but avoid testing diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 953c04a1007..4bc263730c3 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -344,7 +344,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let align = match Align::from_bytes(align) { Ok(a) => a, - Err(err) => bug!("align has to power of 2, {}", err), + Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), }; let ptr = diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index ce64923727c..1319ecd5b2e 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -42,7 +42,7 @@ impl MayLeak for MemoryKind { fn may_leak(self) -> bool { match self { MemoryKind::Stack => false, - MemoryKind::Heap => true, + MemoryKind::Heap => false, MemoryKind::Vtable => true, MemoryKind::CallerLocation => true, MemoryKind::Machine(k) => k.may_leak(), @@ -54,7 +54,7 @@ impl fmt::Display for MemoryKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { MemoryKind::Stack => write!(f, "stack variable"), - MemoryKind::Heap => write!(f, "heap variable"), + MemoryKind::Heap => write!(f, "heap allocation"), MemoryKind::Vtable => write!(f, "vtable"), MemoryKind::CallerLocation => write!(f, "caller location"), MemoryKind::Machine(m) => write!(f, "{}", m), diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 72282a93b70..73df8e53f82 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1734,7 +1734,7 @@ extern "rust-intrinsic" { pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool; /// Allocate at compile time. Should not be called at runtime. - #[rustc_const_unstable(feature = "const_heap", issue = "none")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] #[cfg(not(bootstrap))] pub fn const_allocate(size: usize, align: usize) -> *mut u8; } diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs new file mode 100644 index 00000000000..0d809ca9a62 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs @@ -0,0 +1,17 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: i32 = foo(); +const fn foo() -> i32 { + unsafe { + let _ = intrinsics::const_allocate(4, 3) as * mut i32; + //~^ error: any use of this value will cause an error [const_err] + } + 1 + +} + +fn main() {} diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr new file mode 100644 index 00000000000..41c1b977269 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr @@ -0,0 +1,17 @@ +error: any use of this value will cause an error + --> $DIR/alloc_intrinsic_errors.rs:10:17 + | +LL | const FOO: i32 = foo(); + | ----------------------- +... +LL | let _ = intrinsics::const_allocate(4, 3) as * mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | align has to be a power of 2, `3` is not a power of 2 + | inside `foo` at $DIR/alloc_intrinsic_errors.rs:10:17 + | inside `FOO` at $DIR/alloc_intrinsic_errors.rs:7:18 + | + = note: `#[deny(const_err)]` on by default + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs index db650f8817f..7cfe4734c1d 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -1,4 +1,3 @@ -// run-pass #![feature(core_intrinsics)] #![feature(const_heap)] #![feature(const_raw_ptr_deref)] @@ -6,6 +5,7 @@ use std::intrinsics; const FOO: *const i32 = foo(); +//~^ error: untyped pointers are not allowed in constant const fn foo() -> &'static i32 { let t = unsafe { diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.stderr new file mode 100644 index 00000000000..cabd39dde31 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/alloc_intrinsic_nontransient.rs:7:1 + | +LL | const FOO: *const i32 = foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From a6c4cbd46a087de58b59063fca936efff31e212c Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Tue, 1 Dec 2020 20:12:22 +0530 Subject: [PATCH 126/274] review comment and one more test --- compiler/rustc_mir/src/const_eval/machine.rs | 13 ++++++------ .../heap/alloc_intrinsic_nontransient.rs | 6 +++--- .../heap/alloc_intrinsic_nontransient.stderr | 8 -------- .../heap/alloc_intrinsic_nontransient_fail.rs | 20 +++++++++++++++++++ 4 files changed, 29 insertions(+), 18 deletions(-) delete mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.stderr create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index ada9a0f887a..6449b7cdebc 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -38,6 +38,10 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { if instance.def.requires_caller_location(self.tcx()) { return Ok(false); } + // only memoize instrinsics + if !matches!(instance.def, InstanceDef::Intrinsic(_)) { + return Ok(false); + } // For the moment we only do this for functions which take no arguments // (or all arguments are ZSTs) so that we don't memoize too much. if args.iter().any(|a| !a.layout.is_zst()) { @@ -232,13 +236,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, if ecx.tcx.is_const_fn_raw(def.did) { // If this function is a `const fn` then under certain circumstances we // can evaluate call via the query system, thus memoizing all future calls. - match instance.def { - InstanceDef::Intrinsic(_) => { - if ecx.try_eval_const_fn_call(instance, ret, args)? { - return Ok(None); - } - } - _ => {} + if ecx.try_eval_const_fn_call(instance, ret, args)? { + return Ok(None); } } else { // Some functions we support even if they are non-const -- but avoid testing diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs index 7cfe4734c1d..de7fb65f685 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -1,11 +1,11 @@ +// run-pass #![feature(core_intrinsics)] #![feature(const_heap)] #![feature(const_raw_ptr_deref)] #![feature(const_mut_refs)] use std::intrinsics; -const FOO: *const i32 = foo(); -//~^ error: untyped pointers are not allowed in constant +const FOO: &i32 = foo(); const fn foo() -> &'static i32 { let t = unsafe { @@ -16,5 +16,5 @@ const fn foo() -> &'static i32 { unsafe { &*t } } fn main() { - assert_eq!(unsafe { *FOO }, 20) + assert_eq!(*FOO, 20) } diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.stderr deleted file mode 100644 index cabd39dde31..00000000000 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: untyped pointers are not allowed in constant - --> $DIR/alloc_intrinsic_nontransient.rs:7:1 - | -LL | const FOO: *const i32 = foo(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs new file mode 100644 index 00000000000..de7fb65f685 --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs @@ -0,0 +1,20 @@ +// run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +#![feature(const_raw_ptr_deref)] +#![feature(const_mut_refs)] +use std::intrinsics; + +const FOO: &i32 = foo(); + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as * mut i32; + *i = 20; + i + }; + unsafe { &*t } +} +fn main() { + assert_eq!(*FOO, 20) +} From f2f3a8e6453beeffb1e69c994e613dca68e4e76e Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Sun, 29 Nov 2020 20:48:17 +0900 Subject: [PATCH 127/274] Add long explanation of E0546 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0546.md | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0546.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 0a88759f84c..636c37142ad 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -283,6 +283,7 @@ E0537: include_str!("./error_codes/E0537.md"), E0538: include_str!("./error_codes/E0538.md"), E0539: include_str!("./error_codes/E0539.md"), E0541: include_str!("./error_codes/E0541.md"), +E0546: include_str!("./error_codes/E0546.md"), E0550: include_str!("./error_codes/E0550.md"), E0551: include_str!("./error_codes/E0551.md"), E0552: include_str!("./error_codes/E0552.md"), @@ -603,7 +604,6 @@ E0779: include_str!("./error_codes/E0779.md"), E0543, // missing 'reason' E0544, // multiple stability levels E0545, // incorrect 'issue' - E0546, // missing 'feature' E0547, // missing 'issue' // E0548, // replaced with a generic attribute input check // rustc_deprecated attribute must be paired with either stable or unstable diff --git a/compiler/rustc_error_codes/src/error_codes/E0546.md b/compiler/rustc_error_codes/src/error_codes/E0546.md new file mode 100644 index 00000000000..b2df22c0f8f --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0546.md @@ -0,0 +1,27 @@ +A feature name is missing. + +Erroneous code example: + +```compile_fail,E0546 +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "test")] + +#[unstable(issue = "none")] // invalid +fn unstable_fn() {} + +#[stable(since = "1.0.0")] // invalid +fn stable_fn() {} +``` + +To fix the issue you need to provide a feature name. + +``` +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "test")] + +#[unstable(feature = "unstable_fn", issue = "none")] // ok! +fn unstable_fn() {} + +#[stable(feature = "stable_fn", since = "1.0.0")] // ok! +fn stable_fn() {} +``` From ea5aff4565fccd5f09b0ec676dcdd7affd166d09 Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Sun, 29 Nov 2020 20:50:51 +0900 Subject: [PATCH 128/274] bless stability-attribute-sanity ui test --- .../ui/stability-attribute/stability-attribute-sanity.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index bf2436a535f..97089f7df52 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -110,5 +110,5 @@ LL | #[rustc_deprecated(since = "a", reason = "text")] error: aborting due to 18 previous errors -Some errors have detailed explanations: E0539, E0541, E0550. +Some errors have detailed explanations: E0539, E0541, E0546, E0550. For more information about an error, try `rustc --explain E0539`. From b787d723fc489ef50bd6cf32464fc638a1773fda Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 1 Dec 2020 15:36:14 +0100 Subject: [PATCH 129/274] Fix SGX CI Broken in #79038 --- library/std/tests/env.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs index 0e55ec648c9..76056637a4c 100644 --- a/library/std/tests/env.rs +++ b/library/std/tests/env.rs @@ -1,6 +1,5 @@ use std::env::*; use std::ffi::{OsStr, OsString}; -use std::path::PathBuf; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; @@ -92,6 +91,8 @@ fn env_home_dir() { cfg_if::cfg_if! { if #[cfg(unix)] { + use std::path::PathBuf; + let oldhome = var_to_os_string(var("HOME")); set_var("HOME", "/home/MountainView"); @@ -109,6 +110,8 @@ fn env_home_dir() { if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } } else if #[cfg(windows)] { + use std::path::PathBuf; + let oldhome = var_to_os_string(var("HOME")); let olduserprofile = var_to_os_string(var("USERPROFILE")); From 878cfb5a4abe70f6f813ae68216efe935ea40f5d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 30 Nov 2020 22:54:20 -0500 Subject: [PATCH 130/274] Fix `unknown-crate` when using self-profile with rustdoc ... by removing a duplicate `crate_name` field in `interface::Config`, making it clear that rustdoc should be passing it to `config::Options` instead. --- compiler/rustc_driver/src/lib.rs | 2 -- compiler/rustc_interface/src/interface.rs | 3 --- compiler/rustc_interface/src/queries.rs | 12 +++++------- compiler/rustc_session/src/session.rs | 2 +- src/librustdoc/core.rs | 2 +- src/librustdoc/doctest.rs | 2 +- src/test/run-make-fulldeps/issue-19371/foo.rs | 1 - 7 files changed, 8 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index c1741bfaaba..b3466f49b9f 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -223,7 +223,6 @@ fn run_compiler( file_loader: None, diagnostic_output, stderr: None, - crate_name: None, lint_caps: Default::default(), register_lints: None, override_queries: None, @@ -307,7 +306,6 @@ fn run_compiler( file_loader, diagnostic_output, stderr: None, - crate_name: None, lint_caps: Default::default(), register_lints: None, override_queries: None, diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 11dd6ec32c0..acd49d86c2c 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -34,7 +34,6 @@ pub struct Compiler { pub(crate) input_path: Option, pub(crate) output_dir: Option, pub(crate) output_file: Option, - pub(crate) crate_name: Option, pub(crate) register_lints: Option>, pub(crate) override_queries: Option, @@ -140,7 +139,6 @@ pub struct Config { /// Set to capture stderr output during compiler execution pub stderr: Option>>>, - pub crate_name: Option, pub lint_caps: FxHashMap, /// This is a callback from the driver that is called when we're registering lints; @@ -185,7 +183,6 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R input_path: config.input_path, output_dir: config.output_dir, output_file: config.output_file, - crate_name: config.crate_name, register_lints: config.register_lints, override_queries: config.override_queries, }; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index a2704c3adbf..4c340b3fc1f 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -156,13 +156,11 @@ impl<'tcx> Queries<'tcx> { pub fn crate_name(&self) -> Result<&Query> { self.crate_name.compute(|| { - Ok(match self.compiler.crate_name { - Some(ref crate_name) => crate_name.clone(), - None => { - let parse_result = self.parse()?; - let krate = parse_result.peek(); - find_crate_name(self.session(), &krate.attrs, &self.compiler.input) - } + Ok({ + let parse_result = self.parse()?; + let krate = parse_result.peek(); + // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. + find_crate_name(self.session(), &krate.attrs, &self.compiler.input) }) }) } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 5dddf0eb72e..1352ab53cab 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1338,7 +1338,7 @@ pub fn build_session( let profiler = SelfProfiler::new( directory, - sopts.crate_name.as_ref().map(|s| &s[..]), + sopts.crate_name.as_deref(), &sopts.debugging_opts.self_profile_events, ); match profiler { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b63acdc114e..eecdc929ab6 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -371,6 +371,7 @@ crate fn run_core( error_format, edition, describe_lints, + crate_name, ..Options::default() }; @@ -384,7 +385,6 @@ crate fn run_core( file_loader: None, diagnostic_output: DiagnosticOutput::Default, stderr: None, - crate_name, lint_caps, register_lints: None, override_queries: Some(|_sess, providers, _external_providers| { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a615701f253..37fe13c32ce 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -74,6 +74,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { debugging_opts: config::DebuggingOptions { ..config::basic_debugging_options() }, edition: options.edition, target_triple: options.target.clone(), + crate_name: options.crate_name.clone(), ..config::Options::default() }; @@ -90,7 +91,6 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { file_loader: None, diagnostic_output: DiagnosticOutput::Default, stderr: None, - crate_name: options.crate_name.clone(), lint_caps, register_lints: None, override_queries: None, diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index 2636423c1a4..fdd7e8b24c5 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -56,7 +56,6 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { file_loader: None, diagnostic_output: DiagnosticOutput::Default, stderr: None, - crate_name: None, lint_caps: Default::default(), register_lints: None, override_queries: None, From 66884e318f2edfb0dd66d76a7d3b080d0dd9e4c5 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Mon, 3 Aug 2020 12:45:27 -0500 Subject: [PATCH 131/274] Add json backend Respond to comments and start adding tests Fix re-exports and extern-crate Add expected output tests Add restricted paths Format Fix: associated methods missing in output Ignore stripped items Mark stripped items removing them creates dangling references Fix tests and update conversions Don't panic if JSON backend fails to create a file Fix attribute error in JSON testsuite Move rustdoc-json to rustdoc/ This way it doesn't have to build rustc twice. Eventually it should probably get its own suite, like rustdoc-js, but that can be fixed in a follow-up. Small cleanups Don't prettify json before printing This fully halves the size of the emitted JSON. Add comments [BREAKING CHANGE] rename version -> crate_version [BREAKING CHANGE] rename source -> span Use exhaustive matches Don't qualify imports for DefId Rename clean::{ItemEnum -> ItemKind}, clean::Item::{inner -> kind} Fix Visibility conversion clean::Visability was changed here: https://github.com/rust-lang/rust/pull/77820/files#diff-df9f90aae0b7769e1eb6ea6f1d73c1c3f649e1ac48a20e169662a8930eb427beL1467-R1509 More churn catchup Format --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 41 ++ src/librustdoc/json/conversions.rs | 596 ++++++++++++++++++ src/librustdoc/json/mod.rs | 223 ++++++- src/librustdoc/json/types.rs | 493 +++++++++++++++ src/test/rustdoc/rustdoc-json/Makefile | 6 + .../rustdoc-json/check_missing_items.py | 181 ++++++ src/test/rustdoc/rustdoc-json/compare.py | 107 ++++ .../rustdoc/rustdoc-json/structs.expected | 468 ++++++++++++++ src/test/rustdoc/rustdoc-json/structs.rs | 17 + 10 files changed, 2117 insertions(+), 17 deletions(-) create mode 100644 src/librustdoc/json/conversions.rs create mode 100644 src/librustdoc/json/types.rs create mode 100644 src/test/rustdoc/rustdoc-json/Makefile create mode 100644 src/test/rustdoc/rustdoc-json/check_missing_items.py create mode 100644 src/test/rustdoc/rustdoc-json/compare.py create mode 100644 src/test/rustdoc/rustdoc-json/structs.expected create mode 100644 src/test/rustdoc/rustdoc-json/structs.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d294d8f02a8..9d42705da82 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2281,7 +2281,7 @@ impl Clean> for doctree::Import<'_> { name: None, attrs: self.attrs.clean(cx), source: self.span.clean(cx), - def_id: DefId::local(CRATE_DEF_INDEX), + def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: None, const_stability: None, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 38d25d8d98e..d4796b7ed66 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -337,6 +337,42 @@ crate enum ItemKind { } impl ItemKind { + /// Some items contain others such as structs (for their fields) and Enums + /// (for their variants). This method returns those contained items. + crate fn inner_items(&self) -> impl Iterator { + match self { + StructItem(s) => s.fields.iter(), + UnionItem(u) => u.fields.iter(), + VariantItem(Variant { kind: VariantKind::Struct(v) }) => v.fields.iter(), + EnumItem(e) => e.variants.iter(), + TraitItem(t) => t.items.iter(), + ImplItem(i) => i.items.iter(), + ModuleItem(m) => m.items.iter(), + ExternCrateItem(_, _) + | ImportItem(_) + | FunctionItem(_) + | TypedefItem(_, _) + | OpaqueTyItem(_) + | StaticItem(_) + | ConstantItem(_) + | TraitAliasItem(_) + | TyMethodItem(_) + | MethodItem(_, _) + | StructFieldItem(_) + | VariantItem(_) + | ForeignFunctionItem(_) + | ForeignStaticItem(_) + | ForeignTypeItem + | MacroItem(_) + | ProcMacroItem(_) + | PrimitiveItem(_) + | AssocConstItem(_, _) + | AssocTypeItem(_, _) + | StrippedItem(_) + | KeywordItem(_) => [].iter(), + } + } + crate fn is_type_alias(&self) -> bool { match *self { ItemKind::TypedefItem(_, _) | ItemKind::AssocTypeItem(_, _) => true, @@ -1613,6 +1649,11 @@ impl Path { crate fn last_name(&self) -> &str { self.segments.last().expect("segments were empty").name.as_str() } + + crate fn whole_name(&self) -> String { + String::from(if self.global { "::" } else { "" }) + + &self.segments.iter().map(|s| s.name.clone()).collect::>().join("::") + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs new file mode 100644 index 00000000000..80192623d54 --- /dev/null +++ b/src/librustdoc/json/conversions.rs @@ -0,0 +1,596 @@ +//! These from impls are used to create the JSON types which get serialized. They're very close to +//! the `clean` types but with some fields removed or stringified to simplify the output and not +//! expose unstable compiler internals. + +use std::convert::From; + +use rustc_ast::ast; +use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; + +use crate::clean; +use crate::doctree; +use crate::formats::item_type::ItemType; +use crate::json::types::*; + +impl From for Item { + fn from(item: clean::Item) -> Self { + let item_type = ItemType::from(&item); + let clean::Item { + source, + name, + attrs, + kind: inner, + visibility, + def_id, + stability: _, + deprecation, + } = item; + Item { + id: def_id.into(), + crate_id: def_id.krate.as_u32(), + name, + stripped: match inner { + clean::StrippedItem(_) => true, + _ => false, + }, + source: source.into(), + visibility: visibility.into(), + docs: attrs.collapsed_doc_value().unwrap_or_default(), + links: attrs + .links + .into_iter() + .filter_map(|clean::ItemLink { link, did, .. }| did.map(|did| (link, did.into()))) + .collect(), + attrs: attrs + .other_attrs + .iter() + .map(rustc_ast_pretty::pprust::attribute_to_string) + .collect(), + deprecation: deprecation.map(Into::into), + kind: item_type.into(), + inner: inner.into(), + } + } +} + +impl From for Option { + fn from(span: clean::Span) -> Self { + let clean::Span { loline, locol, hiline, hicol, .. } = span; + match span.filename { + rustc_span::FileName::Real(name) => Some(Span { + filename: match name { + rustc_span::RealFileName::Named(path) => path, + rustc_span::RealFileName::Devirtualized { local_path, virtual_name: _ } => { + local_path + } + }, + begin: (loline, locol), + end: (hiline, hicol), + }), + _ => None, + } + } +} + +impl From for Deprecation { + fn from(deprecation: clean::Deprecation) -> Self { + let clean::Deprecation { since, note, is_since_rustc_version: _ } = deprecation; + Deprecation { since, note } + } +} + +impl From for Visibility { + fn from(v: clean::Visibility) -> Self { + use clean::Visibility::*; + match v { + Public => Visibility::Public, + Inherited => Visibility::Default, + Restricted(did, _) if did.index == CRATE_DEF_INDEX => Visibility::Crate, + Restricted(did, path) => Visibility::Restricted { + parent: did.into(), + path: path.to_string_no_crate_verbose(), + }, + } + } +} + +impl From for GenericArgs { + fn from(args: clean::GenericArgs) -> Self { + use clean::GenericArgs::*; + match args { + AngleBracketed { args, bindings } => GenericArgs::AngleBracketed { + args: args.into_iter().map(Into::into).collect(), + bindings: bindings.into_iter().map(Into::into).collect(), + }, + Parenthesized { inputs, output } => GenericArgs::Parenthesized { + inputs: inputs.into_iter().map(Into::into).collect(), + output: output.map(Into::into), + }, + } + } +} + +impl From for GenericArg { + fn from(arg: clean::GenericArg) -> Self { + use clean::GenericArg::*; + match arg { + Lifetime(l) => GenericArg::Lifetime(l.0), + Type(t) => GenericArg::Type(t.into()), + Const(c) => GenericArg::Const(c.into()), + } + } +} + +impl From for Constant { + fn from(constant: clean::Constant) -> Self { + let clean::Constant { type_, expr, value, is_literal } = constant; + Constant { type_: type_.into(), expr, value, is_literal } + } +} + +impl From for TypeBinding { + fn from(binding: clean::TypeBinding) -> Self { + TypeBinding { name: binding.name, binding: binding.kind.into() } + } +} + +impl From for TypeBindingKind { + fn from(kind: clean::TypeBindingKind) -> Self { + use clean::TypeBindingKind::*; + match kind { + Equality { ty } => TypeBindingKind::Equality(ty.into()), + Constraint { bounds } => { + TypeBindingKind::Constraint(bounds.into_iter().map(Into::into).collect()) + } + } + } +} + +impl From for Id { + fn from(did: DefId) -> Self { + Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index))) + } +} + +impl From for ItemEnum { + fn from(item: clean::ItemKind) -> Self { + use clean::ItemKind::*; + match item { + ModuleItem(m) => ItemEnum::ModuleItem(m.into()), + ExternCrateItem(c, a) => ItemEnum::ExternCrateItem { name: c, rename: a }, + ImportItem(i) => ItemEnum::ImportItem(i.into()), + StructItem(s) => ItemEnum::StructItem(s.into()), + UnionItem(u) => ItemEnum::StructItem(u.into()), + StructFieldItem(f) => ItemEnum::StructFieldItem(f.into()), + EnumItem(e) => ItemEnum::EnumItem(e.into()), + VariantItem(v) => ItemEnum::VariantItem(v.into()), + FunctionItem(f) => ItemEnum::FunctionItem(f.into()), + ForeignFunctionItem(f) => ItemEnum::FunctionItem(f.into()), + TraitItem(t) => ItemEnum::TraitItem(t.into()), + TraitAliasItem(t) => ItemEnum::TraitAliasItem(t.into()), + MethodItem(m, _) => ItemEnum::MethodItem(m.into()), + TyMethodItem(m) => ItemEnum::MethodItem(m.into()), + ImplItem(i) => ItemEnum::ImplItem(i.into()), + StaticItem(s) => ItemEnum::StaticItem(s.into()), + ForeignStaticItem(s) => ItemEnum::StaticItem(s.into()), + ForeignTypeItem => ItemEnum::ForeignTypeItem, + TypedefItem(t, _) => ItemEnum::TypedefItem(t.into()), + OpaqueTyItem(t) => ItemEnum::OpaqueTyItem(t.into()), + ConstantItem(c) => ItemEnum::ConstantItem(c.into()), + MacroItem(m) => ItemEnum::MacroItem(m.source), + ProcMacroItem(m) => ItemEnum::ProcMacroItem(m.into()), + AssocConstItem(t, s) => ItemEnum::AssocConstItem { type_: t.into(), default: s }, + AssocTypeItem(g, t) => ItemEnum::AssocTypeItem { + bounds: g.into_iter().map(Into::into).collect(), + default: t.map(Into::into), + }, + StrippedItem(inner) => (*inner).into(), + PrimitiveItem(_) | KeywordItem(_) => { + panic!("{:?} is not supported for JSON output", item) + } + } + } +} + +impl From for Module { + fn from(module: clean::Module) -> Self { + Module { + is_crate: module.is_crate, + items: module.items.into_iter().map(|i| i.def_id.into()).collect(), + } + } +} + +impl From for Struct { + fn from(struct_: clean::Struct) -> Self { + let clean::Struct { struct_type, generics, fields, fields_stripped } = struct_; + Struct { + struct_type: struct_type.into(), + generics: generics.into(), + fields_stripped, + fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + impls: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for Struct { + fn from(struct_: clean::Union) -> Self { + let clean::Union { struct_type, generics, fields, fields_stripped } = struct_; + Struct { + struct_type: struct_type.into(), + generics: generics.into(), + fields_stripped, + fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + impls: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for StructType { + fn from(struct_type: doctree::StructType) -> Self { + use doctree::StructType::*; + match struct_type { + Plain => StructType::Plain, + Tuple => StructType::Tuple, + Unit => StructType::Unit, + } + } +} + +fn stringify_header(header: &rustc_hir::FnHeader) -> String { + let mut s = String::from(header.unsafety.prefix_str()); + if header.asyncness == rustc_hir::IsAsync::Async { + s.push_str("async ") + } + if header.constness == rustc_hir::Constness::Const { + s.push_str("const ") + } + s +} + +impl From for Function { + fn from(function: clean::Function) -> Self { + let clean::Function { decl, generics, header, all_types: _, ret_types: _ } = function; + Function { + decl: decl.into(), + generics: generics.into(), + header: stringify_header(&header), + abi: header.abi.to_string(), + } + } +} + +impl From for Generics { + fn from(generics: clean::Generics) -> Self { + Generics { + params: generics.params.into_iter().map(Into::into).collect(), + where_predicates: generics.where_predicates.into_iter().map(Into::into).collect(), + } + } +} + +impl From for GenericParamDef { + fn from(generic_param: clean::GenericParamDef) -> Self { + GenericParamDef { name: generic_param.name, kind: generic_param.kind.into() } + } +} + +impl From for GenericParamDefKind { + fn from(kind: clean::GenericParamDefKind) -> Self { + use clean::GenericParamDefKind::*; + match kind { + Lifetime => GenericParamDefKind::Lifetime, + Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type { + bounds: bounds.into_iter().map(Into::into).collect(), + default: default.map(Into::into), + }, + Const { did: _, ty } => GenericParamDefKind::Const(ty.into()), + } + } +} + +impl From for WherePredicate { + fn from(predicate: clean::WherePredicate) -> Self { + use clean::WherePredicate::*; + match predicate { + BoundPredicate { ty, bounds } => WherePredicate::BoundPredicate { + ty: ty.into(), + bounds: bounds.into_iter().map(Into::into).collect(), + }, + RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { + lifetime: lifetime.0, + bounds: bounds.into_iter().map(Into::into).collect(), + }, + EqPredicate { lhs, rhs } => { + WherePredicate::EqPredicate { lhs: lhs.into(), rhs: rhs.into() } + } + } + } +} + +impl From for GenericBound { + fn from(bound: clean::GenericBound) -> Self { + use clean::GenericBound::*; + match bound { + TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { + GenericBound::TraitBound { + trait_: trait_.into(), + generic_params: generic_params.into_iter().map(Into::into).collect(), + modifier: modifier.into(), + } + } + Outlives(lifetime) => GenericBound::Outlives(lifetime.0), + } + } +} + +impl From for TraitBoundModifier { + fn from(modifier: rustc_hir::TraitBoundModifier) -> Self { + use rustc_hir::TraitBoundModifier::*; + match modifier { + None => TraitBoundModifier::None, + Maybe => TraitBoundModifier::Maybe, + MaybeConst => TraitBoundModifier::MaybeConst, + } + } +} + +impl From for Type { + fn from(ty: clean::Type) -> Self { + use clean::Type::*; + match ty { + ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath { + name: path.whole_name(), + id: did.into(), + args: path.segments.last().map(|args| Box::new(args.clone().args.into())), + param_names: param_names + .map(|v| v.into_iter().map(Into::into).collect()) + .unwrap_or_default(), + }, + Generic(s) => Type::Generic(s), + Primitive(p) => Type::Primitive(p.as_str().to_string()), + BareFunction(f) => Type::FunctionPointer(Box::new((*f).into())), + Tuple(t) => Type::Tuple(t.into_iter().map(Into::into).collect()), + Slice(t) => Type::Slice(Box::new((*t).into())), + Array(t, s) => Type::Array { type_: Box::new((*t).into()), len: s }, + ImplTrait(g) => Type::ImplTrait(g.into_iter().map(Into::into).collect()), + Never => Type::Never, + Infer => Type::Infer, + RawPointer(mutability, type_) => Type::RawPointer { + mutable: mutability == ast::Mutability::Mut, + type_: Box::new((*type_).into()), + }, + BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { + lifetime: lifetime.map(|l| l.0), + mutable: mutability == ast::Mutability::Mut, + type_: Box::new((*type_).into()), + }, + QPath { name, self_type, trait_ } => Type::QualifiedPath { + name, + self_type: Box::new((*self_type).into()), + trait_: Box::new((*trait_).into()), + }, + } + } +} + +impl From for FunctionPointer { + fn from(bare_decl: clean::BareFunctionDecl) -> Self { + let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl; + FunctionPointer { + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, + generic_params: generic_params.into_iter().map(Into::into).collect(), + decl: decl.into(), + abi: abi.to_string(), + } + } +} + +impl From for FnDecl { + fn from(decl: clean::FnDecl) -> Self { + let clean::FnDecl { inputs, output, c_variadic, attrs: _ } = decl; + FnDecl { + inputs: inputs.values.into_iter().map(|arg| (arg.name, arg.type_.into())).collect(), + output: match output { + clean::FnRetTy::Return(t) => Some(t.into()), + clean::FnRetTy::DefaultReturn => None, + }, + c_variadic, + } + } +} + +impl From for Trait { + fn from(trait_: clean::Trait) -> Self { + let clean::Trait { unsafety, items, generics, bounds, is_spotlight: _, is_auto } = trait_; + Trait { + is_auto, + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, + items: items.into_iter().map(|i| i.def_id.into()).collect(), + generics: generics.into(), + bounds: bounds.into_iter().map(Into::into).collect(), + implementors: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for Impl { + fn from(impl_: clean::Impl) -> Self { + let clean::Impl { + unsafety, + generics, + provided_trait_methods, + trait_, + for_, + items, + polarity, + synthetic, + blanket_impl, + } = impl_; + Impl { + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, + generics: generics.into(), + provided_trait_methods: provided_trait_methods.into_iter().collect(), + trait_: trait_.map(Into::into), + for_: for_.into(), + items: items.into_iter().map(|i| i.def_id.into()).collect(), + negative: polarity == Some(clean::ImplPolarity::Negative), + synthetic, + blanket_impl: blanket_impl.map(Into::into), + } + } +} + +impl From for Method { + fn from(function: clean::Function) -> Self { + let clean::Function { header, decl, generics, all_types: _, ret_types: _ } = function; + Method { + decl: decl.into(), + generics: generics.into(), + header: stringify_header(&header), + has_body: true, + } + } +} + +impl From for Enum { + fn from(enum_: clean::Enum) -> Self { + let clean::Enum { variants, generics, variants_stripped } = enum_; + Enum { + generics: generics.into(), + variants_stripped, + variants: variants.into_iter().map(|i| i.def_id.into()).collect(), + impls: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for Struct { + fn from(struct_: clean::VariantStruct) -> Self { + let clean::VariantStruct { struct_type, fields, fields_stripped } = struct_; + Struct { + struct_type: struct_type.into(), + generics: Default::default(), + fields_stripped, + fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + impls: Vec::new(), + } + } +} + +impl From for Variant { + fn from(variant: clean::Variant) -> Self { + use clean::VariantKind::*; + match variant.kind { + CLike => Variant::Plain, + Tuple(t) => Variant::Tuple(t.into_iter().map(Into::into).collect()), + Struct(s) => Variant::Struct(s.fields.into_iter().map(|i| i.def_id.into()).collect()), + } + } +} + +impl From for Import { + fn from(import: clean::Import) -> Self { + use clean::ImportKind::*; + match import.kind { + Simple(s) => Import { + span: import.source.path.whole_name(), + name: s, + id: import.source.did.map(Into::into), + glob: false, + }, + Glob => Import { + span: import.source.path.whole_name(), + name: import.source.path.last_name().to_string(), + id: import.source.did.map(Into::into), + glob: true, + }, + } + } +} + +impl From for ProcMacro { + fn from(mac: clean::ProcMacro) -> Self { + ProcMacro { kind: mac.kind.into(), helpers: mac.helpers } + } +} + +impl From for MacroKind { + fn from(kind: rustc_span::hygiene::MacroKind) -> Self { + use rustc_span::hygiene::MacroKind::*; + match kind { + Bang => MacroKind::Bang, + Attr => MacroKind::Attr, + Derive => MacroKind::Derive, + } + } +} + +impl From for Typedef { + fn from(typedef: clean::Typedef) -> Self { + let clean::Typedef { type_, generics, item_type: _ } = typedef; + Typedef { type_: type_.into(), generics: generics.into() } + } +} + +impl From for OpaqueTy { + fn from(opaque: clean::OpaqueTy) -> Self { + OpaqueTy { + bounds: opaque.bounds.into_iter().map(Into::into).collect(), + generics: opaque.generics.into(), + } + } +} + +impl From for Static { + fn from(stat: clean::Static) -> Self { + Static { + type_: stat.type_.into(), + mutable: stat.mutability == ast::Mutability::Mut, + expr: stat.expr, + } + } +} + +impl From for TraitAlias { + fn from(alias: clean::TraitAlias) -> Self { + TraitAlias { + generics: alias.generics.into(), + params: alias.bounds.into_iter().map(Into::into).collect(), + } + } +} + +impl From for ItemKind { + fn from(kind: ItemType) -> Self { + use ItemType::*; + match kind { + Module => ItemKind::Module, + ExternCrate => ItemKind::ExternCrate, + Import => ItemKind::Import, + Struct => ItemKind::Struct, + Union => ItemKind::Union, + Enum => ItemKind::Enum, + Function => ItemKind::Function, + Typedef => ItemKind::Typedef, + OpaqueTy => ItemKind::OpaqueTy, + Static => ItemKind::Static, + Constant => ItemKind::Constant, + Trait => ItemKind::Trait, + Impl => ItemKind::Impl, + TyMethod | Method => ItemKind::Method, + StructField => ItemKind::StructField, + Variant => ItemKind::Variant, + Macro => ItemKind::Macro, + Primitive => ItemKind::Primitive, + AssocConst => ItemKind::AssocConst, + AssocType => ItemKind::AssocType, + ForeignType => ItemKind::ForeignType, + Keyword => ItemKind::Keyword, + TraitAlias => ItemKind::TraitAlias, + ProcAttribute => ItemKind::ProcAttribute, + ProcDerive => ItemKind::ProcDerive, + } + } +} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 5eb1f7b1f77..20a8de144ad 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -1,47 +1,238 @@ +//! Rustdoc's JSON backend +//! +//! This module contains the logic for rendering a crate as JSON rather than the normal static HTML +//! output. See [the RFC](https://github.com/rust-lang/rfcs/pull/2963) and the [`types`] module +//! docs for usage and details. + +mod conversions; +pub mod types; + +use std::cell::RefCell; +use std::fs::File; +use std::path::PathBuf; +use std::rc::Rc; + +use rustc_data_structures::fx::FxHashMap; +use rustc_span::edition::Edition; + use crate::clean; use crate::config::{RenderInfo, RenderOptions}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer; - -use rustc_span::edition::Edition; +use crate::html::render::cache::ExternalLocation; #[derive(Clone)] -crate struct JsonRenderer {} +crate struct JsonRenderer { + /// A mapping of IDs that contains all local items for this crate which gets output as a top + /// level field of the JSON blob. + index: Rc>>, + /// The directory where the blob will be written to. + out_path: PathBuf, +} + +impl JsonRenderer { + fn get_trait_implementors( + &mut self, + id: rustc_span::def_id::DefId, + cache: &Cache, + ) -> Vec { + cache + .implementors + .get(&id) + .map(|implementors| { + implementors + .iter() + .map(|i| { + let item = &i.impl_item; + self.item(item.clone(), cache).unwrap(); + item.def_id.into() + }) + .collect() + }) + .unwrap_or_default() + } + + fn get_impls(&mut self, id: rustc_span::def_id::DefId, cache: &Cache) -> Vec { + cache + .impls + .get(&id) + .map(|impls| { + impls + .iter() + .filter_map(|i| { + let item = &i.impl_item; + if item.def_id.is_local() { + self.item(item.clone(), cache).unwrap(); + Some(item.def_id.into()) + } else { + None + } + }) + .collect() + }) + .unwrap_or_default() + } + + fn get_trait_items(&mut self, cache: &Cache) -> Vec<(types::Id, types::Item)> { + cache + .traits + .iter() + .filter_map(|(&id, trait_item)| { + // only need to synthesize items for external traits + if !id.is_local() { + trait_item.items.clone().into_iter().for_each(|i| self.item(i, cache).unwrap()); + Some(( + id.into(), + types::Item { + id: id.into(), + crate_id: id.krate.as_u32(), + name: cache + .paths + .get(&id) + .unwrap_or_else(|| { + cache + .external_paths + .get(&id) + .expect("Trait should either be in local or external paths") + }) + .0 + .last() + .map(Clone::clone), + stripped: false, + visibility: types::Visibility::Public, + kind: types::ItemKind::Trait, + inner: types::ItemEnum::TraitItem(trait_item.clone().into()), + source: None, + docs: Default::default(), + links: Default::default(), + attrs: Default::default(), + deprecation: Default::default(), + }, + )) + } else { + None + } + }) + .collect() + } +} impl FormatRenderer for JsonRenderer { fn init( - _krate: clean::Crate, - _options: RenderOptions, + krate: clean::Crate, + options: RenderOptions, _render_info: RenderInfo, _edition: Edition, _cache: &mut Cache, ) -> Result<(Self, clean::Crate), Error> { - unimplemented!() + debug!("Initializing json renderer"); + Ok(( + JsonRenderer { + index: Rc::new(RefCell::new(FxHashMap::default())), + out_path: options.output, + }, + krate, + )) } - fn item(&mut self, _item: clean::Item, _cache: &Cache) -> Result<(), Error> { - unimplemented!() + /// Inserts an item into the index. This should be used rather than directly calling insert on + /// the hashmap because certain items (traits and types) need to have their mappings for trait + /// implementations filled out before they're inserted. + fn item(&mut self, item: clean::Item, cache: &Cache) -> Result<(), Error> { + // Flatten items that recursively store other items + item.kind.inner_items().for_each(|i| self.item(i.clone(), cache).unwrap()); + + let id = item.def_id; + let mut new_item: types::Item = item.into(); + if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner { + t.implementors = self.get_trait_implementors(id, cache) + } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner { + s.impls = self.get_impls(id, cache) + } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner { + e.impls = self.get_impls(id, cache) + } + + self.index.borrow_mut().insert(id.into(), new_item); + Ok(()) } fn mod_item_in( &mut self, - _item: &clean::Item, - _item_name: &str, - _cache: &Cache, + item: &clean::Item, + _module_name: &str, + cache: &Cache, ) -> Result<(), Error> { - unimplemented!() + use clean::types::ItemKind::*; + if let ModuleItem(m) = &item.kind { + for item in &m.items { + match &item.kind { + // These don't have names so they don't get added to the output by default + ImportItem(_) => self.item(item.clone(), cache).unwrap(), + ExternCrateItem(_, _) => self.item(item.clone(), cache).unwrap(), + ImplItem(i) => { + i.items.iter().for_each(|i| self.item(i.clone(), cache).unwrap()) + } + _ => {} + } + } + } + self.item(item.clone(), cache).unwrap(); + Ok(()) } fn mod_item_out(&mut self, _item_name: &str) -> Result<(), Error> { - unimplemented!() + Ok(()) } - fn after_krate(&mut self, _krate: &clean::Crate, _cache: &Cache) -> Result<(), Error> { - unimplemented!() + fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> { + debug!("Done with crate"); + let mut index = (*self.index).clone().into_inner(); + index.extend(self.get_trait_items(cache)); + let output = types::Crate { + root: types::Id(String::from("0:0")), + crate_version: krate.version.clone(), + includes_private: cache.document_private, + index, + paths: cache + .paths + .clone() + .into_iter() + .chain(cache.external_paths.clone().into_iter()) + .map(|(k, (path, kind))| { + ( + k.into(), + types::ItemSummary { crate_id: k.krate.as_u32(), path, kind: kind.into() }, + ) + }) + .collect(), + external_crates: cache + .extern_locations + .iter() + .map(|(k, v)| { + ( + k.as_u32(), + types::ExternalCrate { + name: v.0.clone(), + html_root_url: match &v.2 { + ExternalLocation::Remote(s) => Some(s.clone()), + _ => None, + }, + }, + ) + }) + .collect(), + format_version: 1, + }; + let mut p = self.out_path.clone(); + p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); + p.set_extension("json"); + let file = File::create(&p).map_err(|error| Error { error: error.to_string(), file: p })?; + serde_json::ser::to_writer(&file, &output).unwrap(); + Ok(()) } fn after_run(&mut self, _diag: &rustc_errors::Handler) -> Result<(), Error> { - unimplemented!() + Ok(()) } } diff --git a/src/librustdoc/json/types.rs b/src/librustdoc/json/types.rs new file mode 100644 index 00000000000..62705affafc --- /dev/null +++ b/src/librustdoc/json/types.rs @@ -0,0 +1,493 @@ +//! Rustdoc's JSON output interface +//! +//! These types are the public API exposed through the `--output-format json` flag. The [`Crate`] +//! struct is the root of the JSON blob and all other items are contained within. + +use std::path::PathBuf; + +use rustc_data_structures::fx::FxHashMap; +use serde::{Deserialize, Serialize}; + +/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information +/// about the language items in the local crate, as well as info about external items to allow +/// tools to find or link to them. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Crate { + /// The id of the root [`Module`] item of the local crate. + pub root: Id, + /// The version string given to `--crate-version`, if any. + pub crate_version: Option, + /// Whether or not the output includes private items. + pub includes_private: bool, + /// A collection of all items in the local crate as well as some external traits and their + /// items that are referenced locally. + pub index: FxHashMap, + /// Maps IDs to fully qualified paths and other info helpful for generating links. + pub paths: FxHashMap, + /// Maps `crate_id` of items to a crate name and html_root_url if it exists. + pub external_crates: FxHashMap, + /// A single version number to be used in the future when making backwards incompatible changes + /// to the JSON output. + pub format_version: u32, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ExternalCrate { + pub name: String, + pub html_root_url: Option, +} + +/// For external (not defined in the local crate) items, you don't get the same level of +/// information. This struct should contain enough to generate a link/reference to the item in +/// question, or can be used by a tool that takes the json output of multiple crates to find +/// the actual item definition with all the relevant info. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ItemSummary { + /// Can be used to look up the name and html_root_url of the crate this item came from in the + /// `external_crates` map. + pub crate_id: u32, + /// The list of path components for the fully qualified path of this item (e.g. + /// `["std", "io", "lazy", "Lazy"]` for `std::io::lazy::Lazy`). + pub path: Vec, + /// Whether this item is a struct, trait, macro, etc. + pub kind: ItemKind, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Item { + /// The unique identifier of this item. Can be used to find this item in various mappings. + pub id: Id, + /// This can be used as a key to the `external_crates` map of [`Crate`] to see which crate + /// this item came from. + pub crate_id: u32, + /// Some items such as impls don't have names. + pub name: Option, + /// Whether this item is meant to be omitted from the generated documentation due to `#doc(hidden)`, + /// because it is private, or because it was inlined. + pub stripped: bool, + /// The source location of this item (absent if it came from a macro expansion or inline + /// assembly). + pub source: Option, + /// By default all documented items are public, but you can tell rustdoc to output private items + /// so this field is needed to differentiate. + pub visibility: Visibility, + /// The full markdown docstring of this item. + pub docs: String, + /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs + pub links: FxHashMap, + /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`) + pub attrs: Vec, + pub deprecation: Option, + pub kind: ItemKind, + pub inner: ItemEnum, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Span { + /// The path to the source file for this span relative to the path `rustdoc` was invoked with. + pub filename: PathBuf, + /// Zero indexed Line and Column of the first character of the `Span` + pub begin: (usize, usize), + /// Zero indexed Line and Column of the last character of the `Span` + pub end: (usize, usize), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Deprecation { + pub since: Option, + pub note: Option, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Visibility { + Public, + /// For the most part items are private by default. The exceptions are associated items of + /// public traits and variants of public enums. + Default, + Crate, + /// For `pub(in path)` visibility. `parent` is the module it's restricted to and `path` is how + /// that module was referenced (like `"super::super"` or `"crate::foo::bar"`). + Restricted { + parent: Id, + path: String, + }, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericArgs { + /// <'a, 32, B: Copy, C = u32> + AngleBracketed { args: Vec, bindings: Vec }, + /// Fn(A, B) -> C + Parenthesized { inputs: Vec, output: Option }, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericArg { + Lifetime(String), + Type(Type), + Const(Constant), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Constant { + #[serde(rename = "type")] + pub type_: Type, + pub expr: String, + pub value: Option, + pub is_literal: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TypeBinding { + pub name: String, + pub binding: TypeBindingKind, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum TypeBindingKind { + Equality(Type), + Constraint(Vec), +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Id(pub String); + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ItemKind { + Module, + ExternCrate, + Import, + Struct, + StructField, + Union, + Enum, + Variant, + Function, + Typedef, + OpaqueTy, + Constant, + Trait, + TraitAlias, + Method, + Impl, + Static, + ForeignType, + Macro, + ProcAttribute, + ProcDerive, + AssocConst, + AssocType, + Primitive, + Keyword, +} + +#[serde(untagged)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ItemEnum { + ModuleItem(Module), + ExternCrateItem { + name: String, + rename: Option, + }, + ImportItem(Import), + + StructItem(Struct), + StructFieldItem(Type), + EnumItem(Enum), + VariantItem(Variant), + + FunctionItem(Function), + + TraitItem(Trait), + TraitAliasItem(TraitAlias), + MethodItem(Method), + ImplItem(Impl), + + TypedefItem(Typedef), + OpaqueTyItem(OpaqueTy), + ConstantItem(Constant), + + StaticItem(Static), + + /// `type`s from an extern block + ForeignTypeItem, + + /// Declarative macro_rules! macro + MacroItem(String), + ProcMacroItem(ProcMacro), + + AssocConstItem { + #[serde(rename = "type")] + type_: Type, + /// e.g. `const X: usize = 5;` + default: Option, + }, + AssocTypeItem { + bounds: Vec, + /// e.g. `type X = usize;` + default: Option, + }, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Module { + pub is_crate: bool, + pub items: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Struct { + pub struct_type: StructType, + pub generics: Generics, + pub fields_stripped: bool, + pub fields: Vec, + pub impls: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Enum { + pub generics: Generics, + pub variants_stripped: bool, + pub variants: Vec, + pub impls: Vec, +} + +#[serde(rename_all = "snake_case")] +#[serde(tag = "variant_kind", content = "variant_inner")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Variant { + Plain, + Tuple(Vec), + Struct(Vec), +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum StructType { + Plain, + Tuple, + Unit, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Function { + pub decl: FnDecl, + pub generics: Generics, + pub header: String, + pub abi: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Method { + pub decl: FnDecl, + pub generics: Generics, + pub header: String, + pub has_body: bool, +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct Generics { + pub params: Vec, + pub where_predicates: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct GenericParamDef { + pub name: String, + pub kind: GenericParamDefKind, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericParamDefKind { + Lifetime, + Type { bounds: Vec, default: Option }, + Const(Type), +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum WherePredicate { + BoundPredicate { ty: Type, bounds: Vec }, + RegionPredicate { lifetime: String, bounds: Vec }, + EqPredicate { lhs: Type, rhs: Type }, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericBound { + TraitBound { + #[serde(rename = "trait")] + trait_: Type, + /// Used for HRTBs + generic_params: Vec, + modifier: TraitBoundModifier, + }, + Outlives(String), +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum TraitBoundModifier { + None, + Maybe, + MaybeConst, +} + +#[serde(rename_all = "snake_case")] +#[serde(tag = "kind", content = "inner")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Type { + /// Structs, enums, and traits + ResolvedPath { + name: String, + id: Id, + args: Option>, + param_names: Vec, + }, + /// Parameterized types + Generic(String), + /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples + Primitive(String), + /// `extern "ABI" fn` + FunctionPointer(Box), + /// `(String, u32, Box)` + Tuple(Vec), + /// `[u32]` + Slice(Box), + /// [u32; 15] + Array { + #[serde(rename = "type")] + type_: Box, + len: String, + }, + /// `impl TraitA + TraitB + ...` + ImplTrait(Vec), + /// `!` + Never, + /// `_` + Infer, + /// `*mut u32`, `*u8`, etc. + RawPointer { + mutable: bool, + #[serde(rename = "type")] + type_: Box, + }, + /// `&'a mut String`, `&str`, etc. + BorrowedRef { + lifetime: Option, + mutable: bool, + #[serde(rename = "type")] + type_: Box, + }, + /// `::Name` or associated types like `T::Item` where `T: Iterator` + QualifiedPath { + name: String, + self_type: Box, + #[serde(rename = "trait")] + trait_: Box, + }, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct FunctionPointer { + pub is_unsafe: bool, + pub generic_params: Vec, + pub decl: FnDecl, + pub abi: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct FnDecl { + pub inputs: Vec<(String, Type)>, + pub output: Option, + pub c_variadic: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Trait { + pub is_auto: bool, + pub is_unsafe: bool, + pub items: Vec, + pub generics: Generics, + pub bounds: Vec, + pub implementors: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TraitAlias { + pub generics: Generics, + pub params: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Impl { + pub is_unsafe: bool, + pub generics: Generics, + pub provided_trait_methods: Vec, + #[serde(rename = "trait")] + pub trait_: Option, + #[serde(rename = "for")] + pub for_: Type, + pub items: Vec, + pub negative: bool, + pub synthetic: bool, + pub blanket_impl: Option, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Import { + /// The full path being imported. + pub span: String, + /// May be different from the last segment of `source` when renaming imports: + /// `use source as name;` + pub name: String, + /// The ID of the item being imported. + pub id: Option, // FIXME is this actually ever None? + /// Whether this import uses a glob: `use source::*;` + pub glob: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ProcMacro { + pub kind: MacroKind, + pub helpers: Vec, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum MacroKind { + /// A bang macro `foo!()`. + Bang, + /// An attribute macro `#[foo]`. + Attr, + /// A derive macro `#[derive(Foo)]` + Derive, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Typedef { + #[serde(rename = "type")] + pub type_: Type, + pub generics: Generics, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct OpaqueTy { + pub bounds: Vec, + pub generics: Generics, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Static { + #[serde(rename = "type")] + pub type_: Type, + pub mutable: bool, + pub expr: String, +} diff --git a/src/test/rustdoc/rustdoc-json/Makefile b/src/test/rustdoc/rustdoc-json/Makefile new file mode 100644 index 00000000000..ad517ae95eb --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +tests: *.rs + $(RUSTDOC) $< -o $(TMPDIR) --output-format json + $(PYTHON) check_missing_items.py $(TMPDIR)/$(basename $<).json + $(PYTHON) compare.py $(basename $<).expected $(TMPDIR)/$(basename $<).json diff --git a/src/test/rustdoc/rustdoc-json/check_missing_items.py b/src/test/rustdoc/rustdoc-json/check_missing_items.py new file mode 100644 index 00000000000..0004dc8fb14 --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/check_missing_items.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python + +# This test ensures that every ID in the produced json actually resolves to an item either in +# `index` or `paths`. It DOES NOT check that the structure of the produced json is actually in +# any way correct, for example an empty map would pass. + +import sys +import json + +crate = json.load(open(sys.argv[1])) + + +def get_local_item(item_id): + if item_id in crate["index"]: + return crate["index"][item_id] + print("Missing local ID:", item_id) + sys.exit(1) + + +# local IDs have to be in `index`, external ones can sometimes be in `index` but otherwise have +# to be in `paths` +def valid_id(item_id): + return item_id in crate["index"] or item_id[0] != "0" and item_id in crate["paths"] + + +def check_generics(generics): + for param in generics["params"]: + check_generic_param(param) + for where_predicate in generics["where_predicates"]: + if "bound_predicate" in where_predicate: + pred = where_predicate["bound_predicate"] + check_type(pred["ty"]) + for bound in pred["bounds"]: + check_generic_bound(bound) + elif "region_predicate" in where_predicate: + pred = where_predicate["region_predicate"] + for bound in pred["bounds"]: + check_generic_bound(bound) + elif "eq_predicate" in where_predicate: + pred = where_predicate["eq_predicate"] + check_type(pred["rhs"]) + check_type(pred["lhs"]) + + +def check_generic_param(param): + if "type" in param["kind"]: + ty = param["kind"]["type"] + if ty["default"]: + check_type(ty["default"]) + for bound in ty["bounds"]: + check_generic_bound(bound) + elif "const" in param["kind"]: + check_type(param["kind"]["const"]) + + +def check_generic_bound(bound): + if "trait_bound" in bound: + for param in bound["trait_bound"]["generic_params"]: + check_generic_param(param) + check_type(bound["trait_bound"]["trait"]) + + +def check_decl(decl): + for (_name, ty) in decl["inputs"]: + check_type(ty) + if decl["output"]: + check_type(decl["output"]) + + +def check_type(ty): + if ty["kind"] == "resolved_path": + for bound in ty["inner"]["param_names"]: + check_generic_bound(bound) + args = ty["inner"]["args"] + if args: + if "angle_bracketed" in args: + for arg in args["angle_bracketed"]["args"]: + if "type" in arg: + check_type(arg["type"]) + elif "const" in arg: + check_type(arg["const"]["type"]) + for binding in args["angle_bracketed"]["bindings"]: + if "equality" in binding["binding"]: + check_type(binding["binding"]["equality"]) + elif "constraint" in binding["binding"]: + for bound in binding["binding"]["constraint"]: + check_generic_bound(bound) + elif "parenthesized" in args: + for ty in args["parenthesized"]["inputs"]: + check_type(ty) + if args["parenthesized"]["output"]: + check_type(args["parenthesized"]["output"]) + if not valid_id(ty["inner"]["id"]): + print("Type contained an invalid ID:", ty["inner"]["id"]) + sys.exit(1) + elif ty["kind"] == "tuple": + for ty in ty["inner"]: + check_type(ty) + elif ty["kind"] == "slice": + check_type(ty["inner"]) + elif ty["kind"] == "impl_trait": + for bound in ty["inner"]: + check_generic_bound(bound) + elif ty["kind"] in ("raw_pointer", "borrowed_ref", "array"): + check_type(ty["inner"]["type"]) + elif ty["kind"] == "function_pointer": + for param in ty["inner"]["generic_params"]: + check_generic_param(param) + check_decl(ty["inner"]["inner"]) + elif ty["kind"] == "qualified_path": + check_type(ty["inner"]["self_type"]) + check_type(ty["inner"]["trait"]) + + +work_list = set([crate["root"]]) +visited = work_list.copy() + +while work_list: + current = work_list.pop() + visited.add(current) + item = get_local_item(current) + # check intradoc links + for (_name, link) in item["links"].items(): + if not valid_id(link): + print("Intra-doc link contains invalid ID:", link) + + # check all fields that reference types such as generics as well as nested items + # (modules, structs, traits, and enums) + if item["kind"] == "module": + work_list |= set(item["inner"]["items"]) - visited + elif item["kind"] == "struct": + check_generics(item["inner"]["generics"]) + work_list |= (set(item["inner"]["fields"]) | set(item["inner"]["impls"])) - visited + elif item["kind"] == "struct_field": + check_type(item["inner"]) + elif item["kind"] == "enum": + check_generics(item["inner"]["generics"]) + work_list |= (set(item["inner"]["variants"]) | set(item["inner"]["impls"])) - visited + elif item["kind"] == "variant": + if item["inner"]["variant_kind"] == "tuple": + for ty in item["inner"]["variant_inner"]: + check_type(ty) + elif item["inner"]["variant_kind"] == "struct": + work_list |= set(item["inner"]["variant_inner"]) - visited + elif item["kind"] in ("function", "method"): + check_generics(item["inner"]["generics"]) + check_decl(item["inner"]["decl"]) + elif item["kind"] in ("static", "constant", "assoc_const"): + check_type(item["inner"]["type"]) + elif item["kind"] == "typedef": + check_type(item["inner"]["type"]) + check_generics(item["inner"]["generics"]) + elif item["kind"] == "opaque_ty": + check_generics(item["inner"]["generics"]) + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + elif item["kind"] == "trait_alias": + check_generics(item["inner"]["params"]) + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + elif item["kind"] == "trait": + check_generics(item["inner"]["generics"]) + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + work_list |= (set(item["inner"]["items"]) | set(item["inner"]["implementors"])) - visited + elif item["kind"] == "impl": + check_generics(item["inner"]["generics"]) + if item["inner"]["trait"]: + check_type(item["inner"]["trait"]) + if item["inner"]["blanket_impl"]: + check_type(item["inner"]["blanket_impl"]) + check_type(item["inner"]["for"]) + for assoc_item in item["inner"]["items"]: + if not valid_id(assoc_item): + print("Impl block referenced a missing ID:", assoc_item) + sys.exit(1) + elif item["kind"] == "assoc_type": + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + if item["inner"]["default"]: + check_type(item["inner"]["default"]) diff --git a/src/test/rustdoc/rustdoc-json/compare.py b/src/test/rustdoc/rustdoc-json/compare.py new file mode 100644 index 00000000000..5daf8903e20 --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/compare.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +# This script can check that an expected json blob is a subset of what actually gets produced. +# The comparison is independent of the value of IDs (which are unstable) and instead uses their +# relative ordering to check them against eachother by looking them up in their respective blob's +# `index` or `paths` mappings. To add a new test run `rustdoc --output-format json -o . yourtest.rs` +# and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. + +import copy +import sys +import json +import types + +# Used instead of the string ids when used as references. +# Not used as keys in `index` or `paths` +class ID(str): + pass + + +class SubsetException(Exception): + def __init__(self, msg, trace): + self.msg = msg + self.trace = msg + super().__init__("{}: {}".format(trace, msg)) + + +def check_subset(expected_main, actual_main): + expected_index = expected_main["index"] + expected_paths = expected_main["paths"] + actual_index = actual_main["index"] + actual_paths = actual_main["paths"] + already_checked = set() + + def _check_subset(expected, actual, trace): + expected_type = type(expected) + actual_type = type(actual) + if expected_type is not actual_type: + raise SubsetException( + "expected type `{}`, got `{}`".format(expected_type, actual_type), trace + ) + if expected_type in (str, int, bool) and expected != actual: + raise SubsetException("expected `{}`, got: `{}`".format(expected, actual), trace) + if expected_type is dict: + for key in expected: + if key not in actual: + raise SubsetException("Key `{}` not found in output".format(key), trace) + new_trace = copy.deepcopy(trace) + new_trace.append(key) + _check_subset(expected[key], actual[key], new_trace) + elif expected_type is list: + expected_elements = len(expected) + actual_elements = len(actual) + if expected_elements != actual_elements: + raise SubsetException( + "Found {} items, expected {}".format(expected_elements, actual_elements), trace + ) + for expected, actual in zip(expected, actual): + new_trace = copy.deepcopy(trace) + new_trace.append(expected) + _check_subset(expected, actual, new_trace) + elif expected_type is ID and expected not in already_checked: + already_checked.add(expected) + _check_subset(expected_index.get(expected, {}), actual_index.get(actual, {}), trace) + _check_subset(expected_paths.get(expected, {}), actual_paths.get(actual, {}), trace) + + _check_subset(expected_main["root"], actual_main["root"], []) + + +def rustdoc_object_hook(obj): + # No need to convert paths, index and external_crates keys to ids, since + # they are the target of resolution, and never a source itself. + if "id" in obj and obj["id"]: + obj["id"] = ID(obj["id"]) + if "root" in obj: + obj["root"] = ID(obj["root"]) + if "items" in obj: + obj["items"] = [ID(id) for id in obj["items"]] + if "variants" in obj: + obj["variants"] = [ID(id) for id in obj["variants"]] + if "fields" in obj: + obj["fields"] = [ID(id) for id in obj["fields"]] + if "impls" in obj: + obj["impls"] = [ID(id) for id in obj["impls"]] + if "implementors" in obj: + obj["implementors"] = [ID(id) for id in obj["implementors"]] + if "links" in obj: + obj["links"] = {s: ID(id) for s, id in obj["links"]} + if "variant_kind" in obj and obj["variant_kind"] == "struct": + obj["variant_inner"] = [ID(id) for id in obj["variant_inner"]] + return obj + + +def main(expected_fpath, actual_fpath): + print("checking that {} is a logical subset of {}".format(expected_fpath, actual_fpath)) + with open(expected_fpath) as expected_file: + expected_main = json.load(expected_file, object_hook=rustdoc_object_hook) + with open(actual_fpath) as actual_file: + actual_main = json.load(actual_file, object_hook=rustdoc_object_hook) + check_subset(expected_main, actual_main) + print("all checks passed") + + +if __name__ == "__main__": + if len(sys.argv) < 3: + print("Usage: `compare.py expected.json actual.json`") + else: + main(sys.argv[1], sys.argv[2]) diff --git a/src/test/rustdoc/rustdoc-json/structs.expected b/src/test/rustdoc/rustdoc-json/structs.expected new file mode 100644 index 00000000000..45b23534bc7 --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/structs.expected @@ -0,0 +1,468 @@ +{ + "root": "0:0", + "version": null, + "includes_private": false, + "index": { + "0:9": { + "crate_id": 0, + "name": "Unit", + "source": { + "filename": "structs.rs", + "begin": [ + 7, + 0 + ], + "end": [ + 7, + 16 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "unit", + "generics": { + "params": [], + "where_predicates": [] + }, + "fields_stripped": false, + "fields": [] + } + }, + "0:8": { + "crate_id": 0, + "name": "1", + "source": { + "filename": "structs.rs", + "begin": [ + 5, + 22 + ], + "end": [ + 5, + 28 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "resolved_path", + "inner": { + "name": "String", + "id": "5:5035", + "args": { + "angle_bracketed": { + "args": [], + "bindings": [] + } + }, + "param_names": [] + } + } + }, + "0:18": { + "crate_id": 0, + "name": "stuff", + "source": { + "filename": "structs.rs", + "begin": [ + 15, + 4 + ], + "end": [ + 15, + 17 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "resolved_path", + "inner": { + "name": "Vec", + "id": "5:4322", + "args": { + "angle_bracketed": { + "args": [ + { + "type": { + "kind": "generic", + "inner": "T" + } + } + ], + "bindings": [] + } + }, + "param_names": [] + } + } + }, + "0:11": { + "crate_id": 0, + "name": "WithPrimitives", + "source": { + "filename": "structs.rs", + "begin": [ + 9, + 0 + ], + "end": [ + 12, + 1 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "plain", + "generics": { + "params": [ + { + "name": "'a", + "kind": "lifetime" + } + ], + "where_predicates": [] + }, + "fields_stripped": true, + "fields": [ + "0:13", + "0:14" + ] + } + }, + "0:14": { + "crate_id": 0, + "name": "s", + "source": { + "filename": "structs.rs", + "begin": [ + 11, + 4 + ], + "end": [ + 11, + 14 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "borrowed_ref", + "inner": { + "lifetime": "'a", + "mutable": false, + "type": { + "kind": "primitive", + "inner": "str" + } + } + } + }, + "0:19": { + "crate_id": 0, + "name": "things", + "source": { + "filename": "structs.rs", + "begin": [ + 16, + 4 + ], + "end": [ + 16, + 25 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "resolved_path", + "inner": { + "name": "HashMap", + "id": "1:6600", + "args": { + "angle_bracketed": { + "args": [ + { + "type": { + "kind": "generic", + "inner": "U" + } + }, + { + "type": { + "kind": "generic", + "inner": "U" + } + } + ], + "bindings": [] + } + }, + "param_names": [] + } + } + }, + "0:15": { + "crate_id": 0, + "name": "WithGenerics", + "source": { + "filename": "structs.rs", + "begin": [ + 14, + 0 + ], + "end": [ + 17, + 1 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "plain", + "generics": { + "params": [ + { + "name": "T", + "kind": { + "type": { + "bounds": [], + "default": null + } + } + }, + { + "name": "U", + "kind": { + "type": { + "bounds": [], + "default": null + } + } + } + ], + "where_predicates": [] + }, + "fields_stripped": true, + "fields": [ + "0:18", + "0:19" + ] + } + }, + "0:0": { + "crate_id": 0, + "name": "structs", + "source": { + "filename": "structs.rs", + "begin": [ + 1, + 0 + ], + "end": [ + 17, + 1 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "module", + "inner": { + "is_crate": true, + "items": [ + "0:4", + "0:5", + "0:9", + "0:11", + "0:15" + ] + } + }, + "0:13": { + "crate_id": 0, + "name": "num", + "source": { + "filename": "structs.rs", + "begin": [ + 10, + 4 + ], + "end": [ + 10, + 12 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "primitive", + "inner": "u32" + } + }, + "0:5": { + "crate_id": 0, + "name": "Tuple", + "source": { + "filename": "structs.rs", + "begin": [ + 5, + 0 + ], + "end": [ + 5, + 30 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "tuple", + "generics": { + "params": [], + "where_predicates": [] + }, + "fields_stripped": true, + "fields": [ + "0:7", + "0:8" + ] + } + }, + "0:4": { + "crate_id": 0, + "name": "PlainEmpty", + "source": { + "filename": "structs.rs", + "begin": [ + 3, + 0 + ], + "end": [ + 3, + 24 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "plain", + "generics": { + "params": [], + "where_predicates": [] + }, + "fields_stripped": false, + "fields": [] + } + }, + "0:7": { + "crate_id": 0, + "name": "0", + "source": { + "filename": "structs.rs", + "begin": [ + 5, + 17 + ], + "end": [ + 5, + 20 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "primitive", + "inner": "u32" + } + } + }, + "paths": { + "5:4322": { + "crate_id": 5, + "path": [ + "alloc", + "vec", + "Vec" + ], + "kind": "struct" + }, + "5:5035": { + "crate_id": 5, + "path": [ + "alloc", + "string", + "String" + ], + "kind": "struct" + }, + "1:6600": { + "crate_id": 1, + "path": [ + "std", + "collections", + "hash", + "map", + "HashMap" + ], + "kind": "struct" + } + }, + "external_crates": { + "1": { + "name": "std" + }, + "5": { + "name": "alloc" + } + }, + "format_version": 1 +} diff --git a/src/test/rustdoc/rustdoc-json/structs.rs b/src/test/rustdoc/rustdoc-json/structs.rs new file mode 100644 index 00000000000..43fc4743503 --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/structs.rs @@ -0,0 +1,17 @@ +use std::collections::HashMap; + +pub struct PlainEmpty {} + +pub struct Tuple(u32, String); + +pub struct Unit; + +pub struct WithPrimitives<'a> { + num: u32, + s: &'a str, +} + +pub struct WithGenerics { + stuff: Vec, + things: HashMap, +} From 1098cce27acb2d52cb3b5ddbcf28c3a06e38dc7c Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sun, 29 Nov 2020 16:16:25 +0000 Subject: [PATCH 132/274] Add tests for rustdoc json Move rustdoc/rustdoc-json to rustdoc-json Scaffold rustdoc-json test mode Implement run_rustdoc_json_test Fix up python Make tidy happy --- src/bootstrap/builder.rs | 1 + src/bootstrap/test.rs | 7 ++ src/test/{rustdoc => }/rustdoc-json/Makefile | 0 .../rustdoc-json/check_missing_items.py | 12 +++- .../{rustdoc => }/rustdoc-json/compare.py | 48 +++++++++---- .../rustdoc-json/structs.expected | 0 .../{rustdoc => }/rustdoc-json/structs.rs | 0 src/tools/compiletest/src/common.rs | 3 + src/tools/compiletest/src/main.rs | 2 +- src/tools/compiletest/src/runtest.rs | 67 ++++++++++++++++--- 10 files changed, 115 insertions(+), 25 deletions(-) rename src/test/{rustdoc => }/rustdoc-json/Makefile (100%) rename src/test/{rustdoc => }/rustdoc-json/check_missing_items.py (95%) rename src/test/{rustdoc => }/rustdoc-json/compare.py (69%) rename src/test/{rustdoc => }/rustdoc-json/structs.expected (100%) rename src/test/{rustdoc => }/rustdoc-json/structs.rs (100%) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index b5bbb6372ee..6d97943548d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -425,6 +425,7 @@ impl<'a> Builder<'a> { test::RustdocJSNotStd, test::RustdocTheme, test::RustdocUi, + test::RustdocJson, // Run bootstrap close to the end as it's unlikely to fail test::Bootstrap, // Run run-make last, since these won't pass without make on Windows diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 1df50322a07..78b5de7897d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -904,6 +904,12 @@ host_test!(UiFullDeps { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-ful host_test!(Rustdoc { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" }); host_test!(RustdocUi { path: "src/test/rustdoc-ui", mode: "ui", suite: "rustdoc-ui" }); +host_test!(RustdocJson { + path: "src/test/rustdoc-json", + mode: "rustdoc-json", + suite: "rustdoc-json" +}); + host_test!(Pretty { path: "src/test/pretty", mode: "pretty", suite: "pretty" }); default_test!(RunMake { path: "src/test/run-make", mode: "run-make", suite: "run-make" }); @@ -1001,6 +1007,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the || (mode == "run-make" && suite.ends_with("fulldeps")) || (mode == "ui" && is_rustdoc) || mode == "js-doc-test" + || mode == "rustdoc-json" { cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler)); } diff --git a/src/test/rustdoc/rustdoc-json/Makefile b/src/test/rustdoc-json/Makefile similarity index 100% rename from src/test/rustdoc/rustdoc-json/Makefile rename to src/test/rustdoc-json/Makefile diff --git a/src/test/rustdoc/rustdoc-json/check_missing_items.py b/src/test/rustdoc-json/check_missing_items.py similarity index 95% rename from src/test/rustdoc/rustdoc-json/check_missing_items.py rename to src/test/rustdoc-json/check_missing_items.py index 0004dc8fb14..3a3bf7fa3ed 100644 --- a/src/test/rustdoc/rustdoc-json/check_missing_items.py +++ b/src/test/rustdoc-json/check_missing_items.py @@ -130,12 +130,16 @@ def check_type(ty): work_list |= set(item["inner"]["items"]) - visited elif item["kind"] == "struct": check_generics(item["inner"]["generics"]) - work_list |= (set(item["inner"]["fields"]) | set(item["inner"]["impls"])) - visited + work_list |= ( + set(item["inner"]["fields"]) | set(item["inner"]["impls"]) + ) - visited elif item["kind"] == "struct_field": check_type(item["inner"]) elif item["kind"] == "enum": check_generics(item["inner"]["generics"]) - work_list |= (set(item["inner"]["variants"]) | set(item["inner"]["impls"])) - visited + work_list |= ( + set(item["inner"]["variants"]) | set(item["inner"]["impls"]) + ) - visited elif item["kind"] == "variant": if item["inner"]["variant_kind"] == "tuple": for ty in item["inner"]["variant_inner"]: @@ -162,7 +166,9 @@ def check_type(ty): check_generics(item["inner"]["generics"]) for bound in item["inner"]["bounds"]: check_generic_bound(bound) - work_list |= (set(item["inner"]["items"]) | set(item["inner"]["implementors"])) - visited + work_list |= ( + set(item["inner"]["items"]) | set(item["inner"]["implementors"]) + ) - visited elif item["kind"] == "impl": check_generics(item["inner"]["generics"]) if item["inner"]["trait"]: diff --git a/src/test/rustdoc/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py similarity index 69% rename from src/test/rustdoc/rustdoc-json/compare.py rename to src/test/rustdoc-json/compare.py index 5daf8903e20..afc8066685c 100644 --- a/src/test/rustdoc/rustdoc-json/compare.py +++ b/src/test/rustdoc-json/compare.py @@ -24,7 +24,7 @@ def __init__(self, msg, trace): super().__init__("{}: {}".format(trace, msg)) -def check_subset(expected_main, actual_main): +def check_subset(expected_main, actual_main, base_dir): expected_index = expected_main["index"] expected_paths = expected_main["paths"] actual_index = actual_main["index"] @@ -39,11 +39,24 @@ def _check_subset(expected, actual, trace): "expected type `{}`, got `{}`".format(expected_type, actual_type), trace ) if expected_type in (str, int, bool) and expected != actual: - raise SubsetException("expected `{}`, got: `{}`".format(expected, actual), trace) + if expected_type == str and actual.startswith(base_dir): + if actual.replace(base_dir + "/", "") != expected: + raise SubsetException( + "expected `{}`, got: `{}`".format( + expected, actual.replace(base_dir + "/", "") + ), + trace, + ) + else: + raise SubsetException( + "expected `{}`, got: `{}`".format(expected, actual), trace + ) if expected_type is dict: for key in expected: if key not in actual: - raise SubsetException("Key `{}` not found in output".format(key), trace) + raise SubsetException( + "Key `{}` not found in output".format(key), trace + ) new_trace = copy.deepcopy(trace) new_trace.append(key) _check_subset(expected[key], actual[key], new_trace) @@ -52,7 +65,10 @@ def _check_subset(expected, actual, trace): actual_elements = len(actual) if expected_elements != actual_elements: raise SubsetException( - "Found {} items, expected {}".format(expected_elements, actual_elements), trace + "Found {} items, expected {}".format( + expected_elements, actual_elements + ), + trace, ) for expected, actual in zip(expected, actual): new_trace = copy.deepcopy(trace) @@ -60,8 +76,12 @@ def _check_subset(expected, actual, trace): _check_subset(expected, actual, new_trace) elif expected_type is ID and expected not in already_checked: already_checked.add(expected) - _check_subset(expected_index.get(expected, {}), actual_index.get(actual, {}), trace) - _check_subset(expected_paths.get(expected, {}), actual_paths.get(actual, {}), trace) + _check_subset( + expected_index.get(expected, {}), actual_index.get(actual, {}), trace + ) + _check_subset( + expected_paths.get(expected, {}), actual_paths.get(actual, {}), trace + ) _check_subset(expected_main["root"], actual_main["root"], []) @@ -90,18 +110,22 @@ def rustdoc_object_hook(obj): return obj -def main(expected_fpath, actual_fpath): - print("checking that {} is a logical subset of {}".format(expected_fpath, actual_fpath)) +def main(expected_fpath, actual_fpath, base_dir): + print( + "checking that {} is a logical subset of {}".format( + expected_fpath, actual_fpath + ) + ) with open(expected_fpath) as expected_file: expected_main = json.load(expected_file, object_hook=rustdoc_object_hook) with open(actual_fpath) as actual_file: actual_main = json.load(actual_file, object_hook=rustdoc_object_hook) - check_subset(expected_main, actual_main) + check_subset(expected_main, actual_main, base_dir) print("all checks passed") if __name__ == "__main__": - if len(sys.argv) < 3: - print("Usage: `compare.py expected.json actual.json`") + if len(sys.argv) < 4: + print("Usage: `compare.py expected.json actual.json test-dir`") else: - main(sys.argv[1], sys.argv[2]) + main(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/src/test/rustdoc/rustdoc-json/structs.expected b/src/test/rustdoc-json/structs.expected similarity index 100% rename from src/test/rustdoc/rustdoc-json/structs.expected rename to src/test/rustdoc-json/structs.expected diff --git a/src/test/rustdoc/rustdoc-json/structs.rs b/src/test/rustdoc-json/structs.rs similarity index 100% rename from src/test/rustdoc/rustdoc-json/structs.rs rename to src/test/rustdoc-json/structs.rs diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 24ef98cd784..eba02333c8c 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -17,6 +17,7 @@ pub enum Mode { DebugInfo, Codegen, Rustdoc, + RustdocJson, CodegenUnits, Incremental, RunMake, @@ -48,6 +49,7 @@ impl FromStr for Mode { "debuginfo" => Ok(DebugInfo), "codegen" => Ok(Codegen), "rustdoc" => Ok(Rustdoc), + "rustdoc-json" => Ok(RustdocJson), "codegen-units" => Ok(CodegenUnits), "incremental" => Ok(Incremental), "run-make" => Ok(RunMake), @@ -70,6 +72,7 @@ impl fmt::Display for Mode { DebugInfo => "debuginfo", Codegen => "codegen", Rustdoc => "rustdoc", + RustdocJson => "rustdoc-json", CodegenUnits => "codegen-units", Incremental => "incremental", RunMake => "run-make", diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 32347db5dbb..0541548aefd 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -68,7 +68,7 @@ pub fn parse_config(args: Vec) -> Config { "mode", "which sort of compile tests to run", "compile-fail | run-fail | run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ - codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", + | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", ) .reqopt( "", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1b9f0089dce..88cb8544e47 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2,7 +2,7 @@ use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT}; use crate::common::{output_base_dir, output_base_name, output_testname_unique}; -use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, Ui}; +use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui}; use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{CompileFail, Pretty, RunFail, RunPassValgrind}; @@ -342,6 +342,7 @@ impl<'test> TestCx<'test> { DebugInfo => self.run_debuginfo_test(), Codegen => self.run_codegen_test(), Rustdoc => self.run_rustdoc_test(), + RustdocJson => self.run_rustdoc_json_test(), CodegenUnits => self.run_codegen_units_test(), Incremental => self.run_incremental_test(), RunMake => self.run_rmake_test(), @@ -1564,7 +1565,7 @@ impl<'test> TestCx<'test> { self.compose_and_run_compiler(rustc, None) } - fn document(&self, out_dir: &Path) -> ProcRes { + fn document(&self, out_dir: &Path, json: bool) -> ProcRes { if self.props.build_aux_docs { for rel_ab in &self.props.aux_builds { let aux_testpaths = self.compute_aux_test_paths(rel_ab); @@ -1578,7 +1579,7 @@ impl<'test> TestCx<'test> { }; // Create the directory for the stdout/stderr files. create_dir_all(aux_cx.output_base_dir()).unwrap(); - let auxres = aux_cx.document(out_dir); + let auxres = aux_cx.document(out_dir, json); if !auxres.status.success() { return auxres; } @@ -1600,6 +1601,10 @@ impl<'test> TestCx<'test> { .arg(&self.testpaths.file) .args(&self.props.compile_flags); + if json { + rustdoc.arg("--output-format").arg("json"); + } + if let Some(ref linker) = self.config.linker { rustdoc.arg(format!("-Clinker={}", linker)); } @@ -1887,7 +1892,9 @@ impl<'test> TestCx<'test> { } fn is_rustdoc(&self) -> bool { - self.config.src_base.ends_with("rustdoc-ui") || self.config.src_base.ends_with("rustdoc-js") + self.config.src_base.ends_with("rustdoc-ui") + || self.config.src_base.ends_with("rustdoc-js") + || self.config.src_base.ends_with("rustdoc-json") } fn make_compile_args( @@ -1968,8 +1975,8 @@ impl<'test> TestCx<'test> { rustc.arg(dir_opt); } - RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RunMake - | CodegenUnits | JsDocTest | Assembly => { + RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson + | RunMake | CodegenUnits | JsDocTest | Assembly => { // do not use JSON output } } @@ -2329,7 +2336,7 @@ impl<'test> TestCx<'test> { let _ = fs::remove_dir_all(&out_dir); create_dir_all(&out_dir).unwrap(); - let proc_res = self.document(&out_dir); + let proc_res = self.document(&out_dir, false); if !proc_res.status.success() { self.fatal_proc_rec("rustdoc failed!", &proc_res); } @@ -2385,7 +2392,7 @@ impl<'test> TestCx<'test> { rustc.arg("-L").arg(&new_rustdoc.aux_output_dir_name()); new_rustdoc.build_all_auxiliary(&mut rustc); - let proc_res = new_rustdoc.document(&compare_dir); + let proc_res = new_rustdoc.document(&compare_dir, false); if !proc_res.status.success() { proc_res.fatal(Some("failed to run nightly rustdoc"), || ()); } @@ -2466,6 +2473,48 @@ impl<'test> TestCx<'test> { eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } + fn run_rustdoc_json_test(&self) { + //FIXME: Add bless option. + + assert!(self.revision.is_none(), "revisions not relevant here"); + + let out_dir = self.output_base_dir(); + let _ = fs::remove_dir_all(&out_dir); + create_dir_all(&out_dir).unwrap(); + + let proc_res = self.document(&out_dir, true); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc failed!", &proc_res); + } + + let root = self.config.find_rust_src_root().unwrap(); + let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); + json_out.set_extension("json"); + let res = self.cmd2procres( + Command::new(&self.config.docck_python) + .arg(root.join("src/test/rustdoc-json/check_missing_items.py")) + .arg(&json_out), + ); + + if !res.status.success() { + self.fatal_proc_rec("check_missing_items failed!", &res); + } + + let mut expected = self.testpaths.file.clone(); + expected.set_extension("expected"); + let res = self.cmd2procres( + Command::new(&self.config.docck_python) + .arg(root.join("src/test/rustdoc-json/compare.py")) + .arg(&expected) + .arg(&json_out) + .arg(&expected.parent().unwrap()), + ); + + if !res.status.success() { + self.fatal_proc_rec("compare failed!", &res); + } + } + fn get_lines>( &self, path: &P, @@ -3003,7 +3052,7 @@ impl<'test> TestCx<'test> { if let Some(nodejs) = &self.config.nodejs { let out_dir = self.output_base_dir(); - self.document(&out_dir); + self.document(&out_dir, false); let root = self.config.find_rust_src_root().unwrap(); let file_stem = From 40b5470b0db1997fe28bd774171b4f958fa7d240 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 30 Nov 2020 20:24:48 +0000 Subject: [PATCH 133/274] Address review comments. Go back to CRATE_DEF_INDEX Minor niceness improvements Don't output hidden items Remove striped items from fields Add $TEST_BASE_DIR Small catch --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/json/conversions.rs | 76 +++++++++++++------------- src/librustdoc/json/mod.rs | 18 +++--- src/librustdoc/json/types.rs | 3 - src/librustdoc/lib.rs | 1 + src/test/rustdoc-json/Makefile | 6 -- src/test/rustdoc-json/compare.py | 21 +++---- src/test/rustdoc-json/structs.expected | 42 +++++--------- src/tools/compiletest/src/runtest.rs | 14 ++--- 9 files changed, 80 insertions(+), 103 deletions(-) delete mode 100644 src/test/rustdoc-json/Makefile diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9d42705da82..d294d8f02a8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2281,7 +2281,7 @@ impl Clean> for doctree::Import<'_> { name: None, attrs: self.attrs.clean(cx), source: self.span.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), + def_id: DefId::local(CRATE_DEF_INDEX), visibility: self.vis.clean(cx), stability: None, const_stability: None, diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 80192623d54..4d57b337879 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -12,43 +12,44 @@ use crate::doctree; use crate::formats::item_type::ItemType; use crate::json::types::*; -impl From for Item { +impl From for Option { fn from(item: clean::Item) -> Self { let item_type = ItemType::from(&item); let clean::Item { source, name, attrs, - kind: inner, + kind, visibility, def_id, stability: _, deprecation, } = item; - Item { - id: def_id.into(), - crate_id: def_id.krate.as_u32(), - name, - stripped: match inner { - clean::StrippedItem(_) => true, - _ => false, - }, - source: source.into(), - visibility: visibility.into(), - docs: attrs.collapsed_doc_value().unwrap_or_default(), - links: attrs - .links - .into_iter() - .filter_map(|clean::ItemLink { link, did, .. }| did.map(|did| (link, did.into()))) - .collect(), - attrs: attrs - .other_attrs - .iter() - .map(rustc_ast_pretty::pprust::attribute_to_string) - .collect(), - deprecation: deprecation.map(Into::into), - kind: item_type.into(), - inner: inner.into(), + match kind { + clean::StrippedItem(_) => None, + _ => Some(Item { + id: def_id.into(), + crate_id: def_id.krate.as_u32(), + name, + source: source.into(), + visibility: visibility.into(), + docs: attrs.collapsed_doc_value().unwrap_or_default(), + links: attrs + .links + .into_iter() + .filter_map(|clean::ItemLink { link, did, .. }| { + did.map(|did| (link, did.into())) + }) + .collect(), + attrs: attrs + .other_attrs + .iter() + .map(rustc_ast_pretty::pprust::attribute_to_string) + .collect(), + deprecation: deprecation.map(Into::into), + kind: item_type.into(), + inner: kind.into(), + }), } } } @@ -194,10 +195,7 @@ impl From for ItemEnum { impl From for Module { fn from(module: clean::Module) -> Self { - Module { - is_crate: module.is_crate, - items: module.items.into_iter().map(|i| i.def_id.into()).collect(), - } + Module { is_crate: module.is_crate, items: ids(module.items) } } } @@ -208,7 +206,7 @@ impl From for Struct { struct_type: struct_type.into(), generics: generics.into(), fields_stripped, - fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + fields: ids(fields), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -221,7 +219,7 @@ impl From for Struct { struct_type: struct_type.into(), generics: generics.into(), fields_stripped, - fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + fields: ids(fields), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -407,7 +405,7 @@ impl From for Trait { Trait { is_auto, is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, - items: items.into_iter().map(|i| i.def_id.into()).collect(), + items: ids(items), generics: generics.into(), bounds: bounds.into_iter().map(Into::into).collect(), implementors: Vec::new(), // Added in JsonRenderer::item @@ -434,7 +432,7 @@ impl From for Impl { provided_trait_methods: provided_trait_methods.into_iter().collect(), trait_: trait_.map(Into::into), for_: for_.into(), - items: items.into_iter().map(|i| i.def_id.into()).collect(), + items: ids(items), negative: polarity == Some(clean::ImplPolarity::Negative), synthetic, blanket_impl: blanket_impl.map(Into::into), @@ -460,7 +458,7 @@ impl From for Enum { Enum { generics: generics.into(), variants_stripped, - variants: variants.into_iter().map(|i| i.def_id.into()).collect(), + variants: ids(variants), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -473,7 +471,7 @@ impl From for Struct { struct_type: struct_type.into(), generics: Default::default(), fields_stripped, - fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + fields: ids(fields), impls: Vec::new(), } } @@ -485,7 +483,7 @@ impl From for Variant { match variant.kind { CLike => Variant::Plain, Tuple(t) => Variant::Tuple(t.into_iter().map(Into::into).collect()), - Struct(s) => Variant::Struct(s.fields.into_iter().map(|i| i.def_id.into()).collect()), + Struct(s) => Variant::Struct(ids(s.fields)), } } } @@ -594,3 +592,7 @@ impl From for ItemKind { } } } + +fn ids(items: impl IntoIterator) -> Vec { + items.into_iter().filter(|x| !x.is_stripped()).map(|i| i.def_id.into()).collect() +} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 20a8de144ad..c080ad21c0f 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -99,7 +99,6 @@ impl JsonRenderer { .0 .last() .map(Clone::clone), - stripped: false, visibility: types::Visibility::Public, kind: types::ItemKind::Trait, inner: types::ItemEnum::TraitItem(trait_item.clone().into()), @@ -144,16 +143,17 @@ impl FormatRenderer for JsonRenderer { item.kind.inner_items().for_each(|i| self.item(i.clone(), cache).unwrap()); let id = item.def_id; - let mut new_item: types::Item = item.into(); - if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner { - t.implementors = self.get_trait_implementors(id, cache) - } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner { - s.impls = self.get_impls(id, cache) - } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner { - e.impls = self.get_impls(id, cache) + if let Some(mut new_item) = item.into(): Option { + if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner { + t.implementors = self.get_trait_implementors(id, cache) + } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner { + s.impls = self.get_impls(id, cache) + } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner { + e.impls = self.get_impls(id, cache) + } + self.index.borrow_mut().insert(id.into(), new_item); } - self.index.borrow_mut().insert(id.into(), new_item); Ok(()) } diff --git a/src/librustdoc/json/types.rs b/src/librustdoc/json/types.rs index 62705affafc..10bf2a2acc5 100644 --- a/src/librustdoc/json/types.rs +++ b/src/librustdoc/json/types.rs @@ -62,9 +62,6 @@ pub struct Item { pub crate_id: u32, /// Some items such as impls don't have names. pub name: Option, - /// Whether this item is meant to be omitted from the generated documentation due to `#doc(hidden)`, - /// because it is private, or because it was inlined. - pub stripped: bool, /// The source location of this item (absent if it came from a macro expansion or inline /// assembly). pub source: Option, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 751f2301053..80a9c3811cf 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -14,6 +14,7 @@ #![feature(crate_visibility_modifier)] #![feature(never_type)] #![feature(once_cell)] +#![feature(type_ascription)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/test/rustdoc-json/Makefile b/src/test/rustdoc-json/Makefile deleted file mode 100644 index ad517ae95eb..00000000000 --- a/src/test/rustdoc-json/Makefile +++ /dev/null @@ -1,6 +0,0 @@ --include ../tools.mk - -tests: *.rs - $(RUSTDOC) $< -o $(TMPDIR) --output-format json - $(PYTHON) check_missing_items.py $(TMPDIR)/$(basename $<).json - $(PYTHON) compare.py $(basename $<).expected $(TMPDIR)/$(basename $<).json diff --git a/src/test/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py index afc8066685c..422e48ea39a 100644 --- a/src/test/rustdoc-json/compare.py +++ b/src/test/rustdoc-json/compare.py @@ -34,23 +34,18 @@ def check_subset(expected_main, actual_main, base_dir): def _check_subset(expected, actual, trace): expected_type = type(expected) actual_type = type(actual) + + if actual_type is str: + actual = actual.replace(base_dir, "$TEST_BASE_DIR") + if expected_type is not actual_type: raise SubsetException( "expected type `{}`, got `{}`".format(expected_type, actual_type), trace ) - if expected_type in (str, int, bool) and expected != actual: - if expected_type == str and actual.startswith(base_dir): - if actual.replace(base_dir + "/", "") != expected: - raise SubsetException( - "expected `{}`, got: `{}`".format( - expected, actual.replace(base_dir + "/", "") - ), - trace, - ) - else: - raise SubsetException( - "expected `{}`, got: `{}`".format(expected, actual), trace - ) + + + if expected_type in (int, bool, str) and expected != actual: + raise SubsetException("expected `{}`, got: `{}`".format(expected, actual), trace) if expected_type is dict: for key in expected: if key not in actual: diff --git a/src/test/rustdoc-json/structs.expected b/src/test/rustdoc-json/structs.expected index 45b23534bc7..799829de3fd 100644 --- a/src/test/rustdoc-json/structs.expected +++ b/src/test/rustdoc-json/structs.expected @@ -7,7 +7,7 @@ "crate_id": 0, "name": "Unit", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 7, 0 @@ -37,7 +37,7 @@ "crate_id": 0, "name": "1", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 5, 22 @@ -72,7 +72,7 @@ "crate_id": 0, "name": "stuff", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 15, 4 @@ -114,7 +114,7 @@ "crate_id": 0, "name": "WithPrimitives", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 9, 0 @@ -141,18 +141,14 @@ ], "where_predicates": [] }, - "fields_stripped": true, - "fields": [ - "0:13", - "0:14" - ] + "fields_stripped": true } }, "0:14": { "crate_id": 0, "name": "s", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 11, 4 @@ -184,7 +180,7 @@ "crate_id": 0, "name": "things", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 16, 4 @@ -232,7 +228,7 @@ "crate_id": 0, "name": "WithGenerics", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 14, 0 @@ -273,18 +269,14 @@ ], "where_predicates": [] }, - "fields_stripped": true, - "fields": [ - "0:18", - "0:19" - ] + "fields_stripped": true } }, "0:0": { "crate_id": 0, "name": "structs", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 1, 0 @@ -315,7 +307,7 @@ "crate_id": 0, "name": "num", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 10, 4 @@ -340,7 +332,7 @@ "crate_id": 0, "name": "Tuple", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 5, 0 @@ -362,18 +354,14 @@ "params": [], "where_predicates": [] }, - "fields_stripped": true, - "fields": [ - "0:7", - "0:8" - ] + "fields_stripped": true } }, "0:4": { "crate_id": 0, "name": "PlainEmpty", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 3, 0 @@ -403,7 +391,7 @@ "crate_id": 0, "name": "0", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 5, 17 diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 88cb8544e47..e9089b4b15b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1565,7 +1565,7 @@ impl<'test> TestCx<'test> { self.compose_and_run_compiler(rustc, None) } - fn document(&self, out_dir: &Path, json: bool) -> ProcRes { + fn document(&self, out_dir: &Path) -> ProcRes { if self.props.build_aux_docs { for rel_ab in &self.props.aux_builds { let aux_testpaths = self.compute_aux_test_paths(rel_ab); @@ -1579,7 +1579,7 @@ impl<'test> TestCx<'test> { }; // Create the directory for the stdout/stderr files. create_dir_all(aux_cx.output_base_dir()).unwrap(); - let auxres = aux_cx.document(out_dir, json); + let auxres = aux_cx.document(out_dir); if !auxres.status.success() { return auxres; } @@ -1601,7 +1601,7 @@ impl<'test> TestCx<'test> { .arg(&self.testpaths.file) .args(&self.props.compile_flags); - if json { + if self.config.mode == RustdocJson { rustdoc.arg("--output-format").arg("json"); } @@ -2336,7 +2336,7 @@ impl<'test> TestCx<'test> { let _ = fs::remove_dir_all(&out_dir); create_dir_all(&out_dir).unwrap(); - let proc_res = self.document(&out_dir, false); + let proc_res = self.document(&out_dir); if !proc_res.status.success() { self.fatal_proc_rec("rustdoc failed!", &proc_res); } @@ -2392,7 +2392,7 @@ impl<'test> TestCx<'test> { rustc.arg("-L").arg(&new_rustdoc.aux_output_dir_name()); new_rustdoc.build_all_auxiliary(&mut rustc); - let proc_res = new_rustdoc.document(&compare_dir, false); + let proc_res = new_rustdoc.document(&compare_dir); if !proc_res.status.success() { proc_res.fatal(Some("failed to run nightly rustdoc"), || ()); } @@ -2482,7 +2482,7 @@ impl<'test> TestCx<'test> { let _ = fs::remove_dir_all(&out_dir); create_dir_all(&out_dir).unwrap(); - let proc_res = self.document(&out_dir, true); + let proc_res = self.document(&out_dir); if !proc_res.status.success() { self.fatal_proc_rec("rustdoc failed!", &proc_res); } @@ -3052,7 +3052,7 @@ impl<'test> TestCx<'test> { if let Some(nodejs) = &self.config.nodejs { let out_dir = self.output_base_dir(); - self.document(&out_dir, false); + self.document(&out_dir); let root = self.config.find_rust_src_root().unwrap(); let file_stem = From 601820028c01b80b0a5368e6dcd019ef34711943 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 1 Dec 2020 18:43:24 +0000 Subject: [PATCH 134/274] Discard `const_stability` --- src/librustdoc/json/conversions.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 4d57b337879..afb8dfa6766 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -23,6 +23,7 @@ impl From for Option { visibility, def_id, stability: _, + const_stability: _, deprecation, } = item; match kind { From b8defab08dfcac3ecc63247465fdcddd403c44b8 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 29 Oct 2020 22:08:54 +0100 Subject: [PATCH 135/274] rustdoc: move lazy norm tests into const-generics --- .../lazy_normalization_consts/const-equate-pred.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/rustdoc/{ => const-generics}/lazy_normalization_consts/const-equate-pred.rs (100%) diff --git a/src/test/rustdoc/lazy_normalization_consts/const-equate-pred.rs b/src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs similarity index 100% rename from src/test/rustdoc/lazy_normalization_consts/const-equate-pred.rs rename to src/test/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs From 4eb76fcc8eb37e69962d27d990ba693fa612c17a Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Tue, 1 Dec 2020 23:09:03 +0100 Subject: [PATCH 136/274] Use more std:: instead of core:: in docs for consistency, add more intra doc links --- library/core/src/fmt/mod.rs | 2 +- library/core/src/future/pending.rs | 2 +- library/core/src/future/poll_fn.rs | 6 +++--- library/core/src/future/ready.rs | 2 +- library/core/src/panic.rs | 2 +- library/core/src/task/ready.rs | 19 +++++++++++-------- library/std/src/primitive_docs.rs | 4 ++-- 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 4ed62a620c4..0c65c1c9eb7 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -403,7 +403,7 @@ impl<'a> Arguments<'a> { /// ```rust /// #![feature(fmt_as_str)] /// - /// use core::fmt::Arguments; + /// use std::fmt::Arguments; /// /// fn write_str(_: &str) { /* ... */ } /// diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index ab162638a1c..560dd25ecff 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -21,7 +21,7 @@ pub struct Pending { /// # Examples /// /// ```no_run -/// use core::future; +/// use std::future; /// /// # async fn run() { /// let future = future::pending(); diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index af63e1bb097..9ae118e29f1 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -3,7 +3,7 @@ use crate::future::Future; use crate::pin::Pin; use crate::task::{Context, Poll}; -/// Creates a future that wraps a function returning `Poll`. +/// Creates a future that wraps a function returning [`Poll`]. /// /// Polling the future delegates to the wrapped function. /// @@ -13,7 +13,7 @@ use crate::task::{Context, Poll}; /// #![feature(future_poll_fn)] /// # async fn run() { /// use core::future::poll_fn; -/// use core::task::{Context, Poll}; +/// use std::task::{Context, Poll}; /// /// fn read_line(_cx: &mut Context<'_>) -> Poll { /// Poll::Ready("Hello, World!".into()) @@ -31,7 +31,7 @@ where PollFn { f } } -/// A Future that wraps a function returning `Poll`. +/// A Future that wraps a function returning [`Poll`]. /// /// This `struct` is created by [`poll_fn()`]. See its /// documentation for more. diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index e98f5c570bf..b0c7fbb1d7a 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -33,7 +33,7 @@ impl Future for Ready { /// # Examples /// /// ``` -/// use core::future; +/// use std::future; /// /// # async fn run() { /// let a = future::ready(1); diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 34a974b8271..03bb849509a 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -189,7 +189,7 @@ impl<'a> Location<'a> { /// # Examples /// /// ``` - /// use core::panic::Location; + /// use std::panic::Location; /// /// /// Returns the [`Location`] at which it is called. /// #[track_caller] diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index e221aaf3fd6..cbf69900015 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -1,15 +1,18 @@ -/// Extracts the successful type of a `Poll`. +/// Extracts the successful type of a [`Poll`]. /// -/// This macro bakes in propagation of `Pending` signals by returning early. +/// This macro bakes in propagation of [`Pending`] signals by returning early. +/// +/// [`Poll`]: crate::task::Poll +/// [`Pending`]: crate::task::Poll::Pending /// /// # Examples /// /// ``` /// #![feature(ready_macro)] /// -/// use core::task::{ready, Context, Poll}; -/// use core::future::{self, Future}; -/// use core::pin::Pin; +/// use std::task::{ready, Context, Poll}; +/// use std::future::{self, Future}; +/// use std::pin::Pin; /// /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { /// let mut fut = future::ready(42); @@ -28,9 +31,9 @@ /// ``` /// # #![feature(ready_macro)] /// # -/// # use core::task::{Context, Poll}; -/// # use core::future::{self, Future}; -/// # use core::pin::Pin; +/// # use std::task::{Context, Poll}; +/// # use std::future::{self, Future}; +/// # use std::pin::Pin; /// # /// # pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { /// # let mut fut = future::ready(42); diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 83a282c8cd6..55171ef2292 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -198,7 +198,7 @@ mod prim_bool {} /// words, they can't return `!` from every code path. As an example, this code doesn't compile: /// /// ```compile_fail -/// use core::ops::Add; +/// use std::ops::Add; /// /// fn foo() -> impl Add { /// unimplemented!() @@ -208,7 +208,7 @@ mod prim_bool {} /// But this code does: /// /// ``` -/// use core::ops::Add; +/// use std::ops::Add; /// /// fn foo() -> impl Add { /// if true { From 8bd80e25f0bdb7a3282fecee148afed966067f1e Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 02:32:10 +0100 Subject: [PATCH 137/274] Make some of MaybeUninit's methods const --- .../rustc_mir/src/interpret/intrinsics.rs | 24 +++++++++++++++++++ library/core/src/intrinsics.rs | 1 + library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 7 ++++-- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index f666a89ca56..c751f4f7eb6 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -407,6 +407,30 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::transmute => { self.copy_op_transmute(args[0], dest)?; } + sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { + let ty = instance.substs.type_at(0); + let layout = self.layout_of(ty)?; + + if layout.abi.is_uninhabited() { + throw_ub_format!("attempted to instantiate uninhabited type `{}`", ty); + } + if intrinsic_name == sym::assert_zero_valid + && !layout.might_permit_raw_init(self, /*zero:*/ true).unwrap() + { + throw_ub_format!( + "attempted to zero-initialize type `{}`, which is invalid", + ty + ); + } + if intrinsic_name == sym::assert_uninit_valid + && !layout.might_permit_raw_init(self, /*zero:*/ false).unwrap() + { + throw_ub_format!( + "attempted to leave type `{}` uninitialized, which is invalid", + ty + ); + } + } sym::simd_insert => { let index = u64::from(self.read_scalar(args[1])?.to_u32()?); let elem = args[2]; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 1a588b314c4..c0fcfb3a139 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -815,6 +815,7 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] pub fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e3b004be39a..5d56a22bfa5 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -100,6 +100,7 @@ #![feature(const_type_name)] #![feature(const_likely)] #![feature(const_unreachable_unchecked)] +#![feature(const_maybe_assume_init)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 1924720b949..cb32c909717 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -314,8 +314,10 @@ impl MaybeUninit { /// let data = read(&mut buf); /// ``` #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_allow_const_fn_unstable(const_maybe_assume_init)] #[inline(always)] - pub fn uninit_array() -> [Self; LEN] { + pub const fn uninit_array() -> [Self; LEN] { // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. unsafe { MaybeUninit::<[MaybeUninit; LEN]>::uninit().assume_init() } } @@ -503,9 +505,10 @@ impl MaybeUninit { /// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️ /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] #[rustc_diagnostic_item = "assume_init"] - pub unsafe fn assume_init(self) -> T { + pub const unsafe fn assume_init(self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { From 91772c35c83f369283838ab049712a5f746e11ef Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 03:01:18 +0100 Subject: [PATCH 138/274] Even more const --- library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5d56a22bfa5..a901375a958 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -92,6 +92,7 @@ #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_raw_ptr_comparison)] +#![feature(const_raw_ptr_deref)] #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] #![feature(const_size_of_val)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index cb32c909717..6251355b909 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -813,8 +813,9 @@ impl MaybeUninit { /// /// [`assume_init_ref`]: MaybeUninit::assume_init_ref #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { + pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { // SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that // `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`. // The pointer obtained is valid since it refers to memory owned by `slice` which is a @@ -834,8 +835,9 @@ impl MaybeUninit { /// /// [`assume_init_mut`]: MaybeUninit::assume_init_mut #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { + pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a // mutable reference which is also guaranteed to be valid for writes. unsafe { &mut *(slice as *mut [Self] as *mut [T]) } @@ -843,15 +845,17 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } } From cdcce115043a19b2bbc154e56b59fa2f5017bbbc Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 2 Dec 2020 11:39:42 +0900 Subject: [PATCH 139/274] Tweak diagnostics on shadowing lifetimes/labels --- compiler/rustc_resolve/src/late/lifetimes.rs | 2 +- src/test/ui/error-codes/E0496.stderr | 2 +- .../generic-associated-types/shadowing.stderr | 4 +- .../ui/hygiene/hygienic-labels-in-let.stderr | 56 +++++++++---------- src/test/ui/hygiene/hygienic-labels.stderr | 56 +++++++++---------- src/test/ui/in-band-lifetimes/shadow.stderr | 4 +- src/test/ui/lint/unused_labels.stderr | 2 +- .../loops-reject-duplicate-labels-2.stderr | 16 +++--- .../loops-reject-duplicate-labels.stderr | 16 +++--- ...s-reject-labels-shadowing-lifetimes.stderr | 24 ++++---- ...ops-reject-lifetime-shadowing-label.stderr | 2 +- .../macro-lifetime-used-with-labels.stderr | 2 +- src/test/ui/shadowed/shadowed-lifetime.stderr | 4 +- 13 files changed, 95 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 91edbebc05f..69f28045bb5 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1098,7 +1098,7 @@ fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shado ) }; err.span_label(orig.span, "first declared here"); - err.span_label(shadower.span, format!("lifetime {} already in scope", name)); + err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name)); err.emit(); } diff --git a/src/test/ui/error-codes/E0496.stderr b/src/test/ui/error-codes/E0496.stderr index b0294eef04e..80ca2b1fbdb 100644 --- a/src/test/ui/error-codes/E0496.stderr +++ b/src/test/ui/error-codes/E0496.stderr @@ -4,7 +4,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | impl<'a> Foo<'a> { | -- first declared here LL | fn f<'a>(x: &'a i32) { - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index d51c29080a0..95cebbb8681 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -20,7 +20,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | trait Shadow<'a> { | -- first declared here LL | type Bar<'a>; - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope --> $DIR/shadowing.rs:14:14 @@ -28,7 +28,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | impl<'a> NoShadow<'a> for &'a u32 { | -- first declared here LL | type Bar<'a> = i32; - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error: aborting due to 4 previous errors diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.stderr b/src/test/ui/hygiene/hygienic-labels-in-let.stderr index 3ff45a8a566..9e7811b8072 100644 --- a/src/test/ui/hygiene/hygienic-labels-in-let.stderr +++ b/src/test/ui/hygiene/hygienic-labels-in-let.stderr @@ -2,7 +2,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:16:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -19,7 +19,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:64:9 @@ -28,13 +28,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:16:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -51,7 +51,7 @@ LL | 'x: loop { $e } | ^^ | | | first declared here - | lifetime 'x already in scope + | label `'x` already in scope ... LL | loop_x!(break 'x); | ------------------ in this macro invocation @@ -62,7 +62,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:16:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -79,7 +79,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:76:9 @@ -88,7 +88,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:76:9 @@ -97,7 +97,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:76:9 @@ -106,13 +106,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:27:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -129,7 +129,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_true!(break 'x); | ---------------------- in this macro invocation @@ -140,7 +140,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:27:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -157,7 +157,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_true!(break 'x); | ---------------------- in this macro invocation @@ -168,7 +168,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:27:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -185,7 +185,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -194,7 +194,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -203,7 +203,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -212,7 +212,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -221,7 +221,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:90:9 @@ -230,13 +230,13 @@ LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -253,7 +253,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -264,7 +264,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -281,7 +281,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -292,7 +292,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -309,7 +309,7 @@ LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -320,7 +320,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels-in-let.rs:39:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here diff --git a/src/test/ui/hygiene/hygienic-labels.stderr b/src/test/ui/hygiene/hygienic-labels.stderr index 25098c25c82..275478d292d 100644 --- a/src/test/ui/hygiene/hygienic-labels.stderr +++ b/src/test/ui/hygiene/hygienic-labels.stderr @@ -2,7 +2,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:13:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -19,7 +19,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: loop { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:54:5 @@ -28,13 +28,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: loop { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:13:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -51,7 +51,7 @@ LL | 'x: loop { $e } | ^^ | | | first declared here - | lifetime 'x already in scope + | label `'x` already in scope ... LL | loop_x!(break 'x); | ------------------ in this macro invocation @@ -62,7 +62,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:13:9 | LL | 'x: loop { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -79,7 +79,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:63:5 @@ -88,7 +88,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:63:5 @@ -97,7 +97,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:63:5 @@ -106,13 +106,13 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:38:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -129,7 +129,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_x!(break 'x); | ------------------- in this macro invocation @@ -140,7 +140,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:38:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -157,7 +157,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | while_x!(break 'x); | ------------------- in this macro invocation @@ -168,7 +168,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:38:9 | LL | 'x: while 1 + 1 == 2 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: while 1 + 1 == 2 { | -- first declared here @@ -185,7 +185,7 @@ LL | 'x: for _ in 0..1 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -194,7 +194,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -203,7 +203,7 @@ LL | 'x: loop { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -212,7 +212,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -221,7 +221,7 @@ LL | 'x: while 1 + 1 == 2 { | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:73:5 @@ -230,13 +230,13 @@ LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here @@ -253,7 +253,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -264,7 +264,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: loop { | -- first declared here @@ -281,7 +281,7 @@ LL | 'x: loop { $e } | -- first declared here ... LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | run_once!(continue 'x); | ----------------------- in this macro invocation @@ -292,7 +292,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: while 1 + 1 == 2 { | -- first declared here @@ -306,7 +306,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: while 1 + 1 == 2 { $e } | -- first declared here @@ -320,7 +320,7 @@ warning: label name `'x` shadows a label name that is already in scope --> $DIR/hygienic-labels.rs:24:9 | LL | 'x: for _ in 0..1 { $e } - | ^^ lifetime 'x already in scope + | ^^ label `'x` already in scope ... LL | 'x: for _ in 0..1 { | -- first declared here diff --git a/src/test/ui/in-band-lifetimes/shadow.stderr b/src/test/ui/in-band-lifetimes/shadow.stderr index a0a15d3aa88..c7a6f3ac3ad 100644 --- a/src/test/ui/in-band-lifetimes/shadow.stderr +++ b/src/test/ui/in-band-lifetimes/shadow.stderr @@ -4,7 +4,7 @@ error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scop LL | impl Foo<&'s u8> { | -- first declared here LL | fn bar<'s>(&self, x: &'s u8) {} - | ^^ lifetime 's already in scope + | ^^ lifetime `'s` already in scope error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scope --> $DIR/shadow.rs:8:19 @@ -13,7 +13,7 @@ LL | impl Foo<&'s u8> { | -- first declared here LL | fn bar<'s>(&self, x: &'s u8) {} LL | fn baz(x: for<'s> fn(&'s u32)) {} - | ^^ lifetime 's already in scope + | ^^ lifetime `'s` already in scope error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/unused_labels.stderr b/src/test/ui/lint/unused_labels.stderr index 443faebd0f8..4bb1a437d24 100644 --- a/src/test/ui/lint/unused_labels.stderr +++ b/src/test/ui/lint/unused_labels.stderr @@ -59,7 +59,7 @@ LL | 'many_used_shadowed: for _ in 0..10 { | ------------------- first declared here LL | LL | 'many_used_shadowed: for _ in 0..10 { - | ^^^^^^^^^^^^^^^^^^^ lifetime 'many_used_shadowed already in scope + | ^^^^^^^^^^^^^^^^^^^ label `'many_used_shadowed` already in scope warning: 9 warnings emitted diff --git a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr index 3c8e2938d41..724c36e5203 100644 --- a/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr +++ b/src/test/ui/loops/loops-reject-duplicate-labels-2.stderr @@ -4,7 +4,7 @@ warning: label name `'fl` shadows a label name that is already in scope LL | { 'fl: for _ in 0..10 { break; } } | --- first declared here LL | { 'fl: loop { break; } } - | ^^^ lifetime 'fl already in scope + | ^^^ label `'fl` already in scope warning: label name `'lf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:16:7 @@ -12,7 +12,7 @@ warning: label name `'lf` shadows a label name that is already in scope LL | { 'lf: loop { break; } } | --- first declared here LL | { 'lf: for _ in 0..10 { break; } } - | ^^^ lifetime 'lf already in scope + | ^^^ label `'lf` already in scope warning: label name `'wl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:18:7 @@ -20,7 +20,7 @@ warning: label name `'wl` shadows a label name that is already in scope LL | { 'wl: while 2 > 1 { break; } } | --- first declared here LL | { 'wl: loop { break; } } - | ^^^ lifetime 'wl already in scope + | ^^^ label `'wl` already in scope warning: label name `'lw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:20:7 @@ -28,7 +28,7 @@ warning: label name `'lw` shadows a label name that is already in scope LL | { 'lw: loop { break; } } | --- first declared here LL | { 'lw: while 2 > 1 { break; } } - | ^^^ lifetime 'lw already in scope + | ^^^ label `'lw` already in scope warning: label name `'fw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:22:7 @@ -36,7 +36,7 @@ warning: label name `'fw` shadows a label name that is already in scope LL | { 'fw: for _ in 0..10 { break; } } | --- first declared here LL | { 'fw: while 2 > 1 { break; } } - | ^^^ lifetime 'fw already in scope + | ^^^ label `'fw` already in scope warning: label name `'wf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:24:7 @@ -44,7 +44,7 @@ warning: label name `'wf` shadows a label name that is already in scope LL | { 'wf: while 2 > 1 { break; } } | --- first declared here LL | { 'wf: for _ in 0..10 { break; } } - | ^^^ lifetime 'wf already in scope + | ^^^ label `'wf` already in scope warning: label name `'tl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:26:7 @@ -52,7 +52,7 @@ warning: label name `'tl` shadows a label name that is already in scope LL | { 'tl: while let Some(_) = None:: { break; } } | --- first declared here LL | { 'tl: loop { break; } } - | ^^^ lifetime 'tl already in scope + | ^^^ label `'tl` already in scope warning: label name `'lt` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels-2.rs:28:7 @@ -60,7 +60,7 @@ warning: label name `'lt` shadows a label name that is already in scope LL | { 'lt: loop { break; } } | --- first declared here LL | { 'lt: while let Some(_) = None:: { break; } } - | ^^^ lifetime 'lt already in scope + | ^^^ label `'lt` already in scope warning: 8 warnings emitted diff --git a/src/test/ui/loops/loops-reject-duplicate-labels.stderr b/src/test/ui/loops/loops-reject-duplicate-labels.stderr index 5a3e5158fed..2d112812017 100644 --- a/src/test/ui/loops/loops-reject-duplicate-labels.stderr +++ b/src/test/ui/loops/loops-reject-duplicate-labels.stderr @@ -4,7 +4,7 @@ warning: label name `'fl` shadows a label name that is already in scope LL | 'fl: for _ in 0..10 { break; } | --- first declared here LL | 'fl: loop { break; } - | ^^^ lifetime 'fl already in scope + | ^^^ label `'fl` already in scope warning: label name `'lf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:14:5 @@ -12,7 +12,7 @@ warning: label name `'lf` shadows a label name that is already in scope LL | 'lf: loop { break; } | --- first declared here LL | 'lf: for _ in 0..10 { break; } - | ^^^ lifetime 'lf already in scope + | ^^^ label `'lf` already in scope warning: label name `'wl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:16:5 @@ -20,7 +20,7 @@ warning: label name `'wl` shadows a label name that is already in scope LL | 'wl: while 2 > 1 { break; } | --- first declared here LL | 'wl: loop { break; } - | ^^^ lifetime 'wl already in scope + | ^^^ label `'wl` already in scope warning: label name `'lw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:18:5 @@ -28,7 +28,7 @@ warning: label name `'lw` shadows a label name that is already in scope LL | 'lw: loop { break; } | --- first declared here LL | 'lw: while 2 > 1 { break; } - | ^^^ lifetime 'lw already in scope + | ^^^ label `'lw` already in scope warning: label name `'fw` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:20:5 @@ -36,7 +36,7 @@ warning: label name `'fw` shadows a label name that is already in scope LL | 'fw: for _ in 0..10 { break; } | --- first declared here LL | 'fw: while 2 > 1 { break; } - | ^^^ lifetime 'fw already in scope + | ^^^ label `'fw` already in scope warning: label name `'wf` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:22:5 @@ -44,7 +44,7 @@ warning: label name `'wf` shadows a label name that is already in scope LL | 'wf: while 2 > 1 { break; } | --- first declared here LL | 'wf: for _ in 0..10 { break; } - | ^^^ lifetime 'wf already in scope + | ^^^ label `'wf` already in scope warning: label name `'tl` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:24:5 @@ -52,7 +52,7 @@ warning: label name `'tl` shadows a label name that is already in scope LL | 'tl: while let Some(_) = None:: { break; } | --- first declared here LL | 'tl: loop { break; } - | ^^^ lifetime 'tl already in scope + | ^^^ label `'tl` already in scope warning: label name `'lt` shadows a label name that is already in scope --> $DIR/loops-reject-duplicate-labels.rs:26:5 @@ -60,7 +60,7 @@ warning: label name `'lt` shadows a label name that is already in scope LL | 'lt: loop { break; } | --- first declared here LL | 'lt: while let Some(_) = None:: { break; } - | ^^^ lifetime 'lt already in scope + | ^^^ label `'lt` already in scope warning: 8 warnings emitted diff --git a/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr b/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr index c27e61190bb..0d96c0b3a35 100644 --- a/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr +++ b/src/test/ui/loops/loops-reject-labels-shadowing-lifetimes.stderr @@ -4,7 +4,7 @@ warning: label name `'a` shadows a lifetime name that is already in scope LL | fn foo<'a>() { | -- first declared here LL | 'a: loop { break 'a; } - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:35:13 @@ -13,7 +13,7 @@ LL | impl<'bad, 'c> Struct<'bad, 'c> { | ---- first declared here LL | fn meth_bad(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:42:13 @@ -22,7 +22,7 @@ LL | impl<'b, 'bad> Struct<'b, 'bad> { | ---- first declared here LL | fn meth_bad2(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:49:13 @@ -30,7 +30,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad3<'bad>(x: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:54:13 @@ -38,7 +38,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:61:13 @@ -47,7 +47,7 @@ LL | impl <'bad, 'e> Enum<'bad, 'e> { | ---- first declared here LL | fn meth_bad(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:67:13 @@ -56,7 +56,7 @@ LL | impl <'d, 'bad> Enum<'d, 'bad> { | ---- first declared here LL | fn meth_bad2(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:73:13 @@ -64,7 +64,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad3<'bad>(x: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:78:13 @@ -72,7 +72,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad4<'a,'bad>(x: &'bad i8) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:88:13 @@ -81,7 +81,7 @@ LL | trait HasDefaultMethod1<'bad> { | ---- first declared here ... LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:94:13 @@ -90,7 +90,7 @@ LL | trait HasDefaultMethod2<'a,'bad> { | ---- first declared here LL | fn meth_bad(&self) { LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: label name `'bad` shadows a lifetime name that is already in scope --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:100:13 @@ -98,7 +98,7 @@ warning: label name `'bad` shadows a lifetime name that is already in scope LL | fn meth_bad<'bad>(&self) { | ---- first declared here LL | 'bad: loop { break 'bad; } - | ^^^^ lifetime 'bad already in scope + | ^^^^ lifetime `'bad` already in scope warning: 12 warnings emitted diff --git a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr index b31ef273fc6..dcee1a80090 100644 --- a/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr +++ b/src/test/ui/loops/loops-reject-lifetime-shadowing-label.stderr @@ -4,7 +4,7 @@ warning: lifetime name `'a` shadows a label name that is already in scope LL | 'a: loop { | -- first declared here LL | let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; - | ^^ lifetime 'a already in scope + | ^^ label `'a` already in scope warning: 1 warning emitted diff --git a/src/test/ui/macros/macro-lifetime-used-with-labels.stderr b/src/test/ui/macros/macro-lifetime-used-with-labels.stderr index 98ee85d908d..68f885e9e45 100644 --- a/src/test/ui/macros/macro-lifetime-used-with-labels.stderr +++ b/src/test/ui/macros/macro-lifetime-used-with-labels.stderr @@ -2,7 +2,7 @@ warning: label name `'b` shadows a label name that is already in scope --> $DIR/macro-lifetime-used-with-labels.rs:21:9 | LL | 'b: loop { - | ^^ lifetime 'b already in scope + | ^^ label `'b` already in scope ... LL | 'b: loop { | -- first declared here diff --git a/src/test/ui/shadowed/shadowed-lifetime.stderr b/src/test/ui/shadowed/shadowed-lifetime.stderr index 5ea3d926430..68cc505d36d 100644 --- a/src/test/ui/shadowed/shadowed-lifetime.stderr +++ b/src/test/ui/shadowed/shadowed-lifetime.stderr @@ -4,7 +4,7 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scop LL | impl<'a> Foo<'a> { | -- first declared here LL | fn shadow_in_method<'a>(&'a self) -> &'a isize { - | ^^ lifetime 'a already in scope + | ^^ lifetime `'a` already in scope error[E0496]: lifetime name `'b` shadows a lifetime name that is already in scope --> $DIR/shadowed-lifetime.rs:12:20 @@ -12,7 +12,7 @@ error[E0496]: lifetime name `'b` shadows a lifetime name that is already in scop LL | fn shadow_in_type<'b>(&'b self) -> &'b isize { | -- first declared here LL | let x: for<'b> fn(&'b isize) = panic!(); - | ^^ lifetime 'b already in scope + | ^^ lifetime `'b` already in scope error: aborting due to 2 previous errors From 88c6cf88842fa6a321f2630ea154d0267969466d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 1 Dec 2020 23:18:46 -0500 Subject: [PATCH 140/274] Pass around Symbols instead of Idents in doctree The span was unused. --- src/librustdoc/clean/mod.rs | 15 ++++++--------- src/librustdoc/doctree.rs | 8 ++++---- src/librustdoc/visit_ast.rs | 18 +++++++++--------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d294d8f02a8..dc53f09faba 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1989,16 +1989,13 @@ impl Clean for hir::BareFnTy<'_> { } } -impl Clean> for (&hir::Item<'_>, Option) { +impl Clean> for (&hir::Item<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Vec { use hir::ItemKind; let (item, renamed) = self; let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id(); - let mut name = match renamed { - Some(ident) => ident.name, - None => cx.tcx.hir().name(item.hir_id), - }; + let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id)); cx.with_param_env(def_id, || { let kind = match item.kind { ItemKind::Static(ty, mutability, body_id) => StaticItem(Static { @@ -2291,7 +2288,7 @@ impl Clean> for doctree::Import<'_> { } } -impl Clean for (&hir::ForeignItem<'_>, Option) { +impl Clean for (&hir::ForeignItem<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Item { let (item, renamed) = self; cx.with_param_env(cx.tcx.hir().local_def_id(item.hir_id).to_def_id(), || { @@ -2325,7 +2322,7 @@ impl Clean for (&hir::ForeignItem<'_>, Option) { Item::from_hir_id_and_parts( item.hir_id, - Some(renamed.unwrap_or(item.ident).name), + Some(renamed.unwrap_or(item.ident.name)), kind, cx, ) @@ -2333,10 +2330,10 @@ impl Clean for (&hir::ForeignItem<'_>, Option) { } } -impl Clean for (&hir::MacroDef<'_>, Option) { +impl Clean for (&hir::MacroDef<'_>, Option) { fn clean(&self, cx: &DocContext<'_>) -> Item { let (item, renamed) = self; - let name = renamed.unwrap_or(item.ident).name; + let name = renamed.unwrap_or(item.ident.name); let tts = item.ast.body.inner_tokens().trees().collect::>(); // Extract the spans of all matchers. They represent the "interface" of the macro. let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect::>(); diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 3961870a1bf..ee9a6981857 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -3,7 +3,7 @@ crate use self::StructType::*; use rustc_ast as ast; -use rustc_span::{self, symbol::Ident, Span, Symbol}; +use rustc_span::{self, Span, Symbol}; use rustc_hir as hir; @@ -16,9 +16,9 @@ crate struct Module<'hir> { crate mods: Vec>, crate id: hir::HirId, // (item, renamed) - crate items: Vec<(&'hir hir::Item<'hir>, Option)>, - crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, - crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option)>, + crate items: Vec<(&'hir hir::Item<'hir>, Option)>, + crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, + crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option)>, crate is_crate: bool, } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4028293076d..f9cb1d586b1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -10,7 +10,7 @@ use rustc_hir::Node; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{self, Span}; use std::mem; @@ -116,7 +116,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &mut self, id: hir::HirId, res: Res, - renamed: Option, + renamed: Option, glob: bool, om: &mut Module<'tcx>, please_inline: bool, @@ -226,11 +226,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn visit_item( &mut self, item: &'tcx hir::Item<'_>, - renamed: Option, + renamed: Option, om: &mut Module<'tcx>, ) { debug!("visiting item {:?}", item); - let ident = renamed.unwrap_or(item.ident); + let name = renamed.unwrap_or(item.ident.name); if item.vis.node.is_pub() { let def_id = self.cx.tcx.hir().local_def_id(item.hir_id); @@ -266,7 +266,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } _ => false, }); - let ident = if is_glob { None } else { Some(ident) }; + let ident = if is_glob { None } else { Some(name) }; if self.maybe_inline_local( item.hir_id, path.res, @@ -280,7 +280,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } om.imports.push(Import { - name: ident.name, + name, id: item.hir_id, vis: &item.vis, attrs: &item.attrs, @@ -296,7 +296,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &item.vis, item.hir_id, m, - Some(ident.name), + Some(name), )); } hir::ItemKind::Fn(..) @@ -312,7 +312,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. - if ident.name != kw::Underscore { + if name != kw::Underscore { om.items.push((item, renamed)); } } @@ -329,7 +329,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn visit_foreign_item( &mut self, item: &'tcx hir::ForeignItem<'_>, - renamed: Option, + renamed: Option, om: &mut Module<'tcx>, ) { // If inlining we only want to include public functions. From 500979828a376c4118b3c48df1642f8fea1d1c40 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 1 Dec 2020 22:32:56 -0800 Subject: [PATCH 141/274] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index bfca1cd22bf..63d0fe43449 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit bfca1cd22bf514d5f2b6c1089b0ded0ba7dfaa6e +Subproject commit 63d0fe43449adcb316d34d98a982b597faca4178 From 5a228263b861dd5ed4f0b8d799337745b1d1a39b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Dec 2020 14:11:33 +0100 Subject: [PATCH 142/274] Clean up doc attributes check before adding more --- compiler/rustc_passes/src/check_attr.rs | 172 +++++++++++++----------- 1 file changed, 93 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c9e02d56f4b..54621dae1ac 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -78,7 +78,7 @@ impl CheckAttrVisitor<'tcx> { } else if self.tcx.sess.check_name(attr, sym::track_caller) { self.check_track_caller(&attr.span, attrs, span, target) } else if self.tcx.sess.check_name(attr, sym::doc) { - self.check_doc_alias(attr, hir_id, target) + self.check_doc_attrs(attr, hir_id, target) } else if self.tcx.sess.check_name(attr, sym::no_link) { self.check_no_link(&attr, span, target) } else if self.tcx.sess.check_name(attr, sym::export_name) { @@ -297,89 +297,103 @@ impl CheckAttrVisitor<'tcx> { .emit(); } - fn check_doc_alias(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool { + fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool { + if !meta.is_value_str() { + self.doc_alias_str_error(meta); + return false; + } + let doc_alias = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); + if doc_alias.is_empty() { + self.doc_alias_str_error(meta); + return false; + } + if let Some(c) = + doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) + { + self.tcx + .sess + .struct_span_err( + meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + &format!("{:?} character isn't allowed in `#[doc(alias = \"...\")]`", c,), + ) + .emit(); + return false; + } + if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { + self.tcx + .sess + .struct_span_err( + meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + "`#[doc(alias = \"...\")]` cannot start or end with ' '", + ) + .emit(); + return false; + } + if let Some(err) = match target { + Target::Impl => Some("implementation block"), + Target::ForeignMod => Some("extern block"), + Target::AssocTy => { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + if Target::from_item(containing_item) == Target::Impl { + Some("type alias in implementation block") + } else { + None + } + } + Target::AssocConst => { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + // We can't link to trait impl's consts. + let err = "associated constant in trait implementation block"; + match containing_item.kind { + ItemKind::Impl { of_trait: Some(_), .. } => Some(err), + _ => None, + } + } + _ => None, + } { + self.tcx + .sess + .struct_span_err( + meta.span(), + &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err), + ) + .emit(); + return false; + } + true + } + + fn check_attr_crate_level( + &self, + meta: &NestedMetaItem, + hir_id: HirId, + attr_name: &str, + ) -> bool { + if CRATE_HIR_ID == hir_id { + self.tcx + .sess + .struct_span_err( + meta.span(), + &format!( + "`#![doc({} = \"...\")]` isn't allowed as a crate level attribute", + attr_name, + ), + ) + .emit(); + return false; + } + } + + fn check_doc_attrs(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool { if let Some(mi) = attr.meta() { if let Some(list) = mi.meta_item_list() { for meta in list { if meta.has_name(sym::alias) { - if !meta.is_value_str() { - self.doc_alias_str_error(meta); - return false; - } - let doc_alias = - meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); - if doc_alias.is_empty() { - self.doc_alias_str_error(meta); - return false; - } - if let Some(c) = doc_alias - .chars() - .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) + if !self.check_attr_crate_level(meta, hir_id, "alias") + || !self.check_doc_alias(meta, hir_id, target) { - self.tcx - .sess - .struct_span_err( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - &format!( - "{:?} character isn't allowed in `#[doc(alias = \"...\")]`", - c, - ), - ) - .emit(); - return false; - } - if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { - self.tcx - .sess - .struct_span_err( - meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - "`#[doc(alias = \"...\")]` cannot start or end with ' '", - ) - .emit(); - return false; - } - if let Some(err) = match target { - Target::Impl => Some("implementation block"), - Target::ForeignMod => Some("extern block"), - Target::AssocTy => { - let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); - let containing_item = self.tcx.hir().expect_item(parent_hir_id); - if Target::from_item(containing_item) == Target::Impl { - Some("type alias in implementation block") - } else { - None - } - } - Target::AssocConst => { - let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); - let containing_item = self.tcx.hir().expect_item(parent_hir_id); - // We can't link to trait impl's consts. - let err = "associated constant in trait implementation block"; - match containing_item.kind { - ItemKind::Impl { of_trait: Some(_), .. } => Some(err), - _ => None, - } - } - _ => None, - } { - self.tcx - .sess - .struct_span_err( - meta.span(), - &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err), - ) - .emit(); - return false; - } - if CRATE_HIR_ID == hir_id { - self.tcx - .sess - .struct_span_err( - meta.span(), - "`#![doc(alias = \"...\")]` isn't allowed as a crate \ - level attribute", - ) - .emit(); return false; } } From dc10ccfe89d6c8b4ca7993afd66c5dd83f6712ee Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Dec 2020 14:19:53 +0100 Subject: [PATCH 143/274] Add checks for #[doc(keyword = "...")] and move them into rustc_passes --- compiler/rustc_passes/src/check_attr.rs | 60 ++++++++++++++++++++++--- src/librustdoc/clean/mod.rs | 3 -- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 54621dae1ac..fc97ca035b9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -287,24 +287,20 @@ impl CheckAttrVisitor<'tcx> { } } - fn doc_alias_str_error(&self, meta: &NestedMetaItem) { + fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) { self.tcx .sess .struct_span_err( meta.span(), - "doc alias attribute expects a string: #[doc(alias = \"0\")]", + &format!("doc {0} attribute expects a string: #[doc({0} = \"a\")]", attr_name), ) .emit(); } fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool { - if !meta.is_value_str() { - self.doc_alias_str_error(meta); - return false; - } let doc_alias = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); if doc_alias.is_empty() { - self.doc_alias_str_error(meta); + self.doc_attr_str_error(meta, "alias"); return false; } if let Some(c) = @@ -365,6 +361,49 @@ impl CheckAttrVisitor<'tcx> { true } + fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { + let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); + if doc_keyword.is_empty() { + self.doc_attr_str_error(meta, "keyword"); + return false; + } + match self.tcx.hir().expect_item(hir_id).kind { + ItemKind::Mod(ref module) => { + if !module.item_ids.is_empty() { + self.tcx + .sess + .struct_span_err( + meta.span(), + "`#[doc(keyword = \"...\")]` can only be used on empty modules", + ) + .emit(); + return false; + } + } + _ => { + self.tcx + .sess + .struct_span_err( + meta.span(), + "`#[doc(keyword = \"...\")]` can only be used on modules", + ) + .emit(); + return false; + } + } + if !rustc_lexer::is_ident(&doc_keyword) { + self.tcx + .sess + .struct_span_err( + meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + &format!("`{}` is not a valid identifier", doc_keyword), + ) + .emit(); + return false; + } + true + } + fn check_attr_crate_level( &self, meta: &NestedMetaItem, @@ -384,6 +423,7 @@ impl CheckAttrVisitor<'tcx> { .emit(); return false; } + true } fn check_doc_attrs(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool { @@ -396,6 +436,12 @@ impl CheckAttrVisitor<'tcx> { { return false; } + } else if meta.has_name(sym::keyword) { + if !self.check_attr_crate_level(meta, hir_id, "keyword") + || !self.check_doc_keyword(meta, hir_id) + { + return false; + } } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d294d8f02a8..cd2700be5a7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -162,9 +162,6 @@ impl Clean for CrateNum { .collect() }; - let get_span = - |attr: &ast::NestedMetaItem| Some(attr.meta_item()?.name_value_literal()?.span); - let as_keyword = |res: Res| { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = cx.tcx.get_attrs(def_id).clean(cx); From 8a35b93c4d5a0071b99ecb7cf6cd91310222c3ff Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Dec 2020 23:41:12 +0100 Subject: [PATCH 144/274] Add rustc_lexer as dependency to rustc_passes --- Cargo.lock | 1 + compiler/rustc_passes/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index ce1f705bdff..85be4c392af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4011,6 +4011,7 @@ dependencies = [ "rustc_errors", "rustc_hir", "rustc_index", + "rustc_lexer", "rustc_middle", "rustc_serialize", "rustc_session", diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index df6667a29d5..c87799f1c2a 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -18,3 +18,4 @@ rustc_ast = { path = "../rustc_ast" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_lexer = { path = "../rustc_lexer" } From 1b7fe09025f6dfc7f134243fd672ad2c490b466b Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Wed, 2 Dec 2020 17:19:11 +0530 Subject: [PATCH 145/274] add comment and bless some tests --- compiler/rustc_mir/src/const_eval/machine.rs | 6 +- .../const-argument-if-length.full.stderr | 11 +- .../const-argument-if-length.rs | 1 - .../consts/const-eval/erroneous-const.stderr | 16 +- src/test/ui/consts/const-eval/unwind-abort.rs | 4 +- .../ui/consts/const-eval/unwind-abort.stderr | 23 ++- src/test/ui/consts/const-size_of-cycle.stderr | 5 - .../consts/uninhabited-const-issue-61744.rs | 6 +- .../uninhabited-const-issue-61744.stderr | 149 ++++++++--------- .../infinite/infinite-recursion-const-fn.rs | 3 +- .../infinite-recursion-const-fn.stderr | 156 ++++++++++++++++-- 11 files changed, 241 insertions(+), 139 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 6449b7cdebc..29bc14be74d 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -38,7 +38,11 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { if instance.def.requires_caller_location(self.tcx()) { return Ok(false); } - // only memoize instrinsics + // Only memoize instrinsics. This was added in #79594 while adding the `const_allocate` intrinsic. + // We only memoize intrinsics because it would be unsound to memoize functions + // which might interact with the heap. + // Additionally, const_allocate intrinsic is impure and thus should not be memoized; + // it will not be memoized because it has non-ZST args if !matches!(instance.def, InstanceDef::Intrinsic(_)) { return Ok(false); } diff --git a/src/test/ui/const-generics/const-argument-if-length.full.stderr b/src/test/ui/const-generics/const-argument-if-length.full.stderr index 9b1c1be1aa0..4d627f05adc 100644 --- a/src/test/ui/const-generics/const-argument-if-length.full.stderr +++ b/src/test/ui/const-generics/const-argument-if-length.full.stderr @@ -11,12 +11,6 @@ LL | if std::mem::size_of::() == 0 { LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` -error[E0080]: evaluation of constant value failed - --> $DIR/const-argument-if-length.rs:19:15 - | -LL | pad: [u8; is_zst::()], - | ^^^^^^^^^^^^^ referenced constant has errors - error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/const-argument-if-length.rs:17:12 | @@ -36,7 +30,6 @@ help: the `Box` type always has a statically known size and allocates its conten LL | value: Box, | ^^^^ ^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0080, E0277. -For more information about an error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/const-argument-if-length.rs b/src/test/ui/const-generics/const-argument-if-length.rs index a8bffd17b91..80907383124 100644 --- a/src/test/ui/const-generics/const-argument-if-length.rs +++ b/src/test/ui/const-generics/const-argument-if-length.rs @@ -18,7 +18,6 @@ pub struct AtLeastByte { //~^ ERROR the size for values of type `T` cannot be known at compilation time pad: [u8; is_zst::()], //[min]~^ ERROR generic parameters may not be used in const operations - //[full]~^^ ERROR evaluation of constant value failed } fn main() {} diff --git a/src/test/ui/consts/const-eval/erroneous-const.stderr b/src/test/ui/consts/const-eval/erroneous-const.stderr index 7087a6f668c..040cc3fcf79 100644 --- a/src/test/ui/consts/const-eval/erroneous-const.stderr +++ b/src/test/ui/consts/const-eval/erroneous-const.stderr @@ -24,18 +24,18 @@ note: the lint level is defined here LL | #![warn(const_err, unconditional_panic)] | ^^^^^^^^^ -error[E0080]: evaluation of constant value failed +error[E0080]: could not evaluate static initializer --> $DIR/erroneous-const.rs:12:17 | LL | let _ = PrintName::::VOID; - | ^^^^^^^^^^^^^^^^^^^^ referenced constant has errors - -error[E0080]: could not evaluate static initializer - --> $DIR/erroneous-const.rs:16:22 - | + | ^^^^^^^^^^^^^^^^^^^^ + | | + | referenced constant has errors + | inside `no_codegen::` at $DIR/erroneous-const.rs:12:17 +... LL | pub static FOO: () = no_codegen::(); - | ^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | ------------------- inside `FOO` at $DIR/erroneous-const.rs:16:22 -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/unwind-abort.rs b/src/test/ui/consts/const-eval/unwind-abort.rs index b8b95dea1e7..b9e63e2fa20 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.rs +++ b/src/test/ui/consts/const-eval/unwind-abort.rs @@ -2,10 +2,10 @@ #[unwind(aborts)] const fn foo() { - panic!() //~ evaluation of constant value failed + panic!() //~ 5:13: any use of this value will cause an error [const_err] } -const _: () = foo(); //~ any use of this value will cause an error +const _: () = foo(); // Ensure that the CTFE engine handles calls to `#[unwind(aborts)]` gracefully fn main() { diff --git a/src/test/ui/consts/const-eval/unwind-abort.stderr b/src/test/ui/consts/const-eval/unwind-abort.stderr index 084beb19eb9..eee1a35a0dc 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.stderr +++ b/src/test/ui/consts/const-eval/unwind-abort.stderr @@ -1,21 +1,18 @@ -error[E0080]: evaluation of constant value failed +error: any use of this value will cause an error --> $DIR/unwind-abort.rs:5:5 | LL | panic!() - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5 - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: any use of this value will cause an error - --> $DIR/unwind-abort.rs:8:15 - | + | ^^^^^^^^ + | | + | the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5 + | inside `foo` at $SRC_DIR/std/src/macros.rs:LL:COL + | inside `_` at $DIR/unwind-abort.rs:8:15 +... LL | const _: () = foo(); - | --------------^^^^^- - | | - | referenced constant has errors + | -------------------- | = note: `#[deny(const_err)]` on by default + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index fdbe3f0c592..129457ebdf9 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -14,11 +14,6 @@ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`.. | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `std::mem::size_of`... - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL - | -LL | pub const fn size_of() -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `[u8; _]`... = note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.rs b/src/test/ui/consts/uninhabited-const-issue-61744.rs index 15436f9c1b2..7fb1dc988bb 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.rs +++ b/src/test/ui/consts/uninhabited-const-issue-61744.rs @@ -1,15 +1,15 @@ // build-fail pub const unsafe fn fake_type() -> T { - hint_unreachable() + hint_unreachable() //~ 4:23: any use of this value will cause an error [const_err] } pub const unsafe fn hint_unreachable() -> ! { - fake_type() //~ ERROR evaluation of constant value failed + fake_type() } trait Const { - const CONSTANT: i32 = unsafe { fake_type() }; //~ ERROR any use of this value will cause an err + const CONSTANT: i32 = unsafe { fake_type() }; } impl Const for T {} diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr index 024f9782d4a..1fb5ac11df0 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.stderr +++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr @@ -1,150 +1,141 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/uninhabited-const-issue-61744.rs:8:5 +error: any use of this value will cause an error + --> $DIR/uninhabited-const-issue-61744.rs:4:5 | LL | hint_unreachable() - | ------------------ + | ^^^^^^^^^^^^^^^^^^ | | + | reached the configured maximum number of stack frames | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `fake_type::` at $DIR/uninhabited-const-issue-61744.rs:4:5 + | inside `::CONSTANT` at $DIR/uninhabited-const-issue-61744.rs:12:36 ... -LL | fake_type() - | ^^^^^^^^^^^ - | | - | reached the configured maximum number of stack frames - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 - -error: any use of this value will cause an error - --> $DIR/uninhabited-const-issue-61744.rs:12:36 - | LL | const CONSTANT: i32 = unsafe { fake_type() }; - | -------------------------------^^^^^^^^^^^--- - | | - | referenced constant has errors + | --------------------------------------------- | = note: `#[deny(const_err)]` on by default @@ -154,6 +145,6 @@ error[E0080]: erroneous constant used LL | dbg!(i32::CONSTANT); | ^^^^^^^^^^^^^ referenced constant has errors -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.rs b/src/test/ui/infinite/infinite-recursion-const-fn.rs index 34580407926..2e812dc53a6 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite/infinite-recursion-const-fn.rs @@ -1,8 +1,7 @@ //https://github.com/rust-lang/rust/issues/31364 const fn a() -> usize { - //~^ ERROR cycle detected when const-evaluating + checking `a` [E0391] - b() + b() //~ 4:8: evaluation of constant value failed [E0080] } const fn b() -> usize { a() diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index 7ccc7cc987f..620c9e110ff 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -1,21 +1,145 @@ -error[E0391]: cycle detected when const-evaluating + checking `a` - --> $DIR/infinite-recursion-const-fn.rs:3:1 - | -LL | const fn a() -> usize { - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `b`... - --> $DIR/infinite-recursion-const-fn.rs:7:1 - | -LL | const fn b() -> usize { - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating + checking `a`, completing the cycle -note: cycle used when const-evaluating + checking `ARR::{constant#0}` - --> $DIR/infinite-recursion-const-fn.rs:10:18 +error[E0080]: evaluation of constant value failed + --> $DIR/infinite-recursion-const-fn.rs:4:5 | +LL | b() + | ^^^ + | | + | reached the configured maximum number of stack frames + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 + | inside `a` at $DIR/infinite-recursion-const-fn.rs:4:5 +... +LL | a() + | --- + | | + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 + | inside `b` at $DIR/infinite-recursion-const-fn.rs:7:5 +LL | } LL | const ARR: [i32; a()] = [5; 6]; - | ^^^ + | --- inside `ARR::{constant#0}` at $DIR/infinite-recursion-const-fn.rs:9:18 error: aborting due to previous error -For more information about this error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0080`. From 899a59e7ca7817e8c0f56c474186854c7eb5ea9b Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Wed, 2 Dec 2020 17:45:11 +0530 Subject: [PATCH 146/274] rename MemoryKind::Heap to ConstHeap; bless test --- compiler/rustc_mir/src/interpret/intern.rs | 5 ++++- compiler/rustc_mir/src/interpret/intrinsics.rs | 7 +++++-- compiler/rustc_mir/src/interpret/memory.rs | 6 +++--- src/test/ui/consts/const-eval/erroneous-const.rs | 4 ++-- .../const-eval/heap/alloc_intrinsic_nontransient_fail.rs | 5 ++--- .../heap/alloc_intrinsic_nontransient_fail.stderr | 8 ++++++++ src/test/ui/consts/const-eval/unwind-abort.rs | 2 +- src/test/ui/consts/uninhabited-const-issue-61744.rs | 2 +- src/test/ui/infinite/infinite-recursion-const-fn.rs | 2 +- 9 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 443ef072647..db996f72128 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -104,7 +104,10 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( // This match is just a canary for future changes to `MemoryKind`, which most likely need // changes in this function. match kind { - MemoryKind::Stack | MemoryKind::Heap | MemoryKind::Vtable | MemoryKind::CallerLocation => {} + MemoryKind::Stack + | MemoryKind::ConstHeap + | MemoryKind::Vtable + | MemoryKind::CallerLocation => {} } // Set allocation mutability as appropriate. This is used by LLVM to put things into // read-only memory, and also by Miri when evaluating other globals that diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 4bc263730c3..84a53a589a5 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -347,8 +347,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), }; - let ptr = - self.memory.allocate(Size::from_bytes(size as u64), align, MemoryKind::Heap); + let ptr = self.memory.allocate( + Size::from_bytes(size as u64), + align, + MemoryKind::ConstHeap, + ); self.write_scalar(Scalar::Ptr(ptr), dest)?; } sym::offset => { diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index 1319ecd5b2e..47d0fce51b1 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -28,7 +28,7 @@ pub enum MemoryKind { /// Stack memory. Error if deallocated except during a stack pop. Stack, /// Heap memory. - Heap, + ConstHeap, /// Memory backing vtables. Error if ever deallocated. Vtable, /// Memory allocated by `caller_location` intrinsic. Error if ever deallocated. @@ -42,7 +42,7 @@ impl MayLeak for MemoryKind { fn may_leak(self) -> bool { match self { MemoryKind::Stack => false, - MemoryKind::Heap => false, + MemoryKind::ConstHeap => false, MemoryKind::Vtable => true, MemoryKind::CallerLocation => true, MemoryKind::Machine(k) => k.may_leak(), @@ -54,7 +54,7 @@ impl fmt::Display for MemoryKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { MemoryKind::Stack => write!(f, "stack variable"), - MemoryKind::Heap => write!(f, "heap allocation"), + MemoryKind::ConstHeap => write!(f, "heap allocation"), MemoryKind::Vtable => write!(f, "vtable"), MemoryKind::CallerLocation => write!(f, "caller location"), MemoryKind::Machine(m) => write!(f, "{}", m), diff --git a/src/test/ui/consts/const-eval/erroneous-const.rs b/src/test/ui/consts/const-eval/erroneous-const.rs index 3df491bf229..16bf1adf7db 100644 --- a/src/test/ui/consts/const-eval/erroneous-const.rs +++ b/src/test/ui/consts/const-eval/erroneous-const.rs @@ -9,11 +9,11 @@ impl PrintName { const fn no_codegen() { if false { - let _ = PrintName::::VOID; //~ERROR evaluation of constant value failed + let _ = PrintName::::VOID; //~ERROR could not evaluate static initializer } } -pub static FOO: () = no_codegen::(); //~ERROR could not evaluate static initializer +pub static FOO: () = no_codegen::(); fn main() { FOO diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs index de7fb65f685..e6ef9974aa8 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs @@ -1,11 +1,11 @@ -// run-pass #![feature(core_intrinsics)] #![feature(const_heap)] #![feature(const_raw_ptr_deref)] #![feature(const_mut_refs)] use std::intrinsics; -const FOO: &i32 = foo(); +const FOO: *const i32 = foo(); +//~^ ERROR untyped pointers are not allowed in constant const fn foo() -> &'static i32 { let t = unsafe { @@ -16,5 +16,4 @@ const fn foo() -> &'static i32 { unsafe { &*t } } fn main() { - assert_eq!(*FOO, 20) } diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr new file mode 100644 index 00000000000..08679350d6d --- /dev/null +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr @@ -0,0 +1,8 @@ +error: untyped pointers are not allowed in constant + --> $DIR/alloc_intrinsic_nontransient_fail.rs:7:1 + | +LL | const FOO: *const i32 = foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/unwind-abort.rs b/src/test/ui/consts/const-eval/unwind-abort.rs index b9e63e2fa20..2dc8e14bed5 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.rs +++ b/src/test/ui/consts/const-eval/unwind-abort.rs @@ -2,7 +2,7 @@ #[unwind(aborts)] const fn foo() { - panic!() //~ 5:13: any use of this value will cause an error [const_err] + panic!() //~ ERROR any use of this value will cause an error [const_err] } const _: () = foo(); diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.rs b/src/test/ui/consts/uninhabited-const-issue-61744.rs index 7fb1dc988bb..2f4b7578d1c 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.rs +++ b/src/test/ui/consts/uninhabited-const-issue-61744.rs @@ -1,7 +1,7 @@ // build-fail pub const unsafe fn fake_type() -> T { - hint_unreachable() //~ 4:23: any use of this value will cause an error [const_err] + hint_unreachable() //~ ERROR any use of this value will cause an error [const_err] } pub const unsafe fn hint_unreachable() -> ! { diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.rs b/src/test/ui/infinite/infinite-recursion-const-fn.rs index 2e812dc53a6..4209153116d 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite/infinite-recursion-const-fn.rs @@ -1,7 +1,7 @@ //https://github.com/rust-lang/rust/issues/31364 const fn a() -> usize { - b() //~ 4:8: evaluation of constant value failed [E0080] + b() //~ ERROR evaluation of constant value failed [E0080] } const fn b() -> usize { a() From 67a67d827abfe506977938efaeb5c38b3ea94bf6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Dec 2020 13:49:33 +0100 Subject: [PATCH 147/274] disable a ptr equality test on Miri --- library/alloc/tests/str.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index b1301914656..04077f88414 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1978,9 +1978,13 @@ fn const_str_ptr() { const B: &'static [u8; 2] = &A; const C: *const u8 = B as *const u8; - unsafe { + #[cfg(not(miri))] // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) + { let foo = &A as *const u8; assert_eq!(foo, C); + } + + unsafe { assert_eq!(from_utf8_unchecked(&A), "hi"); assert_eq!(*C, A[0]); assert_eq!(*(&B[0] as *const u8), A[0]); From 7e74b72d135c072c49dd0273b9582b4a51eb7a93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Dec 2020 14:09:36 +0100 Subject: [PATCH 148/274] break formatting so rustfmt is happy --- library/alloc/tests/str.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 04077f88414..604835e6cc4 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1978,7 +1978,8 @@ fn const_str_ptr() { const B: &'static [u8; 2] = &A; const C: *const u8 = B as *const u8; - #[cfg(not(miri))] // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) + // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131) + #[cfg(not(miri))] { let foo = &A as *const u8; assert_eq!(foo, C); From 1ef5dbe7167376be7a0babefb0b4971d703e4b5d Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 16:17:37 +0100 Subject: [PATCH 149/274] Resolved some of the comments * Undo fn -> const fn for some fns. * Split feature gate. * Made all three intrinsics const --- library/core/src/intrinsics.rs | 4 +++- library/core/src/lib.rs | 3 ++- library/core/src/mem/maybe_uninit.rs | 15 ++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index c0fcfb3a139..0c37bec4698 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -815,19 +815,21 @@ extern "rust-intrinsic" { /// This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit /// zero-initialization: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_zero_valid(); /// A guard for unsafe functions that cannot ever be executed if `T` has invalid /// bit patterns: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_uninit_valid(); /// Gets a reference to a static `Location` indicating where it was called. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a901375a958..fc44a5a55fb 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -69,6 +69,7 @@ #![feature(asm)] #![feature(cfg_target_has_atomic)] #![feature(const_alloc_layout)] +#![feature(const_assert_type)] #![feature(const_discriminant)] #![feature(const_cell_into_inner)] #![feature(const_checked_int_methods)] @@ -101,7 +102,7 @@ #![feature(const_type_name)] #![feature(const_likely)] #![feature(const_unreachable_unchecked)] -#![feature(const_maybe_assume_init)] +#![feature(const_maybe_uninit_assume_init)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 6251355b909..eddfff6f513 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -314,8 +314,7 @@ impl MaybeUninit { /// let data = read(&mut buf); /// ``` #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] - #[rustc_allow_const_fn_unstable(const_maybe_assume_init)] + #[rustc_const_unstable(feature = "maybe_uninit_uninit_array", issue = "none")] #[inline(always)] pub const fn uninit_array() -> [Self; LEN] { // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. @@ -505,7 +504,7 @@ impl MaybeUninit { /// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️ /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] #[rustc_diagnostic_item = "assume_init"] pub const unsafe fn assume_init(self) -> T { @@ -813,7 +812,7 @@ impl MaybeUninit { /// /// [`assume_init_ref`]: MaybeUninit::assume_init_ref #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { // SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that @@ -835,7 +834,7 @@ impl MaybeUninit { /// /// [`assume_init_mut`]: MaybeUninit::assume_init_mut #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] pub const unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a @@ -845,17 +844,15 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "const_maybe_assume_init", issue = "none")] #[inline(always)] - pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } } From 37354ebc9794b0eb14b08c02177e3094c8fe91cd Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 2 Dec 2020 12:19:38 -0300 Subject: [PATCH 150/274] Revert "Auto merge of #79209 - spastorino:trait-inheritance-self, r=nikomatsakis" This reverts commit 349b3b324dade7ca638091db93ba08bbc443c63d, reversing changes made to b776d1c3e3db8befabb123ebb1e46c3531eaed46. --- compiler/rustc_infer/src/traits/util.rs | 34 +--- compiler/rustc_middle/src/query/mod.rs | 15 +- compiler/rustc_middle/src/ty/context.rs | 38 +--- compiler/rustc_middle/src/ty/query/keys.rs | 24 +-- .../rustc_trait_selection/src/traits/mod.rs | 3 +- compiler/rustc_typeck/src/astconv/mod.rs | 68 ++----- .../rustc_typeck/src/check/fn_ctxt/mod.rs | 8 +- compiler/rustc_typeck/src/collect.rs | 184 +++++------------- .../rustc_typeck/src/collect/item_bounds.rs | 4 +- .../incremental/cyclic-trait-hierarchy.rs | 10 +- .../ambiguous-associated-type2.rs | 12 -- .../ambiguous-associated-type2.stderr | 16 -- .../associated-item-through-where-clause.rs | 21 -- ...e-predicates-that-can-define-assoc-type.rs | 10 - .../missing-trait-bound-for-assoc-fails.rs | 10 - ...missing-trait-bound-for-assoc-fails.stderr | 16 -- .../super-trait-referencing-self.rs | 12 -- .../super-trait-referencing.rs | 19 -- .../super-trait-where-referencing-self.rs | 27 --- .../cycle-projection-based-on-where-clause.rs | 24 +++ ...le-projection-based-on-where-clause.stderr | 16 ++ .../cycle-trait-supertrait-direct.stderr | 11 +- .../cycle-trait-supertrait-indirect.stderr | 18 +- src/test/ui/issues/issue-12511.stderr | 16 +- src/test/ui/issues/issue-20772.stderr | 6 +- src/test/ui/issues/issue-20825.stderr | 6 +- src/test/ui/issues/issue-22673.rs | 5 +- src/test/ui/issues/issue-22673.stderr | 16 ++ 28 files changed, 151 insertions(+), 498 deletions(-) delete mode 100644 src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs delete mode 100644 src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr delete mode 100644 src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs delete mode 100644 src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs delete mode 100644 src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs delete mode 100644 src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr delete mode 100644 src/test/ui/associated-type-bounds/super-trait-referencing-self.rs delete mode 100644 src/test/ui/associated-type-bounds/super-trait-referencing.rs delete mode 100644 src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs create mode 100644 src/test/ui/cycle-projection-based-on-where-clause.rs create mode 100644 src/test/ui/cycle-projection-based-on-where-clause.stderr create mode 100644 src/test/ui/issues/issue-22673.stderr diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 93863ef1d50..8273c2d291d 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,10 +1,9 @@ use smallvec::smallvec; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::outlives::Component; use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness}; -use rustc_span::symbol::Ident; pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, @@ -288,37 +287,6 @@ pub fn transitive_bounds<'tcx>( elaborate_trait_refs(tcx, bounds).filter_to_traits() } -/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may -/// define the given associated type `assoc_name`. It uses the -/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that -/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or -/// `T::Item` and helps to avoid cycle errors (see e.g. #35237). -pub fn transitive_bounds_that_define_assoc_type<'tcx>( - tcx: TyCtxt<'tcx>, - bounds: impl Iterator>, - assoc_name: Ident, -) -> FxIndexSet> { - let mut stack: Vec<_> = bounds.collect(); - let mut trait_refs = FxIndexSet::default(); - - while let Some(trait_ref) = stack.pop() { - if trait_refs.insert(trait_ref) { - let super_predicates = - tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), Some(assoc_name))); - for (super_predicate, _) in super_predicates.predicates { - let bound_predicate = super_predicate.bound_atom(); - let subst_predicate = super_predicate - .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder())); - if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() { - stack.push(binder.value); - } - } - } - } - - trait_refs -} - /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b516810205f..7822ecc2c1f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -433,23 +433,12 @@ rustc_queries! { /// full predicates are available (note that supertraits have /// additional acyclicity requirements). query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } - } - - /// The `Option` is the name of an associated type. If it is `None`, then this query - /// returns the full set of predicates. If `Some`, then the query returns only the - /// subset of super-predicates that reference traits that define the given associated type. - /// This is used to avoid cycles in resolving types like `T::Item`. - query super_predicates_that_define_assoc_type(key: (DefId, Option)) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the super traits of `{}`{}", - tcx.def_path_str(key.0), - if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() }, - } + desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } } /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { + query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the bounds for type parameter `{}`", { let id = tcx.hir().local_def_id_to_hir_id(key.1); tcx.hir().ty_param_name(id) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 744aa39b96c..7207e5a179e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -51,7 +51,7 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Session; use rustc_span::source_map::MultiSpan; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; @@ -2085,42 +2085,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) } - /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` - /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. - pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.super_traits_of(trait_def_id).any(|trait_did| { - self.associated_items(trait_did) - .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did) - .is_some() - }) - } - - /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) - /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used - /// to identify which traits may define a given associated type to help avoid cycle errors. - /// Returns a `DefId` iterator. - fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator + 'tcx { - let mut set = FxHashSet::default(); - let mut stack = vec![trait_def_id]; - - set.insert(trait_def_id); - - iter::from_fn(move || -> Option { - let trait_did = stack.pop()?; - let generic_predicates = self.super_predicates_of(trait_did); - - for (predicate, _) in generic_predicates.predicates { - if let ty::PredicateAtom::Trait(data, _) = predicate.skip_binders() { - if set.insert(data.def_id()) { - stack.push(data.def_id()); - } - } - } - - Some(trait_did) - }) - } - /// Given a closure signature, returns an equivalent fn signature. Detuples /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then /// you would get a `fn(u32, i32)`. diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs index 3949c303f72..a005990264c 100644 --- a/compiler/rustc_middle/src/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -7,7 +7,7 @@ use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_query_system::query::DefaultCacheSelector; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; /// The `Key` trait controls what types can legally be used as the key @@ -149,28 +149,6 @@ impl Key for (LocalDefId, DefId) { } } -impl Key for (DefId, Option) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - tcx.def_span(self.0) - } -} - -impl Key for (DefId, LocalDefId, Ident) { - type CacheSelector = DefaultCacheSelector; - - fn query_crate(&self) -> CrateNum { - self.0.krate - } - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.1.default_span(tcx) - } -} - impl Key for (CrateNum, DefId) { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index d6048d092b1..2fb9b3cd5d3 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,8 +65,7 @@ pub use self::util::{ get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, }; pub use self::util::{ - supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, - SupertraitDefIds, Supertraits, + supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, }; pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 915a15fd245..7888cb1b9f5 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -49,10 +49,9 @@ pub trait AstConv<'tcx> { fn default_constness_for_trait_bounds(&self) -> Constness; - /// Returns predicates in scope of the form `X: Foo`, where `X` - /// is a type parameter `X` with the given id `def_id` and T - /// matches `assoc_name`. This is a subset of the full set of - /// predicates. + /// Returns predicates in scope of the form `X: Foo`, where `X` is + /// a type parameter `X` with the given id `def_id`. This is a + /// subset of the full set of predicates. /// /// This is used for one specific purpose: resolving "short-hand" /// associated type references like `T::Item`. In principle, we @@ -61,12 +60,7 @@ pub trait AstConv<'tcx> { /// but this can lead to cycle errors. The problem is that we have /// to do this resolution *in order to create the predicates in /// the first place*. Hence, we have this "special pass". - fn get_type_parameter_bounds( - &self, - span: Span, - def_id: DefId, - assoc_name: Ident, - ) -> ty::GenericPredicates<'tcx>; + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>; /// Returns the lifetime to use when a lifetime is omitted (and not elided). fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) @@ -768,7 +762,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Returns `true` if a bounds list includes `?Sized`. - pub fn is_unsized(&self, ast_bounds: &[&hir::GenericBound<'_>], span: Span) -> bool { + pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { let tcx = self.tcx(); // Try to find an unbound in bounds. @@ -826,7 +820,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn add_bounds( &self, param_ty: Ty<'tcx>, - ast_bounds: &[&hir::GenericBound<'_>], + ast_bounds: &[hir::GenericBound<'_>], bounds: &mut Bounds<'tcx>, ) { let constness = self.default_constness_for_trait_bounds(); @@ -841,7 +835,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self .instantiate_lang_item_trait_ref( - *lang_item, *span, *hir_id, args, param_ty, bounds, + lang_item, span, hir_id, args, param_ty, bounds, ), hir::GenericBound::Outlives(ref l) => { bounds.region_bounds.push((self.ast_region_to_region(l, None), l.span)) @@ -872,42 +866,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ast_bounds: &[hir::GenericBound<'_>], sized_by_default: SizedByDefault, span: Span, - ) -> Bounds<'tcx> { - let ast_bounds: Vec<_> = ast_bounds.iter().collect(); - self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span) - } - - /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type - /// named `assoc_name` into ty::Bounds. Ignore the rest. - pub fn compute_bounds_that_match_assoc_type( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, - assoc_name: Ident, - ) -> Bounds<'tcx> { - let mut result = Vec::new(); - - for ast_bound in ast_bounds { - if let Some(trait_ref) = ast_bound.trait_ref() { - if let Some(trait_did) = trait_ref.trait_def_id() { - if self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) { - result.push(ast_bound); - } - } - } - } - - self.compute_bounds_inner(param_ty, &result, sized_by_default, span) - } - - fn compute_bounds_inner( - &self, - param_ty: Ty<'tcx>, - ast_bounds: &[&hir::GenericBound<'_>], - sized_by_default: SizedByDefault, - span: Span, ) -> Bounds<'tcx> { let mut bounds = Bounds::default(); @@ -1077,8 +1035,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` // parameter to have a skipped binder. let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs); - let ast_bounds: Vec<_> = ast_bounds.iter().collect(); - self.add_bounds(param_ty, &ast_bounds, bounds); + self.add_bounds(param_ty, ast_bounds, bounds); } } Ok(()) @@ -1395,9 +1352,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty_param_def_id, assoc_name, span, ); - let predicates = &self - .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name) - .predicates; + let predicates = + &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates; debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); @@ -1405,14 +1361,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_name = tcx.hir().ty_param_name(param_hir_id); self.one_bound_for_assoc_type( || { - traits::transitive_bounds_that_define_assoc_type( + traits::transitive_bounds( tcx, predicates.iter().filter_map(|(p, _)| { p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value) }), - assoc_name, ) - .into_iter() }, || param_name.to_string(), assoc_name, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 20c639a0031..f635e0b6f93 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -20,7 +20,6 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::Session; -use rustc_span::symbol::Ident; use rustc_span::{self, Span}; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; @@ -184,12 +183,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } } - fn get_type_parameter_bounds( - &self, - _: Span, - def_id: DefId, - _: Ident, - ) -> ty::GenericPredicates<'tcx> { + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let item_id = tcx.hir().ty_param_owner(hir_id); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index f8b7ccb2cd6..0ff10abb60a 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1,4 +1,3 @@ -// ignore-tidy-filelength //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned //! with *inter-procedural* things -- for example, for a function @@ -80,7 +79,6 @@ pub fn provide(providers: &mut Providers) { projection_ty_from_predicates, explicit_predicates_of, super_predicates_of, - super_predicates_that_define_assoc_type, trait_explicit_predicates_and_bounds, type_param_predicates, trait_def, @@ -312,17 +310,8 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } } - fn get_type_parameter_bounds( - &self, - span: Span, - def_id: DefId, - assoc_name: Ident, - ) -> ty::GenericPredicates<'tcx> { - self.tcx.at(span).type_param_predicates(( - self.item_def_id, - def_id.expect_local(), - assoc_name, - )) + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + self.tcx.at(span).type_param_predicates((self.item_def_id, def_id.expect_local())) } fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option> { @@ -503,7 +492,7 @@ fn get_new_lifetime_name<'tcx>( /// `X: Foo` where `X` is the type parameter `def_id`. fn type_param_predicates( tcx: TyCtxt<'_>, - (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident), + (item_def_id, def_id): (DefId, LocalDefId), ) -> ty::GenericPredicates<'_> { use rustc_hir::*; @@ -528,7 +517,7 @@ fn type_param_predicates( let mut result = parent .map(|parent| { let icx = ItemCtxt::new(tcx, parent); - icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name) + icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id()) }) .unwrap_or_default(); let mut extend = None; @@ -571,18 +560,12 @@ fn type_param_predicates( let icx = ItemCtxt::new(tcx, item_def_id); let extra_predicates = extend.into_iter().chain( - icx.type_parameter_bounds_in_generics( - ast_generics, - param_id, - ty, - OnlySelfBounds(true), - Some(assoc_name), - ) - .into_iter() - .filter(|(predicate, _)| match predicate.skip_binders() { - ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index), - _ => false, - }), + icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true)) + .into_iter() + .filter(|(predicate, _)| match predicate.skip_binders() { + ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index), + _ => false, + }), ); result.predicates = tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates)); @@ -600,7 +583,6 @@ impl ItemCtxt<'tcx> { param_id: hir::HirId, ty: Ty<'tcx>, only_self_bounds: OnlySelfBounds, - assoc_name: Option, ) -> Vec<(ty::Predicate<'tcx>, Span)> { let constness = self.default_constness_for_trait_bounds(); let from_ty_params = ast_generics @@ -611,10 +593,6 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bounds| bounds.iter()) - .filter(|b| match assoc_name { - Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name), - None => true, - }) .flat_map(|b| predicates_from_bound(self, ty, b, constness)); let from_where_clauses = ast_generics @@ -633,34 +611,12 @@ impl ItemCtxt<'tcx> { } else { None }; - bp.bounds - .iter() - .filter(|b| match assoc_name { - Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name), - None => true, - }) - .filter_map(move |b| bt.map(|bt| (bt, b))) + bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b))) }) .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness)); from_ty_params.chain(from_where_clauses).collect() } - - fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool { - debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name); - - match b { - hir::GenericBound::Trait(poly_trait_ref, _) => { - let trait_ref = &poly_trait_ref.trait_ref; - if let Some(trait_did) = trait_ref.trait_def_id() { - self.tcx.trait_may_define_assoc_type(trait_did, assoc_name) - } else { - false - } - } - _ => false, - } - } } /// Tests whether this is the AST for a reference to the type @@ -1029,90 +985,54 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef { /// the transitive super-predicates are converted. fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> { debug!("super_predicates(trait_def_id={:?})", trait_def_id); - tcx.super_predicates_that_define_assoc_type((trait_def_id, None)) -} - -/// Ensures that the super-predicates of the trait with a `DefId` -/// of `trait_def_id` are converted and stored. This also ensures that -/// the transitive super-predicates are converted. -fn super_predicates_that_define_assoc_type( - tcx: TyCtxt<'_>, - (trait_def_id, assoc_name): (DefId, Option), -) -> ty::GenericPredicates<'_> { - debug!( - "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})", - trait_def_id, assoc_name - ); - if trait_def_id.is_local() { - debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id); - let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); - - let item = match tcx.hir().get(trait_hir_id) { - Node::Item(item) => item, - _ => bug!("trait_node_id {} is not an item", trait_hir_id), - }; + let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); - let (generics, bounds) = match item.kind { - hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), - _ => span_bug!(item.span, "super_predicates invoked on non-trait"), - }; - - let icx = ItemCtxt::new(tcx, trait_def_id); + let item = match tcx.hir().get(trait_hir_id) { + Node::Item(item) => item, + _ => bug!("trait_node_id {} is not an item", trait_hir_id), + }; - // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. - let self_param_ty = tcx.types.self_param; - let superbounds1 = if let Some(assoc_name) = assoc_name { - AstConv::compute_bounds_that_match_assoc_type( - &icx, - self_param_ty, - &bounds, - SizedByDefault::No, - item.span, - assoc_name, - ) - } else { - AstConv::compute_bounds(&icx, self_param_ty, &bounds, SizedByDefault::No, item.span) - }; + let (generics, bounds) = match item.kind { + hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), + hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), + _ => span_bug!(item.span, "super_predicates invoked on non-trait"), + }; - let superbounds1 = superbounds1.predicates(tcx, self_param_ty); + let icx = ItemCtxt::new(tcx, trait_def_id); + + // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. + let self_param_ty = tcx.types.self_param; + let superbounds1 = + AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); + + let superbounds1 = superbounds1.predicates(tcx, self_param_ty); + + // Convert any explicit superbounds in the where-clause, + // e.g., `trait Foo where Self: Bar`. + // In the case of trait aliases, however, we include all bounds in the where-clause, + // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` + // as one of its "superpredicates". + let is_trait_alias = tcx.is_trait_alias(trait_def_id); + let superbounds2 = icx.type_parameter_bounds_in_generics( + generics, + item.hir_id, + self_param_ty, + OnlySelfBounds(!is_trait_alias), + ); - // Convert any explicit superbounds in the where-clause, - // e.g., `trait Foo where Self: Bar`. - // In the case of trait aliases, however, we include all bounds in the where-clause, - // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` - // as one of its "superpredicates". - let is_trait_alias = tcx.is_trait_alias(trait_def_id); - let superbounds2 = icx.type_parameter_bounds_in_generics( - generics, - item.hir_id, - self_param_ty, - OnlySelfBounds(!is_trait_alias), - assoc_name, - ); + // Combine the two lists to form the complete set of superbounds: + let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); - // Combine the two lists to form the complete set of superbounds: - let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); - - // Now require that immediate supertraits are converted, - // which will, in turn, reach indirect supertraits. - if assoc_name.is_none() { - // FIXME: move this into the `super_predicates_of` query - for &(pred, span) in superbounds { - debug!("superbound: {:?}", pred); - if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() { - tcx.at(span).super_predicates_of(bound.def_id()); - } - } + // Now require that immediate supertraits are converted, + // which will, in turn, reach indirect supertraits. + for &(pred, span) in superbounds { + debug!("superbound: {:?}", pred); + if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() { + tcx.at(span).super_predicates_of(bound.def_id()); } - - ty::GenericPredicates { parent: None, predicates: superbounds } - } else { - // if `assoc_name` is None, then the query should've been redirected to an - // external provider - assert!(assoc_name.is_some()); - tcx.super_predicates_of(trait_def_id) } + + ty::GenericPredicates { parent: None, predicates: superbounds } } fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index dd1da7d9cff..e596dd1a396 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -28,7 +28,7 @@ fn associated_type_bounds<'tcx>( let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, assoc_item_def_id), item_ty, - &bounds, + bounds, SizedByDefault::Yes, span, ); @@ -68,7 +68,7 @@ fn opaque_type_bounds<'tcx>( let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, opaque_def_id), item_ty, - &bounds, + bounds, SizedByDefault::Yes, span, ) diff --git a/src/test/incremental/cyclic-trait-hierarchy.rs b/src/test/incremental/cyclic-trait-hierarchy.rs index b502e7207d5..03bb5eea765 100644 --- a/src/test/incremental/cyclic-trait-hierarchy.rs +++ b/src/test/incremental/cyclic-trait-hierarchy.rs @@ -3,11 +3,11 @@ // revisions: rpass1 cfail2 #[cfg(rpass1)] -pub trait T2 {} +pub trait T2 { } #[cfg(cfail2)] -pub trait T2: T1 {} -//[cfail2]~^ ERROR cycle detected when computing the super predicates of `T2` +pub trait T2: T1 { } +//[cfail2]~^ ERROR cycle detected when computing the supertraits of `T2` -pub trait T1: T2 {} +pub trait T1: T2 { } -fn main() {} +fn main() { } diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs deleted file mode 100644 index 1b6d6d0ff59..00000000000 --- a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs +++ /dev/null @@ -1,12 +0,0 @@ -// ignore-tidy-linelength - -trait Foo { - type Item; -} -trait Bar { - type Item; -} -trait Baz: Foo + Bar {} -//~^ ERROR cycle detected when computing the super traits of `Baz` with associated type name `Item` [E0391] - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr deleted file mode 100644 index bda1debeac0..00000000000 --- a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0391]: cycle detected when computing the super traits of `Baz` with associated type name `Item` - --> $DIR/ambiguous-associated-type2.rs:9:1 - | -LL | trait Baz: Foo + Bar {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which again requires computing the super traits of `Baz` with associated type name `Item`, completing the cycle -note: cycle used when computing the super traits of `Baz` - --> $DIR/ambiguous-associated-type2.rs:9:1 - | -LL | trait Baz: Foo + Bar {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs b/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs deleted file mode 100644 index 3eb50ab5547..00000000000 --- a/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs +++ /dev/null @@ -1,21 +0,0 @@ -// check-pass - -trait Foo { - type Item; -} - -trait Bar -where - Self: Foo, -{ -} - -#[allow(dead_code)] -fn foo(_m: M) -where - M: Bar, - M::Item: Send, -{ -} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs b/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs deleted file mode 100644 index b1e54ec0449..00000000000 --- a/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs +++ /dev/null @@ -1,10 +0,0 @@ -// check-pass - -trait Foo {} -trait Bar { - type A; - type B; -} -trait Baz: Bar + Foo {} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs deleted file mode 100644 index 07d0f8f8769..00000000000 --- a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[allow(dead_code)] -fn foo(_m: M) -where - M::Item: Temp, - //~^ ERROR cannot find trait `Temp` in this scope [E0405] - //~| ERROR associated type `Item` not found for `M` [E0220] -{ -} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr deleted file mode 100644 index bc2807b0396..00000000000 --- a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0405]: cannot find trait `Temp` in this scope - --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:14 - | -LL | M::Item: Temp, - | ^^^^ not found in this scope - -error[E0220]: associated type `Item` not found for `M` - --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:8 - | -LL | M::Item: Temp, - | ^^^^ associated type `Item` not found - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0220, E0405. -For more information about an error, try `rustc --explain E0220`. diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs b/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs deleted file mode 100644 index c82ec01f4d6..00000000000 --- a/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs +++ /dev/null @@ -1,12 +0,0 @@ -// check-pass -trait Foo { - type Bar; -} -trait Qux: Foo + AsRef {} -trait Foo2 {} - -trait Qux2: Foo2 + AsRef { - type Bar; -} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing.rs b/src/test/ui/associated-type-bounds/super-trait-referencing.rs deleted file mode 100644 index 2e97535157f..00000000000 --- a/src/test/ui/associated-type-bounds/super-trait-referencing.rs +++ /dev/null @@ -1,19 +0,0 @@ -// check-pass - -// The goal of this test is to ensure that T: Bar -// in the where clause does not cycle - -trait Foo { - type Item; -} - -trait Bar {} - -fn baz() -where - T: Foo, - T: Bar, -{ -} - -fn main() {} diff --git a/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs b/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs deleted file mode 100644 index 72a6be9ffc3..00000000000 --- a/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs +++ /dev/null @@ -1,27 +0,0 @@ -// check-pass - -// Test that we do not get a cycle due to -// resolving `Self::Bar` in the where clauses -// on a trait definition (in particular, in -// a where clause that is defining a superpredicate). - -trait Foo { - type Bar; -} -trait Qux -where - Self: Foo, - Self: AsRef, -{ -} -trait Foo2 {} - -trait Qux2 -where - Self: Foo2, - Self: AsRef, -{ - type Bar; -} - -fn main() {} diff --git a/src/test/ui/cycle-projection-based-on-where-clause.rs b/src/test/ui/cycle-projection-based-on-where-clause.rs new file mode 100644 index 00000000000..d3609acfdff --- /dev/null +++ b/src/test/ui/cycle-projection-based-on-where-clause.rs @@ -0,0 +1,24 @@ +// Example cycle where a bound on `T` uses a shorthand for `T`. This +// creates a cycle because we have to know the bounds on `T` to figure +// out what trait defines `Item`, but we can't know the bounds on `T` +// without knowing how to handle `T::Item`. +// +// Note that in the future cases like this could perhaps become legal, +// if we got more fine-grained about our cycle detection or changed +// how we handle `T::Item` resolution. + +use std::ops::Add; + +// Preamble. +trait Trait { type Item; } + +struct A + where T : Trait, + T : Add + //~^ ERROR cycle detected +{ + data: T +} + +fn main() { +} diff --git a/src/test/ui/cycle-projection-based-on-where-clause.stderr b/src/test/ui/cycle-projection-based-on-where-clause.stderr new file mode 100644 index 00000000000..2c337cc6bf9 --- /dev/null +++ b/src/test/ui/cycle-projection-based-on-where-clause.stderr @@ -0,0 +1,16 @@ +error[E0391]: cycle detected when computing the bounds for type parameter `T` + --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 + | +LL | T : Add + | ^^^^^^^ + | + = note: ...which again requires computing the bounds for type parameter `T`, completing the cycle +note: cycle used when computing explicit predicates of `A` + --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 + | +LL | T : Add + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr index ee54b2fd151..8aa3ac8abf5 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr @@ -1,15 +1,10 @@ -error[E0391]: cycle detected when computing the super predicates of `Chromosome` - --> $DIR/cycle-trait-supertrait-direct.rs:3:1 - | -LL | trait Chromosome: Chromosome { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `Chromosome`... +error[E0391]: cycle detected when computing the supertraits of `Chromosome` --> $DIR/cycle-trait-supertrait-direct.rs:3:19 | LL | trait Chromosome: Chromosome { | ^^^^^^^^^^ - = note: ...which again requires computing the super predicates of `Chromosome`, completing the cycle + | + = note: ...which again requires computing the supertraits of `Chromosome`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-supertrait-direct.rs:3:1 | diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr index 0a2284e0efb..9740f43a4ba 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr @@ -1,26 +1,16 @@ -error[E0391]: cycle detected when computing the super predicates of `B` - --> $DIR/cycle-trait-supertrait-indirect.rs:7:1 - | -LL | trait B: C { - | ^^^^^^^^^^ - | -note: ...which requires computing the super traits of `B`... +error[E0391]: cycle detected when computing the supertraits of `B` --> $DIR/cycle-trait-supertrait-indirect.rs:7:10 | LL | trait B: C { | ^ -note: ...which requires computing the super predicates of `C`... - --> $DIR/cycle-trait-supertrait-indirect.rs:11:1 | -LL | trait C: B { } - | ^^^^^^^^^^ -note: ...which requires computing the super traits of `C`... +note: ...which requires computing the supertraits of `C`... --> $DIR/cycle-trait-supertrait-indirect.rs:11:10 | LL | trait C: B { } | ^ - = note: ...which again requires computing the super predicates of `B`, completing the cycle -note: cycle used when computing the super traits of `A` + = note: ...which again requires computing the supertraits of `B`, completing the cycle +note: cycle used when computing the supertraits of `A` --> $DIR/cycle-trait-supertrait-indirect.rs:4:10 | LL | trait A: B { diff --git a/src/test/ui/issues/issue-12511.stderr b/src/test/ui/issues/issue-12511.stderr index 5f2b98c5237..37e38ff60ae 100644 --- a/src/test/ui/issues/issue-12511.stderr +++ b/src/test/ui/issues/issue-12511.stderr @@ -1,25 +1,15 @@ -error[E0391]: cycle detected when computing the super predicates of `T1` - --> $DIR/issue-12511.rs:1:1 - | -LL | trait T1 : T2 { - | ^^^^^^^^^^^^^ - | -note: ...which requires computing the super traits of `T1`... +error[E0391]: cycle detected when computing the supertraits of `T1` --> $DIR/issue-12511.rs:1:12 | LL | trait T1 : T2 { | ^^ -note: ...which requires computing the super predicates of `T2`... - --> $DIR/issue-12511.rs:5:1 | -LL | trait T2 : T1 { - | ^^^^^^^^^^^^^ -note: ...which requires computing the super traits of `T2`... +note: ...which requires computing the supertraits of `T2`... --> $DIR/issue-12511.rs:5:12 | LL | trait T2 : T1 { | ^^ - = note: ...which again requires computing the super predicates of `T1`, completing the cycle + = note: ...which again requires computing the supertraits of `T1`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-12511.rs:1:1 | diff --git a/src/test/ui/issues/issue-20772.stderr b/src/test/ui/issues/issue-20772.stderr index 4aecc7eab46..d64636310a3 100644 --- a/src/test/ui/issues/issue-20772.stderr +++ b/src/test/ui/issues/issue-20772.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing the super traits of `T` with associated type name `Item` +error[E0391]: cycle detected when computing the supertraits of `T` --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator @@ -6,8 +6,8 @@ LL | | LL | | {} | |__^ | - = note: ...which again requires computing the super traits of `T` with associated type name `Item`, completing the cycle -note: cycle used when computing the super traits of `T` + = note: ...which again requires computing the supertraits of `T`, completing the cycle +note: cycle used when collecting item types in top-level module --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator diff --git a/src/test/ui/issues/issue-20825.stderr b/src/test/ui/issues/issue-20825.stderr index ccbe06d9c0d..5f9709d1c64 100644 --- a/src/test/ui/issues/issue-20825.stderr +++ b/src/test/ui/issues/issue-20825.stderr @@ -1,11 +1,11 @@ -error[E0391]: cycle detected when computing the super traits of `Processor` with associated type name `Input` +error[E0391]: cycle detected when computing the supertraits of `Processor` --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing the super traits of `Processor` with associated type name `Input`, completing the cycle -note: cycle used when computing the super traits of `Processor` + = note: ...which again requires computing the supertraits of `Processor`, completing the cycle +note: cycle used when collecting item types in top-level module --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { diff --git a/src/test/ui/issues/issue-22673.rs b/src/test/ui/issues/issue-22673.rs index 4b9b4d6b23d..ba8057b684d 100644 --- a/src/test/ui/issues/issue-22673.rs +++ b/src/test/ui/issues/issue-22673.rs @@ -1,6 +1,5 @@ -// check-pass - -trait Expr: PartialEq { +trait Expr : PartialEq { + //~^ ERROR: cycle detected type Item; } diff --git a/src/test/ui/issues/issue-22673.stderr b/src/test/ui/issues/issue-22673.stderr new file mode 100644 index 00000000000..9e7e4b218b1 --- /dev/null +++ b/src/test/ui/issues/issue-22673.stderr @@ -0,0 +1,16 @@ +error[E0391]: cycle detected when computing the supertraits of `Expr` + --> $DIR/issue-22673.rs:1:1 + | +LL | trait Expr : PartialEq { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ...which again requires computing the supertraits of `Expr`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/issue-22673.rs:1:1 + | +LL | trait Expr : PartialEq { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. From 4e7a2dcabb0aa42f297284ead946d5787027d035 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 2 Dec 2020 10:07:29 -0500 Subject: [PATCH 151/274] Use `item_name` instead of pretty printing Pretty printing would add a `r#` prefix to raw identifiers, which was not correct. In general I think this change makes sense - pretty-printing is for showing to the *user*, `item_name` is suitable to pass to resolve. --- src/librustdoc/passes/collect_intra_doc_links.rs | 13 +++++++++---- src/test/rustdoc/intra-doc/raw-ident-self.rs | 13 +++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 src/test/rustdoc/intra-doc/raw-ident-self.rs diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3dcc0f240a3..551c086a8d4 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -847,12 +847,17 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly let self_name = self_id.and_then(|self_id| { + use ty::TyKind; if matches!(self.cx.tcx.def_kind(self_id), DefKind::Impl) { - // using `ty.to_string()` directly has issues with shortening paths + // using `ty.to_string()` (or any variant) has issues with raw idents let ty = self.cx.tcx.type_of(self_id); - let name = ty::print::with_crate_prefix(|| ty.to_string()); - debug!("using type_of(): {}", name); - Some(name) + let name = match ty.kind() { + TyKind::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()), + other if other.is_primitive() => Some(ty.to_string()), + _ => None, + }; + debug!("using type_of(): {:?}", name); + name } else { let name = self.cx.tcx.opt_item_name(self_id).map(|sym| sym.to_string()); debug!("using item_name(): {:?}", name); diff --git a/src/test/rustdoc/intra-doc/raw-ident-self.rs b/src/test/rustdoc/intra-doc/raw-ident-self.rs new file mode 100644 index 00000000000..d289797f146 --- /dev/null +++ b/src/test/rustdoc/intra-doc/raw-ident-self.rs @@ -0,0 +1,13 @@ +#![deny(broken_intra_doc_links)] +pub mod r#impl { + pub struct S; + + impl S { + /// See [Self::b]. + // @has raw_ident_self/impl/struct.S.html + // @has - '//a[@href="../../raw_ident_self/impl/struct.S.html#method.b"]' 'Self::b' + pub fn a() {} + + pub fn b() {} + } +} From 0273f6f849270a798761e056382f859063c69e21 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Wed, 2 Dec 2020 08:50:17 -0800 Subject: [PATCH 152/274] Add a doctest example of str::split on a slice of chars This is mentioned as supported, but the semantics are not described. --- library/core/src/str/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index a944514f694..83cf47c8c8f 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1131,6 +1131,13 @@ impl str { /// assert_eq!(v, ["lion", "tiger", "leopard"]); /// ``` /// + /// If the pattern is a slice of chars, split on each occurrence of any of the characters: + /// + /// ``` + /// let v: Vec<&str> = "2020-11-03 23:59".split(&['-', ' ', ':', '@'][..]).collect(); + /// assert_eq!(v, ["2020", "11", "03", "23", "59"]); + /// ``` + /// /// A more complex pattern, using a closure: /// /// ``` From f311db100ba338d13a6f590288e027623a8e9434 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 19:14:10 +0100 Subject: [PATCH 153/274] Added tests for assume_init --- library/core/tests/mem.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 59588d97787..7822c69d10b 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -129,3 +129,21 @@ fn test_discriminant_send_sync() { is_send_sync::>(); is_send_sync::>(); } + +#[test] +fn assume_init_good() { + const TRUE: bool = { + let mut x = MaybeUninit::::uninit(); + x.as_mut_ptr().write(true); + x.assume_init() + }; + assert!(TRUE); +} + +#[test] +#[should_panic] +fn assume_init_bad() { + const BAD: () = { + MaybeUninit::::uninit().assume_init(); + }; +} From 9866136bec0040993f26e8c4b7316fb0a5dc94b5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Dec 2020 23:42:07 +0100 Subject: [PATCH 154/274] Add tests for #[doc(keyword = "...")] and update other doc attributes tests --- .../rustdoc-ui/check-doc-alias-attr.stderr | 6 +++--- src/test/ui/check-doc-alias-attr.stderr | 6 +++--- src/test/ui/doc-alias-crate-level.rs | 5 ++++- src/test/ui/doc-alias-crate-level.stderr | 14 +++++++++---- src/test/ui/doc_keyword.rs | 12 +++++++++++ src/test/ui/doc_keyword.stderr | 20 +++++++++++++++++++ 6 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/doc_keyword.rs create mode 100644 src/test/ui/doc_keyword.stderr diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr index 3ba0ba61075..1c7fc83bb8d 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr @@ -1,16 +1,16 @@ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:6:7 | LL | #[doc(alias)] | ^^^^^ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:7:7 | LL | #[doc(alias = 0)] | ^^^^^^^^^ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:8:7 | LL | #[doc(alias("bar"))] diff --git a/src/test/ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr index a92298d1633..dce325f9d38 100644 --- a/src/test/ui/check-doc-alias-attr.stderr +++ b/src/test/ui/check-doc-alias-attr.stderr @@ -1,16 +1,16 @@ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:7:7 | LL | #[doc(alias)] | ^^^^^ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:8:7 | LL | #[doc(alias = 0)] | ^^^^^^^^^ -error: doc alias attribute expects a string: #[doc(alias = "0")] +error: doc alias attribute expects a string: #[doc(alias = "a")] --> $DIR/check-doc-alias-attr.rs:9:7 | LL | #[doc(alias("bar"))] diff --git a/src/test/ui/doc-alias-crate-level.rs b/src/test/ui/doc-alias-crate-level.rs index b1b17f2de8a..9b596ece5b5 100644 --- a/src/test/ui/doc-alias-crate-level.rs +++ b/src/test/ui/doc-alias-crate-level.rs @@ -4,4 +4,7 @@ #![crate_type = "lib"] -#![doc(alias = "shouldn't work!")] //~ ERROR +#![doc(alias = "not working!")] //~ ERROR + +#[doc(alias = "shouldn't work!")] //~ ERROR +pub struct Foo; diff --git a/src/test/ui/doc-alias-crate-level.stderr b/src/test/ui/doc-alias-crate-level.stderr index 32b42cf9be7..b6437fad5d0 100644 --- a/src/test/ui/doc-alias-crate-level.stderr +++ b/src/test/ui/doc-alias-crate-level.stderr @@ -1,8 +1,14 @@ error: '\'' character isn't allowed in `#[doc(alias = "...")]` - --> $DIR/doc-alias-crate-level.rs:7:16 + --> $DIR/doc-alias-crate-level.rs:9:15 | -LL | #![doc(alias = "shouldn't work!")] - | ^^^^^^^^^^^^^^^^^ +LL | #[doc(alias = "shouldn't work!")] + | ^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: `#![doc(alias = "...")]` isn't allowed as a crate level attribute + --> $DIR/doc-alias-crate-level.rs:7:8 + | +LL | #![doc(alias = "not working!")] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/doc_keyword.rs b/src/test/ui/doc_keyword.rs new file mode 100644 index 00000000000..4c72e7e9684 --- /dev/null +++ b/src/test/ui/doc_keyword.rs @@ -0,0 +1,12 @@ +#![crate_type = "lib"] +#![feature(doc_keyword)] + +#![doc(keyword = "hello")] //~ ERROR + +#[doc(keyword = "hell")] //~ ERROR +mod foo { + fn hell() {} +} + +#[doc(keyword = "hall")] //~ ERROR +fn foo() {} diff --git a/src/test/ui/doc_keyword.stderr b/src/test/ui/doc_keyword.stderr new file mode 100644 index 00000000000..d72a876163e --- /dev/null +++ b/src/test/ui/doc_keyword.stderr @@ -0,0 +1,20 @@ +error: `#[doc(keyword = "...")]` can only be used on empty modules + --> $DIR/doc_keyword.rs:6:7 + | +LL | #[doc(keyword = "hell")] + | ^^^^^^^^^^^^^^^^ + +error: `#[doc(keyword = "...")]` can only be used on modules + --> $DIR/doc_keyword.rs:11:7 + | +LL | #[doc(keyword = "hall")] + | ^^^^^^^^^^^^^^^^ + +error: `#![doc(keyword = "...")]` isn't allowed as a crate level attribute + --> $DIR/doc_keyword.rs:4:8 + | +LL | #![doc(keyword = "hello")] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + From 15f9453a260ffc035ea3797c6939b1f61acd3e6d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 2 Dec 2020 10:44:19 +0100 Subject: [PATCH 155/274] Remove check keyword identifier check from rustdoc --- src/librustdoc/clean/mod.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cd2700be5a7..a3c28be3137 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -169,19 +169,7 @@ impl Clean for CrateNum { for attr in attrs.lists(sym::doc) { if attr.has_name(sym::keyword) { if let Some(v) = attr.value_str() { - let k = v.to_string(); - if !rustc_lexer::is_ident(&k) { - let sp = get_span(&attr).unwrap_or_else(|| attr.span()); - cx.tcx - .sess - .struct_span_err( - sp, - &format!("`{}` is not a valid identifier", v), - ) - .emit(); - } else { - keyword = Some(k); - } + keyword = Some(v.to_string()); break; } } From 4f9fd2a5d45a0ea0c49a3a78f8f1c8e091b9c604 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 2 Dec 2020 21:07:40 +0100 Subject: [PATCH 156/274] Undo fn -> const fn for all intrinsics but assert_inhabited --- compiler/rustc_mir/src/interpret/intrinsics.rs | 18 +----------------- library/core/src/intrinsics.rs | 2 -- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index c751f4f7eb6..90018673e1a 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -407,29 +407,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::transmute => { self.copy_op_transmute(args[0], dest)?; } - sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { + sym::assert_inhabited => { let ty = instance.substs.type_at(0); let layout = self.layout_of(ty)?; if layout.abi.is_uninhabited() { throw_ub_format!("attempted to instantiate uninhabited type `{}`", ty); } - if intrinsic_name == sym::assert_zero_valid - && !layout.might_permit_raw_init(self, /*zero:*/ true).unwrap() - { - throw_ub_format!( - "attempted to zero-initialize type `{}`, which is invalid", - ty - ); - } - if intrinsic_name == sym::assert_uninit_valid - && !layout.might_permit_raw_init(self, /*zero:*/ false).unwrap() - { - throw_ub_format!( - "attempted to leave type `{}` uninitialized, which is invalid", - ty - ); - } } sym::simd_insert => { let index = u64::from(self.read_scalar(args[1])?.to_u32()?); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 0c37bec4698..ac31476f227 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -822,14 +822,12 @@ extern "rust-intrinsic" { /// zero-initialization: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_zero_valid(); /// A guard for unsafe functions that cannot ever be executed if `T` has invalid /// bit patterns: This will statically either panic, or do nothing. /// /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_assert_type", issue = "none")] pub fn assert_uninit_valid(); /// Gets a reference to a static `Location` indicating where it was called. From 908bf5a310b7265a3e7c1d1fa021e3b10aa67293 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 2 Dec 2020 23:39:05 +0300 Subject: [PATCH 157/274] rustc_metadata: Remove some dead code --- compiler/rustc_metadata/src/rmeta/decoder.rs | 17 ----------------- .../src/rmeta/decoder/cstore_impl.rs | 12 ++++-------- compiler/rustc_middle/src/middle/cstore.rs | 2 -- src/librustdoc/core.rs | 1 - 4 files changed, 4 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f53a4027806..c571ed7b612 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1592,23 +1592,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.def_path_hash_unlocked(index, &mut def_path_hashes) } - fn all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> { - let mut def_path_hashes = self.def_path_hash_cache.lock(); - let mut def_index_to_data = |index| { - (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) - }; - if let Some(data) = &self.root.proc_macro_data { - std::iter::once(CRATE_DEF_INDEX) - .chain(data.macros.decode(self)) - .map(def_index_to_data) - .collect() - } else { - (0..self.num_def_ids()) - .map(|index| def_index_to_data(DefIndex::from_usize(index))) - .collect() - } - } - /// Get the `DepNodeIndex` corresponding this crate. The result of this /// method is cached in the `dep_node_index` field. fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 2ffd239b2f0..b7f22885217 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -456,6 +456,10 @@ impl CStore { pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId { self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess) } + + pub fn num_def_ids(&self, cnum: CrateNum) -> usize { + self.get_crate_data(cnum).num_def_ids() + } } impl CrateStore for CStore { @@ -498,14 +502,6 @@ impl CrateStore for CStore { self.get_crate_data(def.krate).def_path_hash(def.index) } - fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)> { - self.get_crate_data(cnum).all_def_path_hashes_and_def_ids() - } - - fn num_def_ids(&self, cnum: CrateNum) -> usize { - self.get_crate_data(cnum).num_def_ids() - } - // See `CrateMetadataRef::def_path_hash_to_def_id` for more details fn def_path_hash_to_def_id( &self, diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index bd7121ca1d7..6d2c43874bc 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -189,8 +189,6 @@ pub trait CrateStore { fn def_kind(&self, def: DefId) -> DefKind; fn def_path(&self, def: DefId) -> DefPath; fn def_path_hash(&self, def: DefId) -> DefPathHash; - fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>; - fn num_def_ids(&self, cnum: CrateNum) -> usize; fn def_path_hash_to_def_id( &self, cnum: CrateNum, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b63acdc114e..97117ab1341 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,7 +13,6 @@ use rustc_hir::{ }; use rustc_interface::interface; use rustc_middle::hir::map::Map; -use rustc_middle::middle::cstore::CrateStore; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_resolve as resolve; From d619271f2bf90a4fce327ef868920ef39ee22a4c Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 2 Dec 2020 20:41:20 +0000 Subject: [PATCH 158/274] Normalize windows path seperators. --- src/test/rustdoc-json/compare.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/test/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py index 422e48ea39a..b0c5b16a197 100644 --- a/src/test/rustdoc-json/compare.py +++ b/src/test/rustdoc-json/compare.py @@ -4,7 +4,8 @@ # The comparison is independent of the value of IDs (which are unstable) and instead uses their # relative ordering to check them against eachother by looking them up in their respective blob's # `index` or `paths` mappings. To add a new test run `rustdoc --output-format json -o . yourtest.rs` -# and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. +# and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. If +# you're on windows, replace `\` with `/`. import copy import sys @@ -36,7 +37,7 @@ def _check_subset(expected, actual, trace): actual_type = type(actual) if actual_type is str: - actual = actual.replace(base_dir, "$TEST_BASE_DIR") + actual = normalize(actual).replace(base_dir, "$TEST_BASE_DIR") if expected_type is not actual_type: raise SubsetException( @@ -118,9 +119,11 @@ def main(expected_fpath, actual_fpath, base_dir): check_subset(expected_main, actual_main, base_dir) print("all checks passed") +def normalize(s): + return s.replace('\\', '/') if __name__ == "__main__": if len(sys.argv) < 4: print("Usage: `compare.py expected.json actual.json test-dir`") else: - main(sys.argv[1], sys.argv[2], sys.argv[3]) + main(sys.argv[1], sys.argv[2], normalize(sys.argv[3])) From 9b390e73db26f17415dfeab2e49f13f04ad2474b Mon Sep 17 00:00:00 2001 From: The8472 Date: Wed, 2 Dec 2020 23:33:17 +0100 Subject: [PATCH 159/274] update test to check Take limits after copying --- library/std/src/sys/unix/kernel_copy/tests.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy/tests.rs b/library/std/src/sys/unix/kernel_copy/tests.rs index 554ebd94022..79e99382591 100644 --- a/library/std/src/sys/unix/kernel_copy/tests.rs +++ b/library/std/src/sys/unix/kernel_copy/tests.rs @@ -42,8 +42,15 @@ fn copy_specialization() -> Result<()> { assert_eq!(sink.buffer(), b"wxyz"); let copied = crate::io::copy(&mut source, &mut sink)?; - assert_eq!(copied, 10); - assert_eq!(sink.buffer().len(), 0); + assert_eq!(copied, 10, "copy obeyed limit imposed by Take"); + assert_eq!(sink.buffer().len(), 0, "sink buffer was flushed"); + assert_eq!(source.limit(), 0, "outer Take was exhausted"); + assert_eq!(source.get_ref().buffer().len(), 0, "source buffer should be drained"); + assert_eq!( + source.get_ref().get_ref().limit(), + 1, + "inner Take allowed reading beyond end of file, some bytes should be left" + ); let mut sink = sink.into_inner()?; sink.seek(SeekFrom::Start(0))?; From a9b1381b8dd0704966a5c2ab7e4ca0ff96d05a18 Mon Sep 17 00:00:00 2001 From: The8472 Date: Wed, 2 Dec 2020 23:35:40 +0100 Subject: [PATCH 160/274] fix copy specialization not updating Take wrappers --- library/std/src/sys/unix/fs.rs | 3 +- library/std/src/sys/unix/kernel_copy.rs | 54 ++++++++++++++----- library/std/src/sys/unix/kernel_copy/tests.rs | 2 +- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index e2f0870ef0e..d1b0ad9e5f8 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1211,7 +1211,8 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { use super::kernel_copy::{copy_regular_files, CopyResult}; match copy_regular_files(reader.as_raw_fd(), writer.as_raw_fd(), max_len) { - CopyResult::Ended(result) => result, + CopyResult::Ended(bytes) => Ok(bytes), + CopyResult::Error(e, _) => Err(e), CopyResult::Fallback(written) => match io::copy::generic_copy(&mut reader, &mut writer) { Ok(bytes) => Ok(bytes + written), Err(e) => Err(e), diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index f08c828ecff..5bfac803153 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -167,10 +167,11 @@ impl SpecCopy for Copier<'_, '_, R, W> { if input_meta.copy_file_range_candidate() && output_meta.copy_file_range_candidate() { let result = copy_regular_files(readfd, writefd, max_write); + result.update_take(reader); match result { - CopyResult::Ended(Ok(bytes_copied)) => return Ok(bytes_copied + written), - CopyResult::Ended(err) => return err, + CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written), + CopyResult::Error(e, _) => return Err(e), CopyResult::Fallback(bytes) => written += bytes, } } @@ -182,20 +183,22 @@ impl SpecCopy for Copier<'_, '_, R, W> { // fall back to the generic copy loop. if input_meta.potential_sendfile_source() { let result = sendfile_splice(SpliceMode::Sendfile, readfd, writefd, max_write); + result.update_take(reader); match result { - CopyResult::Ended(Ok(bytes_copied)) => return Ok(bytes_copied + written), - CopyResult::Ended(err) => return err, + CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written), + CopyResult::Error(e, _) => return Err(e), CopyResult::Fallback(bytes) => written += bytes, } } if input_meta.maybe_fifo() || output_meta.maybe_fifo() { let result = sendfile_splice(SpliceMode::Splice, readfd, writefd, max_write); + result.update_take(reader); match result { - CopyResult::Ended(Ok(bytes_copied)) => return Ok(bytes_copied + written), - CopyResult::Ended(err) => return err, + CopyResult::Ended(bytes_copied) => return Ok(bytes_copied + written), + CopyResult::Error(e, _) => return Err(e), CopyResult::Fallback(0) => { /* use the fallback below */ } CopyResult::Fallback(_) => { unreachable!("splice should not return > 0 bytes on the fallback path") @@ -225,6 +228,9 @@ trait CopyRead: Read { Ok(0) } + /// Updates `Take` wrappers to remove the number of bytes copied. + fn taken(&mut self, _bytes: u64) {} + /// The minimum of the limit of all `Take<_>` wrappers, `u64::MAX` otherwise. /// This method does not account for data `BufReader` buffers and would underreport /// the limit of a `Take>>` type. Thus its result is only valid @@ -251,6 +257,10 @@ where (**self).drain_to(writer, limit) } + fn taken(&mut self, bytes: u64) { + (**self).taken(bytes); + } + fn min_limit(&self) -> u64 { (**self).min_limit() } @@ -407,6 +417,11 @@ impl CopyRead for Take { Ok(bytes_drained) } + fn taken(&mut self, bytes: u64) { + self.set_limit(self.limit() - bytes); + self.get_mut().taken(bytes); + } + fn min_limit(&self) -> u64 { min(Take::limit(self), self.get_ref().min_limit()) } @@ -432,6 +447,10 @@ impl CopyRead for BufReader { Ok(bytes as u64 + inner_bytes) } + fn taken(&mut self, bytes: u64) { + self.get_mut().taken(bytes); + } + fn min_limit(&self) -> u64 { self.get_ref().min_limit() } @@ -457,10 +476,21 @@ fn fd_to_meta(fd: &T) -> FdMeta { } pub(super) enum CopyResult { - Ended(Result), + Ended(u64), + Error(Error, u64), Fallback(u64), } +impl CopyResult { + fn update_take(&self, reader: &mut impl CopyRead) { + match *self { + CopyResult::Fallback(bytes) + | CopyResult::Ended(bytes) + | CopyResult::Error(_, bytes) => reader.taken(bytes), + } + } +} + /// linux-specific implementation that will attempt to use copy_file_range for copy offloading /// as the name says, it only works on regular files /// @@ -527,7 +557,7 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> // - copying from an overlay filesystem in docker. reported to occur on fedora 32. return CopyResult::Fallback(0); } - Ok(0) => return CopyResult::Ended(Ok(written)), // reached EOF + Ok(0) => return CopyResult::Ended(written), // reached EOF Ok(ret) => written += ret as u64, Err(err) => { return match err.raw_os_error() { @@ -545,12 +575,12 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> assert_eq!(written, 0); CopyResult::Fallback(0) } - _ => CopyResult::Ended(Err(err)), + _ => CopyResult::Error(err, written), }; } } } - CopyResult::Ended(Ok(written)) + CopyResult::Ended(written) } #[derive(PartialEq)] @@ -623,10 +653,10 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) -> Some(os_err) if mode == SpliceMode::Sendfile && os_err == libc::EOVERFLOW => { CopyResult::Fallback(written) } - _ => CopyResult::Ended(Err(err)), + _ => CopyResult::Error(err, written), }; } } } - CopyResult::Ended(Ok(written)) + CopyResult::Ended(written) } diff --git a/library/std/src/sys/unix/kernel_copy/tests.rs b/library/std/src/sys/unix/kernel_copy/tests.rs index 79e99382591..3937a1ffa38 100644 --- a/library/std/src/sys/unix/kernel_copy/tests.rs +++ b/library/std/src/sys/unix/kernel_copy/tests.rs @@ -217,7 +217,7 @@ fn bench_socket_pipe_socket_copy(b: &mut test::Bencher) { ); match probe { - CopyResult::Ended(Ok(1)) => { + CopyResult::Ended(1) => { // splice works } _ => { From bc6eb6fa5df8b48c85cfbd8b13f503ebbafe9f24 Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Thu, 3 Dec 2020 12:21:47 +0530 Subject: [PATCH 161/274] move intrinsic to CTFE, add FIXME --- compiler/rustc_mir/src/const_eval/machine.rs | 17 +++++++++++++++ .../rustc_mir/src/interpret/intrinsics.rs | 21 ++----------------- compiler/rustc_mir/src/interpret/memory.rs | 1 + 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 29bc14be74d..275496647d9 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -13,6 +13,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::AssertMessage; use rustc_session::Limit; use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::{Align, Size}; use crate::interpret::{ self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx, @@ -304,6 +305,22 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, }; ecx.write_scalar(Scalar::from_bool(cmp), dest)?; } + sym::const_allocate => { + let size = ecx.read_scalar(args[0])?.to_machine_usize(ecx)?; + let align = ecx.read_scalar(args[1])?.to_machine_usize(ecx)?; + + let align = match Align::from_bytes(align) { + Ok(a) => a, + Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), + }; + + let ptr = ecx.memory.allocate( + Size::from_bytes(size as u64), + align, + interpret::MemoryKind::ConstHeap, + ); + ecx.write_scalar(Scalar::Ptr(ptr), dest)?; + } _ => { return Err(ConstEvalErrKind::NeedsRfc(format!( "calling intrinsic `{}`", diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 84a53a589a5..f666a89ca56 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -14,11 +14,10 @@ use rustc_middle::ty; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{Abi, Align, LayoutOf as _, Primitive, Size}; +use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size}; use super::{ - util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, MemoryKind, OpTy, - PlaceTy, + util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy, }; mod caller_location; @@ -338,22 +337,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = Scalar::from_uint(truncated_bits, layout.size); self.write_scalar(result, dest)?; } - sym::const_allocate => { - let size = self.read_scalar(args[0])?.to_machine_usize(self)?; - let align = self.read_scalar(args[1])?.to_machine_usize(self)?; - - let align = match Align::from_bytes(align) { - Ok(a) => a, - Err(err) => throw_ub_format!("align has to be a power of 2, {}", err), - }; - - let ptr = self.memory.allocate( - Size::from_bytes(size as u64), - align, - MemoryKind::ConstHeap, - ); - self.write_scalar(Scalar::Ptr(ptr), dest)?; - } sym::offset => { let ptr = self.read_scalar(args[0])?.check_init()?; let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?; diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index 47d0fce51b1..3294daabe61 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -28,6 +28,7 @@ pub enum MemoryKind { /// Stack memory. Error if deallocated except during a stack pop. Stack, /// Heap memory. + /// FIXME: this variant should be in const_eval ConstHeap, /// Memory backing vtables. Error if ever deallocated. Vtable, From 56c64f871ec25468c55345645713032b615326b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 29 Nov 2020 22:34:41 +0100 Subject: [PATCH 162/274] Add lint pass for doc keyword --- compiler/rustc_lint/src/internal.rs | 46 ++++++++++++++++++++++++++++- compiler/rustc_lint/src/lib.rs | 3 ++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c2d98b8e4ad..b2265727032 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -10,7 +10,7 @@ use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; declare_tool_lint! { pub rustc::DEFAULT_HASH_TYPES, @@ -267,3 +267,47 @@ impl EarlyLintPass for LintPassImpl { } } } + +declare_tool_lint! { + pub rustc::EXISTING_DOC_KEYWORD, + Deny, + "Check that documented keywords in std and core actually exist", + report_in_external_macro: true +} + +declare_lint_pass!(ExistingDocKeyword => [EXISTING_DOC_KEYWORD]); + +fn is_doc_keyword(s: Symbol) -> bool { + s <= kw::Union +} + +impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { + fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { + for attr in item.attrs { + if !attr.has_name(sym::doc) { + continue; + } + if let Some(list) = attr.meta_item_list() { + for nested in list { + if nested.has_name(sym::keyword) { + let v = nested + .value_str() + .expect("#[doc(keyword = \"...\")] expected a value!"); + if is_doc_keyword(v) { + return; + } + cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| { + lint.build(&format!( + "Found non-existing keyword `{}` used in \ + `#[doc(keyword = \"...\")]`", + v, + )) + .help("only existing keywords are allowed in core/std") + .emit(); + }); + } + } + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 81549be4b09..80ef855c385 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -463,6 +463,8 @@ fn register_internals(store: &mut LintStore) { store.register_early_pass(|| box DefaultHashTypes::new()); store.register_lints(&LintPassImpl::get_lints()); store.register_early_pass(|| box LintPassImpl); + store.register_lints(&ExistingDocKeyword::get_lints()); + store.register_late_pass(|| box ExistingDocKeyword); store.register_lints(&TyTyKind::get_lints()); store.register_late_pass(|| box TyTyKind); store.register_group( @@ -475,6 +477,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), LintId::of(TY_PASS_BY_REFERENCE), LintId::of(USAGE_OF_QUALIFIED_TY), + LintId::of(EXISTING_DOC_KEYWORD), ], ); } From 4b23f403e554153f5e7c204448c905762fd17e4b Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 31 Oct 2020 19:54:44 +0100 Subject: [PATCH 163/274] extend the docs for `WithOptConstParam` --- compiler/rustc_middle/src/ty/mod.rs | 51 +++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5d8edcf70bf..2d7f417b64a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1683,34 +1683,59 @@ pub struct BoundConst<'tcx> { pub type PlaceholderConst<'tcx> = Placeholder>; -/// A `DefId` which is potentially bundled with its corresponding generic parameter -/// in case `did` is a const argument. +/// A `DefId` which, in case it is a const argument, is potentially bundled with +/// the `DefId` of the generic parameter it instantiates. /// -/// This is used to prevent cycle errors during typeck -/// as `type_of(const_arg)` depends on `typeck(owning_body)` -/// which once again requires the type of its generic arguments. -/// -/// Luckily we only need to deal with const arguments once we -/// know their corresponding parameters. We (ab)use this by -/// calling `type_of(param_did)` for these arguments. +/// This is used to avoid calls to `type_of` for const arguments during typeck +/// which cause cycle errors. /// /// ```rust /// #![feature(const_generics)] /// /// struct A; /// impl A { -/// fn foo(&self) -> usize { N } +/// fn foo(&self) -> [u8; N] { [0; N] } +/// // ^ const parameter /// } /// struct B; /// impl B { -/// fn foo(&self) -> usize { 42 } +/// fn foo(&self) -> usize { 42 } +/// // ^ const parameter /// } /// /// fn main() { /// let a = A; -/// a.foo::<7>(); +/// let _b = a.foo::<{ 3 + 7 }>(); +/// // ^^^^^^^^^ const argument /// } /// ``` +/// +/// Let's look at the call `a.foo::<{ 3 + 7 }>()` here. We do not know +/// which `foo` is used until we know the type of `a`. +/// +/// We only know the type of `a` once we are inside of `typeck(main)`. +/// We also end up normalizing the type of `_b` during `typeck(main)` which +/// requires us to evaluate the const argument. +/// +/// To evaluate that const argument we need to know its type, +/// which we would get using `type_of(const_arg)`. This requires us to +/// resolve `foo` as it can be either `usize` or `u8` in this example. +/// However, resolving `foo` once again requires `typeck(main)` to get the type of `a`, +/// which results in a cycle. +/// +/// In short we must not call `type_of(const_arg)` during `typeck(main)`. +/// +/// When first creating the `ty::Const` of the const argument inside of `typeck` we have +/// already resolved `foo` so we know which const parameter this argument instantiates. +/// This means that we also know the expected result of `type_of(const_arg)` even if we +/// aren't allowed to call that query: it is equal to `type_of(const_param)` which is +/// trivial to compute. +/// +/// If we now want to use that constant in a place which potentionally needs its type +/// we also pass the type of its `const_param`. This is the point of `WithOptConstParam`, +/// except that instead of a `Ty` we bundle the `DefId` of the const parameter. +/// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some` +/// to get the type of `did`. #[derive(Copy, Clone, Debug, TypeFoldable, Lift, TyEncodable, TyDecodable)] #[derive(PartialEq, Eq, PartialOrd, Ord)] #[derive(Hash, HashStable)] @@ -1721,7 +1746,7 @@ pub struct WithOptConstParam { /// /// Note that even if `did` is a const argument, this may still be `None`. /// All queries taking `WithOptConstParam` start by calling `tcx.opt_const_param_of(def.did)` - /// to potentially update `param_did` in case it `None`. + /// to potentially update `param_did` in the case it is `None`. pub const_param_did: Option, } From 0105e4a54b2ccbfbd62b0d07f636520b39094f5e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 3 Dec 2020 14:05:58 +0100 Subject: [PATCH 164/274] Add test for EXISTING_DOC_KEYWORD internal lint --- .../internal-lints/existing_doc_keyword.rs | 9 +++++++++ .../internal-lints/existing_doc_keyword.stderr | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs create mode 100644 src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs new file mode 100644 index 00000000000..2b4a65b4a4c --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs @@ -0,0 +1,9 @@ +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] +#![feature(doc_keyword)] + +#![crate_type = "lib"] + +#[doc(keyword = "tadam")] //~ ERROR +mod tadam {} diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr new file mode 100644 index 00000000000..6fc288ae434 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr @@ -0,0 +1,11 @@ +error: Found non-existing keyword `tadam` used in `#[doc(keyword = "...")]` + --> $DIR/existing_doc_keyword.rs:8:1 + | +LL | #[doc(keyword = "tadam")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(rustc::existing_doc_keyword)]` on by default + = help: only existing keywords are allowed in core/std + +error: aborting due to previous error + From 50eb3a89f8e2a4c1d809d2b0170b0063b9338d6d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 3 Dec 2020 15:32:41 +0100 Subject: [PATCH 165/274] Only deny doc_keyword in std and set it as "allow" by default --- compiler/rustc_lint/src/internal.rs | 2 +- library/std/src/lib.rs | 1 + .../ui-fulldeps/internal-lints/existing_doc_keyword.rs | 2 ++ .../internal-lints/existing_doc_keyword.stderr | 8 ++++++-- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index b2265727032..af5972c6c81 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -270,7 +270,7 @@ impl EarlyLintPass for LintPassImpl { declare_tool_lint! { pub rustc::EXISTING_DOC_KEYWORD, - Deny, + Allow, "Check that documented keywords in std and core actually exist", report_in_external_macro: true } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 83eb847697d..6c240cb4c3e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -212,6 +212,7 @@ all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform) )] +#![deny(rustc::existing_doc_keyword)] #![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))] // std is implemented with unstable features, many of which are internal // compiler details that will never be stable diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs index 2b4a65b4a4c..053712a4b4e 100644 --- a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs @@ -5,5 +5,7 @@ #![crate_type = "lib"] +#![deny(rustc::existing_doc_keyword)] + #[doc(keyword = "tadam")] //~ ERROR mod tadam {} diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr index 6fc288ae434..bac44f338b7 100644 --- a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr @@ -1,10 +1,14 @@ error: Found non-existing keyword `tadam` used in `#[doc(keyword = "...")]` - --> $DIR/existing_doc_keyword.rs:8:1 + --> $DIR/existing_doc_keyword.rs:10:1 | LL | #[doc(keyword = "tadam")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[deny(rustc::existing_doc_keyword)]` on by default +note: the lint level is defined here + --> $DIR/existing_doc_keyword.rs:8:9 + | +LL | #![deny(rustc::existing_doc_keyword)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: only existing keywords are allowed in core/std error: aborting due to previous error From ff0ebd27a4436729b68cdf5180cfbb0c16c803a0 Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Thu, 3 Dec 2020 21:09:39 +0530 Subject: [PATCH 166/274] move interpret::MemoryKind::Heap to const eval --- compiler/rustc_mir/src/const_eval/machine.rs | 27 ++++++++++++++++++- compiler/rustc_mir/src/interpret/intern.rs | 27 +++++++++++-------- compiler/rustc_mir/src/interpret/machine.rs | 8 +++--- compiler/rustc_mir/src/interpret/memory.rs | 5 ---- .../rustc_mir/src/transform/const_prop.rs | 2 ++ 5 files changed, 48 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 275496647d9..187f6fab518 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -7,6 +7,7 @@ use std::collections::hash_map::Entry; use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; +use std::fmt; use rustc_ast::Mutability; use rustc_hir::def_id::DefId; @@ -179,6 +180,28 @@ impl interpret::AllocMap for FxHashMap { crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>; +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum MemoryKind { + Heap, +} + +impl fmt::Display for MemoryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MemoryKind::Heap => write!(f, "heap allocation"), + } + } +} + +impl interpret::MayLeak for MemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + match self { + MemoryKind::Heap => false, + } + } +} + impl interpret::MayLeak for ! { #[inline(always)] fn may_leak(self) -> bool { @@ -222,6 +245,8 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); + type MemoryKind = MemoryKind; + type MemoryExtra = MemoryExtra; fn find_mir_or_eval_fn( @@ -317,7 +342,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, let ptr = ecx.memory.allocate( Size::from_bytes(size as u64), align, - interpret::MemoryKind::ConstHeap, + interpret::MemoryKind::Machine(MemoryKind::Heap), ); ecx.write_scalar(Scalar::Ptr(ptr), dest)?; } diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index db996f72128..01d58c47e3a 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -25,19 +25,20 @@ use rustc_target::abi::Size; use rustc_ast::Mutability; use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, Scalar, ValueVisitor}; +use crate::const_eval; -pub trait CompileTimeMachine<'mir, 'tcx> = Machine< +pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< 'mir, 'tcx, - MemoryKind = !, + MemoryKind = T, PointerTag = (), ExtraFnVal = !, FrameExtra = (), AllocExtra = (), - MemoryMap = FxHashMap, Allocation)>, + MemoryMap = FxHashMap, Allocation)>, >; -struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> { +struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> { /// The ectx from which we intern. ecx: &'rt mut InterpCx<'mir, 'tcx, M>, /// Previously encountered safe references. @@ -74,7 +75,7 @@ struct IsStaticOrFn; /// `immutable` things might become mutable if `ty` is not frozen. /// `ty` can be `None` if there is no potential interior mutability /// to account for (e.g. for vtables). -fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( +fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>( ecx: &'rt mut InterpCx<'mir, 'tcx, M>, leftover_allocations: &'rt mut FxHashSet, alloc_id: AllocId, @@ -105,7 +106,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( // changes in this function. match kind { MemoryKind::Stack - | MemoryKind::ConstHeap + | MemoryKind::Machine(const_eval::MemoryKind::Heap) | MemoryKind::Vtable | MemoryKind::CallerLocation => {} } @@ -141,7 +142,9 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( None } -impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir, 'tcx, M> { +impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + InternVisitor<'rt, 'mir, 'tcx, M> +{ fn intern_shallow( &mut self, alloc_id: AllocId, @@ -152,8 +155,8 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir } } -impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> - for InternVisitor<'rt, 'mir, 'tcx, M> +impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> + ValueVisitor<'mir, 'tcx, M> for InternVisitor<'rt, 'mir, 'tcx, M> { type V = MPlaceTy<'tcx>; @@ -290,7 +293,7 @@ pub enum InternKind { /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures /// are hard errors. #[tracing::instrument(skip(ecx))] -pub fn intern_const_alloc_recursive>( +pub fn intern_const_alloc_recursive>( ecx: &mut InterpCx<'mir, 'tcx, M>, intern_kind: InternKind, ret: MPlaceTy<'tcx>, @@ -421,7 +424,9 @@ where Ok(()) } -impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { +impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> + InterpCx<'mir, 'tcx, M> +{ /// A helper function that allocates memory for the layout given and gives you access to mutate /// it. Once your own mutation code is done, the backing `Allocation` is removed from the /// current `Memory` and returned. diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 66dbacb2f9d..0bba0273772 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -366,9 +366,9 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type PointerTag = (); type ExtraFnVal = !; - type MemoryKind = !; - type MemoryMap = rustc_data_structures::fx::FxHashMap, Allocation)>; - const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory + type MemoryMap = + rustc_data_structures::fx::FxHashMap, Allocation)>; + const GLOBAL_KIND: Option = None; // no copying of globals from `tcx` to machine memory type AllocExtra = (); type FrameExtra = (); @@ -407,7 +407,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { _memory_extra: &Self::MemoryExtra, _id: AllocId, alloc: Cow<'b, Allocation>, - _kind: Option>, + _kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { // We do not use a tag so we can just cheaply forward the allocation (alloc, ()) diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index 3294daabe61..f3e373813ca 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -27,9 +27,6 @@ use crate::util::pretty; pub enum MemoryKind { /// Stack memory. Error if deallocated except during a stack pop. Stack, - /// Heap memory. - /// FIXME: this variant should be in const_eval - ConstHeap, /// Memory backing vtables. Error if ever deallocated. Vtable, /// Memory allocated by `caller_location` intrinsic. Error if ever deallocated. @@ -43,7 +40,6 @@ impl MayLeak for MemoryKind { fn may_leak(self) -> bool { match self { MemoryKind::Stack => false, - MemoryKind::ConstHeap => false, MemoryKind::Vtable => true, MemoryKind::CallerLocation => true, MemoryKind::Machine(k) => k.may_leak(), @@ -55,7 +51,6 @@ impl fmt::Display for MemoryKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { MemoryKind::Stack => write!(f, "stack variable"), - MemoryKind::ConstHeap => write!(f, "heap allocation"), MemoryKind::Vtable => write!(f, "vtable"), MemoryKind::CallerLocation => write!(f, "caller location"), MemoryKind::Machine(m) => write!(f, "{}", m), diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index abcf1862fd8..1d949e020ed 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -180,6 +180,8 @@ impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> { impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> { compile_time_machine!(<'mir, 'tcx>); + type MemoryKind = !; + type MemoryExtra = (); fn find_mir_or_eval_fn( From c45ee4bb29000cc0d02b11afa682852b5174b8a5 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 16 Nov 2020 09:14:28 -0800 Subject: [PATCH 167/274] Coverage tests for remaining TerminatorKinds and async, improve Assert Tested and validate results for panic unwind, panic abort, assert!() macro, TerminatorKind::Assert (for example, numeric overflow), and async/await. Implemented a previous documented idea to change Assert handling to be the same as FalseUnwind and Goto, so it doesn't get its own BasicCoverageBlock anymore. This changed a couple of coverage regions, but I validated those changes are not any worse than the prior results, and probably help assure some consistency (even if some people might disagree with how the code region is consistently computed). Fixed issue with async/await. AggregateKind::Generator needs to be handled like AggregateKind::Closure; coverage span for the outer async function should not "cover" the async body, which is actually executed in a separate "closure" MIR. --- .../rustc_mir/src/util/generic_graphviz.rs | 8 +- .../source-based-code-coverage.md | 4 +- .../coverage-reports-base/Makefile | 3 + .../expected_export_coverage.abort.json | 59 +++ .../expected_export_coverage.assert.json | 59 +++ .../expected_export_coverage.async.json | 59 +++ .../expected_export_coverage.conditions.json | 28 +- .../expected_export_coverage.inner_items.json | 20 +- ...expected_export_coverage.nested_loops.json | 20 +- .../expected_export_coverage.overflow.json | 59 +++ ...expected_export_coverage.panic_unwind.json | 59 +++ .../expected_export_coverage.yield.json | 59 +++ .../expected_show_coverage.abort.txt | 35 ++ .../expected_show_coverage.assert.txt | 34 ++ .../expected_show_coverage.async.txt | 66 +++ .../expected_show_coverage.conditions.txt | 97 +++-- .../expected_show_coverage.inner_items.txt | 2 +- .../expected_show_coverage.nested_loops.txt | 2 +- .../expected_show_coverage.overflow.txt | 64 +++ .../expected_show_coverage.panic_unwind.txt | 50 +++ .../expected_show_coverage.yield.txt | 38 ++ .../expected_show_coverage_counters.abort.txt | 41 ++ ...expected_show_coverage_counters.assert.txt | 54 +++ .../expected_show_coverage_counters.async.txt | 84 ++++ ...cted_show_coverage_counters.conditions.txt | 358 +++++++++------- ...ted_show_coverage_counters.inner_items.txt | 26 +- ...ed_show_coverage_counters.nested_loops.txt | 42 +- ...pected_show_coverage_counters.overflow.txt | 53 +++ ...ed_show_coverage_counters.panic_unwind.txt | 50 +++ ...ted_show_coverage_counters.simple_loop.txt | 4 +- ...how_coverage_counters.try_error_result.txt | 8 +- ...show_coverage_counters.while_early_ret.txt | 2 +- .../expected_show_coverage_counters.yield.txt | 90 ++++ .../expected_export_coverage.abort.json | 59 +++ .../expected_export_coverage.assert.json | 59 +++ .../expected_export_coverage.async.json | 59 +++ .../expected_export_coverage.conditions.json | 28 +- .../expected_export_coverage.inner_items.json | 20 +- ...expected_export_coverage.nested_loops.json | 20 +- .../expected_export_coverage.overflow.json | 59 +++ ...expected_export_coverage.panic_unwind.json | 59 +++ .../expected_export_coverage.yield.json | 59 +++ .../expected_show_coverage.abort.txt | 35 ++ .../expected_show_coverage.assert.txt | 34 ++ .../expected_show_coverage.async.txt | 66 +++ .../expected_show_coverage.conditions.txt | 97 +++-- .../expected_show_coverage.inner_items.txt | 2 +- .../expected_show_coverage.nested_loops.txt | 2 +- .../expected_show_coverage.overflow.txt | 64 +++ .../expected_show_coverage.panic_unwind.txt | 50 +++ .../expected_show_coverage.yield.txt | 38 ++ .../expected_show_coverage_counters.abort.txt | 41 ++ ...expected_show_coverage_counters.assert.txt | 54 +++ .../expected_show_coverage_counters.async.txt | 85 ++++ ...cted_show_coverage_counters.conditions.txt | 358 +++++++++------- ...ted_show_coverage_counters.inner_items.txt | 26 +- ...ed_show_coverage_counters.nested_loops.txt | 42 +- ...pected_show_coverage_counters.overflow.txt | 53 +++ ...ed_show_coverage_counters.panic_unwind.txt | 50 +++ ...cted_show_coverage_counters.partial_eq.txt | 18 +- ...ted_show_coverage_counters.simple_loop.txt | 4 +- ...how_coverage_counters.try_error_result.txt | 8 +- ...show_coverage_counters.while_early_ret.txt | 2 +- .../expected_show_coverage_counters.yield.txt | 90 ++++ .../coverage-spanview-base/Makefile | 3 + ...ort.main.-------.InstrumentCoverage.0.html | 99 +++++ ...ht_abort.-------.InstrumentCoverage.0.html | 164 ++++++++ ...ert.main.-------.InstrumentCoverage.0.html | 103 +++++ ...l_assert.-------.InstrumentCoverage.0.html | 97 +++++ ...osure#0}.-------.InstrumentCoverage.0.html | 89 ++++ ...osure#1}.-------.InstrumentCoverage.0.html | 89 ++++ ...osure#2}.-------.InstrumentCoverage.0.html | 89 ++++ ...osure#3}.-------.InstrumentCoverage.0.html | 75 ++++ ...block_on.-------.InstrumentCoverage.0.html | 226 ++++++++++ ...osure#0}.-------.InstrumentCoverage.0.html | 75 ++++ .../async.f.-------.InstrumentCoverage.0.html | 74 ++++ ...osure#0}.-------.InstrumentCoverage.0.html | 75 ++++ ...sync.foo.-------.InstrumentCoverage.0.html | 74 ++++ ...osure#0}.-------.InstrumentCoverage.0.html | 80 ++++ .../async.g.-------.InstrumentCoverage.0.html | 79 ++++ ...osure#0}.-------.InstrumentCoverage.0.html | 80 ++++ .../async.h.-------.InstrumentCoverage.0.html | 79 ++++ ...osure#0}.-------.InstrumentCoverage.0.html | 82 ++++ .../async.i.-------.InstrumentCoverage.0.html | 79 ++++ ...ync.main.-------.InstrumentCoverage.0.html | 133 ++++++ ...ons.main.-------.InstrumentCoverage.0.html | 318 +++++++++----- ...-in_func.-------.InstrumentCoverage.0.html | 76 +++- ...ait_func.-------.InstrumentCoverage.0.html | 32 +- ...ops.main.-------.InstrumentCoverage.0.html | 56 ++- ...low.main.-------.InstrumentCoverage.0.html | 259 ++++++++++++ ...overflow.-------.InstrumentCoverage.0.html | 397 ++++++++++++++++++ ...ind.main.-------.InstrumentCoverage.0.html | 103 +++++ ...ht_panic.-------.InstrumentCoverage.0.html | 164 ++++++++ ...oop.main.-------.InstrumentCoverage.0.html | 9 +- ...ult.main.-------.InstrumentCoverage.0.html | 21 +- ...ret.main.-------.InstrumentCoverage.0.html | 9 +- ...osure#0}.-------.InstrumentCoverage.0.html | 79 ++++ ...osure#1}.-------.InstrumentCoverage.0.html | 81 ++++ ...eld.main.-------.InstrumentCoverage.0.html | 138 ++++++ ...ort.main.-------.InstrumentCoverage.0.html | 99 +++++ ...ht_abort.-------.InstrumentCoverage.0.html | 164 ++++++++ ...ert.main.-------.InstrumentCoverage.0.html | 103 +++++ ...l_assert.-------.InstrumentCoverage.0.html | 97 +++++ ...osure#0}.-------.InstrumentCoverage.0.html | 89 ++++ ...osure#1}.-------.InstrumentCoverage.0.html | 89 ++++ ...osure#2}.-------.InstrumentCoverage.0.html | 89 ++++ ...osure#3}.-------.InstrumentCoverage.0.html | 75 ++++ ...block_on.-------.InstrumentCoverage.0.html | 226 ++++++++++ ...osure#0}.-------.InstrumentCoverage.0.html | 75 ++++ .../async.f.-------.InstrumentCoverage.0.html | 74 ++++ ...osure#0}.-------.InstrumentCoverage.0.html | 75 ++++ ...sync.foo.-------.InstrumentCoverage.0.html | 74 ++++ ...osure#0}.-------.InstrumentCoverage.0.html | 80 ++++ .../async.g.-------.InstrumentCoverage.0.html | 79 ++++ ...osure#0}.-------.InstrumentCoverage.0.html | 80 ++++ .../async.h.-------.InstrumentCoverage.0.html | 79 ++++ ...osure#0}.-------.InstrumentCoverage.0.html | 82 ++++ .../async.i.-------.InstrumentCoverage.0.html | 79 ++++ ...ync.main.-------.InstrumentCoverage.0.html | 133 ++++++ ...ons.main.-------.InstrumentCoverage.0.html | 318 +++++++++----- ...-in_func.-------.InstrumentCoverage.0.html | 76 +++- ...ait_func.-------.InstrumentCoverage.0.html | 32 +- ...ops.main.-------.InstrumentCoverage.0.html | 56 ++- ...low.main.-------.InstrumentCoverage.0.html | 259 ++++++++++++ ...overflow.-------.InstrumentCoverage.0.html | 397 ++++++++++++++++++ ...ind.main.-------.InstrumentCoverage.0.html | 103 +++++ ...ht_panic.-------.InstrumentCoverage.0.html | 164 ++++++++ ...oop.main.-------.InstrumentCoverage.0.html | 9 +- ...ult.main.-------.InstrumentCoverage.0.html | 21 +- ...ret.main.-------.InstrumentCoverage.0.html | 9 +- ...osure#0}.-------.InstrumentCoverage.0.html | 79 ++++ ...osure#1}.-------.InstrumentCoverage.0.html | 81 ++++ ...eld.main.-------.InstrumentCoverage.0.html | 138 ++++++ src/test/run-make-fulldeps/coverage/abort.rs | 34 ++ src/test/run-make-fulldeps/coverage/assert.rs | 32 ++ src/test/run-make-fulldeps/coverage/async.rs | 64 +++ .../run-make-fulldeps/coverage/conditions.rs | 36 ++ .../coverage/coverage_tools.mk | 5 - .../run-make-fulldeps/coverage/overflow.rs | 63 +++ .../coverage/panic_unwind.rs | 49 +++ src/test/run-make-fulldeps/coverage/yield.rs | 37 ++ src/tools/compiletest/src/main.rs | 2 - 142 files changed, 10102 insertions(+), 867 deletions(-) create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.abort.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.assert.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.async.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.overflow.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.panic_unwind.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.yield.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.abort.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.assert.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.async.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.overflow.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.panic_unwind.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.yield.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.abort.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.assert.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.async.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.overflow.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.panic_unwind.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.yield.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.abort.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.assert.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.async.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.overflow.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.panic_unwind.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.yield.json create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.abort.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.assert.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.async.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.overflow.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.panic_unwind.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.yield.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.abort.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.assert.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.async.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.overflow.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.panic_unwind.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.yield.txt create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage/abort.rs create mode 100644 src/test/run-make-fulldeps/coverage/assert.rs create mode 100644 src/test/run-make-fulldeps/coverage/async.rs create mode 100644 src/test/run-make-fulldeps/coverage/overflow.rs create mode 100644 src/test/run-make-fulldeps/coverage/panic_unwind.rs create mode 100644 src/test/run-make-fulldeps/coverage/yield.rs diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_mir/src/util/generic_graphviz.rs index 8bd4a512bbb..fd55a4dfc4c 100644 --- a/compiler/rustc_mir/src/util/generic_graphviz.rs +++ b/compiler/rustc_mir/src/util/generic_graphviz.rs @@ -116,9 +116,13 @@ impl< write!(w, r#""#)?; - // FIXME(richkadel): Need generic way to know if node header should have a different color + // FIXME(richkadel): If/when migrating the MIR graphviz to this generic implementation, + // we need generic way to know if node header should have a different color. For example, + // for MIR: + // // let (blk, bgcolor) = if data.is_cleanup { - // (format!("{:?} (cleanup)", node), "lightblue") + // let color = if dark_mode { "royalblue" } else { "lightblue" }; + // (format!("{:?} (cleanup)", node), color) // } else { // let color = if dark_mode { "dimgray" } else { "gray" }; // (format!("{:?}", node), color) diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md index 1dd7272e0f9..0eb425e42aa 100644 --- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md @@ -1,8 +1,6 @@ # `source-based-code-coverage` -The feature request for this feature is: [#34701] - -The Major Change Proposal (MCP) for this feature is: [#278](https://github.com/rust-lang/compiler-team/issues/278) +The tracking issue for this feature is: [#79121](https://github.com/rust-lang/rust/issues/79121). ------------------------ diff --git a/src/test/run-make-fulldeps/coverage-reports-base/Makefile b/src/test/run-make-fulldeps/coverage-reports-base/Makefile index 2dac8fc2225..6ccff43dcdf 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports-base/Makefile @@ -54,6 +54,9 @@ endif %: $(SOURCEDIR)/%.rs # Compile the test program with coverage instrumentation and generate relevant MIR. $(RUSTC) $(SOURCEDIR)/$@.rs \ + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && \ + echo "--edition=2018" \ + ) \ -Zinstrument-coverage \ -Clink-dead-code=$(LINK_DEAD_CODE) diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.abort.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.abort.json new file mode 100644 index 00000000000..33cfc9f3ed7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.abort.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/abort.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 15, + "covered": 13, + "percent": 86.66666666666667 + }, + "regions": { + "count": 10, + "covered": 9, + "notcovered": 1, + "percent": 90 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 15, + "covered": 13, + "percent": 86.66666666666667 + }, + "regions": { + "count": 10, + "covered": 9, + "notcovered": 1, + "percent": 90 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.assert.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.assert.json new file mode 100644 index 00000000000..aa2a0cbebe7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.assert.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/assert.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 13, + "covered": 10, + "percent": 76.92307692307693 + }, + "regions": { + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 13, + "covered": 10, + "percent": 76.92307692307693 + }, + "regions": { + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.async.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.async.json new file mode 100644 index 00000000000..004bedeea62 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.async.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/async.rs", + "summary": { + "functions": { + "count": 9, + "covered": 9, + "percent": 100 + }, + "instantiations": { + "count": 9, + "covered": 9, + "percent": 100 + }, + "lines": { + "count": 31, + "covered": 30, + "percent": 96.7741935483871 + }, + "regions": { + "count": 21, + "covered": 18, + "notcovered": 3, + "percent": 85.71428571428571 + } + } + } + ], + "totals": { + "functions": { + "count": 9, + "covered": 9, + "percent": 100 + }, + "instantiations": { + "count": 9, + "covered": 9, + "percent": 100 + }, + "lines": { + "count": 31, + "covered": 30, + "percent": 96.7741935483871 + }, + "regions": { + "count": 21, + "covered": 18, + "notcovered": 3, + "percent": 85.71428571428571 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json index ed937a1b13f..d69ca80839a 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 49, - "covered": 23, - "percent": 46.93877551020408 + "count": 64, + "covered": 33, + "percent": 51.5625 }, "regions": { - "count": 69, - "covered": 18, - "notcovered": 51, - "percent": 26.08695652173913 + "count": 88, + "covered": 25, + "notcovered": 63, + "percent": 28.40909090909091 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 49, - "covered": 23, - "percent": 46.93877551020408 + "count": 64, + "covered": 33, + "percent": 51.5625 }, "regions": { - "count": 69, - "covered": 18, - "notcovered": 51, - "percent": 26.08695652173913 + "count": 88, + "covered": 25, + "notcovered": 63, + "percent": 28.40909090909091 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json index c178e7f9347..5dc82d2168c 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 26, - "covered": 26, + "count": 27, + "covered": 27, "percent": 100 }, "regions": { - "count": 15, - "covered": 13, + "count": 11, + "covered": 9, "notcovered": 2, - "percent": 86.66666666666667 + "percent": 81.81818181818183 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 26, - "covered": 26, + "count": 27, + "covered": 27, "percent": 100 }, "regions": { - "count": 15, - "covered": 13, + "count": 11, + "covered": 9, "notcovered": 2, - "percent": 86.66666666666667 + "percent": 81.81818181818183 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json index 68163eb7636..ce3c957e660 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 21, + "count": 22, "covered": 16, - "percent": 76.19047619047619 + "percent": 72.72727272727273 }, "regions": { - "count": 18, - "covered": 14, + "count": 17, + "covered": 13, "notcovered": 4, - "percent": 77.77777777777779 + "percent": 76.47058823529412 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 21, + "count": 22, "covered": 16, - "percent": 76.19047619047619 + "percent": 72.72727272727273 }, "regions": { - "count": 18, - "covered": 14, + "count": 17, + "covered": 13, "notcovered": 4, - "percent": 77.77777777777779 + "percent": 76.47058823529412 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.overflow.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.overflow.json new file mode 100644 index 00000000000..176bfd7abeb --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.overflow.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/overflow.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 21, + "covered": 17, + "percent": 80.95238095238095 + }, + "regions": { + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 21, + "covered": 17, + "percent": 80.95238095238095 + }, + "regions": { + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.panic_unwind.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.panic_unwind.json new file mode 100644 index 00000000000..5b13109dbe6 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.panic_unwind.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/panic_unwind.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 17, + "covered": 14, + "percent": 82.35294117647058 + }, + "regions": { + "count": 13, + "covered": 11, + "notcovered": 2, + "percent": 84.61538461538461 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 17, + "covered": 14, + "percent": 82.35294117647058 + }, + "regions": { + "count": 13, + "covered": 11, + "notcovered": 2, + "percent": 84.61538461538461 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.yield.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.yield.json new file mode 100644 index 00000000000..9f25bc971c5 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.yield.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/yield.rs", + "summary": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "lines": { + "count": 23, + "covered": 16, + "percent": 69.56521739130434 + }, + "regions": { + "count": 22, + "covered": 16, + "notcovered": 6, + "percent": 72.72727272727273 + } + } + } + ], + "totals": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "lines": { + "count": 23, + "covered": 16, + "percent": 69.56521739130434 + }, + "regions": { + "count": 22, + "covered": 16, + "notcovered": 6, + "percent": 72.72727272727273 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.abort.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.abort.txt new file mode 100644 index 00000000000..40c9c71a2aa --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.abort.txt @@ -0,0 +1,35 @@ + 1| |#![feature(unwind_attributes)] + 2| |#![allow(unused_assignments)] + 3| | + 4| |#[unwind(aborts)] + 5| |fn might_abort(should_abort: bool) { + 6| 4| if should_abort { + 7| 0| println!("aborting..."); + 8| 0| panic!("panics and aborts"); + 9| 4| } else { + 10| 4| println!("Don't Panic"); + 11| 4| } + 12| 4|} + 13| | + 14| |fn main() -> Result<(),u8> { + 15| 1| let mut countdown = 10; + 16| 11| while countdown > 0 { + 17| 10| if countdown < 5 { + 18| 4| might_abort(false); + 19| 6| } + 20| 10| countdown -= 1; + 21| | } + 22| 1| Ok(()) + 23| 1|} + 24| | + 25| |// Notes: + 26| |// 1. Compare this program and its coverage results to those of the similar tests + 27| |// `panic_unwind.rs` and `try_error_result.rs`. + 28| |// 2. This test confirms the coverage generated when a program includes `TerminatorKind::Abort`. + 29| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage + 30| |// results show where the program did and did not execute. + 31| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as + 32| |// intended"). Coverage results would show no executed coverage regions. + 33| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status + 34| |// (on Linux at least). + diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.assert.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.assert.txt new file mode 100644 index 00000000000..a6efcbabd35 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.assert.txt @@ -0,0 +1,34 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-101 + 3| | + 4| |fn might_fail_assert(one_plus_one: u32) { + 5| 4| println!("does 1 + 1 = {}?", one_plus_one); + 6| 4| assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); + ^1 + 7| 3|} + 8| | + 9| |fn main() -> Result<(),u8> { + 10| 1| let mut countdown = 10; + 11| 10| while countdown > 0 { + 12| 10| if countdown == 1 { + 13| 0| might_fail_assert(3); + 14| 10| } else if countdown < 5 { + 15| 3| might_fail_assert(2); + 16| 15| } + 17| 9| countdown -= 1; + 18| | } + 19| 0| Ok(()) + 20| 0|} + 21| | + 22| |// Notes: + 23| |// 1. Compare this program and its coverage results to those of the very similar test + 24| |// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. + 25| |// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or + 26| |// related `assert_*!()` macro. + 27| |// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce + 28| |// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to + 29| |// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). + 30| |// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test + 31| |// (and in many other coverage tests). The `Assert` terminator is typically generated by the + 32| |// Rust compiler to check for runtime failures, such as numeric overflows. + diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.async.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.async.txt new file mode 100644 index 00000000000..b5d99732102 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.async.txt @@ -0,0 +1,66 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |// require-rust-edition-2018 + 4| | + 5| 1|async fn f() -> u8 { 1 } + 6| | + 7| |async fn foo() -> [bool; 10] { [false; 10] } + 8| | + 9| |pub async fn g(x: u8) { + 10| | match x { + 11| | y if f().await == y => (), + 12| | _ => (), + 13| | } + 14| 1|} + 15| | + 16| |// #78366: check the reference to the binding is recorded even if the binding is not autorefed + 17| | + 18| |async fn h(x: usize) { + 19| | match x { + 20| | y if foo().await[y] => (), + 21| | _ => (), + 22| | } + 23| 1|} + 24| | + 25| 1|async fn i(x: u8) { + 26| 1| match x { + 27| 1| y if f().await == y + 1 => (), + ^0 ^0 + 28| 1| _ => (), + 29| | } + 30| 2|} + 31| | + 32| 1|fn main() { + 33| 1| let _ = g(10); + 34| 1| let _ = h(9); + 35| 1| let mut future = Box::pin(i(8)); + 36| 1| executor::block_on(future.as_mut()); + 37| 1|} + 38| | + 39| |mod executor { + 40| | use core::{ + 41| | future::Future, + 42| | pin::Pin, + 43| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 44| | }; + 45| | + 46| | pub fn block_on(mut future: F) -> F::Output { + 47| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 48| 1| + 49| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + 50| 1| |_| unimplemented!("clone"), + 51| 1| |_| unimplemented!("wake"), + 52| 1| |_| unimplemented!("wake_by_ref"), + 53| 1| |_| (), + 54| 1| ); + 55| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + 56| 1| let mut context = Context::from_waker(&waker); + 57| | + 58| | loop { + 59| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + 60| 1| break val; + 61| | } + 62| 0| } + 63| 1| } + 64| |} + diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt index 173ff4aa4c4..e55a574c056 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt @@ -27,7 +27,8 @@ 27| | 28| 1| if countdown > 7 { 29| 1| countdown -= 4; - 30| 0| } else if countdown > 2 { + 30| 1| } else if countdown > 2 { + ^0 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { 32| 0| countdown = 0; 33| 0| } @@ -36,34 +37,70 @@ 36| 0| return; 37| | } 38| | - 39| 1| let mut countdown = 0; - 40| 1| if true { - 41| 1| countdown = 1; - 42| 1| } - 43| | - 44| 1| let z = if countdown > 7 { - ^0 - 45| 0| countdown -= 4; - 46| 1| } else if countdown > 2 { - 47| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 48| 0| countdown = 0; - 49| 0| } - 50| 0| countdown -= 5; - 51| | } else { - 52| 1| let should_be_reachable = countdown; - 53| 1| println!("reached"); - 54| 1| return; - 55| | }; + 39| 1| if true { + 40| | // Demonstrate the difference with `TerminatorKind::Assert` as of 2020-11-15. Assert is no + 41| | // longer treated as a `BasicCoverageBlock` terminator, which changed the coverage region, + 42| | // for the executed `then` block above, to include the closing brace on line 30. That + 43| | // changed the line count, but the coverage code region (for the `else if` condition) is + 44| | // still valid. + 45| | // + 46| | // Note that `if` (then) and `else` blocks include the closing brace in their coverage + 47| | // code regions when the last line in the block ends in a semicolon, because the Rust + 48| | // compiler inserts a `StatementKind::Assign` to assign `const ()` to a `Place`, for the + 49| | // empty value for the executed block. When the last line does not end in a semicolon + 50| | // (that is, when the block actually results in a value), the additional `Assign` is not + 51| | // generated, and the brace is not included. + 52| 1| let mut countdown = 0; + 53| 1| if true { + 54| 1| countdown = 10; + 55| 1| } 56| | - 57| 0| let w = if countdown > 7 { - 58| 0| countdown -= 4; - 59| 0| } else if countdown > 2 { - 60| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 61| 0| countdown = 0; - 62| 0| } - 63| 0| countdown -= 5; - 64| | } else { - 65| 0| return; - 66| | }; - 67| 1|} + 57| 1| if countdown > 7 { + 58| 1| countdown -= 4; + 59| 1| } + 60| | // The closing brace of the `then` branch is now included in the coverage region, and shown + 61| | // as "executed" (giving its line a count of 1 here). Since, in the original version above, + 62| | // the closing brace shares the same line as the `else if` conditional expression (which is + 63| | // not executed if the first `then` condition is true), only the condition's code region is + 64| | // marked with a count of 0 now. + 65| 0| else if countdown > 2 { + 66| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 67| 0| countdown = 0; + 68| 0| } + 69| 0| countdown -= 5; + 70| | } else { + 71| 0| return; + 72| | } + 73| 1| } + 74| | + 75| 1| let mut countdown = 0; + 76| 1| if true { + 77| 1| countdown = 1; + 78| 1| } + 79| | + 80| 1| let z = if countdown > 7 { + ^0 + 81| 0| countdown -= 4; + 82| 1| } else if countdown > 2 { + 83| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 84| 0| countdown = 0; + 85| 0| } + 86| 0| countdown -= 5; + 87| | } else { + 88| 1| let should_be_reachable = countdown; + 89| 1| println!("reached"); + 90| 1| return; + 91| | }; + 92| | + 93| 0| let w = if countdown > 7 { + 94| 0| countdown -= 4; + 95| 0| } else if countdown > 2 { + 96| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 97| 0| countdown = 0; + 98| 0| } + 99| 0| countdown -= 5; + 100| | } else { + 101| 0| return; + 102| | }; + 103| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt index 4a51f842a4b..efd9cd4f72d 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt @@ -38,7 +38,7 @@ 37| | } 38| | 39| | impl InTrait for InStruct { - 40| | fn trait_func(&mut self, incr: u32) { + 40| 1| fn trait_func(&mut self, incr: u32) { 41| 1| self.in_struct_field += incr; 42| 1| in_func(self.in_struct_field); 43| 1| } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.nested_loops.txt index c9f373bf6a7..dd86a85815b 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.nested_loops.txt +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.nested_loops.txt @@ -15,7 +15,7 @@ 15| 1| a -= 10; 16| 1| if is_true { 17| 1| break 'outer; - 18| | } else { + 18| 0| } else { 19| 0| a -= 2; 20| 0| } 21| 2| } diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.overflow.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.overflow.txt new file mode 100644 index 00000000000..322de1da25a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.overflow.txt @@ -0,0 +1,64 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-101 + 3| | + 4| |fn might_overflow(to_add: u32) -> u32 { + 5| 4| if to_add > 5 { + 6| 1| println!("this will probably overflow"); + 7| 3| } + 8| 4| let add_to = u32::MAX - 5; + 9| 4| println!("does {} + {} overflow?", add_to, to_add); + 10| 4| let result = to_add + add_to; + 11| 4| println!("continuing after overflow check"); + 12| 4| result + 13| 4|} + 14| | + 15| |fn main() -> Result<(),u8> { + 16| 1| let mut countdown = 10; + 17| 10| while countdown > 0 { + 18| 10| if countdown == 1 { + 19| 0| let result = might_overflow(10); + 20| 0| println!("Result: {}", result); + 21| 10| } else if countdown < 5 { + 22| 3| let result = might_overflow(1); + 23| 3| println!("Result: {}", result); + 24| 15| } + 25| 9| countdown -= 1; + 26| | } + 27| 0| Ok(()) + 28| 0|} + 29| | + 30| |// Notes: + 31| |// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, + 32| |// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. + 33| |// 2. This test confirms the coverage generated when a program passes or fails a + 34| |// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). + 35| |// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, + 36| |// compiler-generated assertion failures are assumed to be a symptom of a program bug, not + 37| |// expected behavior. To simplify the coverage graphs and keep instrumented programs as + 38| |// small and fast as possible, `Assert` terminators are assumed to always succeed, and + 39| |// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not + 40| |// get its own coverage counter. + 41| |// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. + 42| |// In this test, the final count for the statements after the `if` block in `might_overflow()` + 43| |// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending + 44| |// on the MIR graph and the structure of the code, this count could have been 3 (which might + 45| |// have been valid for the overflowed add `+`, but should have been 4 for the lines before + 46| |// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented + 47| |// via StatementKind::Counter at the end of the block, but (as in the case in this test), + 48| |// a CounterKind::Expression is always evaluated. In this case, the expression was based on + 49| |// a `Counter` incremented as part of the evaluation of the `if` expression, which was + 50| |// executed, and counted, 4 times, before reaching the overflow add. + 51| | + 52| |// If the program did not overflow, the coverage for `might_overflow()` would look like this: + 53| |// + 54| |// 4| |fn might_overflow(to_add: u32) -> u32 { + 55| |// 5| 4| if to_add > 5 { + 56| |// 6| 0| println!("this will probably overflow"); + 57| |// 7| 4| } + 58| |// 8| 4| let add_to = u32::MAX - 5; + 59| |// 9| 4| println!("does {} + {} overflow?", add_to, to_add); + 60| |// 10| 4| let result = to_add + add_to; + 61| |// 11| 4| println!("continuing after overflow check"); + 62| |// 12| 4| result + 63| |// 13| 4|} + diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.panic_unwind.txt new file mode 100644 index 00000000000..f5149c11b7b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.panic_unwind.txt @@ -0,0 +1,50 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-101 + 3| | + 4| |fn might_panic(should_panic: bool) { + 5| 4| if should_panic { + 6| 1| println!("panicking..."); + 7| 1| panic!("panics"); + 8| 3| } else { + 9| 3| println!("Don't Panic"); + 10| 3| } + 11| 3|} + 12| | + 13| |fn main() -> Result<(),u8> { + 14| 1| let mut countdown = 10; + 15| 10| while countdown > 0 { + 16| 10| if countdown == 1 { + 17| 0| might_panic(true); + 18| 10| } else if countdown < 5 { + 19| 3| might_panic(false); + 20| 15| } + 21| 9| countdown -= 1; + 22| | } + 23| 0| Ok(()) + 24| 0|} + 25| | + 26| |// Notes: + 27| |// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and + 28| |// `try_error_result.rs`. + 29| |// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the + 30| |// normal program exit cleanup, including writing out the current values of the coverage + 31| |// counters. + 32| |// 3. The coverage results show (interestingly) that the `panic!()` call did execute, but it does + 33| |// not show coverage of the `if countdown == 1` branch in `main()` that calls + 34| |// `might_panic(true)` (causing the call to `panic!()`). + 35| |// 4. The reason `main()`s `if countdown == 1` branch, calling `might_panic(true)`, appears + 36| |// "uncovered" is, InstrumentCoverage (intentionally) treats `TerminatorKind::Call` terminators + 37| |// as non-branching, because when a program executes normally, they always are. Errors handled + 38| |// via the try `?` operator produce error handling branches that *are* treated as branches in + 39| |// coverage results. By treating calls without try `?` operators as non-branching (assumed to + 40| |// return normally and continue) the coverage graph can be simplified, producing smaller, + 41| |// faster binaries, and cleaner coverage results. + 42| |// 5. The reason the coverage results actually show `panic!()` was called is most likely because + 43| |// `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or + 44| |// `Terminator`s that execute with a coverage counter before the panic and unwind occur. + 45| |// 6. By best practice, programs should not panic. By design, the coverage implementation will not + 46| |// incur additional cost (in program size and execution time) to improve coverage results for + 47| |// an event that is not supposted to happen. + 48| |// 7. FIXME(#78544): This issue describes a feature request for a proposed option to enable + 49| |// more accurate coverage results for tests that intentionally panic. + diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.yield.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.yield.txt new file mode 100644 index 00000000000..28813dd6d0b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.yield.txt @@ -0,0 +1,38 @@ + 1| |#![feature(generators, generator_trait)] + 2| |#![allow(unused_assignments)] + 3| | + 4| |use std::ops::{Generator, GeneratorState}; + 5| |use std::pin::Pin; + 6| | + 7| |fn main() { + 8| 1| let mut generator = || { + 9| 1| yield 1; + 10| 1| return "foo" + 11| 1| }; + 12| | + 13| 1| match Pin::new(&mut generator).resume(()) { + 14| 1| GeneratorState::Yielded(1) => {} + 15| 0| _ => panic!("unexpected value from resume"), + 16| | } + 17| 1| match Pin::new(&mut generator).resume(()) { + 18| 1| GeneratorState::Complete("foo") => {} + 19| 0| _ => panic!("unexpected value from resume"), + 20| | } + 21| | + 22| 1| let mut generator = || { + 23| 1| yield 1; + 24| 1| yield 2; + 25| 0| yield 3; + 26| 0| return "foo" + 27| 0| }; + 28| | + 29| 1| match Pin::new(&mut generator).resume(()) { + 30| 1| GeneratorState::Yielded(1) => {} + 31| 0| _ => panic!("unexpected value from resume"), + 32| | } + 33| 1| match Pin::new(&mut generator).resume(()) { + 34| 1| GeneratorState::Yielded(2) => {} + 35| 0| _ => panic!("unexpected value from resume"), + 36| | } + 37| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.abort.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.abort.txt new file mode 100644 index 00000000000..e787e5e152d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.abort.txt @@ -0,0 +1,41 @@ +Counter in file 0 15:9 -> 15:27, #1 +Counter in file 0 16:11 -> 16:24, (#1 + (#2 + #3)) +Counter in file 0 17:12 -> 17:25, ((#1 + (#2 + #3)) - #4) +Counter in file 0 17:26 -> 19:10, #2 +Counter in file 0 19:10 -> 19:11, #3 +Counter in file 0 20:9 -> 20:23, (#2 + #3) +Counter in file 0 22:5 -> 23:2, #4 +Counter in file 0 6:8 -> 6:20, #1 +Counter in file 0 7:9 -> 8:37, #2 +Counter in file 0 9:12 -> 12:2, (#1 - #2) +Emitting segments for file: ../coverage/abort.rs +Combined regions: + 6:8 -> 6:20 (count=4) + 7:9 -> 8:37 (count=0) + 9:12 -> 12:2 (count=4) + 15:9 -> 15:27 (count=1) + 16:11 -> 16:24 (count=11) + 17:12 -> 17:25 (count=10) + 17:26 -> 19:10 (count=4) + 19:10 -> 19:11 (count=6) + 20:9 -> 20:23 (count=10) + 22:5 -> 23:2 (count=1) +Segment at 6:8 (count = 4), RegionEntry +Segment at 6:20 (count = 0), Skipped +Segment at 7:9 (count = 0), RegionEntry +Segment at 8:37 (count = 0), Skipped +Segment at 9:12 (count = 4), RegionEntry +Segment at 12:2 (count = 0), Skipped +Segment at 15:9 (count = 1), RegionEntry +Segment at 15:27 (count = 0), Skipped +Segment at 16:11 (count = 11), RegionEntry +Segment at 16:24 (count = 0), Skipped +Segment at 17:12 (count = 10), RegionEntry +Segment at 17:25 (count = 0), Skipped +Segment at 17:26 (count = 4), RegionEntry +Segment at 19:10 (count = 6), RegionEntry +Segment at 19:11 (count = 0), Skipped +Segment at 20:9 (count = 10), RegionEntry +Segment at 20:23 (count = 0), Skipped +Segment at 22:5 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.assert.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.assert.txt new file mode 100644 index 00000000000..81cb6c03da7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.assert.txt @@ -0,0 +1,54 @@ +Counter in file 0 10:9 -> 10:27, #1 +Counter in file 0 11:11 -> 11:24, (#1 + (#2 + (#3 + #4))) +Counter in file 0 12:12 -> 12:26, ((#1 + (#2 + (#3 + #4))) - #5) +Counter in file 0 12:27 -> 14:10, #2 +Counter in file 0 14:19 -> 14:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) +Counter in file 0 14:33 -> 16:10, #3 +Counter in file 0 16:10 -> 16:11, #4 +Counter in file 0 16:10 -> 16:11, (#3 + #4) +Counter in file 0 17:9 -> 17:23, (#2 + (#3 + #4)) +Counter in file 0 19:5 -> 20:2, #5 +Counter in file 0 5:5 -> 5:48, #1 +Counter in file 0 6:16 -> 6:21, (#1 + 0) +Counter in file 0 6:37 -> 6:61, #2 +Counter in file 0 7:1 -> 7:2, (#1 - #2) +Emitting segments for file: ../coverage/assert.rs +Combined regions: + 5:5 -> 5:48 (count=4) + 6:16 -> 6:21 (count=4) + 6:37 -> 6:61 (count=1) + 7:1 -> 7:2 (count=3) + 10:9 -> 10:27 (count=1) + 11:11 -> 11:24 (count=10) + 12:12 -> 12:26 (count=10) + 12:27 -> 14:10 (count=0) + 14:19 -> 14:32 (count=10) + 14:33 -> 16:10 (count=3) + 16:10 -> 16:11 (count=15) + 17:9 -> 17:23 (count=9) + 19:5 -> 20:2 (count=0) +Segment at 5:5 (count = 4), RegionEntry +Segment at 5:48 (count = 0), Skipped +Segment at 6:16 (count = 4), RegionEntry +Segment at 6:21 (count = 0), Skipped +Segment at 6:37 (count = 1), RegionEntry +Segment at 6:61 (count = 0), Skipped +Segment at 7:1 (count = 3), RegionEntry +Segment at 7:2 (count = 0), Skipped +Segment at 10:9 (count = 1), RegionEntry +Segment at 10:27 (count = 0), Skipped +Segment at 11:11 (count = 10), RegionEntry +Segment at 11:24 (count = 0), Skipped +Segment at 12:12 (count = 10), RegionEntry +Segment at 12:26 (count = 0), Skipped +Segment at 12:27 (count = 0), RegionEntry +Segment at 14:10 (count = 0), Skipped +Segment at 14:19 (count = 10), RegionEntry +Segment at 14:32 (count = 0), Skipped +Segment at 14:33 (count = 3), RegionEntry +Segment at 16:10 (count = 15), RegionEntry +Segment at 16:11 (count = 0), Skipped +Segment at 17:9 (count = 9), RegionEntry +Segment at 17:23 (count = 0), Skipped +Segment at 19:5 (count = 0), RegionEntry +Segment at 20:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.async.txt new file mode 100644 index 00000000000..0490a319856 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.async.txt @@ -0,0 +1,84 @@ +Counter in file 0 15:9 -> 15:75, #1 +Counter in file 0 15:9 -> 15:75, #1 +Counter in file 0 15:9 -> 15:75, #1 +Counter in file 0 47:13 -> 56:54, #1 +Counter in file 0 59:32 -> 59:35, ((#1 + #2) - #2) +Counter in file 0 59:39 -> 59:73, (#1 + #2) +Counter in file 0 60:23 -> 60:26, (((#1 + #2) - #2) + 0) +Counter in file 0 62:10 -> 62:11, #2 +Counter in file 0 63:5 -> 63:6, (((#1 + #2) - #2) + 0) +Counter in file 0 53:17 -> 53:19, #1 +Counter in file 0 30:1 -> 30:2, #1 +Counter in file 0 5:24 -> 5:25, #1 +Counter in file 0 14:1 -> 14:2, #1 +Counter in file 0 5:22 -> 5:25, #1 +Counter in file 0 25:19 -> 26:12, #1 +Counter in file 0 27:9 -> 27:10, #3 +Counter in file 0 27:14 -> 27:17, (#1 + 0) +Counter in file 0 27:27 -> 27:32, #2 +Counter in file 0 27:32 -> 27:33, (#2 - #3) +Counter in file 0 27:36 -> 27:38, (#3 + 0) +Counter in file 0 28:14 -> 28:16, #4 +Counter in file 0 30:1 -> 30:2, (#3 + #4) +Counter in file 0 23:1 -> 23:2, #1 +Counter in file 0 32:11 -> 37:2, #1 +Emitting segments for file: ../coverage/async.rs +Combined regions: + 5:22 -> 5:25 (count=1) + 5:24 -> 5:25 (count=1) + 14:1 -> 14:2 (count=1) + 23:1 -> 23:2 (count=1) + 25:19 -> 26:12 (count=1) + 27:9 -> 27:10 (count=0) + 27:14 -> 27:17 (count=1) + 27:27 -> 27:32 (count=1) + 27:32 -> 27:33 (count=1) + 27:36 -> 27:38 (count=0) + 28:14 -> 28:16 (count=1) + 30:1 -> 30:2 (count=2) + 32:11 -> 37:2 (count=1) + 47:13 -> 56:54 (count=1) + 53:17 -> 53:19 (count=1) + 59:32 -> 59:35 (count=1) + 59:39 -> 59:73 (count=1) + 60:23 -> 60:26 (count=1) + 62:10 -> 62:11 (count=0) + 63:5 -> 63:6 (count=1) +Segment at 5:22 (count = 1), RegionEntry +Segment at 5:24 (count = 1), RegionEntry +Segment at 5:25 (count = 0), Skipped +Segment at 14:1 (count = 1), RegionEntry +Segment at 14:2 (count = 0), Skipped +Segment at 23:1 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped +Segment at 25:19 (count = 1), RegionEntry +Segment at 26:12 (count = 0), Skipped +Segment at 27:9 (count = 0), RegionEntry +Segment at 27:10 (count = 0), Skipped +Segment at 27:14 (count = 1), RegionEntry +Segment at 27:17 (count = 0), Skipped +Segment at 27:27 (count = 1), RegionEntry +Segment at 27:32 (count = 1), RegionEntry +Segment at 27:33 (count = 0), Skipped +Segment at 27:36 (count = 0), RegionEntry +Segment at 27:38 (count = 0), Skipped +Segment at 28:14 (count = 1), RegionEntry +Segment at 28:16 (count = 0), Skipped +Segment at 30:1 (count = 2), RegionEntry +Segment at 30:2 (count = 0), Skipped +Segment at 32:11 (count = 1), RegionEntry +Segment at 37:2 (count = 0), Skipped +Segment at 47:13 (count = 1), RegionEntry +Segment at 53:17 (count = 1), RegionEntry +Segment at 53:19 (count = 1) +Segment at 56:54 (count = 0), Skipped +Segment at 59:32 (count = 1), RegionEntry +Segment at 59:35 (count = 0), Skipped +Segment at 59:39 (count = 1), RegionEntry +Segment at 59:73 (count = 0), Skipped +Segment at 60:23 (count = 1), RegionEntry +Segment at 60:26 (count = 0), Skipped +Segment at 62:10 (count = 0), RegionEntry +Segment at 62:11 (count = 0), Skipped +Segment at 63:5 (count = 1), RegionEntry +Segment at 63:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt index d48cd8074be..a4c1a9c0f12 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt @@ -1,72 +1,91 @@ Counter in file 0 4:9 -> 4:26, #1 Counter in file 0 5:8 -> 5:12, (#1 + 0) Counter in file 0 5:13 -> 7:6, #2 -Counter in file 0 10:9 -> 10:10, (#4 + #11) +Counter in file 0 10:9 -> 10:10, (#3 + (#12 + #13)) Counter in file 0 10:16 -> 10:29, (#2 + 0) -Counter in file 0 11:9 -> 12:10, #4 +Counter in file 0 11:9 -> 12:10, #3 Counter in file 0 13:15 -> 13:28, ((#2 + 0) - #3) -Counter in file 0 14:12 -> 14:25, #5 -Counter in file 0 14:29 -> 14:42, (#5 - #13) -Counter in file 0 14:42 -> 14:43, (#13 + #14) -Counter in file 0 14:42 -> 14:43, ((#5 - #13) - #14) -Counter in file 0 14:46 -> 14:60, #21 -Counter in file 0 14:60 -> 14:61, (#17 + #18) -Counter in file 0 14:60 -> 14:61, (#21 - #18) -Counter in file 0 14:61 -> 16:10, #22 -Counter in file 0 16:10 -> 16:11, #23 -Counter in file 0 17:9 -> 18:18, #11 -Counter in file 0 20:9 -> 20:15, (((#2 + 0) - #3) - #5) -Counter in file 0 23:9 -> 23:26, ((#4 + #11) + 0) -Counter in file 0 24:8 -> 24:12, ((#4 + #11) + 0) -Counter in file 0 24:13 -> 26:6, #12 -Counter in file 0 28:8 -> 28:21, (#12 + 0) -Counter in file 0 29:9 -> 29:23, #16 -Counter in file 0 30:15 -> 30:28, ((#12 + 0) - #15) -Counter in file 0 31:12 -> 31:25, (((#12 + 0) - #15) - #8) -Counter in file 0 31:29 -> 31:42, ((((#12 + 0) - #15) - #8) - #24) -Counter in file 0 31:42 -> 31:43, (((((#12 + 0) - #15) - #8) - #24) - #25) +Counter in file 0 14:12 -> 14:25, #4 +Counter in file 0 14:29 -> 14:42, (#4 - #15) +Counter in file 0 14:42 -> 14:43, ((#4 - #15) - #16) +Counter in file 0 14:42 -> 14:43, (#15 + #16) +Counter in file 0 14:46 -> 14:60, #23 +Counter in file 0 14:60 -> 14:61, (#18 + #19) +Counter in file 0 14:60 -> 14:61, (#23 - #19) +Counter in file 0 14:61 -> 16:10, #12 +Counter in file 0 16:10 -> 16:11, #13 +Counter in file 0 17:9 -> 18:18, (#12 + #13) +Counter in file 0 20:9 -> 20:15, (((#2 + 0) - #3) - #4) +Counter in file 0 23:9 -> 23:26, ((#3 + (#12 + #13)) + 0) +Counter in file 0 24:8 -> 24:12, ((#3 + (#12 + #13)) + 0) +Counter in file 0 24:13 -> 26:6, #14 +Counter in file 0 28:8 -> 28:21, (#14 + 0) +Counter in file 0 28:22 -> 30:6, #17 +Counter in file 0 30:15 -> 30:28, ((#14 + 0) - #17) +Counter in file 0 31:12 -> 31:25, (((#14 + 0) - #17) - #8) +Counter in file 0 31:29 -> 31:42, ((((#14 + 0) - #17) - #8) - #24) +Counter in file 0 31:42 -> 31:43, (((((#14 + 0) - #17) - #8) - #24) - #25) Counter in file 0 31:42 -> 31:43, (#24 + #25) -Counter in file 0 31:46 -> 31:60, #32 -Counter in file 0 31:60 -> 31:61, (#28 + #29) -Counter in file 0 31:60 -> 31:61, (#32 - #29) -Counter in file 0 31:61 -> 33:10, #33 -Counter in file 0 33:10 -> 33:11, #34 -Counter in file 0 34:9 -> 34:23, #19 +Counter in file 0 31:46 -> 31:60, #34 +Counter in file 0 31:60 -> 31:61, (#34 - #32) +Counter in file 0 31:60 -> 31:61, (#31 + #32) +Counter in file 0 31:61 -> 33:10, #20 +Counter in file 0 33:10 -> 33:11, #21 +Counter in file 0 34:9 -> 34:23, (#20 + #21) Counter in file 0 36:9 -> 36:15, #8 -Counter in file 0 39:9 -> 39:26, (#16 + #19) -Counter in file 0 40:8 -> 40:12, ((#16 + #19) + 0) -Counter in file 0 40:13 -> 42:6, #20 -Counter in file 0 44:9 -> 44:10, (#27 + #30) -Counter in file 0 44:16 -> 44:29, (#20 + 0) -Counter in file 0 45:9 -> 45:23, #27 -Counter in file 0 46:15 -> 46:28, ((#20 + 0) - #26) -Counter in file 0 47:12 -> 47:25, (((#20 + 0) - #26) - #7) -Counter in file 0 47:29 -> 47:42, ((((#20 + 0) - #26) - #7) - #35) -Counter in file 0 47:42 -> 47:43, (#35 + #36) -Counter in file 0 47:42 -> 47:43, (((((#20 + 0) - #26) - #7) - #35) - #36) -Counter in file 0 47:46 -> 47:60, #41 -Counter in file 0 47:60 -> 47:61, (#37 + #38) -Counter in file 0 47:60 -> 47:61, (#41 - #38) -Counter in file 0 47:61 -> 49:10, #42 -Counter in file 0 49:10 -> 49:11, #43 -Counter in file 0 50:9 -> 50:23, #30 -Counter in file 0 52:13 -> 54:15, #7 -Counter in file 0 57:9 -> 57:10, (#9 + #10) -Counter in file 0 57:16 -> 57:29, ((#27 + #30) + 0) -Counter in file 0 58:9 -> 58:23, #9 -Counter in file 0 59:15 -> 59:28, ((#27 + #30) - #31) -Counter in file 0 60:12 -> 60:25, (((#27 + #30) - #31) - #6) -Counter in file 0 60:29 -> 60:42, ((((#27 + #30) - #31) - #6) - #39) -Counter in file 0 60:42 -> 60:43, (#39 + #40) -Counter in file 0 60:42 -> 60:43, (((((#27 + #30) - #31) - #6) - #39) - #40) -Counter in file 0 60:46 -> 60:60, #46 -Counter in file 0 60:60 -> 60:61, (#46 - #45) -Counter in file 0 60:60 -> 60:61, (#44 + #45) -Counter in file 0 60:61 -> 62:10, #47 -Counter in file 0 62:10 -> 62:11, #48 -Counter in file 0 63:9 -> 63:23, #10 -Counter in file 0 65:9 -> 65:15, #6 -Counter in file 0 67:1 -> 67:2, ((#9 + #10) + (((#6 + #7) + #8) + (((#2 + 0) - #3) - #5))) +Counter in file 0 39:8 -> 39:12, (#17 + (#20 + #21)) +Counter in file 0 52:13 -> 52:30, #22 +Counter in file 0 53:12 -> 53:16, (#22 + 0) +Counter in file 0 53:17 -> 55:10, #26 +Counter in file 0 57:12 -> 57:25, (#26 + 0) +Counter in file 0 57:26 -> 59:10, #27 +Counter in file 0 65:17 -> 65:30, ((#26 + 0) - #27) +Counter in file 0 66:16 -> 66:29, (((#26 + 0) - #27) - #7) +Counter in file 0 66:33 -> 66:46, ((((#26 + 0) - #27) - #7) - #37) +Counter in file 0 66:46 -> 66:47, (#37 + #38) +Counter in file 0 66:46 -> 66:47, (((((#26 + 0) - #27) - #7) - #37) - #38) +Counter in file 0 66:50 -> 66:64, #47 +Counter in file 0 66:64 -> 66:65, (#47 - #42) +Counter in file 0 66:64 -> 66:65, (#41 + #42) +Counter in file 0 66:65 -> 68:14, #28 +Counter in file 0 68:14 -> 68:15, #29 +Counter in file 0 69:13 -> 69:27, (#28 + #29) +Counter in file 0 71:13 -> 71:19, #7 +Counter in file 0 73:6 -> 73:7, (#27 + (#28 + #29)) +Counter in file 0 75:9 -> 75:26, ((#27 + (#28 + #29)) + 0) +Counter in file 0 76:8 -> 76:12, (((#27 + (#28 + #29)) + 0) + 0) +Counter in file 0 76:13 -> 78:6, #30 +Counter in file 0 80:9 -> 80:10, (#33 + (#35 + #36)) +Counter in file 0 80:16 -> 80:29, (#30 + 0) +Counter in file 0 80:30 -> 82:6, #33 +Counter in file 0 82:15 -> 82:28, ((#30 + 0) - #33) +Counter in file 0 83:12 -> 83:25, (((#30 + 0) - #33) - #6) +Counter in file 0 83:29 -> 83:42, ((((#30 + 0) - #33) - #6) - #39) +Counter in file 0 83:42 -> 83:43, (#39 + #40) +Counter in file 0 83:42 -> 83:43, (((((#30 + 0) - #33) - #6) - #39) - #40) +Counter in file 0 83:46 -> 83:60, #48 +Counter in file 0 83:60 -> 83:61, (#43 + #44) +Counter in file 0 83:60 -> 83:61, (#48 - #44) +Counter in file 0 83:61 -> 85:10, #35 +Counter in file 0 85:10 -> 85:11, #36 +Counter in file 0 86:9 -> 86:23, (#35 + #36) +Counter in file 0 88:13 -> 90:15, #6 +Counter in file 0 93:9 -> 93:10, (#9 + (#10 + #11)) +Counter in file 0 93:16 -> 93:29, ((#33 + (#35 + #36)) + 0) +Counter in file 0 93:30 -> 95:6, #9 +Counter in file 0 95:15 -> 95:28, ((#33 + (#35 + #36)) - #9) +Counter in file 0 96:12 -> 96:25, (((#33 + (#35 + #36)) - #9) - #5) +Counter in file 0 96:29 -> 96:42, ((((#33 + (#35 + #36)) - #9) - #5) - #45) +Counter in file 0 96:42 -> 96:43, (#45 + #46) +Counter in file 0 96:42 -> 96:43, (((((#33 + (#35 + #36)) - #9) - #5) - #45) - #46) +Counter in file 0 96:46 -> 96:60, #51 +Counter in file 0 96:60 -> 96:61, (#49 + #50) +Counter in file 0 96:60 -> 96:61, (#51 - #50) +Counter in file 0 96:61 -> 98:10, #10 +Counter in file 0 98:10 -> 98:11, #11 +Counter in file 0 99:9 -> 99:23, (#10 + #11) +Counter in file 0 101:9 -> 101:15, #5 +Counter in file 0 103:1 -> 103:2, ((#9 + (#10 + #11)) + (((#5 + #6) + (#7 + #8)) + (((#2 + 0) - #3) - #4))) Emitting segments for file: ../coverage/conditions.rs Combined regions: 4:9 -> 4:26 (count=1) @@ -89,7 +108,7 @@ Combined regions: 24:8 -> 24:12 (count=1) 24:13 -> 26:6 (count=1) 28:8 -> 28:21 (count=1) - 29:9 -> 29:23 (count=1) + 28:22 -> 30:6 (count=1) 30:15 -> 30:28 (count=0) 31:12 -> 31:25 (count=0) 31:29 -> 31:42 (count=0) @@ -100,36 +119,53 @@ Combined regions: 33:10 -> 33:11 (count=0) 34:9 -> 34:23 (count=0) 36:9 -> 36:15 (count=0) - 39:9 -> 39:26 (count=1) - 40:8 -> 40:12 (count=1) - 40:13 -> 42:6 (count=1) - 44:9 -> 44:10 (count=0) - 44:16 -> 44:29 (count=1) - 45:9 -> 45:23 (count=0) - 46:15 -> 46:28 (count=1) - 47:12 -> 47:25 (count=0) - 47:29 -> 47:42 (count=0) - 47:42 -> 47:43 (count=0) - 47:46 -> 47:60 (count=0) - 47:60 -> 47:61 (count=0) - 47:61 -> 49:10 (count=0) - 49:10 -> 49:11 (count=0) - 50:9 -> 50:23 (count=0) - 52:13 -> 54:15 (count=1) - 57:9 -> 57:10 (count=0) - 57:16 -> 57:29 (count=0) - 58:9 -> 58:23 (count=0) - 59:15 -> 59:28 (count=0) - 60:12 -> 60:25 (count=0) - 60:29 -> 60:42 (count=0) - 60:42 -> 60:43 (count=0) - 60:46 -> 60:60 (count=0) - 60:60 -> 60:61 (count=0) - 60:61 -> 62:10 (count=0) - 62:10 -> 62:11 (count=0) - 63:9 -> 63:23 (count=0) - 65:9 -> 65:15 (count=0) - 67:1 -> 67:2 (count=1) + 39:8 -> 39:12 (count=1) + 52:13 -> 52:30 (count=1) + 53:12 -> 53:16 (count=1) + 53:17 -> 55:10 (count=1) + 57:12 -> 57:25 (count=1) + 57:26 -> 59:10 (count=1) + 65:17 -> 65:30 (count=0) + 66:16 -> 66:29 (count=0) + 66:33 -> 66:46 (count=0) + 66:46 -> 66:47 (count=0) + 66:50 -> 66:64 (count=0) + 66:64 -> 66:65 (count=0) + 66:65 -> 68:14 (count=0) + 68:14 -> 68:15 (count=0) + 69:13 -> 69:27 (count=0) + 71:13 -> 71:19 (count=0) + 73:6 -> 73:7 (count=1) + 75:9 -> 75:26 (count=1) + 76:8 -> 76:12 (count=1) + 76:13 -> 78:6 (count=1) + 80:9 -> 80:10 (count=0) + 80:16 -> 80:29 (count=1) + 80:30 -> 82:6 (count=0) + 82:15 -> 82:28 (count=1) + 83:12 -> 83:25 (count=0) + 83:29 -> 83:42 (count=0) + 83:42 -> 83:43 (count=0) + 83:46 -> 83:60 (count=0) + 83:60 -> 83:61 (count=0) + 83:61 -> 85:10 (count=0) + 85:10 -> 85:11 (count=0) + 86:9 -> 86:23 (count=0) + 88:13 -> 90:15 (count=1) + 93:9 -> 93:10 (count=0) + 93:16 -> 93:29 (count=0) + 93:30 -> 95:6 (count=0) + 95:15 -> 95:28 (count=0) + 96:12 -> 96:25 (count=0) + 96:29 -> 96:42 (count=0) + 96:42 -> 96:43 (count=0) + 96:46 -> 96:60 (count=0) + 96:60 -> 96:61 (count=0) + 96:61 -> 98:10 (count=0) + 98:10 -> 98:11 (count=0) + 99:9 -> 99:23 (count=0) + 101:9 -> 101:15 (count=0) + 103:1 -> 103:2 (count=1) Segment at 4:9 (count = 1), RegionEntry Segment at 4:26 (count = 0), Skipped Segment at 5:8 (count = 1), RegionEntry @@ -166,8 +202,8 @@ Segment at 24:13 (count = 1), RegionEntry Segment at 26:6 (count = 0), Skipped Segment at 28:8 (count = 1), RegionEntry Segment at 28:21 (count = 0), Skipped -Segment at 29:9 (count = 1), RegionEntry -Segment at 29:23 (count = 0), Skipped +Segment at 28:22 (count = 1), RegionEntry +Segment at 30:6 (count = 0), Skipped Segment at 30:15 (count = 0), RegionEntry Segment at 30:28 (count = 0), Skipped Segment at 31:12 (count = 0), RegionEntry @@ -184,55 +220,85 @@ Segment at 34:9 (count = 0), RegionEntry Segment at 34:23 (count = 0), Skipped Segment at 36:9 (count = 0), RegionEntry Segment at 36:15 (count = 0), Skipped -Segment at 39:9 (count = 1), RegionEntry -Segment at 39:26 (count = 0), Skipped -Segment at 40:8 (count = 1), RegionEntry -Segment at 40:12 (count = 0), Skipped -Segment at 40:13 (count = 1), RegionEntry -Segment at 42:6 (count = 0), Skipped -Segment at 44:9 (count = 0), RegionEntry -Segment at 44:10 (count = 0), Skipped -Segment at 44:16 (count = 1), RegionEntry -Segment at 44:29 (count = 0), Skipped -Segment at 45:9 (count = 0), RegionEntry -Segment at 45:23 (count = 0), Skipped -Segment at 46:15 (count = 1), RegionEntry -Segment at 46:28 (count = 0), Skipped -Segment at 47:12 (count = 0), RegionEntry -Segment at 47:25 (count = 0), Skipped -Segment at 47:29 (count = 0), RegionEntry -Segment at 47:42 (count = 0), RegionEntry -Segment at 47:43 (count = 0), Skipped -Segment at 47:46 (count = 0), RegionEntry -Segment at 47:60 (count = 0), RegionEntry -Segment at 47:61 (count = 0), RegionEntry -Segment at 49:10 (count = 0), RegionEntry -Segment at 49:11 (count = 0), Skipped -Segment at 50:9 (count = 0), RegionEntry -Segment at 50:23 (count = 0), Skipped +Segment at 39:8 (count = 1), RegionEntry +Segment at 39:12 (count = 0), Skipped Segment at 52:13 (count = 1), RegionEntry -Segment at 54:15 (count = 0), Skipped -Segment at 57:9 (count = 0), RegionEntry -Segment at 57:10 (count = 0), Skipped -Segment at 57:16 (count = 0), RegionEntry -Segment at 57:29 (count = 0), Skipped -Segment at 58:9 (count = 0), RegionEntry -Segment at 58:23 (count = 0), Skipped -Segment at 59:15 (count = 0), RegionEntry -Segment at 59:28 (count = 0), Skipped -Segment at 60:12 (count = 0), RegionEntry -Segment at 60:25 (count = 0), Skipped -Segment at 60:29 (count = 0), RegionEntry -Segment at 60:42 (count = 0), RegionEntry -Segment at 60:43 (count = 0), Skipped -Segment at 60:46 (count = 0), RegionEntry -Segment at 60:60 (count = 0), RegionEntry -Segment at 60:61 (count = 0), RegionEntry -Segment at 62:10 (count = 0), RegionEntry -Segment at 62:11 (count = 0), Skipped -Segment at 63:9 (count = 0), RegionEntry -Segment at 63:23 (count = 0), Skipped -Segment at 65:9 (count = 0), RegionEntry -Segment at 65:15 (count = 0), Skipped -Segment at 67:1 (count = 1), RegionEntry -Segment at 67:2 (count = 0), Skipped +Segment at 52:30 (count = 0), Skipped +Segment at 53:12 (count = 1), RegionEntry +Segment at 53:16 (count = 0), Skipped +Segment at 53:17 (count = 1), RegionEntry +Segment at 55:10 (count = 0), Skipped +Segment at 57:12 (count = 1), RegionEntry +Segment at 57:25 (count = 0), Skipped +Segment at 57:26 (count = 1), RegionEntry +Segment at 59:10 (count = 0), Skipped +Segment at 65:17 (count = 0), RegionEntry +Segment at 65:30 (count = 0), Skipped +Segment at 66:16 (count = 0), RegionEntry +Segment at 66:29 (count = 0), Skipped +Segment at 66:33 (count = 0), RegionEntry +Segment at 66:46 (count = 0), RegionEntry +Segment at 66:47 (count = 0), Skipped +Segment at 66:50 (count = 0), RegionEntry +Segment at 66:64 (count = 0), RegionEntry +Segment at 66:65 (count = 0), RegionEntry +Segment at 68:14 (count = 0), RegionEntry +Segment at 68:15 (count = 0), Skipped +Segment at 69:13 (count = 0), RegionEntry +Segment at 69:27 (count = 0), Skipped +Segment at 71:13 (count = 0), RegionEntry +Segment at 71:19 (count = 0), Skipped +Segment at 73:6 (count = 1), RegionEntry +Segment at 73:7 (count = 0), Skipped +Segment at 75:9 (count = 1), RegionEntry +Segment at 75:26 (count = 0), Skipped +Segment at 76:8 (count = 1), RegionEntry +Segment at 76:12 (count = 0), Skipped +Segment at 76:13 (count = 1), RegionEntry +Segment at 78:6 (count = 0), Skipped +Segment at 80:9 (count = 0), RegionEntry +Segment at 80:10 (count = 0), Skipped +Segment at 80:16 (count = 1), RegionEntry +Segment at 80:29 (count = 0), Skipped +Segment at 80:30 (count = 0), RegionEntry +Segment at 82:6 (count = 0), Skipped +Segment at 82:15 (count = 1), RegionEntry +Segment at 82:28 (count = 0), Skipped +Segment at 83:12 (count = 0), RegionEntry +Segment at 83:25 (count = 0), Skipped +Segment at 83:29 (count = 0), RegionEntry +Segment at 83:42 (count = 0), RegionEntry +Segment at 83:43 (count = 0), Skipped +Segment at 83:46 (count = 0), RegionEntry +Segment at 83:60 (count = 0), RegionEntry +Segment at 83:61 (count = 0), RegionEntry +Segment at 85:10 (count = 0), RegionEntry +Segment at 85:11 (count = 0), Skipped +Segment at 86:9 (count = 0), RegionEntry +Segment at 86:23 (count = 0), Skipped +Segment at 88:13 (count = 1), RegionEntry +Segment at 90:15 (count = 0), Skipped +Segment at 93:9 (count = 0), RegionEntry +Segment at 93:10 (count = 0), Skipped +Segment at 93:16 (count = 0), RegionEntry +Segment at 93:29 (count = 0), Skipped +Segment at 93:30 (count = 0), RegionEntry +Segment at 95:6 (count = 0), Skipped +Segment at 95:15 (count = 0), RegionEntry +Segment at 95:28 (count = 0), Skipped +Segment at 96:12 (count = 0), RegionEntry +Segment at 96:25 (count = 0), Skipped +Segment at 96:29 (count = 0), RegionEntry +Segment at 96:42 (count = 0), RegionEntry +Segment at 96:43 (count = 0), Skipped +Segment at 96:46 (count = 0), RegionEntry +Segment at 96:60 (count = 0), RegionEntry +Segment at 96:61 (count = 0), RegionEntry +Segment at 98:10 (count = 0), RegionEntry +Segment at 98:11 (count = 0), Skipped +Segment at 99:9 (count = 0), RegionEntry +Segment at 99:23 (count = 0), Skipped +Segment at 101:9 (count = 0), RegionEntry +Segment at 101:15 (count = 0), Skipped +Segment at 103:1 (count = 1), RegionEntry +Segment at 103:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt index 65cd6481af4..e4dfae76817 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt @@ -1,7 +1,4 @@ -Counter in file 0 19:13 -> 19:18, #1 -Counter in file 0 20:13 -> 20:14, #2 -Counter in file 0 20:17 -> 20:22, (#1 + 0) -Counter in file 0 21:9 -> 22:6, (#2 + 0) +Counter in file 0 19:13 -> 22:6, #1 Counter in file 0 7:9 -> 9:26, #1 Counter in file 0 10:8 -> 10:15, (#1 + 0) Counter in file 0 10:16 -> 12:6, #2 @@ -11,21 +8,16 @@ Counter in file 0 48:16 -> 50:6, #3 Counter in file 0 50:6 -> 50:7, ((#2 + (#1 - #2)) - #3) Counter in file 0 52:9 -> 57:2, (#3 + ((#2 + (#1 - #2)) - #3)) Counter in file 0 33:42 -> 36:10, #1 -Counter in file 0 41:37 -> 41:41, #1 -Counter in file 0 42:13 -> 43:10, #2 +Counter in file 0 40:45 -> 43:10, #1 Emitting segments for file: ../coverage/inner_items.rs Combined regions: 7:9 -> 9:26 (count=1) 10:8 -> 10:15 (count=1) 10:16 -> 12:6 (count=1) 12:6 -> 12:7 (count=0) - 19:13 -> 19:18 (count=3) - 20:13 -> 20:14 (count=3) - 20:17 -> 20:22 (count=3) - 21:9 -> 22:6 (count=3) + 19:13 -> 22:6 (count=3) 33:42 -> 36:10 (count=1) - 41:37 -> 41:41 (count=1) - 42:13 -> 43:10 (count=1) + 40:45 -> 43:10 (count=1) 48:8 -> 48:15 (count=1) 48:16 -> 50:6 (count=1) 50:6 -> 50:7 (count=0) @@ -38,18 +30,10 @@ Segment at 10:16 (count = 1), RegionEntry Segment at 12:6 (count = 0), RegionEntry Segment at 12:7 (count = 0), Skipped Segment at 19:13 (count = 3), RegionEntry -Segment at 19:18 (count = 0), Skipped -Segment at 20:13 (count = 3), RegionEntry -Segment at 20:14 (count = 0), Skipped -Segment at 20:17 (count = 3), RegionEntry -Segment at 20:22 (count = 0), Skipped -Segment at 21:9 (count = 3), RegionEntry Segment at 22:6 (count = 0), Skipped Segment at 33:42 (count = 1), RegionEntry Segment at 36:10 (count = 0), Skipped -Segment at 41:37 (count = 1), RegionEntry -Segment at 41:41 (count = 0), Skipped -Segment at 42:13 (count = 1), RegionEntry +Segment at 40:45 (count = 1), RegionEntry Segment at 43:10 (count = 0), Skipped Segment at 48:8 (count = 1), RegionEntry Segment at 48:15 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt index f5030073533..f8e504c56c4 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt @@ -1,21 +1,20 @@ Counter in file 0 2:9 -> 3:27, #1 -Counter in file 0 5:19 -> 5:32, (#1 + #2) -Counter in file 0 6:13 -> 7:24, ((#1 + #2) - #3) -Counter in file 0 8:13 -> 8:14, ((((#1 + #2) - #3) + (#5 + #6)) - #7) -Counter in file 0 8:18 -> 8:23, (((#1 + #2) - #3) + (#5 + #6)) -Counter in file 0 9:16 -> 9:22, (((((#1 + #2) - #3) + (#5 + #6)) - #7) + 0) -Counter in file 0 10:17 -> 10:22, #8 -Counter in file 0 12:13 -> 12:19, #9 -Counter in file 0 13:13 -> 13:19, #10 -Counter in file 0 14:16 -> 14:22, (#10 + 0) -Counter in file 0 15:17 -> 16:27, #11 -Counter in file 0 17:21 -> 17:33, #4 -Counter in file 0 19:21 -> 21:14, #5 -Counter in file 0 21:14 -> 21:15, #6 -Counter in file 0 22:10 -> 22:11, (#5 + #6) -Counter in file 0 23:9 -> 23:23, #2 -Counter in file 0 24:6 -> 24:7, #3 -Counter in file 0 25:1 -> 25:2, (#4 + #3) +Counter in file 0 5:19 -> 5:32, (#1 + (#2 + #3)) +Counter in file 0 6:13 -> 7:24, ((#1 + (#2 + #3)) - #4) +Counter in file 0 8:13 -> 8:14, ((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) +Counter in file 0 8:18 -> 8:23, (((#1 + (#2 + #3)) - #4) + (#6 + #7)) +Counter in file 0 9:16 -> 9:22, (((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) + 0) +Counter in file 0 10:17 -> 10:22, #2 +Counter in file 0 12:13 -> 13:19, (((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) +Counter in file 0 14:16 -> 14:22, ((((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) + 0) +Counter in file 0 15:17 -> 16:27, ((((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) - #7) +Counter in file 0 17:21 -> 17:33, #5 +Counter in file 0 18:24 -> 21:14, #6 +Counter in file 0 21:14 -> 21:15, #7 +Counter in file 0 22:10 -> 22:11, (#6 + #7) +Counter in file 0 23:9 -> 23:23, (#2 + #3) +Counter in file 0 24:6 -> 24:7, #4 +Counter in file 0 25:1 -> 25:2, (#5 + #4) Emitting segments for file: ../coverage/nested_loops.rs Combined regions: 2:9 -> 3:27 (count=1) @@ -25,12 +24,11 @@ Combined regions: 8:18 -> 8:23 (count=3) 9:16 -> 9:22 (count=3) 10:17 -> 10:22 (count=0) - 12:13 -> 12:19 (count=3) - 13:13 -> 13:19 (count=3) + 12:13 -> 13:19 (count=3) 14:16 -> 14:22 (count=3) 15:17 -> 16:27 (count=1) 17:21 -> 17:33 (count=1) - 19:21 -> 21:14 (count=0) + 18:24 -> 21:14 (count=0) 21:14 -> 21:15 (count=2) 22:10 -> 22:11 (count=2) 23:9 -> 23:23 (count=0) @@ -51,8 +49,6 @@ Segment at 9:22 (count = 0), Skipped Segment at 10:17 (count = 0), RegionEntry Segment at 10:22 (count = 0), Skipped Segment at 12:13 (count = 3), RegionEntry -Segment at 12:19 (count = 0), Skipped -Segment at 13:13 (count = 3), RegionEntry Segment at 13:19 (count = 0), Skipped Segment at 14:16 (count = 3), RegionEntry Segment at 14:22 (count = 0), Skipped @@ -60,7 +56,7 @@ Segment at 15:17 (count = 1), RegionEntry Segment at 16:27 (count = 0), Skipped Segment at 17:21 (count = 1), RegionEntry Segment at 17:33 (count = 0), Skipped -Segment at 19:21 (count = 0), RegionEntry +Segment at 18:24 (count = 0), RegionEntry Segment at 21:14 (count = 2), RegionEntry Segment at 21:15 (count = 0), Skipped Segment at 22:10 (count = 2), RegionEntry diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.overflow.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.overflow.txt new file mode 100644 index 00000000000..8696e102b56 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.overflow.txt @@ -0,0 +1,53 @@ +Counter in file 0 16:9 -> 16:27, #1 +Counter in file 0 17:11 -> 17:24, (#1 + (#2 + (#3 + #4))) +Counter in file 0 18:12 -> 18:26, ((#1 + (#2 + (#3 + #4))) - #5) +Counter in file 0 18:27 -> 21:10, #2 +Counter in file 0 21:19 -> 21:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) +Counter in file 0 21:33 -> 24:10, #3 +Counter in file 0 24:10 -> 24:11, #4 +Counter in file 0 24:10 -> 24:11, (#3 + #4) +Counter in file 0 25:9 -> 25:23, (#2 + (#3 + #4)) +Counter in file 0 27:5 -> 28:2, #5 +Counter in file 0 5:8 -> 5:18, #1 +Counter in file 0 5:19 -> 7:6, #2 +Counter in file 0 7:6 -> 7:7, (#1 - #2) +Counter in file 0 8:9 -> 13:2, (#2 + (#1 - #2)) +Emitting segments for file: ../coverage/overflow.rs +Combined regions: + 5:8 -> 5:18 (count=4) + 5:19 -> 7:6 (count=1) + 7:6 -> 7:7 (count=3) + 8:9 -> 13:2 (count=4) + 16:9 -> 16:27 (count=1) + 17:11 -> 17:24 (count=10) + 18:12 -> 18:26 (count=10) + 18:27 -> 21:10 (count=0) + 21:19 -> 21:32 (count=10) + 21:33 -> 24:10 (count=3) + 24:10 -> 24:11 (count=15) + 25:9 -> 25:23 (count=9) + 27:5 -> 28:2 (count=0) +Segment at 5:8 (count = 4), RegionEntry +Segment at 5:18 (count = 0), Skipped +Segment at 5:19 (count = 1), RegionEntry +Segment at 7:6 (count = 3), RegionEntry +Segment at 7:7 (count = 0), Skipped +Segment at 8:9 (count = 4), RegionEntry +Segment at 13:2 (count = 0), Skipped +Segment at 16:9 (count = 1), RegionEntry +Segment at 16:27 (count = 0), Skipped +Segment at 17:11 (count = 10), RegionEntry +Segment at 17:24 (count = 0), Skipped +Segment at 18:12 (count = 10), RegionEntry +Segment at 18:26 (count = 0), Skipped +Segment at 18:27 (count = 0), RegionEntry +Segment at 21:10 (count = 0), Skipped +Segment at 21:19 (count = 10), RegionEntry +Segment at 21:32 (count = 0), Skipped +Segment at 21:33 (count = 3), RegionEntry +Segment at 24:10 (count = 15), RegionEntry +Segment at 24:11 (count = 0), Skipped +Segment at 25:9 (count = 9), RegionEntry +Segment at 25:23 (count = 0), Skipped +Segment at 27:5 (count = 0), RegionEntry +Segment at 28:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.panic_unwind.txt new file mode 100644 index 00000000000..9602ff1a985 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.panic_unwind.txt @@ -0,0 +1,50 @@ +Counter in file 0 14:9 -> 14:27, #1 +Counter in file 0 15:11 -> 15:24, (#1 + (#2 + (#3 + #4))) +Counter in file 0 16:12 -> 16:26, ((#1 + (#2 + (#3 + #4))) - #5) +Counter in file 0 16:27 -> 18:10, #2 +Counter in file 0 18:19 -> 18:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) +Counter in file 0 18:33 -> 20:10, #3 +Counter in file 0 20:10 -> 20:11, #4 +Counter in file 0 20:10 -> 20:11, (#3 + #4) +Counter in file 0 21:9 -> 21:23, (#2 + (#3 + #4)) +Counter in file 0 23:5 -> 24:2, #5 +Counter in file 0 5:8 -> 5:20, #1 +Counter in file 0 6:9 -> 7:26, #2 +Counter in file 0 8:12 -> 11:2, (#1 - #2) +Emitting segments for file: ../coverage/panic_unwind.rs +Combined regions: + 5:8 -> 5:20 (count=4) + 6:9 -> 7:26 (count=1) + 8:12 -> 11:2 (count=3) + 14:9 -> 14:27 (count=1) + 15:11 -> 15:24 (count=10) + 16:12 -> 16:26 (count=10) + 16:27 -> 18:10 (count=0) + 18:19 -> 18:32 (count=10) + 18:33 -> 20:10 (count=3) + 20:10 -> 20:11 (count=15) + 21:9 -> 21:23 (count=9) + 23:5 -> 24:2 (count=0) +Segment at 5:8 (count = 4), RegionEntry +Segment at 5:20 (count = 0), Skipped +Segment at 6:9 (count = 1), RegionEntry +Segment at 7:26 (count = 0), Skipped +Segment at 8:12 (count = 3), RegionEntry +Segment at 11:2 (count = 0), Skipped +Segment at 14:9 (count = 1), RegionEntry +Segment at 14:27 (count = 0), Skipped +Segment at 15:11 (count = 10), RegionEntry +Segment at 15:24 (count = 0), Skipped +Segment at 16:12 (count = 10), RegionEntry +Segment at 16:26 (count = 0), Skipped +Segment at 16:27 (count = 0), RegionEntry +Segment at 18:10 (count = 0), Skipped +Segment at 18:19 (count = 10), RegionEntry +Segment at 18:32 (count = 0), Skipped +Segment at 18:33 (count = 3), RegionEntry +Segment at 20:10 (count = 15), RegionEntry +Segment at 20:11 (count = 0), Skipped +Segment at 21:9 (count = 9), RegionEntry +Segment at 21:23 (count = 0), Skipped +Segment at 23:5 (count = 0), RegionEntry +Segment at 24:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt index 255173e5534..6ea09248d65 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt @@ -3,10 +3,10 @@ Counter in file 0 12:9 -> 12:16, (#1 + 0) Counter in file 0 13:5 -> 18:6, #2 Counter in file 0 18:6 -> 18:7, (#1 - #2) Counter in file 0 23:13 -> 25:14, ((#2 + (#1 - #2)) + #3) -Counter in file 0 27:13 -> 27:18, #4 +Counter in file 0 27:13 -> 27:18, (((#2 + (#1 - #2)) + #3) - #3) Counter in file 0 30:9 -> 32:10, #3 Counter in file 0 34:6 -> 34:7, (#2 + (#1 - #2)) -Counter in file 0 35:1 -> 35:2, (#4 + 0) +Counter in file 0 35:1 -> 35:2, ((((#2 + (#1 - #2)) + #3) - #3) + 0) Emitting segments for file: ../coverage/simple_loop.rs Combined regions: 7:9 -> 9:26 (count=1) diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt index a317cd79291..5b7f5496af8 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt @@ -1,12 +1,12 @@ Counter in file 0 13:9 -> 14:23, #1 Counter in file 0 17:9 -> 17:10, ((#1 + (#2 + #3)) - #4) Counter in file 0 19:9 -> 19:14, (#1 + (#2 + #3)) -Counter in file 0 21:9 -> 25:26, #8 -Counter in file 0 27:13 -> 27:41, #9 +Counter in file 0 21:9 -> 25:26, (((#1 + (#2 + #3)) - #4) + 0) +Counter in file 0 27:13 -> 27:41, #8 Counter in file 0 27:41 -> 27:42, #5 -Counter in file 0 28:13 -> 28:42, (#9 - #5) +Counter in file 0 28:13 -> 28:42, (#8 - #5) Counter in file 0 28:42 -> 28:43, #6 -Counter in file 0 32:13 -> 32:42, (#8 - #9) +Counter in file 0 32:13 -> 32:42, (((#1 + (#2 + #3)) - #4) - #8) Counter in file 0 32:42 -> 32:43, #7 Counter in file 0 33:10 -> 33:11, #2 Counter in file 0 33:10 -> 33:11, #3 diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt index f541baec50c..7e79a8f00e1 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt @@ -1,7 +1,7 @@ Counter in file 0 5:9 -> 5:27, #1 Counter in file 0 7:9 -> 9:10, (#1 + #2) Counter in file 0 12:13 -> 14:14, ((#1 + #2) - #3) -Counter in file 0 18:21 -> 20:22, #6 +Counter in file 0 18:21 -> 20:22, (((#1 + #2) - #3) - #2) Counter in file 0 22:21 -> 22:27, #4 Counter in file 0 26:21 -> 26:27, #5 Counter in file 0 30:9 -> 32:10, #2 diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.yield.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.yield.txt new file mode 100644 index 00000000000..a1075358211 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.yield.txt @@ -0,0 +1,90 @@ +Counter in file 0 8:9 -> 8:22, #1 +Counter in file 0 13:11 -> 14:35, (#1 + 0) +Counter in file 0 14:39 -> 14:41, #4 +Counter in file 0 15:14 -> 15:52, (#2 + #3) +Counter in file 0 17:11 -> 17:46, (#4 + 0) +Counter in file 0 18:34 -> 18:39, (#4 - #5) +Counter in file 0 18:44 -> 18:46, ((#4 - #5) - #6) +Counter in file 0 19:14 -> 19:52, (#5 + #6) +Counter in file 0 22:9 -> 22:22, (((#4 - #5) - #6) + 0) +Counter in file 0 29:11 -> 30:35, (((#4 - #5) - #6) + 0) +Counter in file 0 30:39 -> 30:41, #9 +Counter in file 0 31:14 -> 31:52, (#7 + #8) +Counter in file 0 33:11 -> 34:35, (#9 + 0) +Counter in file 0 34:39 -> 34:41, #12 +Counter in file 0 35:14 -> 35:52, (#10 + #11) +Counter in file 0 37:1 -> 37:2, (#12 + 0) +Counter in file 0 9:9 -> 9:16, #1 +Counter in file 0 10:16 -> 11:6, #2 +Counter in file 0 23:9 -> 23:16, #1 +Counter in file 0 24:9 -> 24:16, #2 +Counter in file 0 25:9 -> 25:16, #3 +Counter in file 0 26:16 -> 27:6, #4 +Emitting segments for file: ../coverage/yield.rs +Combined regions: + 8:9 -> 8:22 (count=1) + 9:9 -> 9:16 (count=1) + 10:16 -> 11:6 (count=1) + 13:11 -> 14:35 (count=1) + 14:39 -> 14:41 (count=1) + 15:14 -> 15:52 (count=0) + 17:11 -> 17:46 (count=1) + 18:34 -> 18:39 (count=1) + 18:44 -> 18:46 (count=1) + 19:14 -> 19:52 (count=0) + 22:9 -> 22:22 (count=1) + 23:9 -> 23:16 (count=1) + 24:9 -> 24:16 (count=1) + 25:9 -> 25:16 (count=0) + 26:16 -> 27:6 (count=0) + 29:11 -> 30:35 (count=1) + 30:39 -> 30:41 (count=1) + 31:14 -> 31:52 (count=0) + 33:11 -> 34:35 (count=1) + 34:39 -> 34:41 (count=1) + 35:14 -> 35:52 (count=0) + 37:1 -> 37:2 (count=1) +Segment at 8:9 (count = 1), RegionEntry +Segment at 8:22 (count = 0), Skipped +Segment at 9:9 (count = 1), RegionEntry +Segment at 9:16 (count = 0), Skipped +Segment at 10:16 (count = 1), RegionEntry +Segment at 11:6 (count = 0), Skipped +Segment at 13:11 (count = 1), RegionEntry +Segment at 14:35 (count = 0), Skipped +Segment at 14:39 (count = 1), RegionEntry +Segment at 14:41 (count = 0), Skipped +Segment at 15:14 (count = 0), RegionEntry +Segment at 15:52 (count = 0), Skipped +Segment at 17:11 (count = 1), RegionEntry +Segment at 17:46 (count = 0), Skipped +Segment at 18:34 (count = 1), RegionEntry +Segment at 18:39 (count = 0), Skipped +Segment at 18:44 (count = 1), RegionEntry +Segment at 18:46 (count = 0), Skipped +Segment at 19:14 (count = 0), RegionEntry +Segment at 19:52 (count = 0), Skipped +Segment at 22:9 (count = 1), RegionEntry +Segment at 22:22 (count = 0), Skipped +Segment at 23:9 (count = 1), RegionEntry +Segment at 23:16 (count = 0), Skipped +Segment at 24:9 (count = 1), RegionEntry +Segment at 24:16 (count = 0), Skipped +Segment at 25:9 (count = 0), RegionEntry +Segment at 25:16 (count = 0), Skipped +Segment at 26:16 (count = 0), RegionEntry +Segment at 27:6 (count = 0), Skipped +Segment at 29:11 (count = 1), RegionEntry +Segment at 30:35 (count = 0), Skipped +Segment at 30:39 (count = 1), RegionEntry +Segment at 30:41 (count = 0), Skipped +Segment at 31:14 (count = 0), RegionEntry +Segment at 31:52 (count = 0), Skipped +Segment at 33:11 (count = 1), RegionEntry +Segment at 34:35 (count = 0), Skipped +Segment at 34:39 (count = 1), RegionEntry +Segment at 34:41 (count = 0), Skipped +Segment at 35:14 (count = 0), RegionEntry +Segment at 35:52 (count = 0), Skipped +Segment at 37:1 (count = 1), RegionEntry +Segment at 37:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.abort.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.abort.json new file mode 100644 index 00000000000..33cfc9f3ed7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.abort.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/abort.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 15, + "covered": 13, + "percent": 86.66666666666667 + }, + "regions": { + "count": 10, + "covered": 9, + "notcovered": 1, + "percent": 90 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 15, + "covered": 13, + "percent": 86.66666666666667 + }, + "regions": { + "count": 10, + "covered": 9, + "notcovered": 1, + "percent": 90 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.assert.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.assert.json new file mode 100644 index 00000000000..aa2a0cbebe7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.assert.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/assert.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 13, + "covered": 10, + "percent": 76.92307692307693 + }, + "regions": { + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 13, + "covered": 10, + "percent": 76.92307692307693 + }, + "regions": { + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.async.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.async.json new file mode 100644 index 00000000000..004bedeea62 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.async.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/async.rs", + "summary": { + "functions": { + "count": 9, + "covered": 9, + "percent": 100 + }, + "instantiations": { + "count": 9, + "covered": 9, + "percent": 100 + }, + "lines": { + "count": 31, + "covered": 30, + "percent": 96.7741935483871 + }, + "regions": { + "count": 21, + "covered": 18, + "notcovered": 3, + "percent": 85.71428571428571 + } + } + } + ], + "totals": { + "functions": { + "count": 9, + "covered": 9, + "percent": 100 + }, + "instantiations": { + "count": 9, + "covered": 9, + "percent": 100 + }, + "lines": { + "count": 31, + "covered": 30, + "percent": 96.7741935483871 + }, + "regions": { + "count": 21, + "covered": 18, + "notcovered": 3, + "percent": 85.71428571428571 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.conditions.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.conditions.json index ed937a1b13f..d69ca80839a 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.conditions.json +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.conditions.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 49, - "covered": 23, - "percent": 46.93877551020408 + "count": 64, + "covered": 33, + "percent": 51.5625 }, "regions": { - "count": 69, - "covered": 18, - "notcovered": 51, - "percent": 26.08695652173913 + "count": 88, + "covered": 25, + "notcovered": 63, + "percent": 28.40909090909091 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 49, - "covered": 23, - "percent": 46.93877551020408 + "count": 64, + "covered": 33, + "percent": 51.5625 }, "regions": { - "count": 69, - "covered": 18, - "notcovered": 51, - "percent": 26.08695652173913 + "count": 88, + "covered": 25, + "notcovered": 63, + "percent": 28.40909090909091 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json index c178e7f9347..5dc82d2168c 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 26, - "covered": 26, + "count": 27, + "covered": 27, "percent": 100 }, "regions": { - "count": 15, - "covered": 13, + "count": 11, + "covered": 9, "notcovered": 2, - "percent": 86.66666666666667 + "percent": 81.81818181818183 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 26, - "covered": 26, + "count": 27, + "covered": 27, "percent": 100 }, "regions": { - "count": 15, - "covered": 13, + "count": 11, + "covered": 9, "notcovered": 2, - "percent": 86.66666666666667 + "percent": 81.81818181818183 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.nested_loops.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.nested_loops.json index 68163eb7636..ce3c957e660 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.nested_loops.json +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.nested_loops.json @@ -16,15 +16,15 @@ "percent": 100 }, "lines": { - "count": 21, + "count": 22, "covered": 16, - "percent": 76.19047619047619 + "percent": 72.72727272727273 }, "regions": { - "count": 18, - "covered": 14, + "count": 17, + "covered": 13, "notcovered": 4, - "percent": 77.77777777777779 + "percent": 76.47058823529412 } } } @@ -41,15 +41,15 @@ "percent": 100 }, "lines": { - "count": 21, + "count": 22, "covered": 16, - "percent": 76.19047619047619 + "percent": 72.72727272727273 }, "regions": { - "count": 18, - "covered": 14, + "count": 17, + "covered": 13, "notcovered": 4, - "percent": 77.77777777777779 + "percent": 76.47058823529412 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.overflow.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.overflow.json new file mode 100644 index 00000000000..176bfd7abeb --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.overflow.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/overflow.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 21, + "covered": 17, + "percent": 80.95238095238095 + }, + "regions": { + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 21, + "covered": 17, + "percent": 80.95238095238095 + }, + "regions": { + "count": 14, + "covered": 12, + "notcovered": 2, + "percent": 85.71428571428571 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.panic_unwind.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.panic_unwind.json new file mode 100644 index 00000000000..5b13109dbe6 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.panic_unwind.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/panic_unwind.rs", + "summary": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 17, + "covered": 14, + "percent": 82.35294117647058 + }, + "regions": { + "count": 13, + "covered": 11, + "notcovered": 2, + "percent": 84.61538461538461 + } + } + } + ], + "totals": { + "functions": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "instantiations": { + "count": 2, + "covered": 2, + "percent": 100 + }, + "lines": { + "count": 17, + "covered": 14, + "percent": 82.35294117647058 + }, + "regions": { + "count": 13, + "covered": 11, + "notcovered": 2, + "percent": 84.61538461538461 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.yield.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.yield.json new file mode 100644 index 00000000000..9f25bc971c5 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.yield.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/yield.rs", + "summary": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "lines": { + "count": 23, + "covered": 16, + "percent": 69.56521739130434 + }, + "regions": { + "count": 22, + "covered": 16, + "notcovered": 6, + "percent": 72.72727272727273 + } + } + } + ], + "totals": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "lines": { + "count": 23, + "covered": 16, + "percent": 69.56521739130434 + }, + "regions": { + "count": 22, + "covered": 16, + "notcovered": 6, + "percent": 72.72727272727273 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.abort.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.abort.txt new file mode 100644 index 00000000000..40c9c71a2aa --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.abort.txt @@ -0,0 +1,35 @@ + 1| |#![feature(unwind_attributes)] + 2| |#![allow(unused_assignments)] + 3| | + 4| |#[unwind(aborts)] + 5| |fn might_abort(should_abort: bool) { + 6| 4| if should_abort { + 7| 0| println!("aborting..."); + 8| 0| panic!("panics and aborts"); + 9| 4| } else { + 10| 4| println!("Don't Panic"); + 11| 4| } + 12| 4|} + 13| | + 14| |fn main() -> Result<(),u8> { + 15| 1| let mut countdown = 10; + 16| 11| while countdown > 0 { + 17| 10| if countdown < 5 { + 18| 4| might_abort(false); + 19| 6| } + 20| 10| countdown -= 1; + 21| | } + 22| 1| Ok(()) + 23| 1|} + 24| | + 25| |// Notes: + 26| |// 1. Compare this program and its coverage results to those of the similar tests + 27| |// `panic_unwind.rs` and `try_error_result.rs`. + 28| |// 2. This test confirms the coverage generated when a program includes `TerminatorKind::Abort`. + 29| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage + 30| |// results show where the program did and did not execute. + 31| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as + 32| |// intended"). Coverage results would show no executed coverage regions. + 33| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status + 34| |// (on Linux at least). + diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.assert.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.assert.txt new file mode 100644 index 00000000000..a6efcbabd35 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.assert.txt @@ -0,0 +1,34 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-101 + 3| | + 4| |fn might_fail_assert(one_plus_one: u32) { + 5| 4| println!("does 1 + 1 = {}?", one_plus_one); + 6| 4| assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); + ^1 + 7| 3|} + 8| | + 9| |fn main() -> Result<(),u8> { + 10| 1| let mut countdown = 10; + 11| 10| while countdown > 0 { + 12| 10| if countdown == 1 { + 13| 0| might_fail_assert(3); + 14| 10| } else if countdown < 5 { + 15| 3| might_fail_assert(2); + 16| 15| } + 17| 9| countdown -= 1; + 18| | } + 19| 0| Ok(()) + 20| 0|} + 21| | + 22| |// Notes: + 23| |// 1. Compare this program and its coverage results to those of the very similar test + 24| |// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. + 25| |// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or + 26| |// related `assert_*!()` macro. + 27| |// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce + 28| |// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to + 29| |// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). + 30| |// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test + 31| |// (and in many other coverage tests). The `Assert` terminator is typically generated by the + 32| |// Rust compiler to check for runtime failures, such as numeric overflows. + diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.async.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.async.txt new file mode 100644 index 00000000000..b5d99732102 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.async.txt @@ -0,0 +1,66 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |// require-rust-edition-2018 + 4| | + 5| 1|async fn f() -> u8 { 1 } + 6| | + 7| |async fn foo() -> [bool; 10] { [false; 10] } + 8| | + 9| |pub async fn g(x: u8) { + 10| | match x { + 11| | y if f().await == y => (), + 12| | _ => (), + 13| | } + 14| 1|} + 15| | + 16| |// #78366: check the reference to the binding is recorded even if the binding is not autorefed + 17| | + 18| |async fn h(x: usize) { + 19| | match x { + 20| | y if foo().await[y] => (), + 21| | _ => (), + 22| | } + 23| 1|} + 24| | + 25| 1|async fn i(x: u8) { + 26| 1| match x { + 27| 1| y if f().await == y + 1 => (), + ^0 ^0 + 28| 1| _ => (), + 29| | } + 30| 2|} + 31| | + 32| 1|fn main() { + 33| 1| let _ = g(10); + 34| 1| let _ = h(9); + 35| 1| let mut future = Box::pin(i(8)); + 36| 1| executor::block_on(future.as_mut()); + 37| 1|} + 38| | + 39| |mod executor { + 40| | use core::{ + 41| | future::Future, + 42| | pin::Pin, + 43| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 44| | }; + 45| | + 46| | pub fn block_on(mut future: F) -> F::Output { + 47| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 48| 1| + 49| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + 50| 1| |_| unimplemented!("clone"), + 51| 1| |_| unimplemented!("wake"), + 52| 1| |_| unimplemented!("wake_by_ref"), + 53| 1| |_| (), + 54| 1| ); + 55| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + 56| 1| let mut context = Context::from_waker(&waker); + 57| | + 58| | loop { + 59| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + 60| 1| break val; + 61| | } + 62| 0| } + 63| 1| } + 64| |} + diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.conditions.txt index 173ff4aa4c4..e55a574c056 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.conditions.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.conditions.txt @@ -27,7 +27,8 @@ 27| | 28| 1| if countdown > 7 { 29| 1| countdown -= 4; - 30| 0| } else if countdown > 2 { + 30| 1| } else if countdown > 2 { + ^0 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { 32| 0| countdown = 0; 33| 0| } @@ -36,34 +37,70 @@ 36| 0| return; 37| | } 38| | - 39| 1| let mut countdown = 0; - 40| 1| if true { - 41| 1| countdown = 1; - 42| 1| } - 43| | - 44| 1| let z = if countdown > 7 { - ^0 - 45| 0| countdown -= 4; - 46| 1| } else if countdown > 2 { - 47| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 48| 0| countdown = 0; - 49| 0| } - 50| 0| countdown -= 5; - 51| | } else { - 52| 1| let should_be_reachable = countdown; - 53| 1| println!("reached"); - 54| 1| return; - 55| | }; + 39| 1| if true { + 40| | // Demonstrate the difference with `TerminatorKind::Assert` as of 2020-11-15. Assert is no + 41| | // longer treated as a `BasicCoverageBlock` terminator, which changed the coverage region, + 42| | // for the executed `then` block above, to include the closing brace on line 30. That + 43| | // changed the line count, but the coverage code region (for the `else if` condition) is + 44| | // still valid. + 45| | // + 46| | // Note that `if` (then) and `else` blocks include the closing brace in their coverage + 47| | // code regions when the last line in the block ends in a semicolon, because the Rust + 48| | // compiler inserts a `StatementKind::Assign` to assign `const ()` to a `Place`, for the + 49| | // empty value for the executed block. When the last line does not end in a semicolon + 50| | // (that is, when the block actually results in a value), the additional `Assign` is not + 51| | // generated, and the brace is not included. + 52| 1| let mut countdown = 0; + 53| 1| if true { + 54| 1| countdown = 10; + 55| 1| } 56| | - 57| 0| let w = if countdown > 7 { - 58| 0| countdown -= 4; - 59| 0| } else if countdown > 2 { - 60| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 61| 0| countdown = 0; - 62| 0| } - 63| 0| countdown -= 5; - 64| | } else { - 65| 0| return; - 66| | }; - 67| 1|} + 57| 1| if countdown > 7 { + 58| 1| countdown -= 4; + 59| 1| } + 60| | // The closing brace of the `then` branch is now included in the coverage region, and shown + 61| | // as "executed" (giving its line a count of 1 here). Since, in the original version above, + 62| | // the closing brace shares the same line as the `else if` conditional expression (which is + 63| | // not executed if the first `then` condition is true), only the condition's code region is + 64| | // marked with a count of 0 now. + 65| 0| else if countdown > 2 { + 66| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 67| 0| countdown = 0; + 68| 0| } + 69| 0| countdown -= 5; + 70| | } else { + 71| 0| return; + 72| | } + 73| 1| } + 74| | + 75| 1| let mut countdown = 0; + 76| 1| if true { + 77| 1| countdown = 1; + 78| 1| } + 79| | + 80| 1| let z = if countdown > 7 { + ^0 + 81| 0| countdown -= 4; + 82| 1| } else if countdown > 2 { + 83| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 84| 0| countdown = 0; + 85| 0| } + 86| 0| countdown -= 5; + 87| | } else { + 88| 1| let should_be_reachable = countdown; + 89| 1| println!("reached"); + 90| 1| return; + 91| | }; + 92| | + 93| 0| let w = if countdown > 7 { + 94| 0| countdown -= 4; + 95| 0| } else if countdown > 2 { + 96| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 97| 0| countdown = 0; + 98| 0| } + 99| 0| countdown -= 5; + 100| | } else { + 101| 0| return; + 102| | }; + 103| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt index 4a51f842a4b..efd9cd4f72d 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt @@ -38,7 +38,7 @@ 37| | } 38| | 39| | impl InTrait for InStruct { - 40| | fn trait_func(&mut self, incr: u32) { + 40| 1| fn trait_func(&mut self, incr: u32) { 41| 1| self.in_struct_field += incr; 42| 1| in_func(self.in_struct_field); 43| 1| } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.nested_loops.txt index c9f373bf6a7..dd86a85815b 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.nested_loops.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.nested_loops.txt @@ -15,7 +15,7 @@ 15| 1| a -= 10; 16| 1| if is_true { 17| 1| break 'outer; - 18| | } else { + 18| 0| } else { 19| 0| a -= 2; 20| 0| } 21| 2| } diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.overflow.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.overflow.txt new file mode 100644 index 00000000000..322de1da25a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.overflow.txt @@ -0,0 +1,64 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-101 + 3| | + 4| |fn might_overflow(to_add: u32) -> u32 { + 5| 4| if to_add > 5 { + 6| 1| println!("this will probably overflow"); + 7| 3| } + 8| 4| let add_to = u32::MAX - 5; + 9| 4| println!("does {} + {} overflow?", add_to, to_add); + 10| 4| let result = to_add + add_to; + 11| 4| println!("continuing after overflow check"); + 12| 4| result + 13| 4|} + 14| | + 15| |fn main() -> Result<(),u8> { + 16| 1| let mut countdown = 10; + 17| 10| while countdown > 0 { + 18| 10| if countdown == 1 { + 19| 0| let result = might_overflow(10); + 20| 0| println!("Result: {}", result); + 21| 10| } else if countdown < 5 { + 22| 3| let result = might_overflow(1); + 23| 3| println!("Result: {}", result); + 24| 15| } + 25| 9| countdown -= 1; + 26| | } + 27| 0| Ok(()) + 28| 0|} + 29| | + 30| |// Notes: + 31| |// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, + 32| |// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. + 33| |// 2. This test confirms the coverage generated when a program passes or fails a + 34| |// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). + 35| |// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, + 36| |// compiler-generated assertion failures are assumed to be a symptom of a program bug, not + 37| |// expected behavior. To simplify the coverage graphs and keep instrumented programs as + 38| |// small and fast as possible, `Assert` terminators are assumed to always succeed, and + 39| |// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not + 40| |// get its own coverage counter. + 41| |// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. + 42| |// In this test, the final count for the statements after the `if` block in `might_overflow()` + 43| |// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending + 44| |// on the MIR graph and the structure of the code, this count could have been 3 (which might + 45| |// have been valid for the overflowed add `+`, but should have been 4 for the lines before + 46| |// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented + 47| |// via StatementKind::Counter at the end of the block, but (as in the case in this test), + 48| |// a CounterKind::Expression is always evaluated. In this case, the expression was based on + 49| |// a `Counter` incremented as part of the evaluation of the `if` expression, which was + 50| |// executed, and counted, 4 times, before reaching the overflow add. + 51| | + 52| |// If the program did not overflow, the coverage for `might_overflow()` would look like this: + 53| |// + 54| |// 4| |fn might_overflow(to_add: u32) -> u32 { + 55| |// 5| 4| if to_add > 5 { + 56| |// 6| 0| println!("this will probably overflow"); + 57| |// 7| 4| } + 58| |// 8| 4| let add_to = u32::MAX - 5; + 59| |// 9| 4| println!("does {} + {} overflow?", add_to, to_add); + 60| |// 10| 4| let result = to_add + add_to; + 61| |// 11| 4| println!("continuing after overflow check"); + 62| |// 12| 4| result + 63| |// 13| 4|} + diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.panic_unwind.txt new file mode 100644 index 00000000000..f5149c11b7b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.panic_unwind.txt @@ -0,0 +1,50 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-101 + 3| | + 4| |fn might_panic(should_panic: bool) { + 5| 4| if should_panic { + 6| 1| println!("panicking..."); + 7| 1| panic!("panics"); + 8| 3| } else { + 9| 3| println!("Don't Panic"); + 10| 3| } + 11| 3|} + 12| | + 13| |fn main() -> Result<(),u8> { + 14| 1| let mut countdown = 10; + 15| 10| while countdown > 0 { + 16| 10| if countdown == 1 { + 17| 0| might_panic(true); + 18| 10| } else if countdown < 5 { + 19| 3| might_panic(false); + 20| 15| } + 21| 9| countdown -= 1; + 22| | } + 23| 0| Ok(()) + 24| 0|} + 25| | + 26| |// Notes: + 27| |// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and + 28| |// `try_error_result.rs`. + 29| |// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the + 30| |// normal program exit cleanup, including writing out the current values of the coverage + 31| |// counters. + 32| |// 3. The coverage results show (interestingly) that the `panic!()` call did execute, but it does + 33| |// not show coverage of the `if countdown == 1` branch in `main()` that calls + 34| |// `might_panic(true)` (causing the call to `panic!()`). + 35| |// 4. The reason `main()`s `if countdown == 1` branch, calling `might_panic(true)`, appears + 36| |// "uncovered" is, InstrumentCoverage (intentionally) treats `TerminatorKind::Call` terminators + 37| |// as non-branching, because when a program executes normally, they always are. Errors handled + 38| |// via the try `?` operator produce error handling branches that *are* treated as branches in + 39| |// coverage results. By treating calls without try `?` operators as non-branching (assumed to + 40| |// return normally and continue) the coverage graph can be simplified, producing smaller, + 41| |// faster binaries, and cleaner coverage results. + 42| |// 5. The reason the coverage results actually show `panic!()` was called is most likely because + 43| |// `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or + 44| |// `Terminator`s that execute with a coverage counter before the panic and unwind occur. + 45| |// 6. By best practice, programs should not panic. By design, the coverage implementation will not + 46| |// incur additional cost (in program size and execution time) to improve coverage results for + 47| |// an event that is not supposted to happen. + 48| |// 7. FIXME(#78544): This issue describes a feature request for a proposed option to enable + 49| |// more accurate coverage results for tests that intentionally panic. + diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.yield.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.yield.txt new file mode 100644 index 00000000000..28813dd6d0b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.yield.txt @@ -0,0 +1,38 @@ + 1| |#![feature(generators, generator_trait)] + 2| |#![allow(unused_assignments)] + 3| | + 4| |use std::ops::{Generator, GeneratorState}; + 5| |use std::pin::Pin; + 6| | + 7| |fn main() { + 8| 1| let mut generator = || { + 9| 1| yield 1; + 10| 1| return "foo" + 11| 1| }; + 12| | + 13| 1| match Pin::new(&mut generator).resume(()) { + 14| 1| GeneratorState::Yielded(1) => {} + 15| 0| _ => panic!("unexpected value from resume"), + 16| | } + 17| 1| match Pin::new(&mut generator).resume(()) { + 18| 1| GeneratorState::Complete("foo") => {} + 19| 0| _ => panic!("unexpected value from resume"), + 20| | } + 21| | + 22| 1| let mut generator = || { + 23| 1| yield 1; + 24| 1| yield 2; + 25| 0| yield 3; + 26| 0| return "foo" + 27| 0| }; + 28| | + 29| 1| match Pin::new(&mut generator).resume(()) { + 30| 1| GeneratorState::Yielded(1) => {} + 31| 0| _ => panic!("unexpected value from resume"), + 32| | } + 33| 1| match Pin::new(&mut generator).resume(()) { + 34| 1| GeneratorState::Yielded(2) => {} + 35| 0| _ => panic!("unexpected value from resume"), + 36| | } + 37| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.abort.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.abort.txt new file mode 100644 index 00000000000..e787e5e152d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.abort.txt @@ -0,0 +1,41 @@ +Counter in file 0 15:9 -> 15:27, #1 +Counter in file 0 16:11 -> 16:24, (#1 + (#2 + #3)) +Counter in file 0 17:12 -> 17:25, ((#1 + (#2 + #3)) - #4) +Counter in file 0 17:26 -> 19:10, #2 +Counter in file 0 19:10 -> 19:11, #3 +Counter in file 0 20:9 -> 20:23, (#2 + #3) +Counter in file 0 22:5 -> 23:2, #4 +Counter in file 0 6:8 -> 6:20, #1 +Counter in file 0 7:9 -> 8:37, #2 +Counter in file 0 9:12 -> 12:2, (#1 - #2) +Emitting segments for file: ../coverage/abort.rs +Combined regions: + 6:8 -> 6:20 (count=4) + 7:9 -> 8:37 (count=0) + 9:12 -> 12:2 (count=4) + 15:9 -> 15:27 (count=1) + 16:11 -> 16:24 (count=11) + 17:12 -> 17:25 (count=10) + 17:26 -> 19:10 (count=4) + 19:10 -> 19:11 (count=6) + 20:9 -> 20:23 (count=10) + 22:5 -> 23:2 (count=1) +Segment at 6:8 (count = 4), RegionEntry +Segment at 6:20 (count = 0), Skipped +Segment at 7:9 (count = 0), RegionEntry +Segment at 8:37 (count = 0), Skipped +Segment at 9:12 (count = 4), RegionEntry +Segment at 12:2 (count = 0), Skipped +Segment at 15:9 (count = 1), RegionEntry +Segment at 15:27 (count = 0), Skipped +Segment at 16:11 (count = 11), RegionEntry +Segment at 16:24 (count = 0), Skipped +Segment at 17:12 (count = 10), RegionEntry +Segment at 17:25 (count = 0), Skipped +Segment at 17:26 (count = 4), RegionEntry +Segment at 19:10 (count = 6), RegionEntry +Segment at 19:11 (count = 0), Skipped +Segment at 20:9 (count = 10), RegionEntry +Segment at 20:23 (count = 0), Skipped +Segment at 22:5 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.assert.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.assert.txt new file mode 100644 index 00000000000..81cb6c03da7 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.assert.txt @@ -0,0 +1,54 @@ +Counter in file 0 10:9 -> 10:27, #1 +Counter in file 0 11:11 -> 11:24, (#1 + (#2 + (#3 + #4))) +Counter in file 0 12:12 -> 12:26, ((#1 + (#2 + (#3 + #4))) - #5) +Counter in file 0 12:27 -> 14:10, #2 +Counter in file 0 14:19 -> 14:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) +Counter in file 0 14:33 -> 16:10, #3 +Counter in file 0 16:10 -> 16:11, #4 +Counter in file 0 16:10 -> 16:11, (#3 + #4) +Counter in file 0 17:9 -> 17:23, (#2 + (#3 + #4)) +Counter in file 0 19:5 -> 20:2, #5 +Counter in file 0 5:5 -> 5:48, #1 +Counter in file 0 6:16 -> 6:21, (#1 + 0) +Counter in file 0 6:37 -> 6:61, #2 +Counter in file 0 7:1 -> 7:2, (#1 - #2) +Emitting segments for file: ../coverage/assert.rs +Combined regions: + 5:5 -> 5:48 (count=4) + 6:16 -> 6:21 (count=4) + 6:37 -> 6:61 (count=1) + 7:1 -> 7:2 (count=3) + 10:9 -> 10:27 (count=1) + 11:11 -> 11:24 (count=10) + 12:12 -> 12:26 (count=10) + 12:27 -> 14:10 (count=0) + 14:19 -> 14:32 (count=10) + 14:33 -> 16:10 (count=3) + 16:10 -> 16:11 (count=15) + 17:9 -> 17:23 (count=9) + 19:5 -> 20:2 (count=0) +Segment at 5:5 (count = 4), RegionEntry +Segment at 5:48 (count = 0), Skipped +Segment at 6:16 (count = 4), RegionEntry +Segment at 6:21 (count = 0), Skipped +Segment at 6:37 (count = 1), RegionEntry +Segment at 6:61 (count = 0), Skipped +Segment at 7:1 (count = 3), RegionEntry +Segment at 7:2 (count = 0), Skipped +Segment at 10:9 (count = 1), RegionEntry +Segment at 10:27 (count = 0), Skipped +Segment at 11:11 (count = 10), RegionEntry +Segment at 11:24 (count = 0), Skipped +Segment at 12:12 (count = 10), RegionEntry +Segment at 12:26 (count = 0), Skipped +Segment at 12:27 (count = 0), RegionEntry +Segment at 14:10 (count = 0), Skipped +Segment at 14:19 (count = 10), RegionEntry +Segment at 14:32 (count = 0), Skipped +Segment at 14:33 (count = 3), RegionEntry +Segment at 16:10 (count = 15), RegionEntry +Segment at 16:11 (count = 0), Skipped +Segment at 17:9 (count = 9), RegionEntry +Segment at 17:23 (count = 0), Skipped +Segment at 19:5 (count = 0), RegionEntry +Segment at 20:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.async.txt new file mode 100644 index 00000000000..f1f02faba53 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.async.txt @@ -0,0 +1,85 @@ +Counter in file 0 15:9 -> 15:75, #1 +Counter in file 0 15:9 -> 15:75, #1 +Counter in file 0 15:9 -> 15:75, #1 +Counter in file 0 47:13 -> 56:54, #1 +Counter in file 0 59:32 -> 59:35, ((#1 + #2) - #2) +Counter in file 0 59:39 -> 59:73, (#1 + #2) +Counter in file 0 60:23 -> 60:26, (((#1 + #2) - #2) + 0) +Counter in file 0 62:10 -> 62:11, #2 +Counter in file 0 63:5 -> 63:6, (((#1 + #2) - #2) + 0) +Counter in file 0 53:17 -> 53:19, #1 +Counter in file 0 7:44 -> 7:45, #1 +Counter in file 0 5:24 -> 5:25, #1 +Counter in file 0 5:22 -> 5:25, #1 +Counter in file 0 25:19 -> 26:12, #1 +Counter in file 0 27:9 -> 27:10, #3 +Counter in file 0 27:14 -> 27:17, (#1 + 0) +Counter in file 0 27:27 -> 27:32, #2 +Counter in file 0 27:32 -> 27:33, (#2 - #3) +Counter in file 0 27:36 -> 27:38, (#3 + 0) +Counter in file 0 28:14 -> 28:16, #4 +Counter in file 0 30:1 -> 30:2, (#3 + #4) +Counter in file 0 32:11 -> 37:2, #1 +Counter in file 0 30:1 -> 30:2, #1 +Counter in file 0 14:1 -> 14:2, #1 +Counter in file 0 23:1 -> 23:2, #1 +Emitting segments for file: ../coverage/async.rs +Combined regions: + 5:22 -> 5:25 (count=1) + 5:24 -> 5:25 (count=1) + 14:1 -> 14:2 (count=1) + 23:1 -> 23:2 (count=1) + 25:19 -> 26:12 (count=1) + 27:9 -> 27:10 (count=0) + 27:14 -> 27:17 (count=1) + 27:27 -> 27:32 (count=1) + 27:32 -> 27:33 (count=1) + 27:36 -> 27:38 (count=0) + 28:14 -> 28:16 (count=1) + 30:1 -> 30:2 (count=2) + 32:11 -> 37:2 (count=1) + 47:13 -> 56:54 (count=1) + 53:17 -> 53:19 (count=1) + 59:32 -> 59:35 (count=1) + 59:39 -> 59:73 (count=1) + 60:23 -> 60:26 (count=1) + 62:10 -> 62:11 (count=0) + 63:5 -> 63:6 (count=1) +Segment at 5:22 (count = 1), RegionEntry +Segment at 5:24 (count = 1), RegionEntry +Segment at 5:25 (count = 0), Skipped +Segment at 14:1 (count = 1), RegionEntry +Segment at 14:2 (count = 0), Skipped +Segment at 23:1 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped +Segment at 25:19 (count = 1), RegionEntry +Segment at 26:12 (count = 0), Skipped +Segment at 27:9 (count = 0), RegionEntry +Segment at 27:10 (count = 0), Skipped +Segment at 27:14 (count = 1), RegionEntry +Segment at 27:17 (count = 0), Skipped +Segment at 27:27 (count = 1), RegionEntry +Segment at 27:32 (count = 1), RegionEntry +Segment at 27:33 (count = 0), Skipped +Segment at 27:36 (count = 0), RegionEntry +Segment at 27:38 (count = 0), Skipped +Segment at 28:14 (count = 1), RegionEntry +Segment at 28:16 (count = 0), Skipped +Segment at 30:1 (count = 2), RegionEntry +Segment at 30:2 (count = 0), Skipped +Segment at 32:11 (count = 1), RegionEntry +Segment at 37:2 (count = 0), Skipped +Segment at 47:13 (count = 1), RegionEntry +Segment at 53:17 (count = 1), RegionEntry +Segment at 53:19 (count = 1) +Segment at 56:54 (count = 0), Skipped +Segment at 59:32 (count = 1), RegionEntry +Segment at 59:35 (count = 0), Skipped +Segment at 59:39 (count = 1), RegionEntry +Segment at 59:73 (count = 0), Skipped +Segment at 60:23 (count = 1), RegionEntry +Segment at 60:26 (count = 0), Skipped +Segment at 62:10 (count = 0), RegionEntry +Segment at 62:11 (count = 0), Skipped +Segment at 63:5 (count = 1), RegionEntry +Segment at 63:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.conditions.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.conditions.txt index d48cd8074be..a4c1a9c0f12 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.conditions.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.conditions.txt @@ -1,72 +1,91 @@ Counter in file 0 4:9 -> 4:26, #1 Counter in file 0 5:8 -> 5:12, (#1 + 0) Counter in file 0 5:13 -> 7:6, #2 -Counter in file 0 10:9 -> 10:10, (#4 + #11) +Counter in file 0 10:9 -> 10:10, (#3 + (#12 + #13)) Counter in file 0 10:16 -> 10:29, (#2 + 0) -Counter in file 0 11:9 -> 12:10, #4 +Counter in file 0 11:9 -> 12:10, #3 Counter in file 0 13:15 -> 13:28, ((#2 + 0) - #3) -Counter in file 0 14:12 -> 14:25, #5 -Counter in file 0 14:29 -> 14:42, (#5 - #13) -Counter in file 0 14:42 -> 14:43, (#13 + #14) -Counter in file 0 14:42 -> 14:43, ((#5 - #13) - #14) -Counter in file 0 14:46 -> 14:60, #21 -Counter in file 0 14:60 -> 14:61, (#17 + #18) -Counter in file 0 14:60 -> 14:61, (#21 - #18) -Counter in file 0 14:61 -> 16:10, #22 -Counter in file 0 16:10 -> 16:11, #23 -Counter in file 0 17:9 -> 18:18, #11 -Counter in file 0 20:9 -> 20:15, (((#2 + 0) - #3) - #5) -Counter in file 0 23:9 -> 23:26, ((#4 + #11) + 0) -Counter in file 0 24:8 -> 24:12, ((#4 + #11) + 0) -Counter in file 0 24:13 -> 26:6, #12 -Counter in file 0 28:8 -> 28:21, (#12 + 0) -Counter in file 0 29:9 -> 29:23, #16 -Counter in file 0 30:15 -> 30:28, ((#12 + 0) - #15) -Counter in file 0 31:12 -> 31:25, (((#12 + 0) - #15) - #8) -Counter in file 0 31:29 -> 31:42, ((((#12 + 0) - #15) - #8) - #24) -Counter in file 0 31:42 -> 31:43, (((((#12 + 0) - #15) - #8) - #24) - #25) +Counter in file 0 14:12 -> 14:25, #4 +Counter in file 0 14:29 -> 14:42, (#4 - #15) +Counter in file 0 14:42 -> 14:43, ((#4 - #15) - #16) +Counter in file 0 14:42 -> 14:43, (#15 + #16) +Counter in file 0 14:46 -> 14:60, #23 +Counter in file 0 14:60 -> 14:61, (#18 + #19) +Counter in file 0 14:60 -> 14:61, (#23 - #19) +Counter in file 0 14:61 -> 16:10, #12 +Counter in file 0 16:10 -> 16:11, #13 +Counter in file 0 17:9 -> 18:18, (#12 + #13) +Counter in file 0 20:9 -> 20:15, (((#2 + 0) - #3) - #4) +Counter in file 0 23:9 -> 23:26, ((#3 + (#12 + #13)) + 0) +Counter in file 0 24:8 -> 24:12, ((#3 + (#12 + #13)) + 0) +Counter in file 0 24:13 -> 26:6, #14 +Counter in file 0 28:8 -> 28:21, (#14 + 0) +Counter in file 0 28:22 -> 30:6, #17 +Counter in file 0 30:15 -> 30:28, ((#14 + 0) - #17) +Counter in file 0 31:12 -> 31:25, (((#14 + 0) - #17) - #8) +Counter in file 0 31:29 -> 31:42, ((((#14 + 0) - #17) - #8) - #24) +Counter in file 0 31:42 -> 31:43, (((((#14 + 0) - #17) - #8) - #24) - #25) Counter in file 0 31:42 -> 31:43, (#24 + #25) -Counter in file 0 31:46 -> 31:60, #32 -Counter in file 0 31:60 -> 31:61, (#28 + #29) -Counter in file 0 31:60 -> 31:61, (#32 - #29) -Counter in file 0 31:61 -> 33:10, #33 -Counter in file 0 33:10 -> 33:11, #34 -Counter in file 0 34:9 -> 34:23, #19 +Counter in file 0 31:46 -> 31:60, #34 +Counter in file 0 31:60 -> 31:61, (#34 - #32) +Counter in file 0 31:60 -> 31:61, (#31 + #32) +Counter in file 0 31:61 -> 33:10, #20 +Counter in file 0 33:10 -> 33:11, #21 +Counter in file 0 34:9 -> 34:23, (#20 + #21) Counter in file 0 36:9 -> 36:15, #8 -Counter in file 0 39:9 -> 39:26, (#16 + #19) -Counter in file 0 40:8 -> 40:12, ((#16 + #19) + 0) -Counter in file 0 40:13 -> 42:6, #20 -Counter in file 0 44:9 -> 44:10, (#27 + #30) -Counter in file 0 44:16 -> 44:29, (#20 + 0) -Counter in file 0 45:9 -> 45:23, #27 -Counter in file 0 46:15 -> 46:28, ((#20 + 0) - #26) -Counter in file 0 47:12 -> 47:25, (((#20 + 0) - #26) - #7) -Counter in file 0 47:29 -> 47:42, ((((#20 + 0) - #26) - #7) - #35) -Counter in file 0 47:42 -> 47:43, (#35 + #36) -Counter in file 0 47:42 -> 47:43, (((((#20 + 0) - #26) - #7) - #35) - #36) -Counter in file 0 47:46 -> 47:60, #41 -Counter in file 0 47:60 -> 47:61, (#37 + #38) -Counter in file 0 47:60 -> 47:61, (#41 - #38) -Counter in file 0 47:61 -> 49:10, #42 -Counter in file 0 49:10 -> 49:11, #43 -Counter in file 0 50:9 -> 50:23, #30 -Counter in file 0 52:13 -> 54:15, #7 -Counter in file 0 57:9 -> 57:10, (#9 + #10) -Counter in file 0 57:16 -> 57:29, ((#27 + #30) + 0) -Counter in file 0 58:9 -> 58:23, #9 -Counter in file 0 59:15 -> 59:28, ((#27 + #30) - #31) -Counter in file 0 60:12 -> 60:25, (((#27 + #30) - #31) - #6) -Counter in file 0 60:29 -> 60:42, ((((#27 + #30) - #31) - #6) - #39) -Counter in file 0 60:42 -> 60:43, (#39 + #40) -Counter in file 0 60:42 -> 60:43, (((((#27 + #30) - #31) - #6) - #39) - #40) -Counter in file 0 60:46 -> 60:60, #46 -Counter in file 0 60:60 -> 60:61, (#46 - #45) -Counter in file 0 60:60 -> 60:61, (#44 + #45) -Counter in file 0 60:61 -> 62:10, #47 -Counter in file 0 62:10 -> 62:11, #48 -Counter in file 0 63:9 -> 63:23, #10 -Counter in file 0 65:9 -> 65:15, #6 -Counter in file 0 67:1 -> 67:2, ((#9 + #10) + (((#6 + #7) + #8) + (((#2 + 0) - #3) - #5))) +Counter in file 0 39:8 -> 39:12, (#17 + (#20 + #21)) +Counter in file 0 52:13 -> 52:30, #22 +Counter in file 0 53:12 -> 53:16, (#22 + 0) +Counter in file 0 53:17 -> 55:10, #26 +Counter in file 0 57:12 -> 57:25, (#26 + 0) +Counter in file 0 57:26 -> 59:10, #27 +Counter in file 0 65:17 -> 65:30, ((#26 + 0) - #27) +Counter in file 0 66:16 -> 66:29, (((#26 + 0) - #27) - #7) +Counter in file 0 66:33 -> 66:46, ((((#26 + 0) - #27) - #7) - #37) +Counter in file 0 66:46 -> 66:47, (#37 + #38) +Counter in file 0 66:46 -> 66:47, (((((#26 + 0) - #27) - #7) - #37) - #38) +Counter in file 0 66:50 -> 66:64, #47 +Counter in file 0 66:64 -> 66:65, (#47 - #42) +Counter in file 0 66:64 -> 66:65, (#41 + #42) +Counter in file 0 66:65 -> 68:14, #28 +Counter in file 0 68:14 -> 68:15, #29 +Counter in file 0 69:13 -> 69:27, (#28 + #29) +Counter in file 0 71:13 -> 71:19, #7 +Counter in file 0 73:6 -> 73:7, (#27 + (#28 + #29)) +Counter in file 0 75:9 -> 75:26, ((#27 + (#28 + #29)) + 0) +Counter in file 0 76:8 -> 76:12, (((#27 + (#28 + #29)) + 0) + 0) +Counter in file 0 76:13 -> 78:6, #30 +Counter in file 0 80:9 -> 80:10, (#33 + (#35 + #36)) +Counter in file 0 80:16 -> 80:29, (#30 + 0) +Counter in file 0 80:30 -> 82:6, #33 +Counter in file 0 82:15 -> 82:28, ((#30 + 0) - #33) +Counter in file 0 83:12 -> 83:25, (((#30 + 0) - #33) - #6) +Counter in file 0 83:29 -> 83:42, ((((#30 + 0) - #33) - #6) - #39) +Counter in file 0 83:42 -> 83:43, (#39 + #40) +Counter in file 0 83:42 -> 83:43, (((((#30 + 0) - #33) - #6) - #39) - #40) +Counter in file 0 83:46 -> 83:60, #48 +Counter in file 0 83:60 -> 83:61, (#43 + #44) +Counter in file 0 83:60 -> 83:61, (#48 - #44) +Counter in file 0 83:61 -> 85:10, #35 +Counter in file 0 85:10 -> 85:11, #36 +Counter in file 0 86:9 -> 86:23, (#35 + #36) +Counter in file 0 88:13 -> 90:15, #6 +Counter in file 0 93:9 -> 93:10, (#9 + (#10 + #11)) +Counter in file 0 93:16 -> 93:29, ((#33 + (#35 + #36)) + 0) +Counter in file 0 93:30 -> 95:6, #9 +Counter in file 0 95:15 -> 95:28, ((#33 + (#35 + #36)) - #9) +Counter in file 0 96:12 -> 96:25, (((#33 + (#35 + #36)) - #9) - #5) +Counter in file 0 96:29 -> 96:42, ((((#33 + (#35 + #36)) - #9) - #5) - #45) +Counter in file 0 96:42 -> 96:43, (#45 + #46) +Counter in file 0 96:42 -> 96:43, (((((#33 + (#35 + #36)) - #9) - #5) - #45) - #46) +Counter in file 0 96:46 -> 96:60, #51 +Counter in file 0 96:60 -> 96:61, (#49 + #50) +Counter in file 0 96:60 -> 96:61, (#51 - #50) +Counter in file 0 96:61 -> 98:10, #10 +Counter in file 0 98:10 -> 98:11, #11 +Counter in file 0 99:9 -> 99:23, (#10 + #11) +Counter in file 0 101:9 -> 101:15, #5 +Counter in file 0 103:1 -> 103:2, ((#9 + (#10 + #11)) + (((#5 + #6) + (#7 + #8)) + (((#2 + 0) - #3) - #4))) Emitting segments for file: ../coverage/conditions.rs Combined regions: 4:9 -> 4:26 (count=1) @@ -89,7 +108,7 @@ Combined regions: 24:8 -> 24:12 (count=1) 24:13 -> 26:6 (count=1) 28:8 -> 28:21 (count=1) - 29:9 -> 29:23 (count=1) + 28:22 -> 30:6 (count=1) 30:15 -> 30:28 (count=0) 31:12 -> 31:25 (count=0) 31:29 -> 31:42 (count=0) @@ -100,36 +119,53 @@ Combined regions: 33:10 -> 33:11 (count=0) 34:9 -> 34:23 (count=0) 36:9 -> 36:15 (count=0) - 39:9 -> 39:26 (count=1) - 40:8 -> 40:12 (count=1) - 40:13 -> 42:6 (count=1) - 44:9 -> 44:10 (count=0) - 44:16 -> 44:29 (count=1) - 45:9 -> 45:23 (count=0) - 46:15 -> 46:28 (count=1) - 47:12 -> 47:25 (count=0) - 47:29 -> 47:42 (count=0) - 47:42 -> 47:43 (count=0) - 47:46 -> 47:60 (count=0) - 47:60 -> 47:61 (count=0) - 47:61 -> 49:10 (count=0) - 49:10 -> 49:11 (count=0) - 50:9 -> 50:23 (count=0) - 52:13 -> 54:15 (count=1) - 57:9 -> 57:10 (count=0) - 57:16 -> 57:29 (count=0) - 58:9 -> 58:23 (count=0) - 59:15 -> 59:28 (count=0) - 60:12 -> 60:25 (count=0) - 60:29 -> 60:42 (count=0) - 60:42 -> 60:43 (count=0) - 60:46 -> 60:60 (count=0) - 60:60 -> 60:61 (count=0) - 60:61 -> 62:10 (count=0) - 62:10 -> 62:11 (count=0) - 63:9 -> 63:23 (count=0) - 65:9 -> 65:15 (count=0) - 67:1 -> 67:2 (count=1) + 39:8 -> 39:12 (count=1) + 52:13 -> 52:30 (count=1) + 53:12 -> 53:16 (count=1) + 53:17 -> 55:10 (count=1) + 57:12 -> 57:25 (count=1) + 57:26 -> 59:10 (count=1) + 65:17 -> 65:30 (count=0) + 66:16 -> 66:29 (count=0) + 66:33 -> 66:46 (count=0) + 66:46 -> 66:47 (count=0) + 66:50 -> 66:64 (count=0) + 66:64 -> 66:65 (count=0) + 66:65 -> 68:14 (count=0) + 68:14 -> 68:15 (count=0) + 69:13 -> 69:27 (count=0) + 71:13 -> 71:19 (count=0) + 73:6 -> 73:7 (count=1) + 75:9 -> 75:26 (count=1) + 76:8 -> 76:12 (count=1) + 76:13 -> 78:6 (count=1) + 80:9 -> 80:10 (count=0) + 80:16 -> 80:29 (count=1) + 80:30 -> 82:6 (count=0) + 82:15 -> 82:28 (count=1) + 83:12 -> 83:25 (count=0) + 83:29 -> 83:42 (count=0) + 83:42 -> 83:43 (count=0) + 83:46 -> 83:60 (count=0) + 83:60 -> 83:61 (count=0) + 83:61 -> 85:10 (count=0) + 85:10 -> 85:11 (count=0) + 86:9 -> 86:23 (count=0) + 88:13 -> 90:15 (count=1) + 93:9 -> 93:10 (count=0) + 93:16 -> 93:29 (count=0) + 93:30 -> 95:6 (count=0) + 95:15 -> 95:28 (count=0) + 96:12 -> 96:25 (count=0) + 96:29 -> 96:42 (count=0) + 96:42 -> 96:43 (count=0) + 96:46 -> 96:60 (count=0) + 96:60 -> 96:61 (count=0) + 96:61 -> 98:10 (count=0) + 98:10 -> 98:11 (count=0) + 99:9 -> 99:23 (count=0) + 101:9 -> 101:15 (count=0) + 103:1 -> 103:2 (count=1) Segment at 4:9 (count = 1), RegionEntry Segment at 4:26 (count = 0), Skipped Segment at 5:8 (count = 1), RegionEntry @@ -166,8 +202,8 @@ Segment at 24:13 (count = 1), RegionEntry Segment at 26:6 (count = 0), Skipped Segment at 28:8 (count = 1), RegionEntry Segment at 28:21 (count = 0), Skipped -Segment at 29:9 (count = 1), RegionEntry -Segment at 29:23 (count = 0), Skipped +Segment at 28:22 (count = 1), RegionEntry +Segment at 30:6 (count = 0), Skipped Segment at 30:15 (count = 0), RegionEntry Segment at 30:28 (count = 0), Skipped Segment at 31:12 (count = 0), RegionEntry @@ -184,55 +220,85 @@ Segment at 34:9 (count = 0), RegionEntry Segment at 34:23 (count = 0), Skipped Segment at 36:9 (count = 0), RegionEntry Segment at 36:15 (count = 0), Skipped -Segment at 39:9 (count = 1), RegionEntry -Segment at 39:26 (count = 0), Skipped -Segment at 40:8 (count = 1), RegionEntry -Segment at 40:12 (count = 0), Skipped -Segment at 40:13 (count = 1), RegionEntry -Segment at 42:6 (count = 0), Skipped -Segment at 44:9 (count = 0), RegionEntry -Segment at 44:10 (count = 0), Skipped -Segment at 44:16 (count = 1), RegionEntry -Segment at 44:29 (count = 0), Skipped -Segment at 45:9 (count = 0), RegionEntry -Segment at 45:23 (count = 0), Skipped -Segment at 46:15 (count = 1), RegionEntry -Segment at 46:28 (count = 0), Skipped -Segment at 47:12 (count = 0), RegionEntry -Segment at 47:25 (count = 0), Skipped -Segment at 47:29 (count = 0), RegionEntry -Segment at 47:42 (count = 0), RegionEntry -Segment at 47:43 (count = 0), Skipped -Segment at 47:46 (count = 0), RegionEntry -Segment at 47:60 (count = 0), RegionEntry -Segment at 47:61 (count = 0), RegionEntry -Segment at 49:10 (count = 0), RegionEntry -Segment at 49:11 (count = 0), Skipped -Segment at 50:9 (count = 0), RegionEntry -Segment at 50:23 (count = 0), Skipped +Segment at 39:8 (count = 1), RegionEntry +Segment at 39:12 (count = 0), Skipped Segment at 52:13 (count = 1), RegionEntry -Segment at 54:15 (count = 0), Skipped -Segment at 57:9 (count = 0), RegionEntry -Segment at 57:10 (count = 0), Skipped -Segment at 57:16 (count = 0), RegionEntry -Segment at 57:29 (count = 0), Skipped -Segment at 58:9 (count = 0), RegionEntry -Segment at 58:23 (count = 0), Skipped -Segment at 59:15 (count = 0), RegionEntry -Segment at 59:28 (count = 0), Skipped -Segment at 60:12 (count = 0), RegionEntry -Segment at 60:25 (count = 0), Skipped -Segment at 60:29 (count = 0), RegionEntry -Segment at 60:42 (count = 0), RegionEntry -Segment at 60:43 (count = 0), Skipped -Segment at 60:46 (count = 0), RegionEntry -Segment at 60:60 (count = 0), RegionEntry -Segment at 60:61 (count = 0), RegionEntry -Segment at 62:10 (count = 0), RegionEntry -Segment at 62:11 (count = 0), Skipped -Segment at 63:9 (count = 0), RegionEntry -Segment at 63:23 (count = 0), Skipped -Segment at 65:9 (count = 0), RegionEntry -Segment at 65:15 (count = 0), Skipped -Segment at 67:1 (count = 1), RegionEntry -Segment at 67:2 (count = 0), Skipped +Segment at 52:30 (count = 0), Skipped +Segment at 53:12 (count = 1), RegionEntry +Segment at 53:16 (count = 0), Skipped +Segment at 53:17 (count = 1), RegionEntry +Segment at 55:10 (count = 0), Skipped +Segment at 57:12 (count = 1), RegionEntry +Segment at 57:25 (count = 0), Skipped +Segment at 57:26 (count = 1), RegionEntry +Segment at 59:10 (count = 0), Skipped +Segment at 65:17 (count = 0), RegionEntry +Segment at 65:30 (count = 0), Skipped +Segment at 66:16 (count = 0), RegionEntry +Segment at 66:29 (count = 0), Skipped +Segment at 66:33 (count = 0), RegionEntry +Segment at 66:46 (count = 0), RegionEntry +Segment at 66:47 (count = 0), Skipped +Segment at 66:50 (count = 0), RegionEntry +Segment at 66:64 (count = 0), RegionEntry +Segment at 66:65 (count = 0), RegionEntry +Segment at 68:14 (count = 0), RegionEntry +Segment at 68:15 (count = 0), Skipped +Segment at 69:13 (count = 0), RegionEntry +Segment at 69:27 (count = 0), Skipped +Segment at 71:13 (count = 0), RegionEntry +Segment at 71:19 (count = 0), Skipped +Segment at 73:6 (count = 1), RegionEntry +Segment at 73:7 (count = 0), Skipped +Segment at 75:9 (count = 1), RegionEntry +Segment at 75:26 (count = 0), Skipped +Segment at 76:8 (count = 1), RegionEntry +Segment at 76:12 (count = 0), Skipped +Segment at 76:13 (count = 1), RegionEntry +Segment at 78:6 (count = 0), Skipped +Segment at 80:9 (count = 0), RegionEntry +Segment at 80:10 (count = 0), Skipped +Segment at 80:16 (count = 1), RegionEntry +Segment at 80:29 (count = 0), Skipped +Segment at 80:30 (count = 0), RegionEntry +Segment at 82:6 (count = 0), Skipped +Segment at 82:15 (count = 1), RegionEntry +Segment at 82:28 (count = 0), Skipped +Segment at 83:12 (count = 0), RegionEntry +Segment at 83:25 (count = 0), Skipped +Segment at 83:29 (count = 0), RegionEntry +Segment at 83:42 (count = 0), RegionEntry +Segment at 83:43 (count = 0), Skipped +Segment at 83:46 (count = 0), RegionEntry +Segment at 83:60 (count = 0), RegionEntry +Segment at 83:61 (count = 0), RegionEntry +Segment at 85:10 (count = 0), RegionEntry +Segment at 85:11 (count = 0), Skipped +Segment at 86:9 (count = 0), RegionEntry +Segment at 86:23 (count = 0), Skipped +Segment at 88:13 (count = 1), RegionEntry +Segment at 90:15 (count = 0), Skipped +Segment at 93:9 (count = 0), RegionEntry +Segment at 93:10 (count = 0), Skipped +Segment at 93:16 (count = 0), RegionEntry +Segment at 93:29 (count = 0), Skipped +Segment at 93:30 (count = 0), RegionEntry +Segment at 95:6 (count = 0), Skipped +Segment at 95:15 (count = 0), RegionEntry +Segment at 95:28 (count = 0), Skipped +Segment at 96:12 (count = 0), RegionEntry +Segment at 96:25 (count = 0), Skipped +Segment at 96:29 (count = 0), RegionEntry +Segment at 96:42 (count = 0), RegionEntry +Segment at 96:43 (count = 0), Skipped +Segment at 96:46 (count = 0), RegionEntry +Segment at 96:60 (count = 0), RegionEntry +Segment at 96:61 (count = 0), RegionEntry +Segment at 98:10 (count = 0), RegionEntry +Segment at 98:11 (count = 0), Skipped +Segment at 99:9 (count = 0), RegionEntry +Segment at 99:23 (count = 0), Skipped +Segment at 101:9 (count = 0), RegionEntry +Segment at 101:15 (count = 0), Skipped +Segment at 103:1 (count = 1), RegionEntry +Segment at 103:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.inner_items.txt index 65cd6481af4..e4dfae76817 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.inner_items.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.inner_items.txt @@ -1,7 +1,4 @@ -Counter in file 0 19:13 -> 19:18, #1 -Counter in file 0 20:13 -> 20:14, #2 -Counter in file 0 20:17 -> 20:22, (#1 + 0) -Counter in file 0 21:9 -> 22:6, (#2 + 0) +Counter in file 0 19:13 -> 22:6, #1 Counter in file 0 7:9 -> 9:26, #1 Counter in file 0 10:8 -> 10:15, (#1 + 0) Counter in file 0 10:16 -> 12:6, #2 @@ -11,21 +8,16 @@ Counter in file 0 48:16 -> 50:6, #3 Counter in file 0 50:6 -> 50:7, ((#2 + (#1 - #2)) - #3) Counter in file 0 52:9 -> 57:2, (#3 + ((#2 + (#1 - #2)) - #3)) Counter in file 0 33:42 -> 36:10, #1 -Counter in file 0 41:37 -> 41:41, #1 -Counter in file 0 42:13 -> 43:10, #2 +Counter in file 0 40:45 -> 43:10, #1 Emitting segments for file: ../coverage/inner_items.rs Combined regions: 7:9 -> 9:26 (count=1) 10:8 -> 10:15 (count=1) 10:16 -> 12:6 (count=1) 12:6 -> 12:7 (count=0) - 19:13 -> 19:18 (count=3) - 20:13 -> 20:14 (count=3) - 20:17 -> 20:22 (count=3) - 21:9 -> 22:6 (count=3) + 19:13 -> 22:6 (count=3) 33:42 -> 36:10 (count=1) - 41:37 -> 41:41 (count=1) - 42:13 -> 43:10 (count=1) + 40:45 -> 43:10 (count=1) 48:8 -> 48:15 (count=1) 48:16 -> 50:6 (count=1) 50:6 -> 50:7 (count=0) @@ -38,18 +30,10 @@ Segment at 10:16 (count = 1), RegionEntry Segment at 12:6 (count = 0), RegionEntry Segment at 12:7 (count = 0), Skipped Segment at 19:13 (count = 3), RegionEntry -Segment at 19:18 (count = 0), Skipped -Segment at 20:13 (count = 3), RegionEntry -Segment at 20:14 (count = 0), Skipped -Segment at 20:17 (count = 3), RegionEntry -Segment at 20:22 (count = 0), Skipped -Segment at 21:9 (count = 3), RegionEntry Segment at 22:6 (count = 0), Skipped Segment at 33:42 (count = 1), RegionEntry Segment at 36:10 (count = 0), Skipped -Segment at 41:37 (count = 1), RegionEntry -Segment at 41:41 (count = 0), Skipped -Segment at 42:13 (count = 1), RegionEntry +Segment at 40:45 (count = 1), RegionEntry Segment at 43:10 (count = 0), Skipped Segment at 48:8 (count = 1), RegionEntry Segment at 48:15 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.nested_loops.txt index f5030073533..f8e504c56c4 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.nested_loops.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.nested_loops.txt @@ -1,21 +1,20 @@ Counter in file 0 2:9 -> 3:27, #1 -Counter in file 0 5:19 -> 5:32, (#1 + #2) -Counter in file 0 6:13 -> 7:24, ((#1 + #2) - #3) -Counter in file 0 8:13 -> 8:14, ((((#1 + #2) - #3) + (#5 + #6)) - #7) -Counter in file 0 8:18 -> 8:23, (((#1 + #2) - #3) + (#5 + #6)) -Counter in file 0 9:16 -> 9:22, (((((#1 + #2) - #3) + (#5 + #6)) - #7) + 0) -Counter in file 0 10:17 -> 10:22, #8 -Counter in file 0 12:13 -> 12:19, #9 -Counter in file 0 13:13 -> 13:19, #10 -Counter in file 0 14:16 -> 14:22, (#10 + 0) -Counter in file 0 15:17 -> 16:27, #11 -Counter in file 0 17:21 -> 17:33, #4 -Counter in file 0 19:21 -> 21:14, #5 -Counter in file 0 21:14 -> 21:15, #6 -Counter in file 0 22:10 -> 22:11, (#5 + #6) -Counter in file 0 23:9 -> 23:23, #2 -Counter in file 0 24:6 -> 24:7, #3 -Counter in file 0 25:1 -> 25:2, (#4 + #3) +Counter in file 0 5:19 -> 5:32, (#1 + (#2 + #3)) +Counter in file 0 6:13 -> 7:24, ((#1 + (#2 + #3)) - #4) +Counter in file 0 8:13 -> 8:14, ((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) +Counter in file 0 8:18 -> 8:23, (((#1 + (#2 + #3)) - #4) + (#6 + #7)) +Counter in file 0 9:16 -> 9:22, (((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) + 0) +Counter in file 0 10:17 -> 10:22, #2 +Counter in file 0 12:13 -> 13:19, (((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) +Counter in file 0 14:16 -> 14:22, ((((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) + 0) +Counter in file 0 15:17 -> 16:27, ((((((#1 + (#2 + #3)) - #4) + (#6 + #7)) - #3) - #2) - #7) +Counter in file 0 17:21 -> 17:33, #5 +Counter in file 0 18:24 -> 21:14, #6 +Counter in file 0 21:14 -> 21:15, #7 +Counter in file 0 22:10 -> 22:11, (#6 + #7) +Counter in file 0 23:9 -> 23:23, (#2 + #3) +Counter in file 0 24:6 -> 24:7, #4 +Counter in file 0 25:1 -> 25:2, (#5 + #4) Emitting segments for file: ../coverage/nested_loops.rs Combined regions: 2:9 -> 3:27 (count=1) @@ -25,12 +24,11 @@ Combined regions: 8:18 -> 8:23 (count=3) 9:16 -> 9:22 (count=3) 10:17 -> 10:22 (count=0) - 12:13 -> 12:19 (count=3) - 13:13 -> 13:19 (count=3) + 12:13 -> 13:19 (count=3) 14:16 -> 14:22 (count=3) 15:17 -> 16:27 (count=1) 17:21 -> 17:33 (count=1) - 19:21 -> 21:14 (count=0) + 18:24 -> 21:14 (count=0) 21:14 -> 21:15 (count=2) 22:10 -> 22:11 (count=2) 23:9 -> 23:23 (count=0) @@ -51,8 +49,6 @@ Segment at 9:22 (count = 0), Skipped Segment at 10:17 (count = 0), RegionEntry Segment at 10:22 (count = 0), Skipped Segment at 12:13 (count = 3), RegionEntry -Segment at 12:19 (count = 0), Skipped -Segment at 13:13 (count = 3), RegionEntry Segment at 13:19 (count = 0), Skipped Segment at 14:16 (count = 3), RegionEntry Segment at 14:22 (count = 0), Skipped @@ -60,7 +56,7 @@ Segment at 15:17 (count = 1), RegionEntry Segment at 16:27 (count = 0), Skipped Segment at 17:21 (count = 1), RegionEntry Segment at 17:33 (count = 0), Skipped -Segment at 19:21 (count = 0), RegionEntry +Segment at 18:24 (count = 0), RegionEntry Segment at 21:14 (count = 2), RegionEntry Segment at 21:15 (count = 0), Skipped Segment at 22:10 (count = 2), RegionEntry diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.overflow.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.overflow.txt new file mode 100644 index 00000000000..8696e102b56 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.overflow.txt @@ -0,0 +1,53 @@ +Counter in file 0 16:9 -> 16:27, #1 +Counter in file 0 17:11 -> 17:24, (#1 + (#2 + (#3 + #4))) +Counter in file 0 18:12 -> 18:26, ((#1 + (#2 + (#3 + #4))) - #5) +Counter in file 0 18:27 -> 21:10, #2 +Counter in file 0 21:19 -> 21:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) +Counter in file 0 21:33 -> 24:10, #3 +Counter in file 0 24:10 -> 24:11, #4 +Counter in file 0 24:10 -> 24:11, (#3 + #4) +Counter in file 0 25:9 -> 25:23, (#2 + (#3 + #4)) +Counter in file 0 27:5 -> 28:2, #5 +Counter in file 0 5:8 -> 5:18, #1 +Counter in file 0 5:19 -> 7:6, #2 +Counter in file 0 7:6 -> 7:7, (#1 - #2) +Counter in file 0 8:9 -> 13:2, (#2 + (#1 - #2)) +Emitting segments for file: ../coverage/overflow.rs +Combined regions: + 5:8 -> 5:18 (count=4) + 5:19 -> 7:6 (count=1) + 7:6 -> 7:7 (count=3) + 8:9 -> 13:2 (count=4) + 16:9 -> 16:27 (count=1) + 17:11 -> 17:24 (count=10) + 18:12 -> 18:26 (count=10) + 18:27 -> 21:10 (count=0) + 21:19 -> 21:32 (count=10) + 21:33 -> 24:10 (count=3) + 24:10 -> 24:11 (count=15) + 25:9 -> 25:23 (count=9) + 27:5 -> 28:2 (count=0) +Segment at 5:8 (count = 4), RegionEntry +Segment at 5:18 (count = 0), Skipped +Segment at 5:19 (count = 1), RegionEntry +Segment at 7:6 (count = 3), RegionEntry +Segment at 7:7 (count = 0), Skipped +Segment at 8:9 (count = 4), RegionEntry +Segment at 13:2 (count = 0), Skipped +Segment at 16:9 (count = 1), RegionEntry +Segment at 16:27 (count = 0), Skipped +Segment at 17:11 (count = 10), RegionEntry +Segment at 17:24 (count = 0), Skipped +Segment at 18:12 (count = 10), RegionEntry +Segment at 18:26 (count = 0), Skipped +Segment at 18:27 (count = 0), RegionEntry +Segment at 21:10 (count = 0), Skipped +Segment at 21:19 (count = 10), RegionEntry +Segment at 21:32 (count = 0), Skipped +Segment at 21:33 (count = 3), RegionEntry +Segment at 24:10 (count = 15), RegionEntry +Segment at 24:11 (count = 0), Skipped +Segment at 25:9 (count = 9), RegionEntry +Segment at 25:23 (count = 0), Skipped +Segment at 27:5 (count = 0), RegionEntry +Segment at 28:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.panic_unwind.txt new file mode 100644 index 00000000000..9602ff1a985 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.panic_unwind.txt @@ -0,0 +1,50 @@ +Counter in file 0 14:9 -> 14:27, #1 +Counter in file 0 15:11 -> 15:24, (#1 + (#2 + (#3 + #4))) +Counter in file 0 16:12 -> 16:26, ((#1 + (#2 + (#3 + #4))) - #5) +Counter in file 0 16:27 -> 18:10, #2 +Counter in file 0 18:19 -> 18:32, (((#1 + (#2 + (#3 + #4))) - #5) - #2) +Counter in file 0 18:33 -> 20:10, #3 +Counter in file 0 20:10 -> 20:11, #4 +Counter in file 0 20:10 -> 20:11, (#3 + #4) +Counter in file 0 21:9 -> 21:23, (#2 + (#3 + #4)) +Counter in file 0 23:5 -> 24:2, #5 +Counter in file 0 5:8 -> 5:20, #1 +Counter in file 0 6:9 -> 7:26, #2 +Counter in file 0 8:12 -> 11:2, (#1 - #2) +Emitting segments for file: ../coverage/panic_unwind.rs +Combined regions: + 5:8 -> 5:20 (count=4) + 6:9 -> 7:26 (count=1) + 8:12 -> 11:2 (count=3) + 14:9 -> 14:27 (count=1) + 15:11 -> 15:24 (count=10) + 16:12 -> 16:26 (count=10) + 16:27 -> 18:10 (count=0) + 18:19 -> 18:32 (count=10) + 18:33 -> 20:10 (count=3) + 20:10 -> 20:11 (count=15) + 21:9 -> 21:23 (count=9) + 23:5 -> 24:2 (count=0) +Segment at 5:8 (count = 4), RegionEntry +Segment at 5:20 (count = 0), Skipped +Segment at 6:9 (count = 1), RegionEntry +Segment at 7:26 (count = 0), Skipped +Segment at 8:12 (count = 3), RegionEntry +Segment at 11:2 (count = 0), Skipped +Segment at 14:9 (count = 1), RegionEntry +Segment at 14:27 (count = 0), Skipped +Segment at 15:11 (count = 10), RegionEntry +Segment at 15:24 (count = 0), Skipped +Segment at 16:12 (count = 10), RegionEntry +Segment at 16:26 (count = 0), Skipped +Segment at 16:27 (count = 0), RegionEntry +Segment at 18:10 (count = 0), Skipped +Segment at 18:19 (count = 10), RegionEntry +Segment at 18:32 (count = 0), Skipped +Segment at 18:33 (count = 3), RegionEntry +Segment at 20:10 (count = 15), RegionEntry +Segment at 20:11 (count = 0), Skipped +Segment at 21:9 (count = 9), RegionEntry +Segment at 21:23 (count = 0), Skipped +Segment at 23:5 (count = 0), RegionEntry +Segment at 24:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.partial_eq.txt index 2b9285202f9..329e0f3889a 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.partial_eq.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.partial_eq.txt @@ -1,28 +1,28 @@ -Counter in file 0 4:32 -> 4:33, (#3 + (#1 + #2)) Counter in file 0 4:48 -> 4:49, ((#1 + #2) + ((#3 + #4) + ((#5 + #6) + #7))) +Counter in file 0 7:5 -> 7:6, #1 Counter in file 0 21:11 -> 26:2, #1 -Counter in file 0 8:5 -> 8:17, #1 -Counter in file 0 8:5 -> 8:17, #1 Counter in file 0 4:39 -> 4:40, #1 Counter in file 0 4:48 -> 4:49, (#1 + 0) +Counter in file 0 7:5 -> 7:6, #1 Counter in file 0 4:39 -> 4:40, #1 Counter in file 0 4:48 -> 4:49, (#1 + 0) -Counter in file 0 8:5 -> 8:17, #1 Counter in file 0 4:32 -> 4:33, ((#4 + #5) + #6) +Counter in file 0 7:5 -> 7:6, #1 Counter in file 0 4:53 -> 4:54, (#1 + (#2 + (#3 + #4))) +Counter in file 0 8:5 -> 8:17, #1 Counter in file 0 13:9 -> 18:6, #1 +Counter in file 0 7:5 -> 7:6, #1 Counter in file 0 4:39 -> 4:40, #1 Counter in file 0 4:48 -> 4:49, (#1 + 0) -Counter in file 0 7:5 -> 7:6, #1 Counter in file 0 4:10 -> 4:15, #1 +Counter in file 0 8:5 -> 8:17, #1 Counter in file 0 4:35 -> 4:37, #1 -Counter in file 0 7:5 -> 7:6, #1 -Counter in file 0 7:5 -> 7:6, #1 -Counter in file 0 4:17 -> 4:22, #1 Counter in file 0 8:5 -> 8:17, #1 +Counter in file 0 8:5 -> 8:17, #1 +Counter in file 0 4:17 -> 4:22, #1 Counter in file 0 4:39 -> 4:40, #1 Counter in file 0 4:48 -> 4:49, (#1 + 0) -Counter in file 0 7:5 -> 7:6, #1 +Counter in file 0 4:32 -> 4:33, (#3 + (#1 + #2)) Emitting segments for file: ../coverage/partial_eq.rs Combined regions: 4:17 -> 4:22 (count=2) diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_loop.txt index 255173e5534..6ea09248d65 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_loop.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.simple_loop.txt @@ -3,10 +3,10 @@ Counter in file 0 12:9 -> 12:16, (#1 + 0) Counter in file 0 13:5 -> 18:6, #2 Counter in file 0 18:6 -> 18:7, (#1 - #2) Counter in file 0 23:13 -> 25:14, ((#2 + (#1 - #2)) + #3) -Counter in file 0 27:13 -> 27:18, #4 +Counter in file 0 27:13 -> 27:18, (((#2 + (#1 - #2)) + #3) - #3) Counter in file 0 30:9 -> 32:10, #3 Counter in file 0 34:6 -> 34:7, (#2 + (#1 - #2)) -Counter in file 0 35:1 -> 35:2, (#4 + 0) +Counter in file 0 35:1 -> 35:2, ((((#2 + (#1 - #2)) + #3) - #3) + 0) Emitting segments for file: ../coverage/simple_loop.rs Combined regions: 7:9 -> 9:26 (count=1) diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.try_error_result.txt index a317cd79291..5b7f5496af8 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.try_error_result.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.try_error_result.txt @@ -1,12 +1,12 @@ Counter in file 0 13:9 -> 14:23, #1 Counter in file 0 17:9 -> 17:10, ((#1 + (#2 + #3)) - #4) Counter in file 0 19:9 -> 19:14, (#1 + (#2 + #3)) -Counter in file 0 21:9 -> 25:26, #8 -Counter in file 0 27:13 -> 27:41, #9 +Counter in file 0 21:9 -> 25:26, (((#1 + (#2 + #3)) - #4) + 0) +Counter in file 0 27:13 -> 27:41, #8 Counter in file 0 27:41 -> 27:42, #5 -Counter in file 0 28:13 -> 28:42, (#9 - #5) +Counter in file 0 28:13 -> 28:42, (#8 - #5) Counter in file 0 28:42 -> 28:43, #6 -Counter in file 0 32:13 -> 32:42, (#8 - #9) +Counter in file 0 32:13 -> 32:42, (((#1 + (#2 + #3)) - #4) - #8) Counter in file 0 32:42 -> 32:43, #7 Counter in file 0 33:10 -> 33:11, #2 Counter in file 0 33:10 -> 33:11, #3 diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while_early_ret.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while_early_ret.txt index f541baec50c..7e79a8f00e1 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while_early_ret.txt +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.while_early_ret.txt @@ -1,7 +1,7 @@ Counter in file 0 5:9 -> 5:27, #1 Counter in file 0 7:9 -> 9:10, (#1 + #2) Counter in file 0 12:13 -> 14:14, ((#1 + #2) - #3) -Counter in file 0 18:21 -> 20:22, #6 +Counter in file 0 18:21 -> 20:22, (((#1 + #2) - #3) - #2) Counter in file 0 22:21 -> 22:27, #4 Counter in file 0 26:21 -> 26:27, #5 Counter in file 0 30:9 -> 32:10, #2 diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.yield.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.yield.txt new file mode 100644 index 00000000000..a1075358211 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage_counters.yield.txt @@ -0,0 +1,90 @@ +Counter in file 0 8:9 -> 8:22, #1 +Counter in file 0 13:11 -> 14:35, (#1 + 0) +Counter in file 0 14:39 -> 14:41, #4 +Counter in file 0 15:14 -> 15:52, (#2 + #3) +Counter in file 0 17:11 -> 17:46, (#4 + 0) +Counter in file 0 18:34 -> 18:39, (#4 - #5) +Counter in file 0 18:44 -> 18:46, ((#4 - #5) - #6) +Counter in file 0 19:14 -> 19:52, (#5 + #6) +Counter in file 0 22:9 -> 22:22, (((#4 - #5) - #6) + 0) +Counter in file 0 29:11 -> 30:35, (((#4 - #5) - #6) + 0) +Counter in file 0 30:39 -> 30:41, #9 +Counter in file 0 31:14 -> 31:52, (#7 + #8) +Counter in file 0 33:11 -> 34:35, (#9 + 0) +Counter in file 0 34:39 -> 34:41, #12 +Counter in file 0 35:14 -> 35:52, (#10 + #11) +Counter in file 0 37:1 -> 37:2, (#12 + 0) +Counter in file 0 9:9 -> 9:16, #1 +Counter in file 0 10:16 -> 11:6, #2 +Counter in file 0 23:9 -> 23:16, #1 +Counter in file 0 24:9 -> 24:16, #2 +Counter in file 0 25:9 -> 25:16, #3 +Counter in file 0 26:16 -> 27:6, #4 +Emitting segments for file: ../coverage/yield.rs +Combined regions: + 8:9 -> 8:22 (count=1) + 9:9 -> 9:16 (count=1) + 10:16 -> 11:6 (count=1) + 13:11 -> 14:35 (count=1) + 14:39 -> 14:41 (count=1) + 15:14 -> 15:52 (count=0) + 17:11 -> 17:46 (count=1) + 18:34 -> 18:39 (count=1) + 18:44 -> 18:46 (count=1) + 19:14 -> 19:52 (count=0) + 22:9 -> 22:22 (count=1) + 23:9 -> 23:16 (count=1) + 24:9 -> 24:16 (count=1) + 25:9 -> 25:16 (count=0) + 26:16 -> 27:6 (count=0) + 29:11 -> 30:35 (count=1) + 30:39 -> 30:41 (count=1) + 31:14 -> 31:52 (count=0) + 33:11 -> 34:35 (count=1) + 34:39 -> 34:41 (count=1) + 35:14 -> 35:52 (count=0) + 37:1 -> 37:2 (count=1) +Segment at 8:9 (count = 1), RegionEntry +Segment at 8:22 (count = 0), Skipped +Segment at 9:9 (count = 1), RegionEntry +Segment at 9:16 (count = 0), Skipped +Segment at 10:16 (count = 1), RegionEntry +Segment at 11:6 (count = 0), Skipped +Segment at 13:11 (count = 1), RegionEntry +Segment at 14:35 (count = 0), Skipped +Segment at 14:39 (count = 1), RegionEntry +Segment at 14:41 (count = 0), Skipped +Segment at 15:14 (count = 0), RegionEntry +Segment at 15:52 (count = 0), Skipped +Segment at 17:11 (count = 1), RegionEntry +Segment at 17:46 (count = 0), Skipped +Segment at 18:34 (count = 1), RegionEntry +Segment at 18:39 (count = 0), Skipped +Segment at 18:44 (count = 1), RegionEntry +Segment at 18:46 (count = 0), Skipped +Segment at 19:14 (count = 0), RegionEntry +Segment at 19:52 (count = 0), Skipped +Segment at 22:9 (count = 1), RegionEntry +Segment at 22:22 (count = 0), Skipped +Segment at 23:9 (count = 1), RegionEntry +Segment at 23:16 (count = 0), Skipped +Segment at 24:9 (count = 1), RegionEntry +Segment at 24:16 (count = 0), Skipped +Segment at 25:9 (count = 0), RegionEntry +Segment at 25:16 (count = 0), Skipped +Segment at 26:16 (count = 0), RegionEntry +Segment at 27:6 (count = 0), Skipped +Segment at 29:11 (count = 1), RegionEntry +Segment at 30:35 (count = 0), Skipped +Segment at 30:39 (count = 1), RegionEntry +Segment at 30:41 (count = 0), Skipped +Segment at 31:14 (count = 0), RegionEntry +Segment at 31:52 (count = 0), Skipped +Segment at 33:11 (count = 1), RegionEntry +Segment at 34:35 (count = 0), Skipped +Segment at 34:39 (count = 1), RegionEntry +Segment at 34:41 (count = 0), Skipped +Segment at 35:14 (count = 0), RegionEntry +Segment at 35:52 (count = 0), Skipped +Segment at 37:1 (count = 1), RegionEntry +Segment at 37:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/Makefile b/src/test/run-make-fulldeps/coverage-spanview-base/Makefile index 9f9440340e0..c62cbc1c91f 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-spanview-base/Makefile @@ -43,6 +43,9 @@ endif %: $(SOURCEDIR)/%.rs # Compile the test program with coverage instrumentation and generate relevant MIR. $(RUSTC) $(SOURCEDIR)/$@.rs \ + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && \ + echo "--edition=2018" \ + ) \ -Zinstrument-coverage \ -Clink-dead-code=$(LINK_DEAD_CODE) \ -Zdump-mir=InstrumentCoverage \ diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..a8227cffc60 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,99 @@ + + + + +abort.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown < 5⦉@3,5 @6,8,9⦊{ + might_abort(false); + }⦉@6,8,9@7⦊⦉@7 + @10,11⦊countdown -= 1⦉@10,11; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..daef056a19a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html @@ -0,0 +1,164 @@ + + + + +abort.might_abort - Coverage Spans + + + +
fn might_abort(should_abort: bool) { + if @0⦊should_abort⦉@0 { + @1,3,4,5⦊println!("aborting..."); + panic!("panics and aborts");⦉@1,3,4,5 + } else @2,6,7⦊{ + println!("Don't Panic"); + } +}⦉@2,6,7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..499825445ac --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,103 @@ + + + + +assert.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown == 1⦉@3,5 @6,8,9⦊{ + might_fail_assert(3); + }⦉@6,8,9 else if @7⦊countdown < 5⦉@7 @10,12,13⦊{ + might_fail_assert(2); + }⦉@10,12,13@11⦊⦉@11@14⦊⦉@14 + @15,16⦊countdown -= 1⦉@15,16; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..98be3485a41 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html @@ -0,0 +1,97 @@ + + + + +assert.might_fail_assert - Coverage Spans + + + +
fn might_fail_assert(one_plus_one: u32) { + @0,1,2,3,4⦊println!("does 1 + 1 = {}?", one_plus_one);⦉@0,1,2,3,4 + assert_eq!(@0,1,2,3,4⦊1 + 1⦉@0,1,2,3,4, one_plus_one, @5,7,8,9,10,11,12⦊"the argument was wrong"⦉@5,7,8,9,10,11,12); +}@6⦊⦉@6
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..31646f8ce81 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,89 @@ + + + + +async.executor-block_on-VTABLE-{closure#0} - Coverage Spans + + + +
{ + @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 + }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..ddc791f074f --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html @@ -0,0 +1,89 @@ + + + + +async.executor-block_on-VTABLE-{closure#1} - Coverage Spans + + + +
{ + @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 + }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..709b87fc501 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html @@ -0,0 +1,89 @@ + + + + +async.executor-block_on-VTABLE-{closure#2} - Coverage Spans + + + +
{ + @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 + }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..abd2621481a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.executor-block_on-VTABLE-{closure#3} - Coverage Spans + + + +
|_| @0⦊()⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..9d71d8ccc6e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html @@ -0,0 +1,226 @@ + + + + +async.executor-block_on - Coverage Spans + + + +
pub fn block_on<F: Future>(mut future: F) -> F::Output { + let @0,1,2,3,4,5⦊mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; + + loop { + if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { + break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; + } + }@11,13⦊⦉@11,13 + }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..779f67fd7c1 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.f-{closure#0} - Coverage Spans + + + +
{ @0⦊1 }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..050ae67efc9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.f - Coverage Spans + + + +
async fn f() -> u8 { 1 }@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..d176a607d3b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.foo-{closure#0} - Coverage Spans + + + +
{ @0⦊[false; 10] }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..64eeaefa894 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.foo - Coverage Spans + + + +
async fn foo() -> [bool; 10] { [false; 10] }@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..4e894eecd16 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.g-{closure#0} - Coverage Spans + + + +
@0,2,3⦊{ + match x⦉@0,2,3 { + @16⦊y⦉@16 if @0,2,3⦊f()⦉@0,2,3.await == @9,12,14,15⦊y⦉@9,12,14,15@17⦊⦉@17 => @16⦊()⦉@16, + _ => @1⦊()⦉@1, + } +}@18,19⦊⦉@18,19
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..4788562a9d4 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html @@ -0,0 +1,79 @@ + + + + +async.g - Coverage Spans + + + +
pub async fn g(x: u8) { + match x { + y if f().await == y => (), + _ => (), + } +}@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..de48232efde --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.h-{closure#0} - Coverage Spans + + + +
@0,2,3⦊{ + match x⦉@0,2,3 { + @17⦊y⦉@17 if @0,2,3⦊foo()⦉@0,2,3.await[@9,12,14,15,16⦊y⦉@9,12,14,15,16]@18⦊⦉@18 => @17⦊()⦉@17, + _ => @1⦊()⦉@1, + } +}@19,20⦊⦉@19,20
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..83b0a3e0d43 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html @@ -0,0 +1,79 @@ + + + + +async.h - Coverage Spans + + + +
async fn h(x: usize) { + match x { + y if foo().await[y] => (), + _ => (), + } +}@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..71397d39625 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + + +async.i-{closure#0} - Coverage Spans + + + +
@0,2,3⦊{ + match x⦉@0,2,3 { + @17⦊y⦉@17 if @0,2,3⦊f()⦉@0,2,3.await == @9,12,14,15,16⦊y + 1⦉@9,12,14,15,16@18⦊⦉@18 => @17⦊()⦉@17, + _ => @1⦊()⦉@1, + } +}@19,20⦊⦉@19,20
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..55efca74481 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html @@ -0,0 +1,79 @@ + + + + +async.i - Coverage Spans + + + +
async fn i(x: u8) { + match x { + y if f().await == y + 1 => (), + _ => (), + } +}@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..2f14339d9e9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +async.main - Coverage Spans + + + +
fn main() @0,1,2,3,4,5,6,7,8,9⦊{ + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + executor::block_on(future.as_mut()); +}⦉@0,1,2,3,4,5,6,7,8,9
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html index cda1040c291..09adc12cefd 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html @@ -87,10 +87,12 @@ let @25⦊x⦉@25 = if @4⦊countdown > 7⦉@4 { - @8⦊countdown -= 4; - B⦉@8 + @5,7,8⦊countdown -= 4; + B⦉@5,7,8 } else if @6⦊countdown > 2⦉@6 { @@ -106,10 +108,12 @@ }⦉@20,22@21⦊⦉@21 - @24⦊countdown -= 5; - countdown⦉@24 + @23,24⦊countdown -= 5; + countdown⦉@23,24 } else { @10⦊return⦉@10; }; @@ -129,9 +133,15 @@ if @29⦊countdown > 7⦉@29 { - @33⦊countdown -= 4⦉@33; - } else if @29⦊countdown > 7⦉@29 @30,32,33⦊{ + countdown -= 4; + }⦉@30,32,33 else if @31⦊countdown > 2⦉@31 { if }⦉@45,47@46⦊⦉@46 - @49⦊countdown -= 5⦉@49; + @48,49⦊countdown -= 5⦉@48,49; } else { @35⦊return⦉@35; } - let @50⦊mut countdown = 0⦉@50; - if @50⦊true⦉@50 @51,53⦊{ - countdown = 1; - }⦉@51,53@52⦊⦉@52 + if @50⦊true⦉@50 { + // Demonstrate the difference with `TerminatorKind::Assert` as of 2020-11-15. Assert is no + // longer treated as a `BasicCoverageBlock` terminator, which changed the coverage region, + // for the executed `then` block above, to include the closing brace on line 30. That + // changed the line count, but the coverage code region (for the `else if` condition) is + // still valid. + // + // Note that `if` (then) and `else` blocks include the closing brace in their coverage + // code regions when the last line in the block ends in a semicolon, because the Rust + // compiler inserts a `StatementKind::Assign` to assign `const ()` to a `Place`, for the + // empty value for the executed block. When the last line does not end in a semicolon + // (that is, when the block actually results in a value), the additional `Assign` is not + // generated, and the brace is not included. + let @51,53⦊mut countdown = 0⦉@51,53; + if @51,53⦊true⦉@51,53 @54,56⦊{ + countdown = 10; + }⦉@54,56@55⦊⦉@55 - let @77⦊z⦉@77 = if @54⦊countdown > 7⦉@54 { - @58⦊countdown -= 4⦉@58; - } else if @56⦊countdown > 2⦉@56 { - if @59,61⦊countdown < 1⦉@59,61 || @68⦊countdown > 5⦉@68@66⦊⦉@66@67⦊⦉@67 || @64⦊countdown != 9⦉@64@62⦊⦉@62@63⦊⦉@63 @70,72⦊{ - countdown = 0; - }⦉@70,72@71⦊⦉@71 - @74⦊countdown -= 5⦉@74; + if @57⦊countdown > 7⦉@57 @58,60,61⦊{ + countdown -= 4; + }⦉@58,60,61 + // The closing brace of the `then` branch is now included in the coverage region, and shown + // as "executed" (giving its line a count of 1 here). Since, in the original version above, + // the closing brace shares the same line as the `else if` conditional expression (which is + // not executed if the first `then` condition is true), only the condition's code region is + // marked with a count of 0 now. + else if @59⦊countdown > 2⦉@59 { + if @62,64⦊countdown < 1⦉@62,64 || @71⦊countdown > 5⦉@71@69⦊⦉@69@70⦊⦉@70 || @67⦊countdown != 9⦉@67@65⦊⦉@65@66⦊⦉@66 @73,75⦊{ + countdown = 0; + }⦉@73,75@74⦊⦉@74 + @76,77⦊countdown -= 5⦉@76,77; + } else { + @63⦊return⦉@63; + } + }@78⦊⦉@78@52⦊⦉@52 + + let @79⦊mut countdown = 0⦉@79; + if @79⦊true⦉@79 @80,82⦊{ + countdown = 1; + }⦉@80,82@81⦊⦉@81 + + let @106⦊z⦉@106 = if @83⦊countdown > 7⦉@83 @84,86,87⦊{ + countdown -= 4; + }⦉@84,86,87 else if @85⦊countdown > 2⦉@85 { + if @88,90⦊countdown < 1⦉@88,90 || @97⦊countdown > 5⦉@97@95⦊⦉@95@96⦊⦉@96 || @93⦊countdown != 9⦉@93@91⦊⦉@91@92⦊⦉@92 @99,101⦊{ + countdown = 0; + }⦉@99,101@100⦊⦉@100 + @102,103⦊countdown -= 5⦉@102,103; } else { - let @60,75,76⦊should_be_reachable = countdown; - println!("reached"); - return⦉@60,75,76; + let @89,104,105⦊should_be_reachable = countdown; + println!("reached"); + return⦉@89,104,105; }; - let @98⦊w⦉@98 = if @77⦊countdown > 7⦉@77 { - @81⦊countdown -= 4⦉@81; - } else if @79⦊countdown > 2⦉@79 { - if @82,84⦊countdown < 1⦉@82,84 || @91⦊countdown > 5⦉@91@89⦊⦉@89@90⦊⦉@90 || @87⦊countdown != 9⦉@87@85⦊⦉@85@86⦊⦉@86 @93,95⦊{ - countdown = 0; - }⦉@93,95@94⦊⦉@94 - @97⦊countdown -= 5⦉@97; + let @127⦊w⦉@127 = if @106⦊countdown > 7⦉@106 @107,109,110⦊{ + countdown -= 4; + }⦉@107,109,110 else if @108⦊countdown > 2⦉@108 { + if @111,113⦊countdown < 1⦉@111,113 || @120⦊countdown > 5⦉@120@118⦊⦉@118@119⦊⦉@119 || @116⦊countdown != 9⦉@116@114⦊⦉@114@115⦊⦉@115 @122,124⦊{ + countdown = 0; + }⦉@122,124@123⦊⦉@123 + @125,126⦊countdown -= 5⦉@125,126; } else { - @83⦊return⦉@83; + @112⦊return⦉@112; }; -}@101⦊⦉@101@102⦊⦉@102 +}@130⦊⦉@130@131⦊⦉@131 diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html index 31bb57be81b..fc9f54143ed 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html @@ -71,10 +71,13 @@
fn in_func(a: u32) { let @0⦊b = 1⦉@0; - let @1,2,3,4⦊c⦉@1,2,3,4 = @0⦊a + b⦉@0; - @1,2,3,4⦊println!("c = {}", c) -@0,1,2,3,4⦊b = 1; + }⦉@1,2,3,4
+22:6-22:6: @4.Return: return"> let c = a + b;
+ println!("c = {}", c) + }⦉@0,1,2,3,4 diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html index 6c4ce72305e..325d4483223 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html @@ -69,13 +69,33 @@ -
fn trait_func(&mut self, incr: u32) { - self.in_struct_field += @0⦊incr⦉@0; - fn trait_func(&mut self, incr: u32) @1,2⦊in_func(self.in_struct_field); -@0,1,2⦊{ + }⦉@1,2
+40:45-43:10: @2[2]: _0 = const () +43:10-43:10: @2.Return: return"> self.in_struct_field += incr; + in_func(self.in_struct_field); + }⦉@0,1,2 diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html index 7fbda5d0b3d..509a949cfcf 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html @@ -108,28 +108,46 @@ 9:16-9:22: @16[18]: FakeRead(ForMatchedPlace, _26)">@14,16⦊a < 30⦉@14,16 { @17,19⦊break⦉@17,19; } - @20⦊a -= 5⦉@20; - @21⦊b -= 5⦉@21; - if @18,20,21⦊a -= 5; + b -= 5⦉@18,20,21; + if @21⦊b < 90⦉@21 { - @18,20,21⦊b < 90⦉@18,20,21 { + @25⦊a -= 10; -@22,24,25⦊a -= 10; + if is_true⦉@25 { - @26,28⦊break 'outer⦉@26,28; - } else { - @29⦊a -= 2; - if is_true⦉@22,24,25 { + @26,28⦊break 'outer⦉@26,28; + } else @27,29⦊{ + a -= 2; + } - }⦉@29@23⦊⦉@23 - }@30⦊⦉@30 - @32⦊countdown -= 1⦉@32; - }@7⦊⦉@7 -}@33⦊⦉@33 + }⦉@27,29@23⦊⦉@23 + }@30⦊⦉@30 + @31,32⦊countdown -= 1⦉@31,32; + }@7⦊⦉@7 +}@33⦊⦉@33 diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..2be6bad619e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,259 @@ + + + + +overflow.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown == 1⦉@3,5 @6,8,9,10,11,12⦊{ + let result = might_overflow(10); + println!("Result: {}", result); + }⦉@6,8,9,10,11,12 else if @7⦊countdown < 5⦉@7 @13,15,16,17,18,19⦊{ + let result = might_overflow(1); + println!("Result: {}", result); + }⦉@13,15,16,17,18,19@14⦊⦉@14@20⦊⦉@20 + @21,22⦊countdown -= 1⦉@21,22; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..44fabaf0d7d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html @@ -0,0 +1,397 @@ + + + + +overflow.might_overflow - Coverage Spans + + + +
fn might_overflow(to_add: u32) -> u32 { + if @0⦊to_add > 5⦉@0 @1,3,4,5⦊{ + println!("this will probably overflow"); + }⦉@1,3,4,5@2⦊⦉@2 + let @6,7,8,9,10,11,12,13,14⦊add_to = u32::MAX - 5; + println!("does {} + {} overflow?", add_to, to_add); + let result = to_add + add_to; + println!("continuing after overflow check"); + result +}⦉@6,7,8,9,10,11,12,13,14
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..4a44ca0a97b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,103 @@ + + + + +panic_unwind.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown == 1⦉@3,5 @6,8,9⦊{ + might_panic(true); + }⦉@6,8,9 else if @7⦊countdown < 5⦉@7 @10,12,13⦊{ + might_panic(false); + }⦉@10,12,13@11⦊⦉@11@14⦊⦉@14 + @15,16⦊countdown -= 1⦉@15,16; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..b209ea9eee9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html @@ -0,0 +1,164 @@ + + + + +panic_unwind.might_panic - Coverage Spans + + + +
fn might_panic(should_panic: bool) { + if @0⦊should_panic⦉@0 { + @1,3,4,5⦊println!("panicking..."); + panic!("panics");⦉@1,3,4,5 + } else @2,6,7⦊{ + println!("Don't Panic"); + } +}⦉@2,6,7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html index 914e829faa0..bc3e67b8c99 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html @@ -133,9 +133,12 @@ @10,12⦊break⦉@10,12 ; } - @13⦊countdown - -= - 1⦉@13 + @11,13⦊countdown + -= + 1⦉@11,13 ; }@7⦊⦉@7 }@10,12⦊⦉@10,12 diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html index 5c9baee5d80..23b35499846 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html @@ -79,33 +79,38 @@ @6,8⦊_⦉@6,8 +17:9-17:10: @8[5]: _8 = const ()">@6,8,9⦊_⦉@6,8,9
in @2,3,4⦊0..10⦉@2,3,4 { - @9⦊countdown -@6,8,9⦊countdown + -= 1 - ; - if - countdown < 5⦉@9 +25:13-25:26: @9[6]: FakeRead(ForMatchedPlace, _18)"> countdown < 5⦉@6,8,9 { @10,12,13,14⦊call(/*return_error=*/ true)⦉@10,12,13,14 } ; } - @12⦊countdown - -= - 1⦉@12 + @7,12⦊countdown + -= + 1⦉@7,12 ; } + + +yield.main-{closure#0} - Coverage Spans + + + +
|| { + @0⦊yield 1⦉@0; + return @1⦊"foo" + }⦉@1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..00b2b35f3dd --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html @@ -0,0 +1,81 @@ + + + + +yield.main-{closure#1} - Coverage Spans + + + +
|| { + @0⦊yield 1⦉@0; + @1⦊yield 2⦉@1; + @2⦊yield 3⦉@2; + return @3⦊"foo" + }⦉@3
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..f5ea50692bf --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,138 @@ + + + + +yield.main - Coverage Spans + + + +
fn main() { + let @0,1,2⦊mut generator⦉@0,1,2 = || { + yield 1; + return "foo" + }; + + match @0,1,2⦊Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1)⦉@0,1,2 => @4,6,7,8⦊{}⦉@4,6,7,8 + _ => @5⦊panic!("unexpected value from resume")⦉@5, + } + match @4,6,7,8⦊Pin::new(&mut generator).resume(())⦉@4,6,7,8 { + GeneratorState::Complete(@10,11⦊"foo"⦉@10,11) => @12,13,14,15⦊{}⦉@12,13,14,15 + _ => @9⦊panic!("unexpected value from resume")⦉@9, + } + + let @12,13,14,15⦊mut generator⦉@12,13,14,15 = || { + yield 1; + yield 2; + yield 3; + return "foo" + }; + + match @12,13,14,15⦊Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1)⦉@12,13,14,15 => @17,19,20,21⦊{}⦉@17,19,20,21 + _ => @18⦊panic!("unexpected value from resume")⦉@18, + } + match @17,19,20,21⦊Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(2)⦉@17,19,20,21 => @23,25⦊{}⦉@23,25 + _ => @24⦊panic!("unexpected value from resume")⦉@24, + } +}@23,25⦊⦉@23,25
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..a8227cffc60 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,99 @@ + + + + +abort.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown < 5⦉@3,5 @6,8,9⦊{ + might_abort(false); + }⦉@6,8,9@7⦊⦉@7 + @10,11⦊countdown -= 1⦉@10,11; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..daef056a19a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html @@ -0,0 +1,164 @@ + + + + +abort.might_abort - Coverage Spans + + + +
fn might_abort(should_abort: bool) { + if @0⦊should_abort⦉@0 { + @1,3,4,5⦊println!("aborting..."); + panic!("panics and aborts");⦉@1,3,4,5 + } else @2,6,7⦊{ + println!("Don't Panic"); + } +}⦉@2,6,7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..499825445ac --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,103 @@ + + + + +assert.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown == 1⦉@3,5 @6,8,9⦊{ + might_fail_assert(3); + }⦉@6,8,9 else if @7⦊countdown < 5⦉@7 @10,12,13⦊{ + might_fail_assert(2); + }⦉@10,12,13@11⦊⦉@11@14⦊⦉@14 + @15,16⦊countdown -= 1⦉@15,16; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..98be3485a41 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html @@ -0,0 +1,97 @@ + + + + +assert.might_fail_assert - Coverage Spans + + + +
fn might_fail_assert(one_plus_one: u32) { + @0,1,2,3,4⦊println!("does 1 + 1 = {}?", one_plus_one);⦉@0,1,2,3,4 + assert_eq!(@0,1,2,3,4⦊1 + 1⦉@0,1,2,3,4, one_plus_one, @5,7,8,9,10,11,12⦊"the argument was wrong"⦉@5,7,8,9,10,11,12); +}@6⦊⦉@6
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..31646f8ce81 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,89 @@ + + + + +async.executor-block_on-VTABLE-{closure#0} - Coverage Spans + + + +
{ + @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 + }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..ddc791f074f --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html @@ -0,0 +1,89 @@ + + + + +async.executor-block_on-VTABLE-{closure#1} - Coverage Spans + + + +
{ + @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 + }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..709b87fc501 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html @@ -0,0 +1,89 @@ + + + + +async.executor-block_on-VTABLE-{closure#2} - Coverage Spans + + + +
{ + @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 + }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..abd2621481a --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.executor-block_on-VTABLE-{closure#3} - Coverage Spans + + + +
|_| @0⦊()⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..9d71d8ccc6e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html @@ -0,0 +1,226 @@ + + + + +async.executor-block_on - Coverage Spans + + + +
pub fn block_on<F: Future>(mut future: F) -> F::Output { + let @0,1,2,3,4,5⦊mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; + + loop { + if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { + break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; + } + }@11,13⦊⦉@11,13 + }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..779f67fd7c1 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.f-{closure#0} - Coverage Spans + + + +
{ @0⦊1 }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..050ae67efc9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.f - Coverage Spans + + + +
async fn f() -> u8 { 1 }@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..d176a607d3b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.foo-{closure#0} - Coverage Spans + + + +
{ @0⦊[false; 10] }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..64eeaefa894 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.foo - Coverage Spans + + + +
async fn foo() -> [bool; 10] { [false; 10] }@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..4e894eecd16 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.g-{closure#0} - Coverage Spans + + + +
@0,2,3⦊{ + match x⦉@0,2,3 { + @16⦊y⦉@16 if @0,2,3⦊f()⦉@0,2,3.await == @9,12,14,15⦊y⦉@9,12,14,15@17⦊⦉@17 => @16⦊()⦉@16, + _ => @1⦊()⦉@1, + } +}@18,19⦊⦉@18,19
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..4788562a9d4 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html @@ -0,0 +1,79 @@ + + + + +async.g - Coverage Spans + + + +
pub async fn g(x: u8) { + match x { + y if f().await == y => (), + _ => (), + } +}@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..de48232efde --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.h-{closure#0} - Coverage Spans + + + +
@0,2,3⦊{ + match x⦉@0,2,3 { + @17⦊y⦉@17 if @0,2,3⦊foo()⦉@0,2,3.await[@9,12,14,15,16⦊y⦉@9,12,14,15,16]@18⦊⦉@18 => @17⦊()⦉@17, + _ => @1⦊()⦉@1, + } +}@19,20⦊⦉@19,20
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..83b0a3e0d43 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html @@ -0,0 +1,79 @@ + + + + +async.h - Coverage Spans + + + +
async fn h(x: usize) { + match x { + y if foo().await[y] => (), + _ => (), + } +}@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..71397d39625 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,82 @@ + + + + +async.i-{closure#0} - Coverage Spans + + + +
@0,2,3⦊{ + match x⦉@0,2,3 { + @17⦊y⦉@17 if @0,2,3⦊f()⦉@0,2,3.await == @9,12,14,15,16⦊y + 1⦉@9,12,14,15,16@18⦊⦉@18 => @17⦊()⦉@17, + _ => @1⦊()⦉@1, + } +}@19,20⦊⦉@19,20
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..55efca74481 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html @@ -0,0 +1,79 @@ + + + + +async.i - Coverage Spans + + + +
async fn i(x: u8) { + match x { + y if f().await == y + 1 => (), + _ => (), + } +}@0,1⦊⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..2f14339d9e9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +async.main - Coverage Spans + + + +
fn main() @0,1,2,3,4,5,6,7,8,9⦊{ + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + executor::block_on(future.as_mut()); +}⦉@0,1,2,3,4,5,6,7,8,9
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html index cda1040c291..09adc12cefd 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html @@ -87,10 +87,12 @@ let @25⦊x⦉@25 = if @4⦊countdown > 7⦉@4 { - @8⦊countdown -= 4; - B⦉@8 + @5,7,8⦊countdown -= 4; + B⦉@5,7,8 } else if @6⦊countdown > 2⦉@6 { @@ -106,10 +108,12 @@ }⦉@20,22@21⦊⦉@21
- @24⦊countdown -= 5; - countdown⦉@24 + @23,24⦊countdown -= 5; + countdown⦉@23,24 } else { @10⦊return⦉@10; }; @@ -129,9 +133,15 @@ if @29⦊countdown > 7⦉@29 { - @33⦊countdown -= 4⦉@33; - } else if @29⦊countdown > 7⦉@29 @30,32,33⦊{ + countdown -= 4; + }⦉@30,32,33 else if @31⦊countdown > 2⦉@31 { if }⦉@45,47@46⦊⦉@46 - @49⦊countdown -= 5⦉@49; + @48,49⦊countdown -= 5⦉@48,49; } else { @35⦊return⦉@35; } - let @50⦊mut countdown = 0⦉@50; - if @50⦊true⦉@50 @51,53⦊{ - countdown = 1; - }⦉@51,53@52⦊⦉@52 + if @50⦊true⦉@50 { + // Demonstrate the difference with `TerminatorKind::Assert` as of 2020-11-15. Assert is no + // longer treated as a `BasicCoverageBlock` terminator, which changed the coverage region, + // for the executed `then` block above, to include the closing brace on line 30. That + // changed the line count, but the coverage code region (for the `else if` condition) is + // still valid. + // + // Note that `if` (then) and `else` blocks include the closing brace in their coverage + // code regions when the last line in the block ends in a semicolon, because the Rust + // compiler inserts a `StatementKind::Assign` to assign `const ()` to a `Place`, for the + // empty value for the executed block. When the last line does not end in a semicolon + // (that is, when the block actually results in a value), the additional `Assign` is not + // generated, and the brace is not included. + let @51,53⦊mut countdown = 0⦉@51,53; + if @51,53⦊true⦉@51,53 @54,56⦊{ + countdown = 10; + }⦉@54,56@55⦊⦉@55 - let @77⦊z⦉@77 = if @54⦊countdown > 7⦉@54 { - @58⦊countdown -= 4⦉@58; - } else if @56⦊countdown > 2⦉@56 { - if @59,61⦊countdown < 1⦉@59,61 || @68⦊countdown > 5⦉@68@66⦊⦉@66@67⦊⦉@67 || @64⦊countdown != 9⦉@64@62⦊⦉@62@63⦊⦉@63 @70,72⦊{ - countdown = 0; - }⦉@70,72@71⦊⦉@71 - @74⦊countdown -= 5⦉@74; + if @57⦊countdown > 7⦉@57 @58,60,61⦊{ + countdown -= 4; + }⦉@58,60,61 + // The closing brace of the `then` branch is now included in the coverage region, and shown + // as "executed" (giving its line a count of 1 here). Since, in the original version above, + // the closing brace shares the same line as the `else if` conditional expression (which is + // not executed if the first `then` condition is true), only the condition's code region is + // marked with a count of 0 now. + else if @59⦊countdown > 2⦉@59 { + if @62,64⦊countdown < 1⦉@62,64 || @71⦊countdown > 5⦉@71@69⦊⦉@69@70⦊⦉@70 || @67⦊countdown != 9⦉@67@65⦊⦉@65@66⦊⦉@66 @73,75⦊{ + countdown = 0; + }⦉@73,75@74⦊⦉@74 + @76,77⦊countdown -= 5⦉@76,77; + } else { + @63⦊return⦉@63; + } + }@78⦊⦉@78@52⦊⦉@52 + + let @79⦊mut countdown = 0⦉@79; + if @79⦊true⦉@79 @80,82⦊{ + countdown = 1; + }⦉@80,82@81⦊⦉@81 + + let @106⦊z⦉@106 = if @83⦊countdown > 7⦉@83 @84,86,87⦊{ + countdown -= 4; + }⦉@84,86,87 else if @85⦊countdown > 2⦉@85 { + if @88,90⦊countdown < 1⦉@88,90 || @97⦊countdown > 5⦉@97@95⦊⦉@95@96⦊⦉@96 || @93⦊countdown != 9⦉@93@91⦊⦉@91@92⦊⦉@92 @99,101⦊{ + countdown = 0; + }⦉@99,101@100⦊⦉@100 + @102,103⦊countdown -= 5⦉@102,103; } else { - let @60,75,76⦊should_be_reachable = countdown; - println!("reached"); - return⦉@60,75,76; + let @89,104,105⦊should_be_reachable = countdown; + println!("reached"); + return⦉@89,104,105; }; - let @98⦊w⦉@98 = if @77⦊countdown > 7⦉@77 { - @81⦊countdown -= 4⦉@81; - } else if @79⦊countdown > 2⦉@79 { - if @82,84⦊countdown < 1⦉@82,84 || @91⦊countdown > 5⦉@91@89⦊⦉@89@90⦊⦉@90 || @87⦊countdown != 9⦉@87@85⦊⦉@85@86⦊⦉@86 @93,95⦊{ - countdown = 0; - }⦉@93,95@94⦊⦉@94 - @97⦊countdown -= 5⦉@97; + let @127⦊w⦉@127 = if @106⦊countdown > 7⦉@106 @107,109,110⦊{ + countdown -= 4; + }⦉@107,109,110 else if @108⦊countdown > 2⦉@108 { + if @111,113⦊countdown < 1⦉@111,113 || @120⦊countdown > 5⦉@120@118⦊⦉@118@119⦊⦉@119 || @116⦊countdown != 9⦉@116@114⦊⦉@114@115⦊⦉@115 @122,124⦊{ + countdown = 0; + }⦉@122,124@123⦊⦉@123 + @125,126⦊countdown -= 5⦉@125,126; } else { - @83⦊return⦉@83; + @112⦊return⦉@112; }; -}@101⦊⦉@101@102⦊⦉@102 +}@130⦊⦉@130@131⦊⦉@131 diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html index 31bb57be81b..fc9f54143ed 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html @@ -71,10 +71,13 @@
fn in_func(a: u32) { let @0⦊b = 1⦉@0; - let @1,2,3,4⦊c⦉@1,2,3,4 = @0⦊a + b⦉@0; - @1,2,3,4⦊println!("c = {}", c) -@0,1,2,3,4⦊b = 1; + }⦉@1,2,3,4
+22:6-22:6: @4.Return: return"> let c = a + b;
+ println!("c = {}", c) + }⦉@0,1,2,3,4
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html index 6c4ce72305e..325d4483223 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html @@ -69,13 +69,33 @@ -
fn trait_func(&mut self, incr: u32) { - self.in_struct_field += @0⦊incr⦉@0; - fn trait_func(&mut self, incr: u32) @1,2⦊in_func(self.in_struct_field); -@0,1,2⦊{ + }⦉@1,2
+40:45-43:10: @2[2]: _0 = const () +43:10-43:10: @2.Return: return"> self.in_struct_field += incr;
+ in_func(self.in_struct_field); + }⦉@0,1,2
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html index 7fbda5d0b3d..509a949cfcf 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html @@ -108,28 +108,46 @@ 9:16-9:22: @16[18]: FakeRead(ForMatchedPlace, _26)">@14,16⦊a < 30⦉@14,16
{ @17,19⦊break⦉@17,19; } - @20⦊a -= 5⦉@20; - @21⦊b -= 5⦉@21; - if @18,20,21⦊a -= 5; + b -= 5⦉@18,20,21; + if @21⦊b < 90⦉@21 { - @18,20,21⦊b < 90⦉@18,20,21 { + @25⦊a -= 10; -@22,24,25⦊a -= 10; + if is_true⦉@25 { - @26,28⦊break 'outer⦉@26,28; - } else { - @29⦊a -= 2; - if is_true⦉@22,24,25 { + @26,28⦊break 'outer⦉@26,28; + } else @27,29⦊{ + a -= 2; + } - }⦉@29@23⦊⦉@23 - }@30⦊⦉@30 - @32⦊countdown -= 1⦉@32; - }@7⦊⦉@7 -}@33⦊⦉@33 + }⦉@27,29@23⦊⦉@23 + }@30⦊⦉@30 + @31,32⦊countdown -= 1⦉@31,32; + }@7⦊⦉@7 +}@33⦊⦉@33 diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..2be6bad619e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,259 @@ + + + + +overflow.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown == 1⦉@3,5 @6,8,9,10,11,12⦊{ + let result = might_overflow(10); + println!("Result: {}", result); + }⦉@6,8,9,10,11,12 else if @7⦊countdown < 5⦉@7 @13,15,16,17,18,19⦊{ + let result = might_overflow(1); + println!("Result: {}", result); + }⦉@13,15,16,17,18,19@14⦊⦉@14@20⦊⦉@20 + @21,22⦊countdown -= 1⦉@21,22; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..44fabaf0d7d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html @@ -0,0 +1,397 @@ + + + + +overflow.might_overflow - Coverage Spans + + + +
fn might_overflow(to_add: u32) -> u32 { + if @0⦊to_add > 5⦉@0 @1,3,4,5⦊{ + println!("this will probably overflow"); + }⦉@1,3,4,5@2⦊⦉@2 + let @6,7,8,9,10,11,12,13,14⦊add_to = u32::MAX - 5; + println!("does {} + {} overflow?", add_to, to_add); + let result = to_add + add_to; + println!("continuing after overflow check"); + result +}⦉@6,7,8,9,10,11,12,13,14
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..4a44ca0a97b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,103 @@ + + + + +panic_unwind.main - Coverage Spans + + + +
fn main() -> Result<(),u8> { + let @0⦊mut countdown = 10⦉@0; + while @1,2⦊countdown > 0⦉@1,2 { + if @3,5⦊countdown == 1⦉@3,5 @6,8,9⦊{ + might_panic(true); + }⦉@6,8,9 else if @7⦊countdown < 5⦉@7 @10,12,13⦊{ + might_panic(false); + }⦉@10,12,13@11⦊⦉@11@14⦊⦉@14 + @15,16⦊countdown -= 1⦉@15,16; + } + @4⦊Ok(()) +}⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..b209ea9eee9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html @@ -0,0 +1,164 @@ + + + + +panic_unwind.might_panic - Coverage Spans + + + +
fn might_panic(should_panic: bool) { + if @0⦊should_panic⦉@0 { + @1,3,4,5⦊println!("panicking..."); + panic!("panics");⦉@1,3,4,5 + } else @2,6,7⦊{ + println!("Don't Panic"); + } +}⦉@2,6,7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html index 914e829faa0..bc3e67b8c99 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html @@ -133,9 +133,12 @@ @10,12⦊break⦉@10,12 ; } - @13⦊countdown - -= - 1⦉@13 + @11,13⦊countdown + -= + 1⦉@11,13 ; }@7⦊⦉@7 }@10,12⦊⦉@10,12 diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html index 5c9baee5d80..23b35499846 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html @@ -79,33 +79,38 @@ @6,8⦊_⦉@6,8 +17:9-17:10: @8[5]: _8 = const ()">@6,8,9⦊_⦉@6,8,9
in @2,3,4⦊0..10⦉@2,3,4 { - @9⦊countdown -@6,8,9⦊countdown + -= 1 - ; - if - countdown < 5⦉@9 +25:13-25:26: @9[6]: FakeRead(ForMatchedPlace, _18)"> countdown < 5⦉@6,8,9 { @10,12,13,14⦊call(/*return_error=*/ true)⦉@10,12,13,14 } ; } - @12⦊countdown - -= - 1⦉@12 + @7,12⦊countdown + -= + 1⦉@7,12 ; } + + +yield.main-{closure#0} - Coverage Spans + + + +
|| { + @0⦊yield 1⦉@0; + return @1⦊"foo" + }⦉@1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..00b2b35f3dd --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html @@ -0,0 +1,81 @@ + + + + +yield.main-{closure#1} - Coverage Spans + + + +
|| { + @0⦊yield 1⦉@0; + @1⦊yield 2⦉@1; + @2⦊yield 3⦉@2; + return @3⦊"foo" + }⦉@3
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..f5ea50692bf --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,138 @@ + + + + +yield.main - Coverage Spans + + + +
fn main() { + let @0,1,2⦊mut generator⦉@0,1,2 = || { + yield 1; + return "foo" + }; + + match @0,1,2⦊Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1)⦉@0,1,2 => @4,6,7,8⦊{}⦉@4,6,7,8 + _ => @5⦊panic!("unexpected value from resume")⦉@5, + } + match @4,6,7,8⦊Pin::new(&mut generator).resume(())⦉@4,6,7,8 { + GeneratorState::Complete(@10,11⦊"foo"⦉@10,11) => @12,13,14,15⦊{}⦉@12,13,14,15 + _ => @9⦊panic!("unexpected value from resume")⦉@9, + } + + let @12,13,14,15⦊mut generator⦉@12,13,14,15 = || { + yield 1; + yield 2; + yield 3; + return "foo" + }; + + match @12,13,14,15⦊Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1)⦉@12,13,14,15 => @17,19,20,21⦊{}⦉@17,19,20,21 + _ => @18⦊panic!("unexpected value from resume")⦉@18, + } + match @17,19,20,21⦊Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(2)⦉@17,19,20,21 => @23,25⦊{}⦉@23,25 + _ => @24⦊panic!("unexpected value from resume")⦉@24, + } +}@23,25⦊⦉@23,25
+ + diff --git a/src/test/run-make-fulldeps/coverage/abort.rs b/src/test/run-make-fulldeps/coverage/abort.rs new file mode 100644 index 00000000000..01c5c920547 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/abort.rs @@ -0,0 +1,34 @@ +#![feature(unwind_attributes)] +#![allow(unused_assignments)] + +#[unwind(aborts)] +fn might_abort(should_abort: bool) { + if should_abort { + println!("aborting..."); + panic!("panics and aborts"); + } else { + println!("Don't Panic"); + } +} + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown < 5 { + might_abort(false); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the similar tests +// `panic_unwind.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program includes `TerminatorKind::Abort`. +// 3. The test does not invoke the abort. By executing to a successful completion, the coverage +// results show where the program did and did not execute. +// 4. If the program actually aborted, the coverage counters would not be saved (which "works as +// intended"). Coverage results would show no executed coverage regions. +// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status +// (on Linux at least). diff --git a/src/test/run-make-fulldeps/coverage/assert.rs b/src/test/run-make-fulldeps/coverage/assert.rs new file mode 100644 index 00000000000..c85f2748eb9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/assert.rs @@ -0,0 +1,32 @@ +#![allow(unused_assignments)] +// expect-exit-status-101 + +fn might_fail_assert(one_plus_one: u32) { + println!("does 1 + 1 = {}?", one_plus_one); + assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); +} + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + might_fail_assert(3); + } else if countdown < 5 { + might_fail_assert(2); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the very similar test +// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or +// related `assert_*!()` macro. +// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce +// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to +// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). +// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test +// (and in many other coverage tests). The `Assert` terminator is typically generated by the +// Rust compiler to check for runtime failures, such as numeric overflows. diff --git a/src/test/run-make-fulldeps/coverage/async.rs b/src/test/run-make-fulldeps/coverage/async.rs new file mode 100644 index 00000000000..f69b8dce893 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/async.rs @@ -0,0 +1,64 @@ +#![allow(unused_assignments)] + +// require-rust-edition-2018 + +async fn f() -> u8 { 1 } + +async fn foo() -> [bool; 10] { [false; 10] } + +pub async fn g(x: u8) { + match x { + y if f().await == y => (), + _ => (), + } +} + +// #78366: check the reference to the binding is recorded even if the binding is not autorefed + +async fn h(x: usize) { + match x { + y if foo().await[y] => (), + _ => (), + } +} + +async fn i(x: u8) { + match x { + y if f().await == y + 1 => (), + _ => (), + } +} + +fn main() { + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + executor::block_on(future.as_mut()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + pub fn block_on(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/src/test/run-make-fulldeps/coverage/conditions.rs b/src/test/run-make-fulldeps/coverage/conditions.rs index da206e28f31..1a8bafa50d4 100644 --- a/src/test/run-make-fulldeps/coverage/conditions.rs +++ b/src/test/run-make-fulldeps/coverage/conditions.rs @@ -36,6 +36,42 @@ fn main() { return; } + if true { + // Demonstrate the difference with `TerminatorKind::Assert` as of 2020-11-15. Assert is no + // longer treated as a `BasicCoverageBlock` terminator, which changed the coverage region, + // for the executed `then` block above, to include the closing brace on line 30. That + // changed the line count, but the coverage code region (for the `else if` condition) is + // still valid. + // + // Note that `if` (then) and `else` blocks include the closing brace in their coverage + // code regions when the last line in the block ends in a semicolon, because the Rust + // compiler inserts a `StatementKind::Assign` to assign `const ()` to a `Place`, for the + // empty value for the executed block. When the last line does not end in a semicolon + // (that is, when the block actually results in a value), the additional `Assign` is not + // generated, and the brace is not included. + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } + // The closing brace of the `then` branch is now included in the coverage region, and shown + // as "executed" (giving its line a count of 1 here). Since, in the original version above, + // the closing brace shares the same line as the `else if` conditional expression (which is + // not executed if the first `then` condition is true), only the condition's code region is + // marked with a count of 0 now. + else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + } + let mut countdown = 0; if true { countdown = 1; diff --git a/src/test/run-make-fulldeps/coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk index 99a2e0ba952..867a3566ac3 100644 --- a/src/test/run-make-fulldeps/coverage/coverage_tools.mk +++ b/src/test/run-make-fulldeps/coverage/coverage_tools.mk @@ -44,8 +44,3 @@ LLVM_VERSION_11_PLUS := $(shell \ LLVM_VERSION=$$("$(LLVM_BIN_DIR)"/llvm-config --version) && \ LLVM_VERSION_MAJOR=$${LLVM_VERSION/.*/} && \ [ $$LLVM_VERSION_MAJOR -ge 11 ] && echo true || echo false) - -# FIXME(richkadel): Can any of the features tested by `run-make-fulldeps/coverage-*` tests be tested -# just as completely by more focused unit tests of the code logic itself, to reduce the number of -# test result files generated and maintained, and to help identify specific test failures and root -# causes more easily? diff --git a/src/test/run-make-fulldeps/coverage/overflow.rs b/src/test/run-make-fulldeps/coverage/overflow.rs new file mode 100644 index 00000000000..e537b0e95c3 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/overflow.rs @@ -0,0 +1,63 @@ +#![allow(unused_assignments)] +// expect-exit-status-101 + +fn might_overflow(to_add: u32) -> u32 { + if to_add > 5 { + println!("this will probably overflow"); + } + let add_to = u32::MAX - 5; + println!("does {} + {} overflow?", add_to, to_add); + let result = to_add + add_to; + println!("continuing after overflow check"); + result +} + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + let result = might_overflow(10); + println!("Result: {}", result); + } else if countdown < 5 { + let result = might_overflow(1); + println!("Result: {}", result); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, +// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program passes or fails a +// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). +// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, +// compiler-generated assertion failures are assumed to be a symptom of a program bug, not +// expected behavior. To simplify the coverage graphs and keep instrumented programs as +// small and fast as possible, `Assert` terminators are assumed to always succeed, and +// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not +// get its own coverage counter. +// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. +// In this test, the final count for the statements after the `if` block in `might_overflow()` +// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending +// on the MIR graph and the structure of the code, this count could have been 3 (which might +// have been valid for the overflowed add `+`, but should have been 4 for the lines before +// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented +// via StatementKind::Counter at the end of the block, but (as in the case in this test), +// a CounterKind::Expression is always evaluated. In this case, the expression was based on +// a `Counter` incremented as part of the evaluation of the `if` expression, which was +// executed, and counted, 4 times, before reaching the overflow add. + +// If the program did not overflow, the coverage for `might_overflow()` would look like this: +// +// 4| |fn might_overflow(to_add: u32) -> u32 { +// 5| 4| if to_add > 5 { +// 6| 0| println!("this will probably overflow"); +// 7| 4| } +// 8| 4| let add_to = u32::MAX - 5; +// 9| 4| println!("does {} + {} overflow?", add_to, to_add); +// 10| 4| let result = to_add + add_to; +// 11| 4| println!("continuing after overflow check"); +// 12| 4| result +// 13| 4|} diff --git a/src/test/run-make-fulldeps/coverage/panic_unwind.rs b/src/test/run-make-fulldeps/coverage/panic_unwind.rs new file mode 100644 index 00000000000..02fa01ab962 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/panic_unwind.rs @@ -0,0 +1,49 @@ +#![allow(unused_assignments)] +// expect-exit-status-101 + +fn might_panic(should_panic: bool) { + if should_panic { + println!("panicking..."); + panic!("panics"); + } else { + println!("Don't Panic"); + } +} + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + might_panic(true); + } else if countdown < 5 { + might_panic(false); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and +// `try_error_result.rs`. +// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the +// normal program exit cleanup, including writing out the current values of the coverage +// counters. +// 3. The coverage results show (interestingly) that the `panic!()` call did execute, but it does +// not show coverage of the `if countdown == 1` branch in `main()` that calls +// `might_panic(true)` (causing the call to `panic!()`). +// 4. The reason `main()`s `if countdown == 1` branch, calling `might_panic(true)`, appears +// "uncovered" is, InstrumentCoverage (intentionally) treats `TerminatorKind::Call` terminators +// as non-branching, because when a program executes normally, they always are. Errors handled +// via the try `?` operator produce error handling branches that *are* treated as branches in +// coverage results. By treating calls without try `?` operators as non-branching (assumed to +// return normally and continue) the coverage graph can be simplified, producing smaller, +// faster binaries, and cleaner coverage results. +// 5. The reason the coverage results actually show `panic!()` was called is most likely because +// `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or +// `Terminator`s that execute with a coverage counter before the panic and unwind occur. +// 6. By best practice, programs should not panic. By design, the coverage implementation will not +// incur additional cost (in program size and execution time) to improve coverage results for +// an event that is not supposted to happen. +// 7. FIXME(#78544): This issue describes a feature request for a proposed option to enable +// more accurate coverage results for tests that intentionally panic. diff --git a/src/test/run-make-fulldeps/coverage/yield.rs b/src/test/run-make-fulldeps/coverage/yield.rs new file mode 100644 index 00000000000..ff7616656ff --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/yield.rs @@ -0,0 +1,37 @@ +#![feature(generators, generator_trait)] +#![allow(unused_assignments)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +fn main() { + let mut generator = || { + yield 1; + return "foo" + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Complete("foo") => {} + _ => panic!("unexpected value from resume"), + } + + let mut generator = || { + yield 1; + yield 2; + yield 3; + return "foo" + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(2) => {} + _ => panic!("unexpected value from resume"), + } +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 0541548aefd..5177dae8a66 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -508,8 +508,6 @@ fn common_inputs_stamp(config: &Config) -> Stamp { stamp.add_path(&rustdoc_path); stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); } - // FIXME(richkadel): Do I need to add an `if let Some(rust_demangler_path) contribution to the - // stamp here as well? // Compiletest itself. stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/")); From f6c9c1a576ba485ad5bd072d9fd8e52c9a043788 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 30 Nov 2020 23:37:49 -0800 Subject: [PATCH 168/274] Removed -base from run-make-fulldeps/coverage-*-base In preparation for removing the -deadcode variants --- src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile | 2 +- .../{coverage-llvmir-base => coverage-llvmir}/Makefile | 2 +- .../filecheck.testprog.txt | 0 .../{coverage-llvmir-base => coverage-llvmir}/testprog.rs | 0 src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile | 2 +- .../{coverage-reports-base => coverage-reports}/Makefile | 2 +- .../expected_export_coverage.abort.json | 0 .../expected_export_coverage.assert.json | 0 .../expected_export_coverage.async.json | 0 .../expected_export_coverage.closure.json | 0 .../expected_export_coverage.conditions.json | 0 .../expected_export_coverage.drop_trait.json | 0 .../expected_export_coverage.generics.json | 0 .../expected_export_coverage.if.json | 0 .../expected_export_coverage.if_else.json | 0 .../expected_export_coverage.inner_items.json | 0 .../expected_export_coverage.lazy_boolean.json | 0 .../expected_export_coverage.loop_break_value.json | 0 .../expected_export_coverage.loops_branches.json | 0 .../expected_export_coverage.nested_loops.json | 0 .../expected_export_coverage.overflow.json | 0 .../expected_export_coverage.panic_unwind.json | 0 .../expected_export_coverage.partial_eq.json | 0 .../expected_export_coverage.simple_loop.json | 0 .../expected_export_coverage.simple_match.json | 0 .../expected_export_coverage.tight_inf_loop.json | 0 .../expected_export_coverage.try_error_result.json | 0 .../expected_export_coverage.while.json | 0 .../expected_export_coverage.while_early_ret.json | 0 .../expected_export_coverage.yield.json | 0 .../expected_show_coverage.abort.txt | 0 .../expected_show_coverage.assert.txt | 0 .../expected_show_coverage.async.txt | 0 .../expected_show_coverage.closure.txt | 0 .../expected_show_coverage.conditions.txt | 0 .../expected_show_coverage.drop_trait.txt | 0 .../expected_show_coverage.generics.txt | 0 .../expected_show_coverage.if.txt | 0 .../expected_show_coverage.if_else.txt | 0 .../expected_show_coverage.inner_items.txt | 0 .../expected_show_coverage.lazy_boolean.txt | 0 .../expected_show_coverage.loop_break_value.txt | 0 .../expected_show_coverage.loops_branches.txt | 0 .../expected_show_coverage.nested_loops.txt | 0 .../expected_show_coverage.overflow.txt | 0 .../expected_show_coverage.panic_unwind.txt | 0 .../expected_show_coverage.partial_eq.txt | 0 .../expected_show_coverage.simple_loop.txt | 0 .../expected_show_coverage.simple_match.txt | 0 .../expected_show_coverage.tight_inf_loop.txt | 0 .../expected_show_coverage.try_error_result.txt | 0 .../expected_show_coverage.while.txt | 0 .../expected_show_coverage.while_early_ret.txt | 0 .../expected_show_coverage.yield.txt | 0 .../expected_show_coverage_counters.abort.txt | 0 .../expected_show_coverage_counters.assert.txt | 0 .../expected_show_coverage_counters.async.txt | 0 .../expected_show_coverage_counters.closure.txt | 0 .../expected_show_coverage_counters.conditions.txt | 0 .../expected_show_coverage_counters.drop_trait.txt | 0 .../expected_show_coverage_counters.generics.txt | 0 .../expected_show_coverage_counters.if.txt | 0 .../expected_show_coverage_counters.if_else.txt | 0 .../expected_show_coverage_counters.inner_items.txt | 0 .../expected_show_coverage_counters.lazy_boolean.txt | 0 .../expected_show_coverage_counters.loop_break_value.txt | 0 .../expected_show_coverage_counters.loops_branches.txt | 0 .../expected_show_coverage_counters.nested_loops.txt | 0 .../expected_show_coverage_counters.overflow.txt | 0 .../expected_show_coverage_counters.panic_unwind.txt | 0 .../expected_show_coverage_counters.partial_eq.txt | 0 .../expected_show_coverage_counters.simple_loop.txt | 0 .../expected_show_coverage_counters.simple_match.txt | 0 .../expected_show_coverage_counters.tight_inf_loop.txt | 0 .../expected_show_coverage_counters.try_error_result.txt | 0 .../expected_show_coverage_counters.while.txt | 0 .../expected_show_coverage_counters.while_early_ret.txt | 0 .../expected_show_coverage_counters.yield.txt | 0 .../prettify_json.py | 0 .../run-make-fulldeps/coverage-spanview-deadcode/Makefile | 2 +- .../abort.main.-------.InstrumentCoverage.0.html | 2 +- .../abort.might_abort.-------.InstrumentCoverage.0.html | 2 +- .../assert.main.-------.InstrumentCoverage.0.html | 2 +- ...assert.might_fail_assert.-------.InstrumentCoverage.0.html | 2 +- ...ck_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ...ck_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html | 2 +- ...ck_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html | 2 +- ...ck_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html | 2 +- .../async.executor-block_on.-------.InstrumentCoverage.0.html | 2 +- .../async.f-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.f.-------.InstrumentCoverage.0.html | 2 +- .../async.foo-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.foo.-------.InstrumentCoverage.0.html | 2 +- .../async.g-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.g.-------.InstrumentCoverage.0.html | 2 +- .../async.h-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.h.-------.InstrumentCoverage.0.html | 2 +- .../async.i-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.i.-------.InstrumentCoverage.0.html | 2 +- .../async.main.-------.InstrumentCoverage.0.html | 2 +- ...closure.main-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ...closure.main-{closure#1}.-------.InstrumentCoverage.0.html | 2 +- ...closure.main-{closure#2}.-------.InstrumentCoverage.0.html | 2 +- ...closure.main-{closure#3}.-------.InstrumentCoverage.0.html | 2 +- .../closure.main.-------.InstrumentCoverage.0.html | 2 +- .../conditions.main.-------.InstrumentCoverage.0.html | 2 +- .../drop_trait.main.-------.InstrumentCoverage.0.html | 2 +- ...drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html | 2 +- .../generics.main.-------.InstrumentCoverage.0.html | 2 +- ...cs.{impl#0}-set_strength.-------.InstrumentCoverage.0.html | 2 +- .../generics.{impl#1}-drop.-------.InstrumentCoverage.0.html | 2 +- .../if.main.-------.InstrumentCoverage.0.html | 2 +- .../if_else.main.-------.InstrumentCoverage.0.html | 2 +- ...Trait-default_trait_func.-------.InstrumentCoverage.0.html | 2 +- ...inner_items.main-in_func.-------.InstrumentCoverage.0.html | 2 +- ...main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html | 2 +- .../inner_items.main.-------.InstrumentCoverage.0.html | 2 +- .../lazy_boolean.main.-------.InstrumentCoverage.0.html | 2 +- .../loop_break_value.main.-------.InstrumentCoverage.0.html | 2 +- .../loops_branches.main.-------.InstrumentCoverage.0.html | 2 +- ...ps_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html | 2 +- .../nested_loops.main.-------.InstrumentCoverage.0.html | 2 +- .../overflow.main.-------.InstrumentCoverage.0.html | 2 +- .../overflow.might_overflow.-------.InstrumentCoverage.0.html | 2 +- .../panic_unwind.main.-------.InstrumentCoverage.0.html | 2 +- ...panic_unwind.might_panic.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.main.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html | 2 +- ...-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ....{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html | 2 +- ...-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ....{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html | 2 +- ...-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ....{impl#2}-le-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html | 2 +- ...-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ....{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html | 2 +- ..._eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html | 2 +- ...ert_receiver_is_total_eq.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html | 2 +- ...artial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html | 2 +- .../simple_loop.main.-------.InstrumentCoverage.0.html | 2 +- .../simple_match.main.-------.InstrumentCoverage.0.html | 2 +- .../tight_inf_loop.main.-------.InstrumentCoverage.0.html | 2 +- .../try_error_result.call.-------.InstrumentCoverage.0.html | 2 +- .../try_error_result.main.-------.InstrumentCoverage.0.html | 2 +- .../while.main.-------.InstrumentCoverage.0.html | 2 +- .../while_early_ret.main.-------.InstrumentCoverage.0.html | 2 +- .../yield.main-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../yield.main-{closure#1}.-------.InstrumentCoverage.0.html | 2 +- .../yield.main.-------.InstrumentCoverage.0.html | 2 +- .../{coverage-spanview-base => coverage-spanview}/Makefile | 4 ++-- .../escape_url.py | 0 .../abort.main.-------.InstrumentCoverage.0.html | 2 +- .../abort.might_abort.-------.InstrumentCoverage.0.html | 2 +- .../assert.main.-------.InstrumentCoverage.0.html | 2 +- ...assert.might_fail_assert.-------.InstrumentCoverage.0.html | 2 +- ...ck_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ...ck_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html | 2 +- ...ck_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html | 2 +- ...ck_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html | 2 +- .../async.executor-block_on.-------.InstrumentCoverage.0.html | 2 +- .../async.f-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.f.-------.InstrumentCoverage.0.html | 2 +- .../async.foo-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.foo.-------.InstrumentCoverage.0.html | 2 +- .../async.g-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.g.-------.InstrumentCoverage.0.html | 2 +- .../async.h-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.h.-------.InstrumentCoverage.0.html | 2 +- .../async.i-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../async.i.-------.InstrumentCoverage.0.html | 2 +- .../async.main.-------.InstrumentCoverage.0.html | 2 +- ...closure.main-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ...closure.main-{closure#1}.-------.InstrumentCoverage.0.html | 2 +- ...closure.main-{closure#2}.-------.InstrumentCoverage.0.html | 2 +- ...closure.main-{closure#3}.-------.InstrumentCoverage.0.html | 2 +- .../closure.main.-------.InstrumentCoverage.0.html | 2 +- .../conditions.main.-------.InstrumentCoverage.0.html | 2 +- .../drop_trait.main.-------.InstrumentCoverage.0.html | 2 +- ...drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html | 2 +- .../generics.main.-------.InstrumentCoverage.0.html | 2 +- ...cs.{impl#0}-set_strength.-------.InstrumentCoverage.0.html | 2 +- .../generics.{impl#1}-drop.-------.InstrumentCoverage.0.html | 2 +- .../if.main.-------.InstrumentCoverage.0.html | 2 +- .../if_else.main.-------.InstrumentCoverage.0.html | 2 +- ...Trait-default_trait_func.-------.InstrumentCoverage.0.html | 2 +- ...inner_items.main-in_func.-------.InstrumentCoverage.0.html | 2 +- ...main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html | 2 +- .../inner_items.main.-------.InstrumentCoverage.0.html | 2 +- .../lazy_boolean.main.-------.InstrumentCoverage.0.html | 2 +- .../loop_break_value.main.-------.InstrumentCoverage.0.html | 2 +- .../loops_branches.main.-------.InstrumentCoverage.0.html | 2 +- ...ps_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html | 2 +- .../nested_loops.main.-------.InstrumentCoverage.0.html | 2 +- .../overflow.main.-------.InstrumentCoverage.0.html | 2 +- .../overflow.might_overflow.-------.InstrumentCoverage.0.html | 2 +- .../panic_unwind.main.-------.InstrumentCoverage.0.html | 2 +- ...panic_unwind.might_panic.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.main.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html | 2 +- ...-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ....{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html | 2 +- ...-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ....{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html | 2 +- ...-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ....{impl#2}-le-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html | 2 +- ...-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- ....{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html | 2 +- ..._eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html | 2 +- ...ert_receiver_is_total_eq.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html | 2 +- .../partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html | 2 +- ...artial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html | 2 +- .../simple_loop.main.-------.InstrumentCoverage.0.html | 2 +- .../simple_match.main.-------.InstrumentCoverage.0.html | 2 +- .../tight_inf_loop.main.-------.InstrumentCoverage.0.html | 2 +- .../try_error_result.call.-------.InstrumentCoverage.0.html | 2 +- .../try_error_result.main.-------.InstrumentCoverage.0.html | 2 +- .../while.main.-------.InstrumentCoverage.0.html | 2 +- .../while_early_ret.main.-------.InstrumentCoverage.0.html | 2 +- .../yield.main-{closure#0}.-------.InstrumentCoverage.0.html | 2 +- .../yield.main-{closure#1}.-------.InstrumentCoverage.0.html | 2 +- .../yield.main.-------.InstrumentCoverage.0.html | 2 +- 236 files changed, 161 insertions(+), 161 deletions(-) rename src/test/run-make-fulldeps/{coverage-llvmir-base => coverage-llvmir}/Makefile (98%) rename src/test/run-make-fulldeps/{coverage-llvmir-base => coverage-llvmir}/filecheck.testprog.txt (100%) rename src/test/run-make-fulldeps/{coverage-llvmir-base => coverage-llvmir}/testprog.rs (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/Makefile (99%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.abort.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.assert.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.async.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.closure.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.conditions.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.drop_trait.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.generics.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.if.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.if_else.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.inner_items.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.lazy_boolean.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.loop_break_value.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.loops_branches.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.nested_loops.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.overflow.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.panic_unwind.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.partial_eq.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.simple_loop.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.simple_match.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.tight_inf_loop.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.try_error_result.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.while.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.while_early_ret.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_export_coverage.yield.json (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.abort.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.assert.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.async.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.closure.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.conditions.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.drop_trait.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.generics.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.if.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.if_else.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.inner_items.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.lazy_boolean.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.loop_break_value.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.loops_branches.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.nested_loops.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.overflow.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.panic_unwind.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.partial_eq.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.simple_loop.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.simple_match.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.tight_inf_loop.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.try_error_result.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.while.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.while_early_ret.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage.yield.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.abort.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.assert.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.async.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.closure.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.conditions.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.drop_trait.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.generics.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.if.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.if_else.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.inner_items.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.lazy_boolean.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.loop_break_value.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.loops_branches.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.nested_loops.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.overflow.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.panic_unwind.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.partial_eq.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.simple_loop.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.simple_match.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.tight_inf_loop.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.try_error_result.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.while.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.while_early_ret.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/expected_show_coverage_counters.yield.txt (100%) rename src/test/run-make-fulldeps/{coverage-reports-base => coverage-reports}/prettify_json.py (100%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/Makefile (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/escape_url.py (100%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html (97%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html (92%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html (93%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html (93%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.closure/closure.main-{closure#2}.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html (99%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html (99%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html (97%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html (97%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html (97%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html (99%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html (97%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.loops_branches/loops_branches.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.loops_branches/loops_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html (97%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html (99%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html (99%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html (97%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html (99%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html (93%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html (93%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html (93%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html (93%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html (92%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.partial_eq/partial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html (96%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html (98%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html (94%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html (95%) rename src/test/run-make-fulldeps/{coverage-spanview-base => coverage-spanview}/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html (98%) diff --git a/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile b/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile index 30c7c0fbb51..1b3cd82bb0d 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile @@ -4,7 +4,7 @@ # LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 LINK_DEAD_CODE=yes --include ../coverage-llvmir-base/Makefile +-include ../coverage-llvmir/Makefile # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile b/src/test/run-make-fulldeps/coverage-llvmir/Makefile similarity index 98% rename from src/test/run-make-fulldeps/coverage-llvmir-base/Makefile rename to src/test/run-make-fulldeps/coverage-llvmir/Makefile index 219ba15ad11..bd6cd0ee495 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir/Makefile @@ -6,7 +6,7 @@ -include ../coverage/coverage_tools.mk -BASEDIR=../coverage-llvmir-base +BASEDIR=../coverage-llvmir ifeq ($(UNAME),Darwin) INSTR_PROF_DATA_SUFFIX=,regular,live_support diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt b/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt rename to src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/testprog.rs b/src/test/run-make-fulldeps/coverage-llvmir/testprog.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage-llvmir-base/testprog.rs rename to src/test/run-make-fulldeps/coverage-llvmir/testprog.rs diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile b/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile index b6a9acbf18b..0d40ffee764 100644 --- a/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile @@ -8,7 +8,7 @@ # LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 LINK_DEAD_CODE=yes --include ../coverage-reports-base/Makefile +-include ../coverage-reports/Makefile # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. diff --git a/src/test/run-make-fulldeps/coverage-reports-base/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile similarity index 99% rename from src/test/run-make-fulldeps/coverage-reports-base/Makefile rename to src/test/run-make-fulldeps/coverage-reports/Makefile index 6ccff43dcdf..91acedb68ec 100644 --- a/src/test/run-make-fulldeps/coverage-reports-base/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -10,7 +10,7 @@ -include ../coverage/coverage_tools.mk -BASEDIR=../coverage-reports-base +BASEDIR=../coverage-reports SOURCEDIR=../coverage # The `llvm-cov show` flag `--debug`, used to generate the `counters` output files, is only enabled diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.abort.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.abort.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.abort.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.abort.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.assert.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.assert.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.assert.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.async.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.async.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.closure.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.closure.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.closure.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.closure.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.conditions.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.conditions.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.conditions.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.drop_trait.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.drop_trait.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.drop_trait.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.drop_trait.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.generics.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.generics.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.generics.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.generics.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if_else.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if_else.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if_else.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.if_else.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.inner_items.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.inner_items.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.lazy_boolean.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.lazy_boolean.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.lazy_boolean.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.lazy_boolean.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loop_break_value.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loop_break_value.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loop_break_value.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loop_break_value.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loops_branches.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loops_branches.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loops_branches.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.loops_branches.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.nested_loops.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.nested_loops.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.nested_loops.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.overflow.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.overflow.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.overflow.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.panic_unwind.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.panic_unwind.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.panic_unwind.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.partial_eq.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.partial_eq.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.partial_eq.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.partial_eq.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_loop.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_loop.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_loop.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_loop.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_match.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.simple_match.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.tight_inf_loop.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.tight_inf_loop.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.tight_inf_loop.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.tight_inf_loop.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.try_error_result.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.try_error_result.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_ret.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while_early_ret.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_ret.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.while_early_ret.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.yield.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.yield.json similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.yield.json rename to src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.yield.json diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.abort.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.abort.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.abort.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.abort.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.assert.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.assert.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.async.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.closure.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.conditions.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.drop_trait.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.generics.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if_else.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if_else.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.lazy_boolean.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.lazy_boolean.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.lazy_boolean.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.lazy_boolean.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loop_break_value.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loops_branches.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.nested_loops.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.nested_loops.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.nested_loops.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.overflow.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.overflow.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.panic_unwind.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.partial_eq.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_loop.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_loop.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_loop.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.tight_inf_loop.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while_early_ret.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while_early_ret.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while_early_ret.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while_early_ret.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.yield.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.yield.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.abort.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.abort.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.abort.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.abort.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.assert.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.assert.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.assert.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.async.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.closure.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.closure.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.closure.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.conditions.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.conditions.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.conditions.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.drop_trait.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.drop_trait.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.drop_trait.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.generics.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if_else.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if_else.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.if_else.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.if_else.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.inner_items.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.inner_items.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.inner_items.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.lazy_boolean.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.lazy_boolean.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.lazy_boolean.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.lazy_boolean.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loop_break_value.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loop_break_value.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loop_break_value.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loops_branches.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.loops_branches.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.loops_branches.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.nested_loops.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.nested_loops.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.nested_loops.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.overflow.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.overflow.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.overflow.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.panic_unwind.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.panic_unwind.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.panic_unwind.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.partial_eq.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.partial_eq.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.partial_eq.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_loop.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_loop.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_loop.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_match.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.simple_match.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.simple_match.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.tight_inf_loop.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.tight_inf_loop.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.tight_inf_loop.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.try_error_result.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.try_error_result.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.try_error_result.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while_early_ret.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.while_early_ret.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.while_early_ret.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.yield.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.yield.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage_counters.yield.txt rename to src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.yield.txt diff --git a/src/test/run-make-fulldeps/coverage-reports-base/prettify_json.py b/src/test/run-make-fulldeps/coverage-reports/prettify_json.py similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports-base/prettify_json.py rename to src/test/run-make-fulldeps/coverage-reports/prettify_json.py diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile b/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile index 826e85b35e5..2bc61fccde4 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile @@ -4,7 +4,7 @@ # LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 LINK_DEAD_CODE=yes --include ../coverage-spanview-base/Makefile +-include ../coverage-spanview/Makefile # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html index a8227cffc60..63f7d2dd2d9 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ - - -abort.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; - while @1,2⦊countdown > 0⦉@1,2 { - if @3,5⦊countdown < 5⦉@3,5 @6,8,9⦊{ - might_abort(false); - }⦉@6,8,9@7⦊⦉@7 - @10,11⦊countdown -= 1⦉@10,11; - } - @4⦊Ok(()) -}⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html deleted file mode 100644 index 444ca72ce4c..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,164 +0,0 @@ - - - - -abort.might_abort - Coverage Spans - - - -
fn might_abort(should_abort: bool) { - if @0⦊should_abort⦉@0 { - @1,3,4,5⦊println!("aborting..."); - panic!("panics and aborts");⦉@1,3,4,5 - } else @2,6,7⦊{ - println!("Don't Panic"); - } -}⦉@2,6,7
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index d84e200cc1a..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - -assert.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; - while @1,2⦊countdown > 0⦉@1,2 { - if @3,5⦊countdown == 1⦉@3,5 @6,8,9⦊{ - might_fail_assert(3); - }⦉@6,8,9 else if @7⦊countdown < 5⦉@7 @10,12,13⦊{ - might_fail_assert(2); - }⦉@10,12,13@11⦊⦉@11@14⦊⦉@14 - @15,16⦊countdown -= 1⦉@15,16; - } - @4⦊Ok(()) -}⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html deleted file mode 100644 index c03fc8e416e..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - -assert.might_fail_assert - Coverage Spans - - - -
fn might_fail_assert(one_plus_one: u32) { - @0,1,2,3,4⦊println!("does 1 + 1 = {}?", one_plus_one);⦉@0,1,2,3,4 - assert_eq!(@0,1,2,3,4⦊1 + 1⦉@0,1,2,3,4, one_plus_one, @5,7,8,9,10,11,12⦊"the argument was wrong"⦉@5,7,8,9,10,11,12); -}@6⦊⦉@6
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 4689c34ca0f..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - -async.executor-block_on-VTABLE-{closure#0} - Coverage Spans - - - -
{ - @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 - }
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html deleted file mode 100644 index ccfb1dd0a37..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - -async.executor-block_on-VTABLE-{closure#1} - Coverage Spans - - - -
{ - @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 - }
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 2d402b83081..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - -async.executor-block_on-VTABLE-{closure#2} - Coverage Spans - - - -
{ - @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 - }
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html deleted file mode 100644 index 583a67e6c7f..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,226 +0,0 @@ - - - - -async.executor-block_on - Coverage Spans - - - -
pub fn block_on<F: Future>(mut future: F) -> F::Output { - let @0,1,2,3,4,5⦊mut future = unsafe { Pin::new_unchecked(&mut future) }; - - static VTABLE: RawWakerVTable = RawWakerVTable::new( - |_| unimplemented!("clone"), - |_| unimplemented!("wake"), - |_| unimplemented!("wake_by_ref"), - |_| (), - ); - let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; - - loop { - if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { - break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; - } - }@11,13⦊⦉@11,13 - }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index d3b9609a7f3..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - -async.foo-{closure#0} - Coverage Spans - - - -
{ @0⦊[false; 10] }⦉@0
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 9967a387a05..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - -async.g-{closure#0} - Coverage Spans - - - -
@0,2,3⦊{ - match x⦉@0,2,3 { - @16⦊y⦉@16 if @0,2,3⦊f()⦉@0,2,3.await == @9,12,14,15⦊y⦉@9,12,14,15@17⦊⦉@17 => @16⦊()⦉@16, - _ => @1⦊()⦉@1, - } -}@18,19⦊⦉@18,19
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 986a4b198cb..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - -async.h-{closure#0} - Coverage Spans - - - -
@0,2,3⦊{ - match x⦉@0,2,3 { - @17⦊y⦉@17 if @0,2,3⦊foo()⦉@0,2,3.await[@9,12,14,15,16⦊y⦉@9,12,14,15,16]@18⦊⦉@18 => @17⦊()⦉@17, - _ => @1⦊()⦉@1, - } -}@19,20⦊⦉@19,20
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index ab9bbf85dd7..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - -async.i-{closure#0} - Coverage Spans - - - -
@0,2,3⦊{ - match x⦉@0,2,3 { - @17⦊y⦉@17 if @0,2,3⦊f()⦉@0,2,3.await == @9,12,14,15,16⦊y + 1⦉@9,12,14,15,16@18⦊⦉@18 => @17⦊()⦉@17, - _ => @1⦊()⦉@1, - } -}@19,20⦊⦉@19,20
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 007da5c0ec1..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -async.main - Coverage Spans - - - -
fn main() @0,1,2,3,4,5,6,7,8,9⦊{ - let _ = g(10); - let _ = h(9); - let mut future = Box::pin(i(8)); - executor::block_on(future.as_mut()); -}⦉@0,1,2,3,4,5,6,7,8,9
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index b68c0a1cabe..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - -closure.main-{closure#0} - Coverage Spans - - - -
|| - { - let @0⦊mut countdown = 0⦉@0; - if @0⦊is_false⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - @4,5⦊"alt string 2".to_owned() - }⦉@4,5
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 9358fd4b136..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-{closure#1}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - -closure.main-{closure#1} - Coverage Spans - - - -
|| - { - let @0⦊mut countdown = 0⦉@0; - if @0⦊is_false⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - @4,5⦊"alt string 4".to_owned() - }⦉@4,5
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 2d41918efb2..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,4515 +0,0 @@ - - - - -closure.main - Coverage Spans - - - -
fn main() @0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊{ - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - let is_false = ! is_true; - - let mut some_string = Some(String::from("the string content")); - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 1".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ - ) - ); - - some_string = Some(String::from("the string content")); - let - a - = - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 2".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - a - ) - ); - - some_string = None; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 3".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ - ) - ); - - some_string = None; - let - a - = - ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 4".to_owned() - }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - a - ) - ); -}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index e6f95385910..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,353 +0,0 @@ - - - - -conditions.main - Coverage Spans - - - -
fn main() { - let @0⦊mut countdown = 0⦉@0; - if @0⦊true⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - - const B: u32 = 100; - let @25⦊x⦉@25 = if @4⦊countdown > 7⦉@4 { - @5,7,8⦊countdown -= 4; - B⦉@5,7,8 - } else if @6⦊countdown > 2⦉@6 { - if @9,11⦊countdown < 1⦉@9,11 || @18⦊countdown > 5⦉@18@16⦊⦉@16@17⦊⦉@17 || @14⦊countdown != 9⦉@14@12⦊⦉@12@13⦊⦉@13 @20,22⦊{ - countdown = 0; - }⦉@20,22@21⦊⦉@21 - @23,24⦊countdown -= 5; - countdown⦉@23,24 - } else { - @10⦊return⦉@10; - }; - - let @25⦊mut countdown = 0⦉@25; - if @25⦊true⦉@25 @26,28⦊{ - countdown = 10; - }⦉@26,28@27⦊⦉@27 - - if @29⦊countdown > 7⦉@29 @30,32,33⦊{ - countdown -= 4; - }⦉@30,32,33 else if @31⦊countdown > 2⦉@31 { - if @34,36⦊countdown < 1⦉@34,36 || @43⦊countdown > 5⦉@43@41⦊⦉@41@42⦊⦉@42 || @39⦊countdown != 9⦉@39@37⦊⦉@37@38⦊⦉@38 @45,47⦊{ - countdown = 0; - }⦉@45,47@46⦊⦉@46 - @48,49⦊countdown -= 5⦉@48,49; - } else { - @35⦊return⦉@35; - } - - if @50⦊true⦉@50 { - // Demonstrate the difference with `TerminatorKind::Assert` as of 2020-11-15. Assert is no - // longer treated as a `BasicCoverageBlock` terminator, which changed the coverage region, - // for the executed `then` block above, to include the closing brace on line 30. That - // changed the line count, but the coverage code region (for the `else if` condition) is - // still valid. - // - // Note that `if` (then) and `else` blocks include the closing brace in their coverage - // code regions when the last line in the block ends in a semicolon, because the Rust - // compiler inserts a `StatementKind::Assign` to assign `const ()` to a `Place`, for the - // empty value for the executed block. When the last line does not end in a semicolon - // (that is, when the block actually results in a value), the additional `Assign` is not - // generated, and the brace is not included. - let @51,53⦊mut countdown = 0⦉@51,53; - if @51,53⦊true⦉@51,53 @54,56⦊{ - countdown = 10; - }⦉@54,56@55⦊⦉@55 - - if @57⦊countdown > 7⦉@57 @58,60,61⦊{ - countdown -= 4; - }⦉@58,60,61 - // The closing brace of the `then` branch is now included in the coverage region, and shown - // as "executed" (giving its line a count of 1 here). Since, in the original version above, - // the closing brace shares the same line as the `else if` conditional expression (which is - // not executed if the first `then` condition is true), only the condition's code region is - // marked with a count of 0 now. - else if @59⦊countdown > 2⦉@59 { - if @62,64⦊countdown < 1⦉@62,64 || @71⦊countdown > 5⦉@71@69⦊⦉@69@70⦊⦉@70 || @67⦊countdown != 9⦉@67@65⦊⦉@65@66⦊⦉@66 @73,75⦊{ - countdown = 0; - }⦉@73,75@74⦊⦉@74 - @76,77⦊countdown -= 5⦉@76,77; - } else { - @63⦊return⦉@63; - } - }@78⦊⦉@78@52⦊⦉@52 - - let @79⦊mut countdown = 0⦉@79; - if @79⦊true⦉@79 @80,82⦊{ - countdown = 1; - }⦉@80,82@81⦊⦉@81 - - let @106⦊z⦉@106 = if @83⦊countdown > 7⦉@83 @84,86,87⦊{ - countdown -= 4; - }⦉@84,86,87 else if @85⦊countdown > 2⦉@85 { - if @88,90⦊countdown < 1⦉@88,90 || @97⦊countdown > 5⦉@97@95⦊⦉@95@96⦊⦉@96 || @93⦊countdown != 9⦉@93@91⦊⦉@91@92⦊⦉@92 @99,101⦊{ - countdown = 0; - }⦉@99,101@100⦊⦉@100 - @102,103⦊countdown -= 5⦉@102,103; - } else { - let @89,104,105⦊should_be_reachable = countdown; - println!("reached"); - return⦉@89,104,105; - }; - - let @127⦊w⦉@127 = if @106⦊countdown > 7⦉@106 @107,109,110⦊{ - countdown -= 4; - }⦉@107,109,110 else if @108⦊countdown > 2⦉@108 { - if @111,113⦊countdown < 1⦉@111,113 || @120⦊countdown > 5⦉@120@118⦊⦉@118@119⦊⦉@119 || @116⦊countdown != 9⦉@116@114⦊⦉@114@115⦊⦉@115 @122,124⦊{ - countdown = 0; - }⦉@122,124@123⦊⦉@123 - @125,126⦊countdown -= 5⦉@125,126; - } else { - @112⦊return⦉@112; - }; -}@130⦊⦉@130@131⦊⦉@131
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 8d6f936aadc..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - -drop_trait.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0⦊_firecracker = Firework { strength: 1 }; - - let _tnt = Firework { strength: 100 }⦉@0; - - if @0⦊true⦉@0 { - @1,3,4,5,9,10⦊println!("Exiting with error..."); - return Err(1)⦉@1,3,4,5,9,10; - } - - let _ = @2,6,7,8⦊Firework { strength: 1000 }; - - Ok(())⦉@2,6,7,8 -}@11⦊⦉@11
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html deleted file mode 100644 index 60a24df9ba6..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -drop_trait.{impl#0}-drop - Coverage Spans - - - -
fn drop(&mut self) @0,1,2,3⦊{ - println!("BOOM times {}!!!", self.strength); - }⦉@0,1,2,3
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 3f90fd1e821..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - -generics.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0,1,2,3⦊mut firecracker = Firework { strength: 1 }; - firecracker.set_strength(2); - - let mut tnt = Firework { strength: 100.1 }; - tnt.set_strength(200.1); - tnt.set_strength(300.3)⦉@0,1,2,3; - - if @0,1,2,3⦊true⦉@0,1,2,3 { - @4,6,7,8,12,13⦊println!("Exiting with error..."); - return Err(1)⦉@4,6,7,8,12,13; - } - - let _ = @5,9,10,11⦊Firework { strength: 1000 }; - - Ok(())⦉@5,9,10,11 -}@14⦊⦉@14
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html deleted file mode 100644 index b10da561da9..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - -generics.{impl#0}-set_strength - Coverage Spans - - - -
fn set_strength(&mut self, new_strength: T) @0⦊{ - self.strength = new_strength; - }⦉@0
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html deleted file mode 100644 index 0515e8d7b8c..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.{impl#1}-drop.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -generics.{impl#1}-drop - Coverage Spans - - - -
fn drop(&mut self) @0,1,2,3⦊{ - println!("BOOM times {}!!!", self.strength); - }⦉@0,1,2,3
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index e926079a428..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - -if.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let - @0,1,2,3⦊is_true - = - std::env::args().len() - == - 1 - ; - let - mut - countdown - = - 0⦉@0,1,2,3 - ; - if - @0,1,2,3⦊is_true⦉@0,1,2,3 - @4,6⦊{ - countdown - = - 10 - ; - }⦉@4,6@5⦊⦉@5 -}@7⦊⦉@7
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 586014afeba..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - -if_else.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let mut countdown = 0; - if - is_true⦉@0,1,2,3 - @4,6⦊{ - countdown - = - 10 - ; - }⦉@4,6 - else // Note coverage region difference without semicolon - { - @5⦊countdown - = - 100⦉@5 - } - - if - @7⦊is_true⦉@7 - @8,10⦊{ - countdown - = - 10 - ; - }⦉@8,10 - else - @9⦊{ - countdown - = - 100 - ; - }⦉@9 -}@11⦊⦉@11
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html deleted file mode 100644 index 387f2ba4e41..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - -inner_items.main-InTrait-default_trait_func - Coverage Spans - - - -
fn default_trait_func(&mut self) @0,1,2⦊{ - in_func(IN_CONST); - self.trait_func(IN_CONST); - }⦉@0,1,2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html deleted file mode 100644 index cec099a0ef5..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - -inner_items.main-in_func - Coverage Spans - - - -
fn in_func(a: u32) { - let @0,1,2,3,4⦊b = 1; - let c = a + b; - println!("c = {}", c) - }⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html deleted file mode 100644 index eaecb183ca1..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-{impl#0}-trait_func.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - -inner_items.main-{impl#0}-trait_func - Coverage Spans - - - -
fn trait_func(&mut self, incr: u32) @0,1,2⦊{ - self.in_struct_field += incr; - in_func(self.in_struct_field); - }⦉@0,1,2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 3e54d6566b4..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - -inner_items.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let mut countdown = 0⦉@0,1,2,3; - if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ - countdown = 10; - }⦉@4,6@5⦊⦉@5 - - mod in_mod { - const IN_MOD_CONST: u32 = 1000; - } - - fn in_func(a: u32) { - let b = 1; - let c = a + b; - println!("c = {}", c) - } - - struct InStruct { - in_struct_field: u32, - } - - const IN_CONST: u32 = 1234; - - trait InTrait { - fn trait_func(&mut self, incr: u32); - - fn default_trait_func(&mut self) { - in_func(IN_CONST); - self.trait_func(IN_CONST); - } - } - - impl InTrait for InStruct { - fn trait_func(&mut self, incr: u32) { - self.in_struct_field += incr; - in_func(self.in_struct_field); - } - } - - type InType = String; - - if @7⦊is_true⦉@7 @8,10,11⦊{ - in_func(countdown); - }⦉@8,10,11@9⦊⦉@9 - - let @12,13⦊mut val = InStruct { - in_struct_field: 101, - }; - - val.default_trait_func(); -}⦉@12,13
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index dd21c23acf6..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - -lazy_boolean.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let (mut a, mut b, mut c) = (0, 0, 0)⦉@0,1,2,3; - if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ - a = 1; - b = 10; - c = 100; - }⦉@4,6@5⦊⦉@5 - let - @11⦊somebool⦉@11 - = - @7⦊a < b⦉@7 - || - @10⦊b < c⦉@10@8⦊⦉@8@9⦊⦉@9 - ; - let - @15⦊somebool⦉@15 - = - @11⦊b < a⦉@11 - || - @14⦊b < c⦉@14@12⦊⦉@12@13⦊⦉@13 - ; - let @19⦊somebool⦉@19 = @15⦊a < b⦉@15 && @18⦊b < c⦉@18@16⦊⦉@16@17⦊⦉@17; - let @23⦊somebool⦉@23 = @19⦊b < a⦉@19 && @22⦊b < c⦉@22@20⦊⦉@20@21⦊⦉@21; - - if - @23⦊! - is_true⦉@23 - @24,26⦊{ - a = 2 - ; - }⦉@24,26@25⦊⦉@25 - - if - @27⦊is_true⦉@27 - @28,30⦊{ - b = 30 - ; - }⦉@28,30 - else - @29⦊{ - c = 400 - ; - }⦉@29 - - if @31⦊!is_true⦉@31 @32,34⦊{ - a = 2; - }⦉@32,34@33⦊⦉@33 - - if @35⦊is_true⦉@35 @36,38⦊{ - b = 30; - }⦉@36,38 else @37⦊{ - c = 400; - }⦉@37 -}@39⦊⦉@39
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index eff27bf3557..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - -loop_break_value.main - Coverage Spans - - - -
fn main() @0,1⦊{ - let result - = - loop - { - break - 10 - ; - } - ; -}⦉@0,1
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 73b3e20946c..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - -loops_branches.main - Coverage Spans - - - -
fn main() @0,1,2,3⦊{ - let debug_test = DebugTest; - println!("{:?}", debug_test); -}⦉@0,1,2,3
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html deleted file mode 100644 index a98ed9e8ce1..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loops_branches/loops_branches.{impl#0}-fmt.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - -loops_branches.{impl#0}-fmt - Coverage Spans - - - -
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if @0⦊true⦉@0 { - if @1,3⦊false⦉@1,3 { - while @6,7⦊true⦉@6,7 @8,10⦊{ - }⦉@8,10 - }@9⦊⦉@9@5⦊⦉@5 - @11,12,13,14⦊write!(f, "error")⦉@11,12,13,14@16,18,19,20⦊?⦉@16,18,19,20; - } else @2⦊{ - }⦉@2@15⦊⦉@15 - @21⦊Ok(())⦉@21 - }@22⦊⦉@22
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 0f3ea3ce6a8..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - -nested_loops.main - Coverage Spans - - - -
fn main() { - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - let mut countdown = 10⦉@0,1,2,3; - - 'outer: while @4,5⦊countdown > 0⦉@4,5 { - let @6,8,9⦊mut a = 100; - let mut b = 100⦉@6,8,9; - for @14,16⦊_⦉@14,16 in @10,11,12⦊0..50⦉@10,11,12 { - if @14,16⦊a < 30⦉@14,16 { - @17,19⦊break⦉@17,19; - } - @18,20,21⦊a -= 5; - b -= 5⦉@18,20,21; - if @18,20,21⦊b < 90⦉@18,20,21 { - @22,24,25⦊a -= 10; - if is_true⦉@22,24,25 { - @26,28⦊break 'outer⦉@26,28; - } else @27,29⦊{ - a -= 2; - } - }⦉@27,29@23⦊⦉@23 - }@30⦊⦉@30 - @31,32⦊countdown -= 1⦉@31,32; - }@7⦊⦉@7 -}@33⦊⦉@33
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 4f237d6561d..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,259 +0,0 @@ - - - - -overflow.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; - while @1,2⦊countdown > 0⦉@1,2 { - if @3,5⦊countdown == 1⦉@3,5 @6,8,9,10,11,12⦊{ - let result = might_overflow(10); - println!("Result: {}", result); - }⦉@6,8,9,10,11,12 else if @7⦊countdown < 5⦉@7 @13,15,16,17,18,19⦊{ - let result = might_overflow(1); - println!("Result: {}", result); - }⦉@13,15,16,17,18,19@14⦊⦉@14@20⦊⦉@20 - @21,22⦊countdown -= 1⦉@21,22; - } - @4⦊Ok(()) -}⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html deleted file mode 100644 index b1dbc40ee20..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,397 +0,0 @@ - - - - -overflow.might_overflow - Coverage Spans - - - -
fn might_overflow(to_add: u32) -> u32 { - if @0⦊to_add > 5⦉@0 @1,3,4,5⦊{ - println!("this will probably overflow"); - }⦉@1,3,4,5@2⦊⦉@2 - let @6,7,8,9,10,11,12,13,14⦊add_to = u32::MAX - 5; - println!("does {} + {} overflow?", add_to, to_add); - let result = to_add + add_to; - println!("continuing after overflow check"); - result -}⦉@6,7,8,9,10,11,12,13,14
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index ebacd80c37d..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - -panic_unwind.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; - while @1,2⦊countdown > 0⦉@1,2 { - if @3,5⦊countdown == 1⦉@3,5 @6,8,9⦊{ - might_panic(true); - }⦉@6,8,9 else if @7⦊countdown < 5⦉@7 @10,12,13⦊{ - might_panic(false); - }⦉@10,12,13@11⦊⦉@11@14⦊⦉@14 - @15,16⦊countdown -= 1⦉@15,16; - } - @4⦊Ok(()) -}⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html deleted file mode 100644 index d6002e70af2..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,164 +0,0 @@ - - - - -panic_unwind.might_panic - Coverage Spans - - - -
fn might_panic(should_panic: bool) { - if @0⦊should_panic⦉@0 { - @1,3,4,5⦊println!("panicking..."); - panic!("panics");⦉@1,3,4,5 - } else @2,6,7⦊{ - println!("Don't Panic"); - } -}⦉@2,6,7
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 0c6d81a18b1..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - -partial_eq.main - Coverage Spans - - - -
fn main() @0,1,2,3,4,5,6,7,8⦊{ - let version_3_2_1 = Version::new(3, 2, 1); - let version_3_3_0 = Version::new(3, 3, 0); - - println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); -}⦉@0,1,2,3,4,5,6,7,8
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html deleted file mode 100644 index a888cb14d1d..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#0}-new.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - -partial_eq.{impl#0}-new - Coverage Spans - - - -
pub fn new(major: usize, minor: usize, patch: usize) -> Self { - @0⦊Self { - major, - minor, - patch, - } - }⦉@0
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html deleted file mode 100644 index fa81a7f8afc..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#1}-cmp.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - -partial_eq.{impl#1}-cmp - Coverage Spans - - - -
@14⦊@11,12⦊@13⦊Ord⦉@13⦉@11,12⦉@14@15⦊⦉@15
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 52e6b526276..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - -partial_eq.{impl#2}-ge-{closure#0}-{closure#0} - Coverage Spans - - - -
minor: usize, - @0,1,2⦊patch: usize⦉@0,1,2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 9f0c29c50bf..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - -partial_eq.{impl#2}-ge-{closure#0} - Coverage Spans - - - -
major: usize, - @0,1,2,3⦊⦉@0,1,2,3minor: usize
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html deleted file mode 100644 index b740a63aed9..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -partial_eq.{impl#2}-ge - Coverage Spans - - - -
@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 0ad35d701aa..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - -partial_eq.{impl#2}-gt-{closure#0}-{closure#0} - Coverage Spans - - - -
minor: usize, - @0,1,2⦊patch: usize⦉@0,1,2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index ff7e783dd68..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - -partial_eq.{impl#2}-gt-{closure#0} - Coverage Spans - - - -
major: usize, - @0,1,2,3⦊⦉@0,1,2,3minor: usize
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html deleted file mode 100644 index 95b63edba87..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -partial_eq.{impl#2}-gt - Coverage Spans - - - -
@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index d43d8526a88..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - -partial_eq.{impl#2}-le-{closure#0}-{closure#0} - Coverage Spans - - - -
minor: usize, - @0,1,2⦊patch: usize⦉@0,1,2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 6eb894a166a..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - -partial_eq.{impl#2}-le-{closure#0} - Coverage Spans - - - -
major: usize, - @0,1,2,3⦊⦉@0,1,2,3minor: usize
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html deleted file mode 100644 index 906d074b71f..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -partial_eq.{impl#2}-le - Coverage Spans - - - -
@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index a941c08da5d..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - -partial_eq.{impl#2}-lt-{closure#0}-{closure#0} - Coverage Spans - - - -
minor: usize, - @0,1,2⦊patch: usize⦉@0,1,2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index e54849345b7..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - -partial_eq.{impl#2}-lt-{closure#0} - Coverage Spans - - - -
major: usize, - @0,1,2,3⦊⦉@0,1,2,3minor: usize
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html deleted file mode 100644 index 0da90113bdd..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - -partial_eq.{impl#2}-lt - Coverage Spans - - - -
@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html deleted file mode 100644 index c5a806f7c17..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - -partial_eq.{impl#2}-partial_cmp - Coverage Spans - - - -
@17⦊@14,15⦊@16⦊PartialOrd⦉@16⦉@14,15⦉@17@18⦊⦉@18
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html deleted file mode 100644 index 92f37e4b89a..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - -partial_eq.{impl#6}-eq - Coverage Spans - - - -
@2⦊@1⦊PartialEq⦉@1⦉@2@4⦊⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html deleted file mode 100644 index df561a79224..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - -partial_eq.{impl#6}-ne - Coverage Spans - - - -
@2⦊@5⦊@6⦊@1⦊PartialEq⦉@1⦉@6⦉@5⦉@2@4⦊⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html deleted file mode 100644 index 195ef4da7b4..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#7}-fmt.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,109 +0,0 @@ - - - - -partial_eq.{impl#7}-fmt - Coverage Spans - - - -
@0,1,2,3,4,5⦊Debug⦉@0,1,2,3,4,5
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 29d21cf7ba4..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - -simple_loop.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let mut countdown = 0⦉@0,1,2,3; - - if - @0,1,2,3⦊is_true⦉@0,1,2,3 - @4,6⦊{ - countdown - = - 10 - ; - }⦉@4,6@5⦊⦉@5 - - loop - { - if - @8,9⦊countdown - == - 0⦉@8,9 - { - @10,12⦊break⦉@10,12 - ; - } - @11,13⦊countdown - -= - 1⦉@11,13 - ; - }@7⦊⦉@7 -}@10,12⦊⦉@10,12
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index f1513d458eb..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - -simple_match.main - Coverage Spans - - - -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; - - let mut countdown = 1⦉@0,1,2,3; - if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ - countdown = 0; - }⦉@4,6@5⦊⦉@5 - - for - @13,15,17⦊_⦉@13,15,17 - in - @9,10,11⦊0..2⦉@9,10,11 - { - let z - ; - match - @13,15,17⦊countdown⦉@13,15,17 - { - @18⦊x⦉@18 - if - @13,15,17⦊x - < - 1⦉@13,15,17@19⦊⦉@19 - => - @18⦊{ - z = countdown - ; - let y = countdown - ; - countdown = 10 - ; - }⦉@18 - _ - => - @16⦊{}⦉@16 - } - }@7,8⦊⦉@7,8@20⦊⦉@20 -}@12⦊⦉@12
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 5cf76ecf5c2..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - -tight_inf_loop.main - Coverage Spans - - - -
fn main() { - if @0⦊false⦉@0 { - @4,5⦊loop {}⦉@4,5@1,3⦊⦉@1,3 - } -}@2⦊⦉@2
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index b9391e26c86..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -try_error_result.main - Coverage Spans - - - -
fn main() -> Result<(),()> { - let @0,1⦊mut - countdown = 10⦉@0,1 - ; - for - @6,8,9⦊_⦉@6,8,9 - in - @2,3,4⦊0..10⦉@2,3,4 - { - @6,8,9⦊countdown - -= 1 - ; - if - countdown < 5⦉@6,8,9 - { - @10,12,13,14⦊call(/*return_error=*/ true)⦉@10,12,13,14@16,18,19,20⦊?⦉@16,18,19,20; - @15,21,22⦊call(/*return_error=*/ false)⦉@15,21,22@24,26,27,28⦊?⦉@24,26,27,28; - } - else - { - @11,29,30⦊call(/*return_error=*/ false)⦉@11,29,30@32,34,35,36⦊?⦉@32,34,35,36; - }@23⦊⦉@23@31⦊⦉@31 - }@37⦊⦉@37 - @5⦊Ok(())⦉@5 -}@38⦊⦉@38@39⦊⦉@39
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 05c010da7bc..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - -while.main - Coverage Spans - - - -
fn main() { - let @0⦊num = 9⦉@0; - while @1,2⦊num >= 10⦉@1,2 @3,5⦊{ - }⦉@3,5 -}@4⦊⦉@4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 87ce501ca8c..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - -while_early_ret.main - Coverage Spans - - - -
fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; - while - @1,2⦊countdown - > - 0⦉@1,2 - { - if - @3,5⦊countdown - < - 5⦉@3,5 - { - return - if - @6,8⦊countdown - > - 8⦉@6,8 - { - @9,11⦊Ok(())⦉@9,11 - } - else - { - @10⦊Err(1)⦉@10 - } - ; - } - @7,12⦊countdown - -= - 1⦉@7,12 - ; - } - @4⦊Ok(())⦉@4 -}@13⦊⦉@13@14⦊⦉@14
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html deleted file mode 100644 index b8458f9d8d6..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - -yield.main-{closure#0} - Coverage Spans - - - -
|| { - @0⦊yield 1⦉@0; - return @1⦊"foo" - }⦉@1
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html deleted file mode 100644 index 2387f40847a..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main-{closure#1}.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - -yield.main-{closure#1} - Coverage Spans - - - -
|| { - @0⦊yield 1⦉@0; - @1⦊yield 2⦉@1; - @2⦊yield 3⦉@2; - return @3⦊"foo" - }⦉@3
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html deleted file mode 100644 index 7c974d7f97b..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.yield/yield.main.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,138 +0,0 @@ - - - - -yield.main - Coverage Spans - - - -
fn main() { - let @0,1,2⦊mut generator⦉@0,1,2 = || { - yield 1; - return "foo" - }; - - match @0,1,2⦊Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(1)⦉@0,1,2 => @4,6,7,8⦊{}⦉@4,6,7,8 - _ => @5⦊panic!("unexpected value from resume")⦉@5, - } - match @4,6,7,8⦊Pin::new(&mut generator).resume(())⦉@4,6,7,8 { - GeneratorState::Complete(@10,11⦊"foo"⦉@10,11) => @12,13,14,15⦊{}⦉@12,13,14,15 - _ => @9⦊panic!("unexpected value from resume")⦉@9, - } - - let @12,13,14,15⦊mut generator⦉@12,13,14,15 = || { - yield 1; - yield 2; - yield 3; - return "foo" - }; - - match @12,13,14,15⦊Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(1)⦉@12,13,14,15 => @17,19,20,21⦊{}⦉@17,19,20,21 - _ => @18⦊panic!("unexpected value from resume")⦉@18, - } - match @17,19,20,21⦊Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(2)⦉@17,19,20,21 => @23,25⦊{}⦉@23,25 - _ => @24⦊panic!("unexpected value from resume")⦉@24, - } -}@23,25⦊⦉@23,25
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview/Makefile b/src/test/run-make-fulldeps/coverage-spanview/Makefile index 979c6a3da41..f414fe89eb9 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/Makefile +++ b/src/test/run-make-fulldeps/coverage-spanview/Makefile @@ -1,9 +1,5 @@ # needs-profiler-support -# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and -# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. -# See ../coverage/coverage_tools.mk for more information. - -include ../coverage/coverage_tools.mk BASEDIR=../coverage-spanview @@ -47,7 +43,6 @@ endif echo "--edition=2018" \ ) \ -Zinstrument-coverage \ - -Clink-dead-code=$(LINK_DEAD_CODE) \ -Zdump-mir=InstrumentCoverage \ -Zdump-mir-spanview \ -Zdump-mir-dir="$(TMPDIR)"/mir_dump.$@ diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html index 63f7d2dd2d9..9834124694e 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.main.-------.InstrumentCoverage.0.html @@ -69,31 +69,41 @@ -
fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; +
@0⦊fn main() -> Result<(), u8> { + let mut countdown = 10⦉@0; while @1,2⦊countdown > 0⦉@1,2 { if @3,5⦊countdown < 5⦉@3,5 @6,8,9⦊{ - might_abort(false); - }⦉@6,8,9@7⦊⦉@7 - @10,11⦊countdown -= 1⦉@10,11; +17:12-17:25: @5[6]: FakeRead(ForMatchedPlace, _7)">@3,5⦊countdown < 5⦉@3,5 @6,8,9⦊{ + might_abort(false); + }⦉@6,8,9@7⦊⦉@7 + // See discussion (below the `Notes` section) on coverage results for the closing brace. + if @10⦊countdown < 5⦉@10 @11,13,14⦊{ might_abort(false); }⦉@11,13,14@12⦊⦉@12 // Counts for different regions on one line. + // For the following example, the closing brace is the last character on the line. + // This shows the character after the closing brace is highlighted, even if that next + // character is a newline. + if @15⦊countdown < 5⦉@15 @16,18,19⦊{ might_abort(false); }⦉@16,18,19@17⦊⦉@17 + @20,21⦊countdown -= 1⦉@20,21; } - @4⦊Ok(()) -}⦉@4
+ @4⦊Ok(()) +}⦉@4
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html index 444ca72ce4c..ab7108ae570 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.abort/abort.might_abort.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
fn might_abort(should_abort: bool) { +
@0⦊fn might_abort(should_abort: bool) ⦉@0{ if @0⦊should_abort⦉@0 { fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; +
@0⦊fn main() -> Result<(),u8> { + let mut countdown = 10⦉@0; while @1,2⦊countdown > 0⦉@1,2 { @@ -89,14 +90,14 @@ might_fail_assert(2); }⦉@10,12,13@11⦊⦉@11@14⦊⦉@14 - }⦉@10,12,13@11⦊⦉@11 + @15,16⦊countdown -= 1⦉@15,16; } - @4⦊Ok(()) -}⦉@4
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html index c03fc8e416e..13cfebfe6e5 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.assert/assert.might_fail_assert.-------.InstrumentCoverage.0.html @@ -69,9 +69,9 @@ -
fn might_fail_assert(one_plus_one: u32) { - @0,1,2,3,4⦊fn might_fail_assert(one_plus_one: u32) ⦉@0,1,2,3,4{ + @0,1,2,3,4⦊println!("does 1 + 1 = {}?", one_plus_one);⦉@0,1,2,3,4 - assert_eq!(@0,1,2,3,4⦊1 + 1⦉@0,1,2,3,4, one_plus_one, @5,7,8,9,10,11,12⦊"the argument was wrong"⦉@5,7,8,9,10,11,12); + assert_eq!(@0,1,2,3,4⦊1 + 1⦉@0,1,2,3,4, one_plus_one, @5,7,8,9,10,11,12⦊"the argument was wrong"⦉@5,7,8,9,10,11,12); }@6⦊⦉@6
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c-{closure#0}.-------.InstrumentCoverage.0.html similarity index 65% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c-{closure#0}.-------.InstrumentCoverage.0.html index eeee81daeb2..82a22ccb4e6 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c-{closure#0}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -try_error_result.call - Coverage Spans +async.c-{closure#0} - Coverage Spans -
fn call(return_error: bool) -> Result<(),()> { - if @0⦊return_error⦉@0 { - @1,3⦊Err(())⦉@1,3 +
@0⦊{ + if x == 8⦉@0 { + @1,3⦊1⦉@1,3 } else { - @2⦊Ok(())⦉@2 + @2⦊0⦉@2 } -}@4⦊⦉@4
+}@4⦊⦉@4
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c.-------.InstrumentCoverage.0.html similarity index 77% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c.-------.InstrumentCoverage.0.html index 0b193f4973e..3eee0dd4100 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.c.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -async.i - Coverage Spans +async.c - Coverage Spans -
async fn i(x: u8) { - match x { - y if f().await == y + 1 => (), - _ => (), +
@0,1⦊async fn c(x: u8) -> u8 ⦉@0,1{ + if x == 8 { + 1 + } else { + 0 } -}@0,1⦊⦉@0,1
+}
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d-{closure#0}.-------.InstrumentCoverage.0.html similarity index 79% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d-{closure#0}.-------.InstrumentCoverage.0.html index 7fe94dca7a4..7cf34f07795 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d-{closure#0}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -async.f-{closure#0} - Coverage Spans +async.d-{closure#0} - Coverage Spans -
{ @0⦊1 }⦉@0
+
@0⦊⦉@0{ 1 }
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d.-------.InstrumentCoverage.0.html similarity index 81% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d.-------.InstrumentCoverage.0.html index f5eddba9d4b..5c7f6e00224 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.d.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -async.f - Coverage Spans +async.d - Coverage Spans -
async fn f() -> u8 { 1 }@0,1⦊⦉@0,1
+
@0,1⦊async fn d() -> u8 ⦉@0,1{ 1 }
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e-{closure#0}.-------.InstrumentCoverage.0.html similarity index 78% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e-{closure#0}.-------.InstrumentCoverage.0.html index b4beef867eb..1f95a7d35af 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e-{closure#0}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -partial_eq.{impl#4}-assert_receiver_is_total_eq - Coverage Spans +async.e-{closure#0} - Coverage Spans -
@0⦊Eq⦉@0
+
@0⦊⦉@0{ 1 }
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e.-------.InstrumentCoverage.0.html similarity index 80% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e.-------.InstrumentCoverage.0.html index dea4560ea56..ee3b7b1d7ff 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.e.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -async.foo - Coverage Spans +async.e - Coverage Spans -
async fn foo() -> [bool; 10] { [false; 10] }@0,1⦊⦉@0,1
+
@0,1⦊async fn e() -> u8 ⦉@0,1{ 1 }
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html index 4689c34ca0f..8f61257ca1b 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,21 +69,16 @@ -
{ - @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 - }
+
@0,1,2,3⦊⦉@0,1,2,3$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+))
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html index ccfb1dd0a37..923c669e72d 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#1}.-------.InstrumentCoverage.0.html @@ -69,21 +69,16 @@ -
{ - @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 - }
+
@0,1,2,3⦊⦉@0,1,2,3$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+))
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html index 2d402b83081..59f62959998 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#2}.-------.InstrumentCoverage.0.html @@ -69,21 +69,16 @@ -
{ - @0,1,2,3⦊$crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+))⦉@0,1,2,3 - }
+
@0,1,2,3⦊⦉@0,1,2,3$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+))
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html index adba2d9965d..996c537225d 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
|_| @0⦊()⦉@0
+
|_| @0⦊()⦉@0
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html index 583a67e6c7f..0c597d40de0 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html @@ -69,158 +69,171 @@ -
pub fn block_on<F: Future>(mut future: F) -> F::Output { - let @0,1,2,3,4,5⦊mut future = unsafe { Pin::new_unchecked(&mut future) }; - - static VTABLE: RawWakerVTable = RawWakerVTable::new( - |_| unimplemented!("clone"), - |_| unimplemented!("wake"), - |_| unimplemented!("wake_by_ref"), - |_| (), - ); - let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; +
@0,1,2,3,4,5⦊pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; loop { - if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { - break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; - } - }@11,13⦊⦉@11,13 - }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
+ if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { + break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; + }@11,13⦊⦉@11,13 + } + }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html index 7fe94dca7a4..74b62673ac9 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
{ @0⦊1 }⦉@0
+
@0⦊⦉@0{ 1 }
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html index f5eddba9d4b..a31bca54df2 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.f.-------.InstrumentCoverage.0.html @@ -69,6 +69,6 @@ -
async fn f() -> u8 { 1 }@0,1⦊⦉@0,1
+
@0,1⦊async fn f() -> u8 ⦉@0,1{ 1 }
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html index d3b9609a7f3..b8c53cccabd 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
{ @0⦊[false; 10] }⦉@0
+
@0⦊⦉@0{ [false; 10] }
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html index dea4560ea56..cf72a9d532c 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.foo.-------.InstrumentCoverage.0.html @@ -69,6 +69,6 @@ -
async fn foo() -> [bool; 10] { [false; 10] }@0,1⦊⦉@0,1
+
@0,1⦊async fn foo() -> [bool; 10] ⦉@0,1{ [false; 10] }
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html index 9967a387a05..b10012621b7 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,12 +69,14 @@ -
@0,2,3⦊{ - match x⦉@0,2,3 { - @16⦊y⦉@16 if @0,2,3⦊f()⦉@0,2,3.await == @9,12,14,15⦊y⦉@9,12,14,15@17⦊⦉@17 => @16⦊()⦉@16, - _ => @1⦊()⦉@1, +
@0,3,4⦊{ + match x⦉@0,3,4 { + @17⦊y⦉@17 if @0,3,4⦊e()⦉@0,3,4.await == @10,13,15,16⦊y⦉@10,13,15,16 => @17⦊()⦉@17, + @33⦊y⦉@33 if @1,19,20⦊f()⦉@1,19,20.await == @26,29,31,32⦊y⦉@26,29,31,32 => @33⦊()⦉@33, + _ => @2⦊()⦉@2, } -}@18,19⦊⦉@18,19
+}@35,36⦊⦉@35,36
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html index 5a43e8162cb..973995477b9 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html @@ -69,11 +69,12 @@ -
pub async fn g(x: u8) { +
@0,1⦊pub async fn g(x: u8) ⦉@0,1{ match x { + y if e().await == y => (), y if f().await == y => (), _ => (), } -}@0,1⦊⦉@0,1
+}
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html index 986a4b198cb..6b4b43f8365 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,12 +69,14 @@ -
@0,2,3⦊{ - match x⦉@0,2,3 { - @17⦊y⦉@17 if @0,2,3⦊foo()⦉@0,2,3.await[@9,12,14,15,16⦊y⦉@9,12,14,15,16]@18⦊⦉@18 => @17⦊()⦉@17, - _ => @1⦊()⦉@1, +
@0,2,3⦊{ // The function signature is counted when called, but the body is not + // executed (not awaited) so the open brace has a `0` count (at least when + // displayed with `llvm-cov show` in color-mode). + match x⦉@0,2,3 { + @17⦊y⦉@17 if @0,2,3⦊foo()⦉@0,2,3.await[@9,12,14,15,16⦊y⦉@9,12,14,15,16] => @17⦊()⦉@17, + _ => @1⦊()⦉@1, } -}@19,20⦊⦉@19,20
+}@19,20⦊⦉@19,20
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html index aead25eed64..f2ea01281fe 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html @@ -69,11 +69,13 @@ -
async fn h(x: usize) { +
@0,1⦊async fn h(x: usize) ⦉@0,1{ // The function signature is counted when called, but the body is not + // executed (not awaited) so the open brace has a `0` count (at least when + // displayed with `llvm-cov show` in color-mode). match x { y if foo().await[y] => (), _ => (), } -}@0,1⦊⦉@0,1
+}
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html index ab9bbf85dd7..49297870fa0 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,14 +69,23 @@ -
@0,2,3⦊{ - match x⦉@0,2,3 { - @17⦊y⦉@17 if @0,2,3⦊f()⦉@0,2,3.await == @9,12,14,15,16⦊y + 1⦉@9,12,14,15,16@18⦊⦉@18 => @17⦊()⦉@17, - _ => @1⦊()⦉@1, +
@0,3,4⦊{ // line coverage is 1, but there are 2 regions: + // (a) the function signature, counted when the function is called; and + // (b) the open brace for the function body, counted once when the body is + // executed asynchronously. + match x⦉@0,3,4 { + @18,20⦊y⦉@18,20 if @0,3,4⦊c(x)⦉@0,3,4.await == @10,13,15,16,17⦊y + 1⦉@10,13,15,16,17 => { @18,20⦊d()⦉@18,20.await; } + @48⦊y⦉@48 if @1,33,34⦊f()⦉@1,33,34.await == @40,43,45,46,47⦊y + 1⦉@40,43,45,46,47 => @48⦊()⦉@48, + _ => @2⦊()⦉@2, } -}@19,20⦊⦉@19,20
+}@50,51⦊⦉@50,51
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html index 0b193f4973e..e5dc6ecd4eb 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.i.-------.InstrumentCoverage.0.html @@ -69,11 +69,15 @@ -
async fn i(x: u8) { +
@0,1⦊async fn i(x: u8) ⦉@0,1{ // line coverage is 1, but there are 2 regions: + // (a) the function signature, counted when the function is called; and + // (b) the open brace for the function body, counted once when the body is + // executed asynchronously. match x { + y if c(x).await == y + 1 => { d().await; } y if f().await == y + 1 => (), _ => (), } -}@0,1⦊⦉@0,1
+}
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-c.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-c.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..a8e2d7e2f39 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-c.-------.InstrumentCoverage.0.html @@ -0,0 +1,92 @@ + + + + +async.j-c - Coverage Spans + + + +
@0⦊fn c(x: u8) -> u8 { + if x == 8⦉@0 { + @1,3⦊1⦉@1,3 // This line appears covered, but the 1-character expression span covering the `1` + // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + // `fn j()` executes the open brace for the funciton body, followed by the function's + // first executable statement, `match x`. Inner function declarations are not + // "visible" to the MIR for `j()`, so the code region counts all lines between the + // open brace and the first statement as executed, which is, in a sense, true. + // `llvm-cov show` overcomes this kind of situation by showing the actual counts + // of the enclosed coverages, (that is, the `1` expression was not executed, and + // accurately displays a `0`). + } else { + @2⦊0⦉@2 + } + }@4⦊⦉@4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-d.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-d.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..4eed8ee60dd --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-d.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.j-d - Coverage Spans + + + +
@0⦊fn d() -> u8 { 1 }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-f.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-f.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..6e80c8c786e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j-f.-------.InstrumentCoverage.0.html @@ -0,0 +1,75 @@ + + + + +async.j-f - Coverage Spans + + + +
@0⦊fn f() -> u8 { 1 }⦉@0
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..7cc751074a0 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.j.-------.InstrumentCoverage.0.html @@ -0,0 +1,108 @@ + + + + +async.j - Coverage Spans + + + +
@0,3,4,5⦊fn j(x: u8) { + // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. + fn c(x: u8) -> u8 { + if x == 8 { + 1 // This line appears covered, but the 1-character expression span covering the `1` + // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + // `fn j()` executes the open brace for the funciton body, followed by the function's + // first executable statement, `match x`. Inner function declarations are not + // "visible" to the MIR for `j()`, so the code region counts all lines between the + // open brace and the first statement as executed, which is, in a sense, true. + // `llvm-cov show` overcomes this kind of situation by showing the actual counts + // of the enclosed coverages, (that is, the `1` expression was not executed, and + // accurately displays a `0`). + } else { + 0 + } + } + fn d() -> u8 { 1 } + fn f() -> u8 { 1 } + match x⦉@0,3,4,5 { + @6,8⦊y⦉@6,8 if @0,3,4,5⦊c(x) == y + 1⦉@0,3,4,5 => @6,8⦊{ d(); }⦉@6,8 + @12⦊y⦉@12 if @1,9,10,11⦊f() == y + 1⦉@1,9,10,11 => @12⦊()⦉@12, + _ => @2⦊()⦉@2, + } +}@14⦊⦉@14
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.k.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.k.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..5792521bb2c --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.k.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.k - Coverage Spans + + + +
@0⦊fn k(x: u8) { // unused function + match x⦉@0 { + 1 => @1,4⦊()⦉@1,4, + 2 => @2,5⦊()⦉@2,5, + _ => @3⦊()⦉@3, + } +}@6⦊⦉@6
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.l.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.l.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..cd92b88c24c --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.l.-------.InstrumentCoverage.0.html @@ -0,0 +1,80 @@ + + + + +async.l - Coverage Spans + + + +
@0⦊fn l(x: u8) { + match x⦉@0 { + 1 => @1,4⦊()⦉@1,4, + 2 => @2,5⦊()⦉@2,5, + _ => @3⦊()⦉@3, + } +}@6⦊⦉@6
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html index 007da5c0ec1..2b0eb4f43c7 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html @@ -69,65 +69,101 @@ -
fn main() @0,1,2,3,4,5,6,7,8,9⦊{ - let _ = g(10); - let _ = h(9); - let mut future = Box::pin(i(8)); - executor::block_on(future.as_mut()); -}⦉@0,1,2,3,4,5,6,7,8,9
+
@0,1,2,3,4,5,6,7,8,9,10,11⦊fn main() { + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + j(7); + l(6); + executor::block_on(future.as_mut()); +}⦉@0,1,2,3,4,5,6,7,8,9,10,11
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html index b68c0a1cabe..523e839a918 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#0}.-------.InstrumentCoverage.0.html @@ -70,19 +70,23 @@
|| - { - let @0⦊mut countdown = 0⦉@0; - if @0⦊is_false⦉@0 @1,3⦊{ + @0⦊{ + let mut countdown = 0; + if is_false⦉@0 @1,3⦊{ countdown = 10; +36:21-38:10: @3[1]: _3 = const ()"> countdown = 10; }⦉@1,3@2⦊⦉@2 +36:21-38:10: @3[1]: _3 = const ()"> }⦉@1,3@2⦊⦉@2 -closure.main-{closure#2} - Coverage Spans +closure.main-{closure#10} - Coverage Spans -
|| - { - let @0⦊mut countdown = 0⦉@0; - if @0⦊is_false⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - @4,5⦊"alt string 1".to_owned() - }⦉@4,5
+
|val| + @0⦊{ + let mut countdown = 0; + if is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3@2⦊⦉@2 + @4,5,6,7,8⦊format!("'{}'", val) + }⦉@4,5,6,7,8
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html index 140e33905fb..032a6a7e435 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#3}.-------.InstrumentCoverage.0.html @@ -69,27 +69,25 @@ -
|| - { - let @0⦊mut countdown = 0⦉@0; - if @0⦊is_false⦉@0 @1,3⦊{ - countdown = 10; - }⦉@1,3@2⦊⦉@2 - @4,5⦊"alt string 3".to_owned() - }⦉@4,5
+
| + mut countdown + | + @0⦊{ + if is_false⦉@0 @1,3⦊{ + countdown = 10; + }⦉@1,3@2⦊⦉@2 + @4,5⦊"closure should be unused".to_owned() + }⦉@4,5
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#4}.-------.InstrumentCoverage.0.html similarity index 72% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#4}.-------.InstrumentCoverage.0.html index adba2d9965d..df0172bdf70 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#4}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -async.executor-block_on-VTABLE-{closure#3} - Coverage Spans +closure.main-{closure#4} - Coverage Spans -
|_| @0⦊()⦉@0
+
| _unused_arg: u8 | @0,1⦊countdown += 1⦉@0,1
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#5}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#5}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..e28038fd3fe --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#5}.-------.InstrumentCoverage.0.html @@ -0,0 +1,115 @@ + + + + +closure.main-{closure#5} - Coverage Spans + + + +
@0,1,2⦊{ + $crate::io::_print($crate::format_args_nl!($($arg)*)); + }⦉@0,1,2
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#6}.-------.InstrumentCoverage.0.html similarity index 60% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#6}.-------.InstrumentCoverage.0.html index 27a2ab71827..d479211aa37 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.partial_eq/partial_eq.{impl#8}-clone.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#6}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -partial_eq.{impl#8}-clone - Coverage Spans +closure.main-{closure#6} - Coverage Spans -
@0,1,2,3⦊Clone⦉@0,1,2,3
+
| _unused_arg: u8 | @0,1,2⦊{ println!("not called") }⦉@0,1,2
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#7}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#7}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..2734c0b2468 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#7}.-------.InstrumentCoverage.0.html @@ -0,0 +1,115 @@ + + + + +closure.main-{closure#7} - Coverage Spans + + + +
| _unused_arg: u8 | @0,1,2⦊{ + println!("not called") + }⦉@0,1,2
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#8}.-------.InstrumentCoverage.0.html similarity index 58% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#8}.-------.InstrumentCoverage.0.html index 5a43e8162cb..a032df54ea2 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.g.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#8}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -async.g - Coverage Spans +closure.main-{closure#8} - Coverage Spans -
pub async fn g(x: u8) { - match x { - y if f().await == y => (), - _ => (), - } -}@0,1⦊⦉@0,1
+
| + _unused_arg: u8 + | @0,1,2⦊{ println!("not called") }⦉@0,1,2
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#9}.-------.InstrumentCoverage.0.html similarity index 58% rename from src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#9}.-------.InstrumentCoverage.0.html index aead25eed64..3c174e03ebe 100644 --- a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.async/async.h.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main-{closure#9}.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -async.h - Coverage Spans +closure.main-{closure#9} - Coverage Spans -
async fn h(x: usize) { - match x { - y if foo().await[y] => (), - _ => (), - } -}@0,1⦊⦉@0,1
+
| + _unused_arg: u8 + | @0,1,2⦊{ println!("not called") }⦉@0,1,2
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html index 2d41918efb2..702c7937064 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html @@ -69,4447 +69,10853 @@ -
fn main() @0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊{ -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure - // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. - // dependent conditions. + let is_true = std::env::args().len() == 1; - let is_true = std::env::args().len() == 1; + let is_false = ! is_true; - let is_false = ! is_true; + - + let mut some_string = Some(String::from("the string content")); - let mut some_string = Some(String::from("the string content")); + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 1".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊ + ) - ) + ); - ); + - + some_string = Some(String::from("the string content")); - some_string = Some(String::from("the string content")); + let - let + a - a + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 2".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + a - a + ) - ) + ); - ); + - + some_string = None; - some_string = None; + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 3".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊ -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊ + ) - ) + ); - ); + - + some_string = None; - some_string = None; + let - let + a - a + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34|| +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 4".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + a - a + ) - ) + ); - ); +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34
+97:9-104:6: @33[10]: _100 = &_5 +95:9-95:22: @33[13]: FakeRead(ForLet, _99) +3:11-155:2: @41[38]: _0 = const ()">
+ let + quote_closure + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|val|
+ { + let mut countdown = 0; + if is_false { + countdown = 10; + } + format!("'{}'", val) + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + println!( + "Repeated, quoted string: {:?}" + , + std::iter::repeat("repeat me") + .take(5) + .map + ( + quote_closure + ) + .collect::<Vec<_>>() + ); + + let + _unused_closure + = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| + mut countdown + | + { + if is_false { + countdown = 10; + } + "closure should be unused".to_owned() + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + + let mut countdown = 10; + let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | countdown += 1@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + + // Macros can sometimes confuse the coverage results. Compare this next assignment, with an + // unused closure that invokes the `println!()` macro, with the closure assignment above, that + // does not use a macro. The closure above correctly shows `0` executions. + let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | println!("not called")@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + // The closure assignment above is executed, with a line count of `1`, but the `println!()` + // could not have been called, and yet, there is no indication that it wasn't... + + // ...but adding block braces gives the expected result, showing the block was not executed. + let _short_unused_closure_block = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + + let _shortish_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | { + println!("not called") + }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + + let _as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| + _unused_arg: u8 + | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + + let _almost_as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| + _unused_arg: u8 + | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊ + ; +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html index e6f95385910..e16b366e216 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.conditions/conditions.main.-------.InstrumentCoverage.0.html @@ -69,19 +69,20 @@ -
fn main() { +
@0⦊fn main() ⦉@0{ let @0⦊mut countdown = 0⦉@0; - if @0⦊true⦉@0 @1,3⦊{ +4:9-4:22: @0[2]: FakeRead(ForLet, _1) +5:8-5:12: @0[5]: _3 = const true +5:8-5:12: @0[6]: FakeRead(ForMatchedPlace, _3)">@0⦊mut countdown = 0; + if true⦉@0 @1,3⦊{ countdown = 10; +5:13-7:6: @3[1]: _2 = const ()"> countdown = 10; }⦉@1,3@2⦊⦉@2 +5:13-7:6: @3[1]: _2 = const ()"> }⦉@1,3@2⦊⦉@2 const B: u32 = 100; let @25⦊x⦉@25 = if @6⦊countdown > 2⦉@6 { if @9,11⦊countdown < 1⦉@9,11 || @18⦊countdown > 5⦉@18@16⦊⦉@16@17⦊⦉@17 || @14⦊countdown != 9⦉@14@12⦊⦉@12@13⦊⦉@13 @20,22⦊{ +14:29-14:42: @18[3]: _15 = Gt(move _16, const 5_u32)">@18⦊countdown > 5⦉@18 || @14⦊countdown != 9⦉@14 @20,22⦊{ countdown = 0; +14:61-16:10: @22[1]: _10 = const ()"> countdown = 0; }⦉@20,22@21⦊⦉@21 +14:61-16:10: @22[1]: _10 = const ()"> }⦉@20,22@21⦊⦉@21 @23,24⦊countdown -= 5; @@ -119,17 +117,18 @@ }; let @25⦊mut countdown = 0⦉@25; - if @25⦊true⦉@25 @26,28⦊{ +23:9-23:22: @25[4]: FakeRead(ForLet, _21) +24:8-24:12: @25[7]: _23 = const true +24:8-24:12: @25[8]: FakeRead(ForMatchedPlace, _23)">@25⦊mut countdown = 0; + if true⦉@25 @26,28⦊{ countdown = 10; +24:13-26:6: @28[1]: _22 = const ()"> countdown = 10; }⦉@26,28@27⦊⦉@27 +24:13-26:6: @28[1]: _22 = const ()"> }⦉@26,28@27⦊⦉@27 if @31⦊countdown > 2⦉@31 { if @34,36⦊countdown < 1⦉@34,36 || @43⦊countdown > 5⦉@43@41⦊⦉@41@42⦊⦉@42 || @39⦊countdown != 9⦉@39@37⦊⦉@37@38⦊⦉@38 @45,47⦊{ +31:29-31:42: @43[3]: _35 = Gt(move _36, const 5_i32)">@43⦊countdown > 5⦉@43 || @39⦊countdown != 9⦉@39 @45,47⦊{ countdown = 0; +31:61-33:10: @47[1]: _30 = const ()"> countdown = 0; }⦉@45,47@46⦊⦉@46 +31:61-33:10: @47[1]: _30 = const ()"> }⦉@45,47@46⦊⦉@46 @48,49⦊countdown -= 5⦉@48,49; } else { @@ -164,190 +160,167 @@ if @50⦊true⦉@50 { - // Demonstrate the difference with `TerminatorKind::Assert` as of 2020-11-15. Assert is no - // longer treated as a `BasicCoverageBlock` terminator, which changed the coverage region, - // for the executed `then` block above, to include the closing brace on line 30. That - // changed the line count, but the coverage code region (for the `else if` condition) is - // still valid. - // - // Note that `if` (then) and `else` blocks include the closing brace in their coverage - // code regions when the last line in the block ends in a semicolon, because the Rust - // compiler inserts a `StatementKind::Assign` to assign `const ()` to a `Place`, for the - // empty value for the executed block. When the last line does not end in a semicolon - // (that is, when the block actually results in a value), the additional `Assign` is not - // generated, and the brace is not included. - let @51,53⦊mut countdown = 0⦉@51,53; - if @51,53⦊true⦉@51,53 @54,56⦊{ - countdown = 10; - }⦉@54,56@55⦊⦉@55 + let @51,53⦊mut countdown = 0; + if true⦉@51,53 @54,56⦊{ + countdown = 10; + }⦉@54,56@55⦊⦉@55 - if @57⦊countdown > 7⦉@57 @58,60,61⦊{ - countdown -= 4; - }⦉@58,60,61 - // The closing brace of the `then` branch is now included in the coverage region, and shown - // as "executed" (giving its line a count of 1 here). Since, in the original version above, - // the closing brace shares the same line as the `else if` conditional expression (which is - // not executed if the first `then` condition is true), only the condition's code region is - // marked with a count of 0 now. - else if @59⦊countdown > 2⦉@59 { - if @62,64⦊countdown < 1⦉@62,64 || @71⦊countdown > 5⦉@71@69⦊⦉@69@70⦊⦉@70 || @67⦊countdown != 9⦉@67@65⦊⦉@65@66⦊⦉@66 @73,75⦊{ - countdown = 0; - }⦉@73,75@74⦊⦉@74 - @76,77⦊countdown -= 5⦉@76,77; + if @57⦊countdown > 7⦉@57 @58,60,61⦊{ + countdown -= 4; + }⦉@58,60,61 + else if @59⦊countdown > 2⦉@59 { + if @62,64⦊countdown < 1⦉@62,64 || @71⦊countdown > 5⦉@71 || @67⦊countdown != 9⦉@67 @73,75⦊{ + countdown = 0; + }⦉@73,75@74⦊⦉@74 + @76,77⦊countdown -= 5⦉@76,77; } else { - @63⦊return⦉@63; + @63⦊return⦉@63; } - }@78⦊⦉@78@52⦊⦉@52 + }@52⦊⦉@52 // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal + // `true` was const-evaluated. The compiler knows the `if` block will be executed. - let @79⦊mut countdown = 0⦉@79; - if @79⦊true⦉@79 @80,82⦊{ - countdown = 1; - }⦉@80,82@81⦊⦉@81 + let @79⦊mut countdown = 0; + if true⦉@79 @80,82⦊{ + countdown = 1; + }⦉@80,82@81⦊⦉@81 - let @106⦊z⦉@106 = if @83⦊countdown > 7⦉@83 @84,86,87⦊{ - countdown -= 4; - }⦉@84,86,87 else if @85⦊countdown > 2⦉@85 { - if @88,90⦊countdown < 1⦉@88,90 || @97⦊countdown > 5⦉@97@95⦊⦉@95@96⦊⦉@96 || @93⦊countdown != 9⦉@93@91⦊⦉@91@92⦊⦉@92 @99,101⦊{ - countdown = 0; - }⦉@99,101@100⦊⦉@100 - @102,103⦊countdown -= 5⦉@102,103; + let @106⦊z⦉@106 = if @83⦊countdown > 7⦉@83 @84,86,87⦊{ + countdown -= 4; + }⦉@84,86,87 else if @85⦊countdown > 2⦉@85 { + if @88,90⦊countdown < 1⦉@88,90 || @97⦊countdown > 5⦉@97 || @93⦊countdown != 9⦉@93 @99,101⦊{ + countdown = 0; + }⦉@99,101@100⦊⦉@100 + @102,103⦊countdown -= 5⦉@102,103; } else { - let @89,104,105⦊should_be_reachable = countdown; - println!("reached"); - return⦉@89,104,105; + let @89,104,105⦊should_be_reachable = countdown; + println!("reached"); + return⦉@89,104,105; }; - let @127⦊w⦉@127 = if @106⦊countdown > 7⦉@106 @107,109,110⦊{ - countdown -= 4; - }⦉@107,109,110 else if @108⦊countdown > 2⦉@108 { - if @111,113⦊countdown < 1⦉@111,113 || @120⦊countdown > 5⦉@120@118⦊⦉@118@119⦊⦉@119 || @116⦊countdown != 9⦉@116@114⦊⦉@114@115⦊⦉@115 @122,124⦊{ - countdown = 0; - }⦉@122,124@123⦊⦉@123 - @125,126⦊countdown -= 5⦉@125,126; + let @127⦊w⦉@127 = if @106⦊countdown > 7⦉@106 @107,109,110⦊{ + countdown -= 4; + }⦉@107,109,110 else if @108⦊countdown > 2⦉@108 { + if @111,113⦊countdown < 1⦉@111,113 || @120⦊countdown > 5⦉@120 || @116⦊countdown != 9⦉@116 @122,124⦊{ + countdown = 0; + }⦉@122,124@123⦊⦉@123 + @125,126⦊countdown -= 5⦉@125,126; } else { - @112⦊return⦉@112; + @112⦊return⦉@112; }; -}@130⦊⦉@130@131⦊⦉@131
+}@131⦊⦉@131
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..59d00600738 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,151 @@ + + + + +dead_code.main - Coverage Spans + + + +
@0,1,2,3⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_fn.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_fn.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..1a535b93788 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_fn.-------.InstrumentCoverage.0.html @@ -0,0 +1,151 @@ + + + + +dead_code.unused_fn - Coverage Spans + + + +
@0,1,2,3⦊fn unused_fn() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_pub_fn_not_in_library.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_pub_fn_not_in_library.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..6eff51ad89c --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.dead_code/dead_code.unused_pub_fn_not_in_library.-------.InstrumentCoverage.0.html @@ -0,0 +1,151 @@ + + + + +dead_code.unused_pub_fn_not_in_library - Coverage Spans + + + +
@0,1,2,3⦊pub fn unused_pub_fn_not_in_library() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html index 8d6f936aadc..fa3c4b3c312 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html @@ -69,22 +69,42 @@ -
fn main() -> Result<(),u8> { - let @0⦊_firecracker = Firework { strength: 1 }; +17:9-17:13: @0[5]: FakeRead(ForLet, _2) +19:8-19:12: @0[8]: _4 = const true +19:8-19:12: @0[9]: FakeRead(ForMatchedPlace, _4)">@0⦊fn main() -> Result<(),u8> { +17:9-17:13: @0[5]: FakeRead(ForLet, _2) +19:8-19:12: @0[8]: _4 = const true +19:8-19:12: @0[9]: FakeRead(ForMatchedPlace, _4)"> let _firecracker = Firework { strength: 1 }; let _tnt = Firework { strength: 100 }⦉@0; - - if @0⦊true⦉@0 { +17:9-17:13: @0[5]: FakeRead(ForLet, _2) +19:8-19:12: @0[8]: _4 = const true +19:8-19:12: @0[9]: FakeRead(ForMatchedPlace, _4)"> + let _tnt = Firework { strength: 100 }; + + if true⦉@0 { return Err(1)⦉@1,3,4,5,9,10; - } - - let _ = }@2,6,7,8⦊ + +@2,6,7,8⦊Firework { strength: 1000 }; - let _ = Firework { strength: 1000 }; + - Ok(())⦉@2,6,7,8 }@11⦊⦉@11
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html index 60a24df9ba6..b5dedeec8ac 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.drop_trait/drop_trait.{impl#0}-drop.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
fn drop(&mut self) @0,1,2,3⦊{ +11:6-11:6: @3.Return: return">@0,1,2,3⦊fn drop(&mut self) { fn main() -> Result<(),u8> { - let @0,1,2,3⦊mut firecracker = Firework { strength: 1 }; +28:5-28:28: @2.Call: _7 = Firework::<f64>::set_strength(move _8, const 300.30000000000001f64) -> [return: bb3, unwind: bb15] +30:8-30:12: @3[4]: _10 = const true +30:8-30:12: @3[5]: FakeRead(ForMatchedPlace, _10)">@0,1,2,3⦊fn main() -> Result<(),u8> { firecracker.set_strength(2); +28:5-28:28: @2.Call: _7 = Firework::<f64>::set_strength(move _8, const 300.30000000000001f64) -> [return: bb3, unwind: bb15] +30:8-30:12: @3[4]: _10 = const true +30:8-30:12: @3[5]: FakeRead(ForMatchedPlace, _10)"> let mut firecracker = Firework { strength: 1 }; +28:5-28:28: @2.Call: _7 = Firework::<f64>::set_strength(move _8, const 300.30000000000001f64) -> [return: bb3, unwind: bb15] +30:8-30:12: @3[4]: _10 = const true +30:8-30:12: @3[5]: FakeRead(ForMatchedPlace, _10)"> firecracker.set_strength(2); let mut tnt = Firework { strength: 100.1 }; +28:5-28:28: @2.Call: _7 = Firework::<f64>::set_strength(move _8, const 300.30000000000001f64) -> [return: bb3, unwind: bb15] +30:8-30:12: @3[4]: _10 = const true +30:8-30:12: @3[5]: FakeRead(ForMatchedPlace, _10)"> tnt.set_strength(200.1); +28:5-28:28: @2.Call: _7 = Firework::<f64>::set_strength(move _8, const 300.30000000000001f64) -> [return: bb3, unwind: bb15] +30:8-30:12: @3[4]: _10 = const true +30:8-30:12: @3[5]: FakeRead(ForMatchedPlace, _10)"> let mut tnt = Firework { strength: 100.1 }; tnt.set_strength(300.3)⦉@0,1,2,3; - - if @0,1,2,3⦊true⦉@0,1,2,3 { +28:5-28:28: @2.Call: _7 = Firework::<f64>::set_strength(move _8, const 300.30000000000001f64) -> [return: bb3, unwind: bb15] +30:8-30:12: @3[4]: _10 = const true +30:8-30:12: @3[5]: FakeRead(ForMatchedPlace, _10)"> tnt.set_strength(200.1); + tnt.set_strength(300.3); + + if true⦉@0,1,2,3 { return Err(1)⦉@4,6,7,8,12,13; - } - - let _ = @5,9,10,11⦊Firework { strength: 1000 }; - - Ok(())⦉@5,9,10,11 -}@14⦊⦉@14
+ }@5,9,10,11⦊ // The remaining lines below have no coverage because `if true` (with the constant literal + // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. + // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown + // in other tests, the lines below would have coverage (which would show they had `0` + // executions, assuming the condition still evaluated to `true`). + + let _ = Firework { strength: 1000 }; + + Ok(())⦉@5,9,10,11 +}@14⦊⦉@14
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html index b10da561da9..329641d47bd 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.generics/generics.{impl#0}-set_strength.-------.InstrumentCoverage.0.html @@ -69,10 +69,10 @@ -
fn set_strength(&mut self, new_strength: T) @0⦊{ +12:6-12:6: @0.Return: return">@0⦊fn set_strength(&mut self, new_strength: T) { fn drop(&mut self) @0,1,2,3⦊{ +19:6-19:6: @3.Return: return">@0,1,2,3⦊fn drop(&mut self) { fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let - @0,1,2,3⦊is_true +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)">@0,1,2,3⦊fn main() { = +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> // Initialize test constants in a way that cannot be determined at compile time, to ensure std::env::args().len() +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from == +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> // dependent conditions. 1 +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> let ; +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> is_true let +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> = mut +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> std::env::args().len() countdown +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> == = +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> 1 0⦉@0,1,2,3 - ; - if - @0,1,2,3⦊is_true⦉@0,1,2,3 +15:9-16:14: @3[3]: FakeRead(ForLet, _5) +21:9-21:16: @3[5]: _6 = _1 +21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"> ; + let + mut + countdown + = + 0 + ; + if + is_true⦉@0,1,2,3 @4,6⦊{ +22:5-27:6: @6[1]: _0 = const ()">@4,6⦊{ countdown +22:5-27:6: @6[1]: _0 = const ()"> countdown = +22:5-27:6: @6[1]: _0 = const ()"> = 10 +22:5-27:6: @6[1]: _0 = const ()"> 10 ; +22:5-27:6: @6[1]: _0 = const ()"> ; }⦉@4,6@5⦊⦉@5 +22:5-27:6: @6[1]: _0 = const ()"> }⦉@4,6@5⦊⦉@5 }@7⦊⦉@7
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html index 586014afeba..5b2cce4f648 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html @@ -69,11 +69,7 @@ -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; +11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)">@0,1,2,3⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; fn default_trait_func(&mut self) @0,1,2⦊{ +36:10-36:10: @2.Return: return">@0,1,2⦊fn default_trait_func(&mut self) { fn in_func(a: u32) { - let @0,1,2,3,4⦊b = 1; +22:6-22:6: @4.Return: return">@0,1,2,3,4⦊fn in_func(a: u32) { + let b = 1; fn trait_func(&mut self, incr: u32) @0,1,2⦊{ +43:10-43:10: @2.Return: return">@0,1,2⦊fn trait_func(&mut self, incr: u32) { fn main() { +
@0,1,2,3⦊fn main() ⦉@0,1,2,3{ // Initialize test constants in a way that cannot be determined at compile time, to ensure // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from // dependent conditions. @@ -79,31 +79,41 @@ 7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize) 7:9-7:16: @2[3]: FakeRead(ForLet, _1) 9:25-9:26: @3[2]: _5 = const 0_u32 -9:9-9:22: @3[3]: FakeRead(ForLet, _5)">@0,1,2,3⦊is_true = std::env::args().len() == 1; +9:9-9:22: @3[3]: FakeRead(ForLet, _5) +10:8-10:15: @3[6]: _7 = _1 +10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)">@0,1,2,3⦊is_true = std::env::args().len() == 1; +9:9-9:22: @3[3]: FakeRead(ForLet, _5) +10:8-10:15: @3[6]: _7 = _1 +10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)"> let mut countdown = 0⦉@0,1,2,3; - if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ +9:9-9:22: @3[3]: FakeRead(ForLet, _5) +10:8-10:15: @3[6]: _7 = _1 +10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)"> let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ countdown = 10; +10:16-12:6: @6[1]: _6 = const ()"> countdown = 10; }⦉@4,6@5⦊⦉@5 +10:16-12:6: @6[1]: _6 = const ()"> }⦉@4,6@5⦊⦉@5 mod in_mod { const IN_MOD_CONST: u32 = 1000; @@ -142,16 +152,13 @@ if @7⦊is_true⦉@7 @8,10,11⦊{ +48:16-50:6: @11[2]: _8 = const ()">@8,10,11⦊{ in_func(countdown); +48:16-50:6: @11[2]: _8 = const ()"> in_func(countdown); }⦉@8,10,11@9⦊⦉@9 +48:16-50:6: @11[2]: _8 = const ()"> }⦉@8,10,11@9⦊⦉@9 let fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; +9:24-9:29: @3[8]: _7 = (_8.2: i32) +10:8-10:15: @3[12]: _10 = _1 +10:8-10:15: @3[13]: FakeRead(ForMatchedPlace, _10)">@0,1,2,3⦊fn main() { +9:24-9:29: @3[8]: _7 = (_8.2: i32) +10:8-10:15: @3[12]: _10 = _1 +10:8-10:15: @3[13]: FakeRead(ForMatchedPlace, _10)"> // Initialize test constants in a way that cannot be determined at compile time, to ensure let (mut a, mut b, mut c) = (0, 0, 0)⦉@0,1,2,3; - if @0,1,2,3⦊is_true⦉@0,1,2,3 // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let (mut a, mut b, mut c) = (0, 0, 0); + if is_true⦉@0,1,2,3 @4,6⦊{ +10:16-14:6: @6[3]: _9 = const ()">@4,6⦊{ a = 1; +10:16-14:6: @6[3]: _9 = const ()"> a = 1; b = 10; +10:16-14:6: @6[3]: _9 = const ()"> b = 10; c = 100; +10:16-14:6: @6[3]: _9 = const ()"> c = 100; }⦉@4,6@5⦊⦉@5 +10:16-14:6: @6[3]: _9 = const ()"> }⦉@4,6@5⦊⦉@5 let @11⦊somebool⦉@11 = @@ -135,7 +185,7 @@ || @10⦊b < c⦉@10@8⦊⦉@8@9⦊⦉@9 +20:13-20:18: @10[5]: _15 = Lt(move _16, move _17)">@10⦊b < c⦉@10 ; let @15⦊somebool⦉@15 @@ -146,18 +196,18 @@ || @14⦊b < c⦉@14@12⦊⦉@12@13⦊⦉@13 +27:13-27:18: @14[5]: _22 = Lt(move _23, move _24)">@14⦊b < c⦉@14 ; let @19⦊somebool⦉@19 = @15⦊a < b⦉@15 && @18⦊b < c⦉@18@16⦊⦉@16@17⦊⦉@17; +29:29-29:34: @18[5]: _29 = Lt(move _30, move _31)">@18⦊b < c⦉@18; let @23⦊somebool⦉@23 = @19⦊b < a⦉@19 && @22⦊b < c⦉@22@20⦊⦉@20@21⦊⦉@21; +30:29-30:34: @22[5]: _36 = Lt(move _37, move _38)">@22⦊b < c⦉@22; if is_true⦉@23 @24,26⦊{ +35:5-38:6: @26[1]: _39 = const ()">@24,26⦊{ a = 2 +35:5-38:6: @26[1]: _39 = const ()"> a = 2 ; +35:5-38:6: @26[1]: _39 = const ()"> ; }⦉@24,26@25⦊⦉@25 +35:5-38:6: @26[1]: _39 = const ()"> }⦉@24,26@25⦊⦉@25 if if @31⦊!is_true⦉@31 @32,34⦊{ +52:17-54:6: @34[1]: _44 = const ()">@32,34⦊{ a = 2; +52:17-54:6: @34[1]: _44 = const ()"> a = 2; }⦉@32,34@33⦊⦉@33 +52:17-54:6: @34[1]: _44 = const ()"> }⦉@32,34@33⦊⦉@33 if @35⦊is_true⦉@35 fn main() @0,1⦊{ +13:2-13:2: @1.Return: return">@0,1⦊fn main() { fn main() @0,1,2,3⦊{ +25:2-25:2: @3.Return: return">@0,1,2,3⦊fn main() { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if @0⦊true⦉@0 { +
@0⦊fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if true⦉@0 { if @1,3⦊false⦉@1,3 { while @6,7⦊true⦉@6,7 @8,10⦊{ - }⦉@8,10 - }@9⦊⦉@9@5⦊⦉@5 - @6,7⦊true⦉@6,7 @8,10⦊{ + }⦉@8,10 + }@5⦊⦉@5 + @11,12,13,14⦊write!(f, "error")⦉@11,12,13,14@11,12,13,14⦊write!(f, "error")⦉@11,12,13,14@16,18,19,20⦊?⦉@16,18,19,20; - } else @2⦊{ - }⦉@2@15⦊⦉@15 + } else @2⦊{ + }⦉@2 @21⦊Ok(())⦉@21 }@22⦊⦉@22
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html index 0f3ea3ce6a8..cb60276aa12 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.nested_loops/nested_loops.main.-------.InstrumentCoverage.0.html @@ -69,14 +69,20 @@ -
fn main() { - let @0,1,2,3⦊is_true = std::env::args().len() == 1; +3:9-3:22: @3[3]: FakeRead(ForLet, _5)">@0,1,2,3⦊fn main() { + let is_true = std::env::args().len() == 1; @14,16⦊a < 30⦉@14,16 { @17,19⦊break⦉@17,19; - } - }@18,20,21⦊a -= 5; -@18,20,21⦊ + b -= 5⦉@18,20,21; - if @18,20,21⦊b < 90⦉@18,20,21 { +14:16-14:22: @21[6]: FakeRead(ForMatchedPlace, _31)"> a -= 5; + b -= 5; + if b < 90⦉@18,20,21 { @26,28⦊break 'outer⦉@26,28; } else @27,29⦊{ - a -= 2; +18:24-20:18: @29[1]: _24 = const ()">@27,29⦊{ } +18:24-20:18: @29[1]: _24 = const ()"> a -= 2; }⦉@27,29@23⦊⦉@23 - }@30⦊⦉@30 - }⦉@27,29 + }@23⦊⦉@23 + } + @31,32⦊countdown -= 1⦉@31,32; - }@7⦊⦉@7 + } }@33⦊⦉@33
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html index 4f237d6561d..6739634f65b 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.main.-------.InstrumentCoverage.0.html @@ -69,9 +69,10 @@ -
fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; +
@0⦊fn main() -> Result<(),u8> { + let mut countdown = 10⦉@0; while @1,2⦊countdown > 0⦉@1,2 { @@ -245,14 +246,14 @@ 23:13-23:44: @17.Call: _32 = Arguments::new_v1(move _33, move _37) -> [return: bb18, unwind: bb23] 23:13-23:44: @18.Call: _31 = _print(move _32) -> [return: bb19, unwind: bb23] 23:13-23:44: @19[6]: _30 = const () -21:33-24:10: @19[8]: _6 = const ()"> }⦉@13,15,16,17,18,19@14⦊⦉@14@20⦊⦉@20 - }⦉@13,15,16,17,18,19@14⦊⦉@14 + @21,22⦊countdown -= 1⦉@21,22; } - @4⦊Ok(()) -}⦉@4
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html index b1dbc40ee20..c72ad426356 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.overflow/overflow.might_overflow.-------.InstrumentCoverage.0.html @@ -69,10 +69,12 @@ -
fn might_overflow(to_add: u32) -> u32 { - if @0⦊to_add > 5⦉@0 @0⦊fn might_overflow(to_add: u32) -> u32 { + if to_add > 5⦉@0 @1,3,4,5⦊{ +5:19-7:6: @5[7]: _2 = const ()">@1,3,4,5⦊{ println!("this will probably overflow"); +5:19-7:6: @5[7]: _2 = const ()"> println!("this will probably overflow"); }⦉@1,3,4,5@2⦊⦉@2 +5:19-7:6: @5[7]: _2 = const ()"> }⦉@1,3,4,5@2⦊⦉@2 let fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; +
@0⦊fn main() -> Result<(), u8> { + let mut countdown = 10⦉@0; while @1,2⦊countdown > 0⦉@1,2 { @@ -89,14 +90,14 @@ might_panic(false); }⦉@10,12,13@11⦊⦉@11@14⦊⦉@14 - }⦉@10,12,13@11⦊⦉@11 + @15,16⦊countdown -= 1⦉@15,16; } - @4⦊Ok(()) -}⦉@4
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html index d6002e70af2..290b7b85099 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.panic_unwind/panic_unwind.might_panic.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
fn might_panic(should_panic: bool) { +
@0⦊fn might_panic(should_panic: bool) ⦉@0{ if @0⦊should_panic⦉@0 { fn main() @0,1,2,3,4,5,6,7,8⦊{ +26:2-26:2: @8.Return: return">@0,1,2,3,4,5,6,7,8⦊fn main() { pub fn new(major: usize, minor: usize, patch: usize) -> Self { - @0⦊Self { +18:6-18:6: @0.Return: return">@0⦊pub fn new(major: usize, minor: usize, patch: usize) -> Self { + Self { @14⦊@11,12⦊@13⦊Ord⦉@13⦉@11,12⦉@14@15⦊⦉@15
+
@0,1⦊⦉@0,1Ord@15⦊⦉@15
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html index 52e6b526276..47f9ab2bd5e 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-ge-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
minor: usize, +
minor: usize, // Count: 1 - `PartialOrd` compared `minor` values in 3.2.1 vs. 3.3.0 @0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
+4:39-4:49: @2[10]: _22 = &_5">@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html index 0ad35d701aa..2b9a13fe060 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-gt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
minor: usize, +
minor: usize, // Count: 1 - `PartialOrd` compared `minor` values in 3.2.1 vs. 3.3.0 @0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
+4:39-4:49: @2[10]: _22 = &_5">@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html index d43d8526a88..5c95a635f07 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-le-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
minor: usize, +
minor: usize, // Count: 1 - `PartialOrd` compared `minor` values in 3.2.1 vs. 3.3.0 @0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
+4:39-4:49: @2[10]: _22 = &_5">@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html index a941c08da5d..b2b3e172d53 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-lt-{closure#0}-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
minor: usize, +
minor: usize, // Count: 1 - `PartialOrd` compared `minor` values in 3.2.1 vs. 3.3.0 @0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd@0,1,2,3,4⦊⦉@0,1,2,3,4
+4:39-4:49: @2[10]: _22 = &_5">@0,1,2,3,4⦊⦉@0,1,2,3,4PartialOrd
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html index c5a806f7c17..2f5092bd51f 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#2}-partial_cmp.-------.InstrumentCoverage.0.html @@ -69,10 +69,6 @@ -
@17⦊@14,15⦊@16⦊PartialOrd⦉@16⦉@14,15⦉@17@18⦊⦉@18
+
@0,1⦊⦉@0,1PartialOrd@18⦊⦉@18
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html index b4beef867eb..ebb8b1c15ce 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#4}-assert_receiver_is_total_eq.-------.InstrumentCoverage.0.html @@ -70,6 +70,6 @@
@0⦊Eq⦉@0
+4:37-4:37: @0.Return: return">@0⦊⦉@0Eq
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html index 92f37e4b89a..2e128181c5e 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-eq.-------.InstrumentCoverage.0.html @@ -69,9 +69,6 @@ -
@2⦊@1⦊PartialEq⦉@1⦉@2@4⦊⦉@4
+
@0⦊⦉@0PartialEq@4⦊⦉@4
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html index df561a79224..637b1c62086 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.partial_eq/partial_eq.{impl#6}-ne.-------.InstrumentCoverage.0.html @@ -69,13 +69,6 @@ -
@2⦊@5⦊@6⦊@1⦊PartialEq⦉@1⦉@6⦉@5⦉@2@4⦊⦉@4
+
@0⦊⦉@0PartialEq@4⦊⦉@4
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html index 29d21cf7ba4..1233dfb5bab 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html @@ -69,53 +69,108 @@ -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; +9:9-9:22: @3[3]: FakeRead(ForLet, _5) +12:9-12:16: @3[6]: _7 = _1 +12:9-12:16: @3[7]: FakeRead(ForMatchedPlace, _7)">@0,1,2,3⦊fn main() { +9:9-9:22: @3[3]: FakeRead(ForLet, _5) +12:9-12:16: @3[6]: _7 = _1 +12:9-12:16: @3[7]: FakeRead(ForMatchedPlace, _7)"> // Initialize test constants in a way that cannot be determined at compile time, to ensure let mut countdown = 0⦉@0,1,2,3; - - if - @0,1,2,3⦊is_true⦉@0,1,2,3 +9:9-9:22: @3[3]: FakeRead(ForLet, _5) +12:9-12:16: @3[6]: _7 = _1 +12:9-12:16: @3[7]: FakeRead(ForMatchedPlace, _7)"> // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + + if + is_true⦉@0,1,2,3 @4,6⦊{ +13:5-18:6: @6[1]: _6 = const ()">@4,6⦊{ countdown +13:5-18:6: @6[1]: _6 = const ()"> countdown = +13:5-18:6: @6[1]: _6 = const ()"> = 10 +13:5-18:6: @6[1]: _6 = const ()"> 10 ; +13:5-18:6: @6[1]: _6 = const ()"> ; }⦉@4,6@5⦊⦉@5 +13:5-18:6: @6[1]: _6 = const ()"> }⦉@4,6@5⦊⦉@5 loop { @@ -132,15 +187,20 @@ { @10,12⦊break⦉@10,12 ; - } - @11,13⦊countdown - }@11,13⦊ + countdown + -= - 1⦉@11,13 ; - }@7⦊⦉@7 -}@10,12⦊⦉@10,12
+ } +}@10,12⦊⦉@10,12
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html index f1513d458eb..a8bae32490b 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html @@ -69,41 +69,83 @@ -
fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let @0,1,2,3⦊is_true = std::env::args().len() == 1; +9:9-9:22: @3[3]: FakeRead(ForLet, _5) +10:8-10:15: @3[6]: _7 = _1 +10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)">@0,1,2,3⦊fn main() { +9:9-9:22: @3[3]: FakeRead(ForLet, _5) +10:8-10:15: @3[6]: _7 = _1 +10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)"> // Initialize test constants in a way that cannot be determined at compile time, to ensure let mut countdown = 1⦉@0,1,2,3; - if @0,1,2,3⦊is_true⦉@0,1,2,3 @4,6⦊{ +9:9-9:22: @3[3]: FakeRead(ForLet, _5) +10:8-10:15: @3[6]: _7 = _1 +10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)"> // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 1; + if is_true⦉@0,1,2,3 @4,6⦊{ countdown = 0; +10:16-12:6: @6[1]: _6 = const ()"> countdown = 0; }⦉@4,6@5⦊⦉@5 +10:16-12:6: @6[1]: _6 = const ()"> }⦉@4,6@5⦊⦉@5 for < 1⦉@13,15,17@19⦊⦉@19 +26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)"> 1⦉@13,15,17 => - @18⦊{ - z = countdown - ; - let y = countdown - ; - countdown = 10 - ; - }⦉@18 _ => - @16⦊{}⦉@16 + @16⦊{}⦉@16 } - }@7,8⦊⦉@7,8@20⦊⦉@20 -}@12⦊⦉@12
+ } +}@12⦊⦉@12
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html index 5cf76ecf5c2..d0ee798ca19 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.tight_inf_loop/tight_inf_loop.main.-------.InstrumentCoverage.0.html @@ -69,12 +69,15 @@ -
fn main() { - if @0⦊false⦉@0 { +
@0⦊fn main() { + if false⦉@0 { @4,5⦊loop {}⦉@4,5@1,3⦊⦉@1,3 - } -}@2⦊⦉@2
+3:14-3:16: @5[0]: _3 = const ()">@4,5⦊loop {}⦉@4,5 + }@2⦊ +}⦉@2
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html index eeee81daeb2..804d2f43886 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html @@ -69,9 +69,10 @@ -
fn call(return_error: bool) -> Result<(),()> { - if @0⦊return_error⦉@0 { +
@0⦊fn call(return_error: bool) -> Result<(),()> { + if return_error⦉@0 { @1,3⦊Err(())⦉@1,3 } else { diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html index b9391e26c86..3091eab3e71 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html @@ -69,9 +69,10 @@ -
fn main() -> Result<(),()> { - let @0,1⦊mut +
@0,1⦊fn main() -> Result<(),()> { + let mut countdown = 10⦉@0,1 ; @@ -124,10 +125,10 @@ @11,29,30⦊call(/*return_error=*/ false)⦉@11,29,30@32,34,35,36⦊?⦉@32,34,35,36; - }@23⦊⦉@23@31⦊⦉@31 - }@37⦊⦉@37 - } + } + @5⦊Ok(())⦉@5 -}@38⦊⦉@38@39⦊⦉@39
+}@39⦊⦉@39
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html index 05c010da7bc..f037a8ee5c5 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while/while.main.-------.InstrumentCoverage.0.html @@ -69,9 +69,10 @@ -
fn main() { - let @0⦊num = 9⦉@0; +
@0⦊fn main() { + let num = 9⦉@0; while @1,2⦊num >= 10⦉@1,2 @3,5⦊{ diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html index 87ce501ca8c..4cab153e77f 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.while_early_ret/while_early_ret.main.-------.InstrumentCoverage.0.html @@ -69,9 +69,10 @@ -
fn main() -> Result<(),u8> { - let @0⦊mut countdown = 10⦉@0; +
@0⦊fn main() -> Result<(),u8> { + let mut countdown = 10⦉@0; while @10⦊Err(1)⦉@10 } ; - } - @7,12⦊countdown - }@7,12⦊ + countdown + -= - 1⦉@7,12 ; } @4⦊Ok(())⦉@4 -}@13⦊⦉@13@14⦊⦉@14
+}@14⦊⦉@14
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html index b8458f9d8d6..1e68c345f84 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.yield/yield.main-{closure#0}.-------.InstrumentCoverage.0.html @@ -69,8 +69,8 @@ -
|| { - @0⦊yield 1⦉@0; +
|| @0⦊{ + yield 1⦉@0; return @1⦊"foo" || { - @0⦊yield 1⦉@0; +
|| @0⦊{ + yield 1⦉@0; @1⦊yield 2⦉@1; @2⦊yield 3⦉@2; return fn main() { +
@0,1,2⦊fn main() ⦉@0,1,2{ let @0,1,2⦊mut generator⦉@0,1,2 = || { yield 1; return "foo" diff --git a/src/test/run-make-fulldeps/coverage/abort.rs b/src/test/run-make-fulldeps/coverage/abort.rs index 01c5c920547..52c6ff333e4 100644 --- a/src/test/run-make-fulldeps/coverage/abort.rs +++ b/src/test/run-make-fulldeps/coverage/abort.rs @@ -11,12 +11,18 @@ fn might_abort(should_abort: bool) { } } -fn main() -> Result<(),u8> { +fn main() -> Result<(), u8> { let mut countdown = 10; while countdown > 0 { if countdown < 5 { might_abort(false); } + // See discussion (below the `Notes` section) on coverage results for the closing brace. + if countdown < 5 { might_abort(false); } // Counts for different regions on one line. + // For the following example, the closing brace is the last character on the line. + // This shows the character after the closing brace is highlighted, even if that next + // character is a newline. + if countdown < 5 { might_abort(false); } countdown -= 1; } Ok(()) @@ -32,3 +38,30 @@ fn main() -> Result<(),u8> { // intended"). Coverage results would show no executed coverage regions. // 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status // (on Linux at least). + +/* + +Expect the following coverage results: + +```text + 16| 11| while countdown > 0 { + 17| 10| if countdown < 5 { + 18| 4| might_abort(false); + 19| 6| } +``` + +This is actually correct. + +The condition `countdown < 5` executed 10 times (10 loop iterations). + +It evaluated to `true` 4 times, and executed the `might_abort()` call. + +It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit +`else`, the coverage implementation injects a counter, at the character immediately after the `if`s +closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the +non-true condition. + +As another example of why this is important, say the condition was `countdown < 50`, which is always +`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. +The closing brace would have a count of `0`, highlighting the missed coverage. +*/ diff --git a/src/test/run-make-fulldeps/coverage/async.rs b/src/test/run-make-fulldeps/coverage/async.rs index f69b8dce893..fcf6f76944e 100644 --- a/src/test/run-make-fulldeps/coverage/async.rs +++ b/src/test/run-make-fulldeps/coverage/async.rs @@ -2,37 +2,98 @@ // require-rust-edition-2018 +async fn c(x: u8) -> u8 { + if x == 8 { + 1 + } else { + 0 + } +} + +async fn d() -> u8 { 1 } + +async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` + async fn f() -> u8 { 1 } -async fn foo() -> [bool; 10] { [false; 10] } +async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` pub async fn g(x: u8) { match x { + y if e().await == y => (), y if f().await == y => (), _ => (), } } -// #78366: check the reference to the binding is recorded even if the binding is not autorefed - -async fn h(x: usize) { +async fn h(x: usize) { // The function signature is counted when called, but the body is not + // executed (not awaited) so the open brace has a `0` count (at least when + // displayed with `llvm-cov show` in color-mode). match x { y if foo().await[y] => (), _ => (), } } -async fn i(x: u8) { +async fn i(x: u8) { // line coverage is 1, but there are 2 regions: + // (a) the function signature, counted when the function is called; and + // (b) the open brace for the function body, counted once when the body is + // executed asynchronously. match x { + y if c(x).await == y + 1 => { d().await; } y if f().await == y + 1 => (), _ => (), } } +fn j(x: u8) { + // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. + fn c(x: u8) -> u8 { + if x == 8 { + 1 // This line appears covered, but the 1-character expression span covering the `1` + // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + // `fn j()` executes the open brace for the funciton body, followed by the function's + // first executable statement, `match x`. Inner function declarations are not + // "visible" to the MIR for `j()`, so the code region counts all lines between the + // open brace and the first statement as executed, which is, in a sense, true. + // `llvm-cov show` overcomes this kind of situation by showing the actual counts + // of the enclosed coverages, (that is, the `1` expression was not executed, and + // accurately displays a `0`). + } else { + 0 + } + } + fn d() -> u8 { 1 } + fn f() -> u8 { 1 } + match x { + y if c(x) == y + 1 => { d(); } + y if f() == y + 1 => (), + _ => (), + } +} + +fn k(x: u8) { // unused function + match x { + 1 => (), + 2 => (), + _ => (), + } +} + +fn l(x: u8) { + match x { + 1 => (), + 2 => (), + _ => (), + } +} + fn main() { let _ = g(10); let _ = h(9); let mut future = Box::pin(i(8)); + j(7); + l(6); executor::block_on(future.as_mut()); } diff --git a/src/test/run-make-fulldeps/coverage/closure.rs b/src/test/run-make-fulldeps/coverage/closure.rs index 66bbbc55399..914cb0fe051 100644 --- a/src/test/run-make-fulldeps/coverage/closure.rs +++ b/src/test/run-make-fulldeps/coverage/closure.rs @@ -90,4 +90,66 @@ fn main() { a ) ); + + let + quote_closure + = + |val| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + format!("'{}'", val) + }; + println!( + "Repeated, quoted string: {:?}" + , + std::iter::repeat("repeat me") + .take(5) + .map + ( + quote_closure + ) + .collect::>() + ); + + let + _unused_closure + = + | + mut countdown + | + { + if is_false { + countdown = 10; + } + "closure should be unused".to_owned() + }; + + let mut countdown = 10; + let _short_unused_closure = | _unused_arg: u8 | countdown += 1; + + // Macros can sometimes confuse the coverage results. Compare this next assignment, with an + // unused closure that invokes the `println!()` macro, with the closure assignment above, that + // does not use a macro. The closure above correctly shows `0` executions. + let _short_unused_closure = | _unused_arg: u8 | println!("not called"); + // The closure assignment above is executed, with a line count of `1`, but the `println!()` + // could not have been called, and yet, there is no indication that it wasn't... + + // ...but adding block braces gives the expected result, showing the block was not executed. + let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; + + let _shortish_unused_closure = | _unused_arg: u8 | { + println!("not called") + }; + + let _as_short_unused_closure = | + _unused_arg: u8 + | { println!("not called") }; + + let _almost_as_short_unused_closure = | + _unused_arg: u8 + | { println!("not called") } + ; } diff --git a/src/test/run-make-fulldeps/coverage/conditions.rs b/src/test/run-make-fulldeps/coverage/conditions.rs index 1a8bafa50d4..8a2a0b53e58 100644 --- a/src/test/run-make-fulldeps/coverage/conditions.rs +++ b/src/test/run-make-fulldeps/coverage/conditions.rs @@ -37,18 +37,6 @@ fn main() { } if true { - // Demonstrate the difference with `TerminatorKind::Assert` as of 2020-11-15. Assert is no - // longer treated as a `BasicCoverageBlock` terminator, which changed the coverage region, - // for the executed `then` block above, to include the closing brace on line 30. That - // changed the line count, but the coverage code region (for the `else if` condition) is - // still valid. - // - // Note that `if` (then) and `else` blocks include the closing brace in their coverage - // code regions when the last line in the block ends in a semicolon, because the Rust - // compiler inserts a `StatementKind::Assign` to assign `const ()` to a `Place`, for the - // empty value for the executed block. When the last line does not end in a semicolon - // (that is, when the block actually results in a value), the additional `Assign` is not - // generated, and the brace is not included. let mut countdown = 0; if true { countdown = 10; @@ -57,11 +45,6 @@ fn main() { if countdown > 7 { countdown -= 4; } - // The closing brace of the `then` branch is now included in the coverage region, and shown - // as "executed" (giving its line a count of 1 here). Since, in the original version above, - // the closing brace shares the same line as the `else if` conditional expression (which is - // not executed if the first `then` condition is true), only the condition's code region is - // marked with a count of 0 now. else if countdown > 2 { if countdown < 1 || countdown > 5 || countdown != 9 { countdown = 0; @@ -70,7 +53,8 @@ fn main() { } else { return; } - } + } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal + // `true` was const-evaluated. The compiler knows the `if` block will be executed. let mut countdown = 0; if true { diff --git a/src/test/run-make-fulldeps/coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk index 867a3566ac3..7dc485cd94d 100644 --- a/src/test/run-make-fulldeps/coverage/coverage_tools.mk +++ b/src/test/run-make-fulldeps/coverage/coverage_tools.mk @@ -2,39 +2,16 @@ # file with the line: # # -include ../instrument-coverage/coverage_tools.mk -# -# To enable the Rust compiler option `-C link-dead-code`, also set the following variable -# *BEFORE* the `-include` line: -# -# LINK_DEAD_CODE=yes -include ../tools.mk -ifndef LINK_DEAD_CODE - LINK_DEAD_CODE=no -endif - # ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and # `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw` # file, required for coverage reports. # -# Enabling `-C link-dead-code` is preferred when compiling with `-Z instrument-coverage`, so -# `-C link-dead-code` is automatically enabled for all platform targets _except_ MSVC. -# -# Making the state of `-C link-dead-code` platform-dependent creates a problem for cross-platform -# tests because the injected counters, coverage reports, and some low-level output can be different, -# depending on the `-C link-dead-code` setting. For example, coverage reports will not report any -# coverage for a dead code region when the `-C link-dead-code` option is disabled, but with the -# option enabled, those same regions will show coverage counter values (of zero, of course). -# -# To ensure cross-platform `-Z instrument-coverage` generate consistent output, the -# `-C link-dead-code` option is always explicitly enabled or disabled. -# -# Since tests that execute binaries enabled with both `-Z instrument-coverage` and -# `-C link-dead-code` are known to fail, those tests will need the `# ignore-msvc` setting. -# -# If and when the above issue is resolved, the `# ignore-msvc` option can be removed, and the -# tests can be simplified to always test with `-C link-dead-code`. +# Enabling `-C link-dead-code` is not necessary when compiling with `-Z instrument-coverage`, +# due to improvements in the coverage map generation, to add unreachable functions known to Rust. +# Therefore, `-C link-dead-code` is no longer automatically enabled. UNAME = $(shell uname) diff --git a/src/test/run-make-fulldeps/coverage/dead_code.rs b/src/test/run-make-fulldeps/coverage/dead_code.rs new file mode 100644 index 00000000000..a1285df0ec6 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/dead_code.rs @@ -0,0 +1,37 @@ +#![allow(unused_assignments, unused_variables)] + +pub fn unused_pub_fn_not_in_library() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} + +fn unused_fn() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} diff --git a/src/test/run-make-fulldeps/coverage/generics.rs b/src/test/run-make-fulldeps/coverage/generics.rs index f4e64026944..cbeda35d3b8 100644 --- a/src/test/run-make-fulldeps/coverage/generics.rs +++ b/src/test/run-make-fulldeps/coverage/generics.rs @@ -30,7 +30,11 @@ fn main() -> Result<(),u8> { if true { println!("Exiting with error..."); return Err(1); - } + } // The remaining lines below have no coverage because `if true` (with the constant literal + // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. + // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown + // in other tests, the lines below would have coverage (which would show they had `0` + // executions, assuming the condition still evaluated to `true`). let _ = Firework { strength: 1000 }; diff --git a/src/test/run-make-fulldeps/coverage/panic_unwind.rs b/src/test/run-make-fulldeps/coverage/panic_unwind.rs index 02fa01ab962..b6c0c080762 100644 --- a/src/test/run-make-fulldeps/coverage/panic_unwind.rs +++ b/src/test/run-make-fulldeps/coverage/panic_unwind.rs @@ -10,7 +10,7 @@ fn might_panic(should_panic: bool) { } } -fn main() -> Result<(),u8> { +fn main() -> Result<(), u8> { let mut countdown = 10; while countdown > 0 { if countdown == 1 { @@ -42,8 +42,8 @@ fn main() -> Result<(),u8> { // 5. The reason the coverage results actually show `panic!()` was called is most likely because // `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or // `Terminator`s that execute with a coverage counter before the panic and unwind occur. -// 6. By best practice, programs should not panic. By design, the coverage implementation will not -// incur additional cost (in program size and execution time) to improve coverage results for -// an event that is not supposted to happen. +// 6. Since the common practice is not to use `panic!()` for error handling, the coverage +// implementation avoids incurring an additional cost (in program size and execution time) to +// improve coverage results for an event that is generally not "supposed" to happen. // 7. FIXME(#78544): This issue describes a feature request for a proposed option to enable // more accurate coverage results for tests that intentionally panic. diff --git a/src/test/run-make-fulldeps/coverage/partial_eq.rs b/src/test/run-make-fulldeps/coverage/partial_eq.rs index 334fb3364cc..547026f9502 100644 --- a/src/test/run-make-fulldeps/coverage/partial_eq.rs +++ b/src/test/run-make-fulldeps/coverage/partial_eq.rs @@ -4,8 +4,8 @@ #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { major: usize, - minor: usize, - patch: usize, + minor: usize, // Count: 1 - `PartialOrd` compared `minor` values in 3.2.1 vs. 3.3.0 + patch: usize, // Count: 0 - `PartialOrd` was determined by `minor` (2 < 3) } impl Version { @@ -44,56 +44,3 @@ one expression, which is allowed, but the `function_source_hash` was only passed `function_source_hash` without a code region, if necessary. */ - -// FIXME(richkadel): It may be worth investigating why the coverage report for this test produces -// the following results: - -/* - -1. Why are their two counts below different characters (first and last) of `PartialOrd`, on line 17? - -2. Line 17 is counted twice, but the `::lt` instance shows a line count of 1? Is there a missing - line count with a different instance? Or was it really only called once? - -3. Line 20 shows another line count (of 1) for a line within a `struct` declaration (on only one of - its 3 fields). I doubt the specific field (`minor`) is relevant, but rather I suspect there's a - problem computing the file position here, for some reason. - - - 16| | - 17| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - ^1 ^1 ------------------- -|Unexecuted instantiation: ::gt ------------------- -|Unexecuted instantiation: ::le ------------------- -|Unexecuted instantiation: ::ge ------------------- -|::lt: -| 17| 1|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] ------------------- - 18| |pub struct Version { - 19| | major: usize, - 20| 1| minor: usize, - 21| | patch: usize, - 22| |} - 23| | - 24| |impl Version { - 25| | pub fn new(major: usize, minor: usize, patch: usize) -> Self { - 26| 2| Version { - 27| 2| major, - 28| 2| minor, - 29| 2| patch, - 30| 2| } - 31| 2| } - 32| |} - 33| | - 34| 1|fn main() { - 35| 1| let version_3_2_1 = Version::new(3, 2, 1); - 36| 1| let version_3_3_0 = Version::new(3, 3, 0); - 37| 1| - 38| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version -_3_3_0); - 39| 1|} -*/ diff --git a/src/test/run-make-fulldeps/coverage/while_early_ret.rs b/src/test/run-make-fulldeps/coverage/while_early_ret.rs index 14ba36238d6..1fcea9c85c4 100644 --- a/src/test/run-make-fulldeps/coverage/while_early_ret.rs +++ b/src/test/run-make-fulldeps/coverage/while_early_ret.rs @@ -40,8 +40,3 @@ fn main() -> Result<(),u8> { // and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program // without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical // to the coverage test for early returns, but this is a limitation that should be fixed. -// -// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`, -// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping -// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the -// problem exists on MSVC only). From d96f351fa36d31f2b95b1cd2ad37ceaed3d395a8 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 1 Dec 2020 23:01:26 -0800 Subject: [PATCH 170/274] Addressed feedback from 2020-12-01 Added one more test (two files) showing coverage of generics and unused functions across crates. Created and referenced new Issues, as requested. Added comments. Added a note about the possible effects of compiler options on LLVM coverage maps. --- .../src/coverageinfo/mapgen.rs | 19 + .../rustc_mir/src/transform/coverage/graph.rs | 4 +- .../rustc_mir/src/transform/coverage/mod.rs | 2 + .../rustc_mir/src/transform/coverage/spans.rs | 12 +- .../source-based-code-coverage.md | 2 + .../expected_export_coverage.async.json | 52 +-- .../expected_export_coverage.uses_crate.json | 85 +++++ .../expected_show_coverage.async.txt | 74 ++-- .../expected_show_coverage.partial_eq.txt | 15 + .../expected_show_coverage.uses_crate.txt | 69 ++++ .../expected_show_coverage_counters.async.txt | 81 +++-- ...cted_show_coverage_counters.uses_crate.txt | 80 +++++ ...osure#3}.-------.InstrumentCoverage.0.html | 4 +- ...block_on.-------.InstrumentCoverage.0.html | 326 +++++++++--------- ...osure#0}.-------.InstrumentCoverage.0.html | 79 +++++ .../async.m.-------.InstrumentCoverage.0.html | 74 ++++ ...ync.main.-------.InstrumentCoverage.0.html | 213 ++++++------ ...ate.main.-------.InstrumentCoverage.0.html | 151 ++++++++ ...function.-------.InstrumentCoverage.0.html | 119 +++++++ ...function.-------.InstrumentCoverage.0.html | 133 +++++++ ...function.-------.InstrumentCoverage.0.html | 119 +++++++ ...function.-------.InstrumentCoverage.0.html | 113 ++++++ ...function.-------.InstrumentCoverage.0.html | 133 +++++++ ...function.-------.InstrumentCoverage.0.html | 133 +++++++ src/test/run-make-fulldeps/coverage/async.rs | 3 + .../run-make-fulldeps/coverage/partial_eq.rs | 15 + .../coverage/used_crate/mod.rs | 43 +++ .../run-make-fulldeps/coverage/uses_crate.rs | 10 + 28 files changed, 1797 insertions(+), 366 deletions(-) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage/used_crate/mod.rs create mode 100644 src/test/run-make-fulldeps/coverage/uses_crate.rs diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index ced3f21f744..1c7e727f9b0 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -262,6 +262,10 @@ fn add_unreachable_coverage<'tcx>( tcx: TyCtxt<'tcx>, function_coverage_map: &mut FxHashMap, FunctionCoverage<'tcx>>, ) { + // FIXME(#79622): Can this solution be simplified and/or improved? Are there other sources + // of compiler state data that might help (or better sources that could be exposed, but + // aren't yet)? + // Note: If the crate *only* defines generic functions, there are no codegenerated non-generic // functions to add any unreachable code to. In this case, the unreachable code regions will // have no coverage, instead of having coverage with zero executions. @@ -359,6 +363,21 @@ fn add_unreachable_coverage<'tcx>( for def_id in unreachable_def_ids_by_file.remove(&covered_file_name).into_iter().flatten() { + // Note, this loop adds an unreachable code regions for each MIR-derived region. + // Alternatively, we could add a single code region for the maximum span of all + // code regions here. + // + // Observed downsides of this approach are: + // + // 1. The coverage results will appear inconsistent compared with the same (or + // similar) code in a function that is reached. + // 2. If the function is unreachable from one crate but reachable when compiling + // another referencing crate (such as a cross-crate reference to a + // generic function or inlined function), actual coverage regions overlaid + // on a single larger code span of `Zero` coverage can appear confusing or + // wrong. Chaning the unreachable coverage from a `code_region` to a + // `gap_region` can help, but still can look odd with `0` line counts for + // lines between executed (> 0) lines (such as for blank lines or comments). for ®ion in tcx.covered_code_regions(def_id) { function_coverage.add_unreachable_region(region.clone()); } diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs index 7db88a686a7..f79f0d32538 100644 --- a/compiler/rustc_mir/src/transform/coverage/graph.rs +++ b/compiler/rustc_mir/src/transform/coverage/graph.rs @@ -140,7 +140,9 @@ impl CoverageGraph { // The following `TerminatorKind`s are either not expected outside an unwind branch, // or they should not (under normal circumstances) branch. Coverage graphs are - // simplified by assuring coverage results are accurate for well-behaved programs. + // simplified by assuring coverage results are accurate for program executions that + // don't panic. + // // Programs that panic and unwind may record slightly inaccurate coverage results // for a coverage region containing the `Terminator` that began the panic. This // is as intended. (See Issue #78544 for a possible future option to support diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 18249530577..10f522d6746 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -499,6 +499,8 @@ fn fn_sig_and_body<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, ) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) { + // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back + // to HIR for it. let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); (hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id)) diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs index 38d66a442ad..6eb89754ee6 100644 --- a/compiler/rustc_mir/src/transform/coverage/spans.rs +++ b/compiler/rustc_mir/src/transform/coverage/spans.rs @@ -359,12 +359,12 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } // Async functions wrap a closure that implements the body to be executed. The enclosing - // function is initially called, posts the closure to the executor, and returns. To avoid - // showing the return from the enclosing function as a "covered" return from the closure, - // the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is excluded. The - // closure's `Return` is the only one that will be counted. This provides adequate - // coverage, and more intuitive counts. (Avoids double-counting the closing brace of the - // function body.) + // function is called and returns an `impl Future` without initially executing any of the + // body. To avoid showing the return from the enclosing function as a "covered" return from + // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is + // excluded. The closure's `Return` is the only one that will be counted. This provides + // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace + // of the function body.) let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() { last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi() } else { diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md index 95c2450ae57..9930bc67cd5 100644 --- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md @@ -76,6 +76,8 @@ $ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \ cargo build --example formatjson5 ``` +Note that some compiler options, combined with `-Zinstrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect. + ## Running the instrumented binary to generate raw coverage profiling data In the previous example, `cargo` generated the coverage-instrumented binary `formatjson5`: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json index 4cc6ea39425..794a2e38253 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json @@ -6,50 +6,50 @@ "filename": "../coverage/async.rs", "summary": { "functions": { - "count": 16, - "covered": 15, - "percent": 93.75 + "count": 17, + "covered": 16, + "percent": 94.11764705882352 }, "instantiations": { - "count": 16, - "covered": 15, - "percent": 93.75 + "count": 17, + "covered": 16, + "percent": 94.11764705882352 }, "lines": { - "count": 102, - "covered": 75, - "percent": 73.52941176470588 + "count": 105, + "covered": 77, + "percent": 73.33333333333333 }, "regions": { - "count": 76, - "covered": 35, - "notcovered": 41, - "percent": 46.05263157894737 + "count": 78, + "covered": 36, + "notcovered": 42, + "percent": 46.15384615384615 } } } ], "totals": { "functions": { - "count": 16, - "covered": 15, - "percent": 93.75 + "count": 17, + "covered": 16, + "percent": 94.11764705882352 }, "instantiations": { - "count": 16, - "covered": 15, - "percent": 93.75 + "count": 17, + "covered": 16, + "percent": 94.11764705882352 }, "lines": { - "count": 102, - "covered": 75, - "percent": 73.52941176470588 + "count": 105, + "covered": 77, + "percent": 73.33333333333333 }, "regions": { - "count": 76, - "covered": 35, - "notcovered": 41, - "percent": 46.05263157894737 + "count": 78, + "covered": 36, + "notcovered": 42, + "percent": 46.15384615384615 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json new file mode 100644 index 00000000000..6189c7b7b64 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json @@ -0,0 +1,85 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/used_crate/mod.rs", + "summary": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "lines": { + "count": 31, + "covered": 14, + "percent": 45.16129032258064 + }, + "regions": { + "count": 16, + "covered": 6, + "notcovered": 10, + "percent": 37.5 + } + } + }, + { + "filename": "../coverage/uses_crate.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 6, + "covered": 6, + "percent": 100 + }, + "regions": { + "count": 1, + "covered": 1, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "instantiations": { + "count": 5, + "covered": 5, + "percent": 100 + }, + "lines": { + "count": 37, + "covered": 20, + "percent": 54.054054054054056 + }, + "regions": { + "count": 17, + "covered": 7, + "notcovered": 10, + "percent": 41.17647058823529 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt index f6d02891eea..5c9dc0d22b5 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt @@ -93,39 +93,43 @@ 88| | } 89| 1|} 90| | - 91| 1|fn main() { - 92| 1| let _ = g(10); - 93| 1| let _ = h(9); - 94| 1| let mut future = Box::pin(i(8)); - 95| 1| j(7); - 96| 1| l(6); - 97| 1| executor::block_on(future.as_mut()); - 98| 1|} - 99| | - 100| |mod executor { - 101| | use core::{ - 102| | future::Future, - 103| | pin::Pin, - 104| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - 105| | }; - 106| | - 107| 1| pub fn block_on(mut future: F) -> F::Output { - 108| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - 109| 1| - 110| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( - 111| 1| |_| unimplemented!("clone"), - 112| 1| |_| unimplemented!("wake"), - 113| 1| |_| unimplemented!("wake_by_ref"), - 114| 1| |_| (), - 115| 1| ); - 116| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - 117| 1| let mut context = Context::from_waker(&waker); - 118| | - 119| | loop { - 120| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - 121| 1| break val; - 122| 0| } - 123| | } - 124| 1| } - 125| |} + 91| 1|async fn m(x: u8) -> u8 { x - 1 } + ^0 + 92| | + 93| 1|fn main() { + 94| 1| let _ = g(10); + 95| 1| let _ = h(9); + 96| 1| let mut future = Box::pin(i(8)); + 97| 1| j(7); + 98| 1| l(6); + 99| 1| let _ = m(5); + 100| 1| executor::block_on(future.as_mut()); + 101| 1|} + 102| | + 103| |mod executor { + 104| | use core::{ + 105| | future::Future, + 106| | pin::Pin, + 107| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 108| | }; + 109| | + 110| 1| pub fn block_on(mut future: F) -> F::Output { + 111| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 112| 1| + 113| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + 114| 1| |_| unimplemented!("clone"), + 115| 1| |_| unimplemented!("wake"), + 116| 1| |_| unimplemented!("wake_by_ref"), + 117| 1| |_| (), + 118| 1| ); + 119| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + 120| 1| let mut context = Context::from_waker(&waker); + 121| | + 122| | loop { + 123| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + 124| 1| break val; + 125| 0| } + 126| | } + 127| 1| } + 128| |} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt index c05cb36cd02..0fe124f12d9 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt @@ -45,4 +45,19 @@ 44| |`function_source_hash` without a code region, if necessary. 45| | 46| |*/ + 47| | + 48| |// FIXME(#79626): The derived traits get coverage, which is great, but some of the traits appear + 49| |// to get two coverage execution counts at different positions: + 50| |// + 51| |// ```text + 52| |// 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + 53| |// ^0 ^0 ^0 ^0 ^1 ^0 ^0^0 + 54| |// ```text + 55| |// + 56| |// `PartialEq`, `PartialOrd`, and `Ord` (and possibly `Eq`, if the trait name was longer than 2 + 57| |// characters) have counts at their first and last characters. + 58| |// + 59| |// Why is this? Why does `PartialOrd` have two values (1 and 0)? This must mean we are checking + 60| |// distinct coverages, so maybe we don't want to eliminate one of them. Should we merge them? + 61| |// If merged, do we lose some information? diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt new file mode 100644 index 00000000000..81b355a29ac --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -0,0 +1,69 @@ +../coverage/used_crate/mod.rs: + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |use std::fmt::Debug; + 4| | + 5| 1|pub fn used_function() { + 6| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 7| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 8| | // dependent conditions. + 9| 1| let is_true = std::env::args().len() == 1; + 10| 1| let mut countdown = 0; + 11| 1| if is_true { + 12| 1| countdown = 10; + 13| 1| } + ^0 + 14| 1| used_twice_generic_function("some str"); + 15| 1|} + 16| | + 17| 1|pub fn used_generic_function(arg: T) { + 18| 1| println!("used_generic_function with {:?}", arg); + 19| 1|} + 20| | + 21| 2|pub fn used_twice_generic_function(arg: T) { + 22| 2| println!("used_twice_generic_function with {:?}", arg); + 23| 2|} + ------------------ + | uses_crate::used_crate::used_twice_generic_function::>: + | 21| 1|pub fn used_twice_generic_function(arg: T) { + | 22| 1| println!("used_twice_generic_function with {:?}", arg); + | 23| 1|} + ------------------ + | uses_crate::used_crate::used_twice_generic_function::<&str>: + | 21| 1|pub fn used_twice_generic_function(arg: T) { + | 22| 1| println!("used_twice_generic_function with {:?}", arg); + | 23| 1|} + ------------------ + 24| | + 25| 0|pub fn unused_generic_function(arg: T) { + 26| 0| println!("unused_generic_function with {:?}", arg); + 27| 0|} + 28| | + 29| 0|pub fn unused_function() { + 30| 0| let is_true = std::env::args().len() == 1; + 31| 0| let mut countdown = 2; + 32| 0| if !is_true { + 33| 0| countdown = 20; + 34| 0| } + 35| 0|} + 36| | + 37| 0|fn unused_private_function() { + 38| 0| let is_true = std::env::args().len() == 1; + 39| 0| let mut countdown = 2; + 40| 0| if !is_true { + 41| 0| countdown = 20; + 42| 0| } + 43| 0|} + +../coverage/uses_crate.rs: + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |mod used_crate; + 4| | + 5| 1|fn main() { + 6| 1| used_crate::used_function(); + 7| 1| let some_vec = vec![1, 2, 3, 4]; + 8| 1| used_crate::used_generic_function(&some_vec); + 9| 1| used_crate::used_twice_generic_function(some_vec); + 10| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt index ce6ee3b1ed8..2fac0fea84b 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt @@ -26,18 +26,18 @@ Counter in file 0 77:14 -> 77:16, 0 Counter in file 0 78:14 -> 78:16, 0 Counter in file 0 79:14 -> 79:16, 0 Counter in file 0 81:1 -> 81:2, 0 +Counter in file 0 91:25 -> 91:34, 0 Counter in file 0 5:1 -> 5:25, #1 -Counter in file 0 21:1 -> 21:23, #1 -Counter in file 0 17:20 -> 17:21, #1 -Counter in file 0 67:5 -> 67:23, #1 -Counter in file 0 38:1 -> 38:19, #1 -Counter in file 0 13:20 -> 13:21, #1 -Counter in file 0 29:1 -> 29:22, #1 -Counter in file 0 91:1 -> 98:2, #1 Counter in file 0 5:25 -> 6:14, #1 Counter in file 0 7:9 -> 7:10, #2 Counter in file 0 9:9 -> 9:10, (#1 - #2) Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) +Counter in file 0 21:1 -> 21:23, #1 +Counter in file 0 67:5 -> 67:23, #1 +Counter in file 0 38:1 -> 38:19, #1 +Counter in file 0 29:1 -> 29:22, #1 +Counter in file 0 93:1 -> 101:2, #1 +Counter in file 0 91:1 -> 91:25, #1 Counter in file 0 38:19 -> 42:12, #1 Counter in file 0 43:9 -> 43:10, #3 Counter in file 0 43:14 -> 43:18, (#1 + 0) @@ -53,6 +53,7 @@ Counter in file 0 51:5 -> 52:18, #1 Counter in file 0 53:13 -> 53:14, #2 Counter in file 0 63:13 -> 63:14, (#1 - #2) Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2)) +Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 49:1 -> 68:12, #1 Counter in file 0 69:9 -> 69:10, #2 Counter in file 0 69:14 -> 69:27, (#1 + 0) @@ -68,17 +69,18 @@ Counter in file 0 86:14 -> 86:16, #2 Counter in file 0 87:14 -> 87:16, #3 Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2)))) Counter in file 0 17:1 -> 17:20, #1 +Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 66:5 -> 66:23, #1 -Counter in file 0 107:5 -> 117:54, #1 -Counter in file 0 120:32 -> 120:35, ((#1 + #2) - #2) -Counter in file 0 120:39 -> 120:73, (#1 + #2) -Counter in file 0 121:23 -> 121:26, (((#1 + #2) - #2) + 0) -Counter in file 0 122:14 -> 122:15, #2 -Counter in file 0 124:5 -> 124:6, (((#1 + #2) - #2) + 0) -Counter in file 0 114:17 -> 114:19, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 17:9 -> 17:10, #1 +Counter in file 0 117:17 -> 117:19, #1 Counter in file 0 17:9 -> 17:10, #1 +Counter in file 0 110:5 -> 120:54, #1 +Counter in file 0 123:32 -> 123:35, ((#1 + #2) - #2) +Counter in file 0 123:39 -> 123:73, (#1 + #2) +Counter in file 0 124:23 -> 124:26, (((#1 + #2) - #2) + 0) +Counter in file 0 125:14 -> 125:15, #2 +Counter in file 0 127:5 -> 127:6, (((#1 + #2) - #2) + 0) Emitting segments for file: ../coverage/async.rs Combined regions: 5:1 -> 5:25 (count=1) @@ -149,14 +151,16 @@ Combined regions: 86:14 -> 86:16 (count=0) 87:14 -> 87:16 (count=1) 89:1 -> 89:2 (count=1) - 91:1 -> 98:2 (count=1) - 107:5 -> 117:54 (count=1) - 114:17 -> 114:19 (count=1) - 120:32 -> 120:35 (count=1) - 120:39 -> 120:73 (count=1) - 121:23 -> 121:26 (count=1) - 122:14 -> 122:15 (count=0) - 124:5 -> 124:6 (count=1) + 91:1 -> 91:25 (count=1) + 91:25 -> 91:34 (count=0) + 93:1 -> 101:2 (count=1) + 110:5 -> 120:54 (count=1) + 117:17 -> 117:19 (count=1) + 123:32 -> 123:35 (count=1) + 123:39 -> 123:73 (count=1) + 124:23 -> 124:26 (count=1) + 125:14 -> 125:15 (count=0) + 127:5 -> 127:6 (count=1) Segment at 5:1 (count = 1), RegionEntry Segment at 5:25 (count = 1), RegionEntry Segment at 6:14 (count = 0), Skipped @@ -287,18 +291,21 @@ Segment at 87:16 (count = 0), Skipped Segment at 89:1 (count = 1), RegionEntry Segment at 89:2 (count = 0), Skipped Segment at 91:1 (count = 1), RegionEntry -Segment at 98:2 (count = 0), Skipped -Segment at 107:5 (count = 1), RegionEntry -Segment at 114:17 (count = 1), RegionEntry -Segment at 114:19 (count = 1) -Segment at 117:54 (count = 0), Skipped -Segment at 120:32 (count = 1), RegionEntry -Segment at 120:35 (count = 0), Skipped -Segment at 120:39 (count = 1), RegionEntry -Segment at 120:73 (count = 0), Skipped -Segment at 121:23 (count = 1), RegionEntry -Segment at 121:26 (count = 0), Skipped -Segment at 122:14 (count = 0), RegionEntry -Segment at 122:15 (count = 0), Skipped -Segment at 124:5 (count = 1), RegionEntry -Segment at 124:6 (count = 0), Skipped +Segment at 91:25 (count = 0), RegionEntry +Segment at 91:34 (count = 0), Skipped +Segment at 93:1 (count = 1), RegionEntry +Segment at 101:2 (count = 0), Skipped +Segment at 110:5 (count = 1), RegionEntry +Segment at 117:17 (count = 1), RegionEntry +Segment at 117:19 (count = 1) +Segment at 120:54 (count = 0), Skipped +Segment at 123:32 (count = 1), RegionEntry +Segment at 123:35 (count = 0), Skipped +Segment at 123:39 (count = 1), RegionEntry +Segment at 123:73 (count = 0), Skipped +Segment at 124:23 (count = 1), RegionEntry +Segment at 124:26 (count = 0), Skipped +Segment at 125:14 (count = 0), RegionEntry +Segment at 125:15 (count = 0), Skipped +Segment at 127:5 (count = 1), RegionEntry +Segment at 127:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt new file mode 100644 index 00000000000..8901019f191 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt @@ -0,0 +1,80 @@ +Counter in file 0 17:1 -> 19:2, #1 +Counter in file 0 25:1 -> 27:2, 0 +Counter in file 0 29:1 -> 32:16, 0 +Counter in file 0 32:17 -> 34:6, 0 +Counter in file 0 34:6 -> 34:7, 0 +Counter in file 0 35:1 -> 35:2, 0 +Counter in file 0 37:1 -> 40:16, 0 +Counter in file 0 40:17 -> 42:6, 0 +Counter in file 0 42:6 -> 42:7, 0 +Counter in file 0 43:1 -> 43:2, 0 +Counter in file 0 5:1 -> 5:24, #1 +Counter in file 0 9:9 -> 11:15, (#1 + 0) +Counter in file 0 11:16 -> 13:6, #2 +Counter in file 0 13:6 -> 13:7, (#1 - #2) +Counter in file 0 14:5 -> 15:2, (#2 + (#1 - #2)) +Counter in file 0 21:1 -> 23:2, #1 +Counter in file 0 21:1 -> 23:2, #1 +Counter in file 0 5:1 -> 10:2, #1 +Emitting segments for file: ../coverage/used_crate/mod.rs +Combined regions: + 5:1 -> 5:24 (count=1) + 9:9 -> 11:15 (count=1) + 11:16 -> 13:6 (count=1) + 13:6 -> 13:7 (count=0) + 14:5 -> 15:2 (count=1) + 17:1 -> 19:2 (count=1) + 21:1 -> 23:2 (count=2) + 25:1 -> 27:2 (count=0) + 29:1 -> 32:16 (count=0) + 32:17 -> 34:6 (count=0) + 34:6 -> 34:7 (count=0) + 35:1 -> 35:2 (count=0) + 37:1 -> 40:16 (count=0) + 40:17 -> 42:6 (count=0) + 42:6 -> 42:7 (count=0) + 43:1 -> 43:2 (count=0) +Segment at 5:1 (count = 1), RegionEntry +Segment at 5:24 (count = 0), Skipped +Segment at 9:9 (count = 1), RegionEntry +Segment at 11:15 (count = 0), Skipped +Segment at 11:16 (count = 1), RegionEntry +Segment at 13:6 (count = 0), RegionEntry +Segment at 13:7 (count = 0), Skipped +Segment at 14:5 (count = 1), RegionEntry +Segment at 15:2 (count = 0), Skipped +Segment at 17:1 (count = 1), RegionEntry +Segment at 19:2 (count = 0), Skipped +Segment at 21:1 (count = 2), RegionEntry +Segment at 23:2 (count = 0), Skipped +Segment at 25:1 (count = 0), RegionEntry +Segment at 27:2 (count = 0), Skipped +Segment at 29:1 (count = 0), RegionEntry +Segment at 32:16 (count = 0), Skipped +Segment at 32:17 (count = 0), RegionEntry +Segment at 34:6 (count = 0), RegionEntry +Segment at 34:7 (count = 0), Skipped +Segment at 35:1 (count = 0), RegionEntry +Segment at 35:2 (count = 0), Skipped +Segment at 37:1 (count = 0), RegionEntry +Segment at 40:16 (count = 0), Skipped +Segment at 40:17 (count = 0), RegionEntry +Segment at 42:6 (count = 0), RegionEntry +Segment at 42:7 (count = 0), Skipped +Segment at 43:1 (count = 0), RegionEntry +Segment at 43:2 (count = 0), Skipped +Emitting segments for function: _RINvNtCs4fqI2P2rA04_10uses_crate10used_crate27used_twice_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEEB4_ +Combined regions: + 21:1 -> 23:2 (count=1) +Segment at 21:1 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped +Emitting segments for function: _RINvNtCs4fqI2P2rA04_10uses_crate10used_crate27used_twice_generic_functionReEB4_ +Combined regions: + 21:1 -> 23:2 (count=1) +Segment at 21:1 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped +Emitting segments for file: ../coverage/uses_crate.rs +Combined regions: + 5:1 -> 10:2 (count=1) +Segment at 5:1 (count = 1), RegionEntry +Segment at 10:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html index 996c537225d..ef2fe7d0682 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ -
|_| @0⦊()⦉@0
+
|_| @0⦊()⦉@0
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html index 0c597d40de0..81310c8cb25 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html @@ -69,171 +69,171 @@ -
@0,1,2,3,4,5⦊pub fn block_on<F: Future>(mut future: F) -> F::Output { - let mut future = unsafe { Pin::new_unchecked(&mut future) }; - - static VTABLE: RawWakerVTable = RawWakerVTable::new( - |_| unimplemented!("clone"), - |_| unimplemented!("wake"), - |_| unimplemented!("wake_by_ref"), - |_| (), - ); - let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; +
@0,1,2,3,4,5⦊pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; loop { - if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { - break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; - }@11,13⦊⦉@11,13 + if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { + break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; + }@11,13⦊⦉@11,13 } - }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
+ }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..9cf86ce34a0 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,79 @@ + + + + +async.m-{closure#0} - Coverage Spans + + + +
@0,1⦊{ x - 1 }⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..04412c1d994 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.m - Coverage Spans + + + +
@0,1⦊async fn m(x: u8) -> u8 ⦉@0,1{ x - 1 }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html index 2b0eb4f43c7..313a36ed6c2 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html @@ -69,101 +69,122 @@ -
@0,1,2,3,4,5,6,7,8,9,10,11⦊fn main() { - let _ = g(10); - let _ = h(9); - let mut future = Box::pin(i(8)); - j(7); - l(6); - executor::block_on(future.as_mut()); -}⦉@0,1,2,3,4,5,6,7,8,9,10,11
+
@0,1,2,3,4,5,6,7,8,9,10,11,12,13⦊fn main() { + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + j(7); + l(6); + let _ = m(5); + executor::block_on(future.as_mut()); +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..52c99558de6 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,151 @@ + + + + +uses_crate.main - Coverage Spans + + + +
@0,1,2,3,4,5,6,7⦊fn main() { + used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; + used_crate::used_generic_function(&some_vec); + used_crate::used_twice_generic_function(some_vec); +}⦉@0,1,2,3,4,5,6,7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..42ba0458349 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,119 @@ + + + + +uses_crate.used_crate-unused_function - Coverage Spans + + + +
@0,1,2,3⦊pub fn unused_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 20; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..d89963a32ce --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +uses_crate.used_crate-unused_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn unused_generic_function<T: Debug>(arg: T) { + println!("unused_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..10e71152c53 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,119 @@ + + + + +uses_crate.used_crate-unused_private_function - Coverage Spans + + + +
@0,1,2,3⦊fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 20; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..15dce97e742 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,113 @@ + + + + +uses_crate.used_crate-used_function - Coverage Spans + + + +
@0,1,2,3⦊pub fn used_function() ⦉@0,1,2,3{ + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6@5⦊⦉@5 + @7,8⦊used_twice_generic_function("some str"); +}⦉@7,8
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..e47ed0b3817 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +uses_crate.used_crate-used_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_generic_function<T: Debug>(arg: T) { + println!("used_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..ef63db45cc0 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +uses_crate.used_crate-used_twice_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_twice_generic_function<T: Debug>(arg: T) { + println!("used_twice_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage/async.rs b/src/test/run-make-fulldeps/coverage/async.rs index fcf6f76944e..491d2746543 100644 --- a/src/test/run-make-fulldeps/coverage/async.rs +++ b/src/test/run-make-fulldeps/coverage/async.rs @@ -88,12 +88,15 @@ fn l(x: u8) { } } +async fn m(x: u8) -> u8 { x - 1 } + fn main() { let _ = g(10); let _ = h(9); let mut future = Box::pin(i(8)); j(7); l(6); + let _ = m(5); executor::block_on(future.as_mut()); } diff --git a/src/test/run-make-fulldeps/coverage/partial_eq.rs b/src/test/run-make-fulldeps/coverage/partial_eq.rs index 547026f9502..7d265ba66a4 100644 --- a/src/test/run-make-fulldeps/coverage/partial_eq.rs +++ b/src/test/run-make-fulldeps/coverage/partial_eq.rs @@ -44,3 +44,18 @@ one expression, which is allowed, but the `function_source_hash` was only passed `function_source_hash` without a code region, if necessary. */ + +// FIXME(#79626): The derived traits get coverage, which is great, but some of the traits appear +// to get two coverage execution counts at different positions: +// +// ```text +// 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +// ^0 ^0 ^0 ^0 ^1 ^0 ^0^0 +// ```text +// +// `PartialEq`, `PartialOrd`, and `Ord` (and possibly `Eq`, if the trait name was longer than 2 +// characters) have counts at their first and last characters. +// +// Why is this? Why does `PartialOrd` have two values (1 and 0)? This must mean we are checking +// distinct coverages, so maybe we don't want to eliminate one of them. Should we merge them? +// If merged, do we lose some information? diff --git a/src/test/run-make-fulldeps/coverage/used_crate/mod.rs b/src/test/run-make-fulldeps/coverage/used_crate/mod.rs new file mode 100644 index 00000000000..825eff4d352 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/used_crate/mod.rs @@ -0,0 +1,43 @@ +#![allow(unused_assignments, unused_variables)] + +use std::fmt::Debug; + +pub fn used_function() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true { + countdown = 10; + } + used_twice_generic_function("some str"); +} + +pub fn used_generic_function(arg: T) { + println!("used_generic_function with {:?}", arg); +} + +pub fn used_twice_generic_function(arg: T) { + println!("used_twice_generic_function with {:?}", arg); +} + +pub fn unused_generic_function(arg: T) { + println!("unused_generic_function with {:?}", arg); +} + +pub fn unused_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} diff --git a/src/test/run-make-fulldeps/coverage/uses_crate.rs b/src/test/run-make-fulldeps/coverage/uses_crate.rs new file mode 100644 index 00000000000..473d43217a9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/uses_crate.rs @@ -0,0 +1,10 @@ +#![allow(unused_assignments, unused_variables)] + +mod used_crate; + +fn main() { + used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; + used_crate::used_generic_function(&some_vec); + used_crate::used_twice_generic_function(some_vec); +} From b0c140a55b589680bbcd76d18fae9f411a7af0c5 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 2 Dec 2020 09:43:46 -0800 Subject: [PATCH 171/274] Workaround for inconsistent order of llvm-cov results on Windows --- .../coverage-reports/Makefile | 39 ++++++++++++++++ .../expected_export_coverage.uses_crate.json | 46 ++++--------------- .../expected_show_coverage.uses_crate.txt | 13 ------ ...cted_show_coverage_counters.uses_crate.txt | 5 -- 4 files changed, 49 insertions(+), 54 deletions(-) diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 0902ad74051..91390f6cc02 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -22,6 +22,43 @@ ifeq ($(LLVM_COV_DEBUG), 1) DEBUG_FLAG=--debug endif +# FIXME(richkadel): I'm adding `--ignore-filename-regex=` line(s) for specific test(s) that produce +# `llvm-cov` results for multiple files (for example `uses_crate.rs` and `used_crate/mod.rs`) as a +# workaround for two problems causing tests to fail on Windows: +# +# 1. When multiple files appear in the `llvm-cov show` results, each file's coverage results can +# appear in different a different order. Whether this is random or, somehow, platform-specific, +# the Windows output flips the order of the files, compared to Linux. In the `uses_crate.rs` +# test, the only test-unique (interesting) results we care about are the results for only one +# of the two files, `mod/uses_crate.rs`, so the workaround is to ignore all but this one file. +# In the future, we may want a more sophisticated solution that splits apart `llvm-cov show` +# results into separate results files for each result (taking care not to create new file +# paths that might be too long for Windows MAX_PATH limits when creating these new sub-results, +# as well). +# 2. When multiple files appear in the `llvm-cov show` results, the results for each file are +# prefixed with their filename, including platform-specific path separators (`\` for Windows, +# and `/` everywhere else). This could be filtered or normalized of course, but by ignoring +# coverage results for all but one of the file, the filenames are no longer included anyway. +# If this changes (if/when we decide to support `llvm-cov show` results for multiple files), +# the file path separator differences may need to be addressed. +# +# Since this is only a workaround, I decided to implement the override by adding an option for +# each file to be ignored, using a `--ignore-filename-regex=` entry for each one, rather than +# implement some more sophisticated solution with a new custom test directive in the test file +# itself (similar to `expect-exit-status`) because that would add a lot of complexity and still +# be a workaround, with the same result, with no benefit. +# +# Yes these `--ignore-filename-regex=` options are included in all invocations of `llvm-cov show` +# for now, but it is effectively ignored for all tests that don't include this file anyway. +# +# Note that it's also possible the `_counters..txt` and `.json` files may order +# results from multiple files inconsistently, which might also have to be accomodated if and when +# we allow `llvm-cov` to produce results for multiple files. (The path separators appear to be +# normalized to `/` in those files, thankfully.) But since we are ignoring results for all but one +# file, this workaround addresses those potential issues as well. +LLVM_COV_IGNORE_FILES=\ + --ignore-filename-regex=uses_crate.rs + # When generating `expected_*` results (using `x.py test --bless`), the `--debug` flag is forced. # If assertions are disabled, the command will fail with an error, rather than attempt to generate # only partial results. @@ -76,6 +113,7 @@ endif # Generate a coverage report using `llvm-cov show`. "$(LLVM_BIN_DIR)"/llvm-cov show \ $(DEBUG_FLAG) \ + $(LLVM_COV_IGNORE_FILES) \ --Xdemangler="$(RUST_DEMANGLER)" \ --show-line-counts-or-regions \ --instr-profile="$(TMPDIR)"/$@.profdata \ @@ -133,6 +171,7 @@ endif # Generate a coverage report in JSON, using `llvm-cov export`, and fail if # there are differences from the expected output. "$(LLVM_BIN_DIR)"/llvm-cov export \ + $(LLVM_COV_IGNORE_FILES) \ --summary-only \ --instr-profile="$(TMPDIR)"/$@.profdata \ $(call BIN,"$(TMPDIR)"/$@) \ diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json index 6189c7b7b64..fc0d7db7c29 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json @@ -27,55 +27,29 @@ "percent": 37.5 } } - }, - { - "filename": "../coverage/uses_crate.rs", - "summary": { - "functions": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "instantiations": { - "count": 1, - "covered": 1, - "percent": 100 - }, - "lines": { - "count": 6, - "covered": 6, - "percent": 100 - }, - "regions": { - "count": 1, - "covered": 1, - "notcovered": 0, - "percent": 100 - } - } } ], "totals": { "functions": { - "count": 4, - "covered": 4, + "count": 3, + "covered": 3, "percent": 100 }, "instantiations": { - "count": 5, - "covered": 5, + "count": 4, + "covered": 4, "percent": 100 }, "lines": { - "count": 37, - "covered": 20, - "percent": 54.054054054054056 + "count": 31, + "covered": 14, + "percent": 45.16129032258064 }, "regions": { - "count": 17, - "covered": 7, + "count": 16, + "covered": 6, "notcovered": 10, - "percent": 41.17647058823529 + "percent": 37.5 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index 81b355a29ac..ad1bdb5d6a5 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -1,4 +1,3 @@ -../coverage/used_crate/mod.rs: 1| |#![allow(unused_assignments, unused_variables)] 2| | 3| |use std::fmt::Debug; @@ -55,15 +54,3 @@ 42| 0| } 43| 0|} -../coverage/uses_crate.rs: - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| |mod used_crate; - 4| | - 5| 1|fn main() { - 6| 1| used_crate::used_function(); - 7| 1| let some_vec = vec![1, 2, 3, 4]; - 8| 1| used_crate::used_generic_function(&some_vec); - 9| 1| used_crate::used_twice_generic_function(some_vec); - 10| 1|} - diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt index 8901019f191..e8be1e685e6 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt @@ -73,8 +73,3 @@ Combined regions: 21:1 -> 23:2 (count=1) Segment at 21:1 (count = 1), RegionEntry Segment at 23:2 (count = 0), Skipped -Emitting segments for file: ../coverage/uses_crate.rs -Combined regions: - 5:1 -> 10:2 (count=1) -Segment at 5:1 (count = 1), RegionEntry -Segment at 10:2 (count = 0), Skipped From f101fd8ff62431927d19c70a06a68483cce37c1f Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 2 Dec 2020 15:39:40 -0800 Subject: [PATCH 172/274] Fixed cross-crate generic call test to compile lib and bin separately The original test produced a single crate with two mods, which was not the goal of the test. --- .../coverage-reports/Makefile | 31 ++- .../expected_export_coverage.uses_crate.json | 54 ++--- .../expected_show_coverage.async.txt | 2 +- .../expected_show_coverage.if_else.txt | 2 +- .../expected_show_coverage.inner_items.txt | 2 +- ...xpected_show_coverage.loop_break_value.txt | 2 +- .../expected_show_coverage.loops_branches.txt | 2 +- .../expected_show_coverage.simple_match.txt | 2 +- .../expected_show_coverage.uses_crate.txt | 130 ++++++++++-- .../expected_show_coverage_counters.async.txt | 12 +- ...cted_show_coverage_counters.uses_crate.txt | 91 ++++++--- .../coverage-spanview/Makefile | 39 +++- ...unction.-------.InstrumentCoverage.0.html} | 6 +- ...function.-------.InstrumentCoverage.0.html | 133 ++++++++++++ ...unction.-------.InstrumentCoverage.0.html} | 96 ++++----- ...ib_crate.-------.InstrumentCoverage.0.html | 190 ++++++++++++++++++ ...function.-------.InstrumentCoverage.0.html | 133 ++++++++++++ ...unction.-------.InstrumentCoverage.0.html} | 10 +- ...function.-------.InstrumentCoverage.0.html | 133 ++++++++++++ ...function.-------.InstrumentCoverage.0.html | 133 ++++++++++++ ...function.-------.InstrumentCoverage.0.html | 133 ++++++++++++ ...ate.main.-------.InstrumentCoverage.0.html | 138 ++++++++----- ...function.-------.InstrumentCoverage.0.html | 133 ------------ ...function.-------.InstrumentCoverage.0.html | 133 ------------ ...function.-------.InstrumentCoverage.0.html | 133 ------------ src/test/run-make-fulldeps/coverage/async.rs | 2 +- .../run-make-fulldeps/coverage/if_else.rs | 2 +- .../run-make-fulldeps/coverage/inner_items.rs | 2 +- .../coverage/lib/used_crate.rs | 104 ++++++++++ .../coverage/loop_break_value.rs | 2 +- .../coverage/loops_branches.rs | 2 +- .../coverage/simple_match.rs | 2 +- .../coverage/used_crate/mod.rs | 43 ---- .../run-make-fulldeps/coverage/uses_crate.rs | 8 +- 34 files changed, 1390 insertions(+), 650 deletions(-) rename src/test/run-make-fulldeps/coverage-spanview/{expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html => expected_mir_dump.used_crate/used_crate.unused_function.-------.InstrumentCoverage.0.html} (95%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_generic_function.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/coverage-spanview/{expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html => expected_mir_dump.used_crate/used_crate.unused_private_function.-------.InstrumentCoverage.0.html} (53%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html rename src/test/run-make-fulldeps/coverage-spanview/{expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html => expected_mir_dump.used_crate/used_crate.used_function.-------.InstrumentCoverage.0.html} (91%) create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_bin_crate_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_this_lib_crate_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html delete mode 100644 src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html create mode 100644 src/test/run-make-fulldeps/coverage/lib/used_crate.rs delete mode 100644 src/test/run-make-fulldeps/coverage/used_crate/mod.rs diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 91390f6cc02..89d5974d73c 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -67,7 +67,7 @@ DEBUG_FLAG=--debug endif ifeq ($(LLVM_VERSION_11_PLUS),true) -all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) +all: $(patsubst $(SOURCEDIR)/lib/%.rs,%,$(wildcard $(SOURCEDIR)/lib/*.rs)) $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) else $(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.) all: @@ -84,12 +84,22 @@ endif -include clear_expected_if_blessed +%: $(SOURCEDIR)/lib/%.rs + # Compile the test library with coverage instrumentation + $(RUSTC) $(SOURCEDIR)/lib/$@.rs \ + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/lib/$@.rs && \ + echo "--edition=2018" \ + ) \ + --crate-type rlib \ + -Zinstrument-coverage + %: $(SOURCEDIR)/%.rs - # Compile the test program with coverage instrumentation and generate relevant MIR. + # Compile the test program with coverage instrumentation $(RUSTC) $(SOURCEDIR)/$@.rs \ $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && \ echo "--edition=2018" \ ) \ + -L "$(TMPDIR)" \ -Zinstrument-coverage # Run it in order to generate some profiling data, @@ -142,8 +152,17 @@ else # Compare the show coverage output (`--bless` refreshes `typical` files) # Note `llvm-cov show` output for some programs can vary, but can be ignored # by inserting `// ignore-llvm-cov-show-diffs` at the top of the source file. - - $(DIFF) expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ + # + # FIXME(richkadel): It looks like most past variations seem to have been mitigated. None of the + # Rust test source samples have the `// ignore-llvm-cov-show-diffs` anymore. The main variation + # I had seen (and is still present in the new `coverage/lib/used_crate.rs`) is the `llvm-cov show` + # reporting of multiple instantiations of a generic function with different type substitutions. + # For some reason, `llvm-cov show` can report these in a non-deterministic order, breaking the + # `diff` comparision. I was able to work around the problem with `diff --ignore-matching-lines=RE` + # to ignore each line prefixing each generic instantiation coverage code region. + + $(DIFF) --ignore-matching-lines='::<.*>.*:$$' \ + expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ ( grep -q '^\/\/ ignore-llvm-cov-show-diffs' $(SOURCEDIR)/$@.rs && \ >&2 echo 'diff failed, but suppressed with `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs' \ ) || \ @@ -177,6 +196,10 @@ endif $(call BIN,"$(TMPDIR)"/$@) \ | "$(PYTHON)" $(BASEDIR)/prettify_json.py \ > "$(TMPDIR)"/actual_export_coverage.$@.json + # FIXME(richkadel): With the addition of `--ignore-matching-lines=RE` to ignore the + # non-deterministically-ordered coverage results for multiple instantiations of generics with + # differing type substitutions, I probably don't need the `.json` files anymore (and may not + # need `prettify_json.py` either). ifdef RUSTC_BLESS_TEST cp "$(TMPDIR)"/actual_export_coverage.$@.json expected_export_coverage.$@.json diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json index fc0d7db7c29..35ddd58fc43 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json @@ -3,53 +3,53 @@ { "files": [ { - "filename": "../coverage/used_crate/mod.rs", + "filename": "../coverage/lib/used_crate.rs", "summary": { "functions": { - "count": 3, - "covered": 3, - "percent": 100 + "count": 6, + "covered": 5, + "percent": 83.33333333333334 }, "instantiations": { - "count": 4, - "covered": 4, - "percent": 100 + "count": 10, + "covered": 8, + "percent": 80 }, "lines": { - "count": 31, - "covered": 14, - "percent": 45.16129032258064 + "count": 46, + "covered": 26, + "percent": 56.52173913043478 }, "regions": { - "count": 16, - "covered": 6, - "notcovered": 10, - "percent": 37.5 + "count": 19, + "covered": 8, + "notcovered": 11, + "percent": 42.10526315789473 } } } ], "totals": { "functions": { - "count": 3, - "covered": 3, - "percent": 100 + "count": 6, + "covered": 5, + "percent": 83.33333333333334 }, "instantiations": { - "count": 4, - "covered": 4, - "percent": 100 + "count": 10, + "covered": 8, + "percent": 80 }, "lines": { - "count": 31, - "covered": 14, - "percent": 45.16129032258064 + "count": 46, + "covered": 26, + "percent": 56.52173913043478 }, "regions": { - "count": 16, - "covered": 6, - "notcovered": 10, - "percent": 37.5 + "count": 19, + "covered": 8, + "notcovered": 11, + "percent": 42.10526315789473 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt index 5c9dc0d22b5..824bddaa401 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt @@ -1,4 +1,4 @@ - 1| |#![allow(unused_assignments)] + 1| |#![allow(unused_assignments, dead_code)] 2| | 3| |// require-rust-edition-2018 4| | diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt index 77113ada103..4285d318686 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt @@ -1,4 +1,4 @@ - 1| |#![allow(unused_assignments)] + 1| |#![allow(unused_assignments, unused_variables)] 2| | 3| 1|fn main() { 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt index db2a19ac4bf..f5b5184044f 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt @@ -1,4 +1,4 @@ - 1| |#![allow(unused_assignments, unused_variables)] + 1| |#![allow(unused_assignments, unused_variables, dead_code)] 2| | 3| 1|fn main() { 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt index b0d668c6d76..022fe4c5962 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt @@ -1,4 +1,4 @@ - 1| |#![allow(unused_assignments)] + 1| |#![allow(unused_assignments, unused_variables)] 2| | 3| 1|fn main() { 4| 1| let result diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt index 135b7b67034..474f02b7007 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt @@ -1,4 +1,4 @@ - 1| |#![allow(unused_assignments)] + 1| |#![allow(unused_assignments, unused_variables, while_true)] 2| | 3| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the 4| |// structure of this `fmt` function. diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt index 336853b96f3..81b4c090a46 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt @@ -1,4 +1,4 @@ - 1| |#![allow(unused_assignments)] + 1| |#![allow(unused_assignments, unused_variables)] 2| | 3| 1|fn main() { 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index ad1bdb5d6a5..e14e733fff6 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -12,45 +12,131 @@ 12| 1| countdown = 10; 13| 1| } ^0 - 14| 1| used_twice_generic_function("some str"); + 14| 1| use_this_lib_crate(); 15| 1|} 16| | - 17| 1|pub fn used_generic_function(arg: T) { - 18| 1| println!("used_generic_function with {:?}", arg); - 19| 1|} + 17| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { + 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + 19| 2|} + ------------------ + | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 19| 1|} + ------------------ + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 19| 1|} + ------------------ 20| | - 21| 2|pub fn used_twice_generic_function(arg: T) { - 22| 2| println!("used_twice_generic_function with {:?}", arg); + 21| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 23| 2|} ------------------ - | uses_crate::used_crate::used_twice_generic_function::>: - | 21| 1|pub fn used_twice_generic_function(arg: T) { - | 22| 1| println!("used_twice_generic_function with {:?}", arg); + | used_crate::used_only_from_this_lib_crate_generic_function::>: + | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} ------------------ - | uses_crate::used_crate::used_twice_generic_function::<&str>: - | 21| 1|pub fn used_twice_generic_function(arg: T) { - | 22| 1| println!("used_twice_generic_function with {:?}", arg); + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} ------------------ 24| | - 25| 0|pub fn unused_generic_function(arg: T) { - 26| 0| println!("unused_generic_function with {:?}", arg); - 27| 0|} + 25| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + 26| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + 27| 2|} + ------------------ + | used_crate::used_from_bin_crate_and_lib_crate_generic_function::>: + | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 27| 1|} + ------------------ + | used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: + | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 27| 1|} + ------------------ 28| | - 29| 0|pub fn unused_function() { - 30| 0| let is_true = std::env::args().len() == 1; - 31| 0| let mut countdown = 2; - 32| 0| if !is_true { - 33| 0| countdown = 20; - 34| 0| } + 29| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + 30| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + 31| 2|} + 32| | + 33| 0|pub fn unused_generic_function(arg: T) { + 34| 0| println!("unused_generic_function with {:?}", arg); 35| 0|} 36| | - 37| 0|fn unused_private_function() { + 37| 0|pub fn unused_function() { 38| 0| let is_true = std::env::args().len() == 1; 39| 0| let mut countdown = 2; 40| 0| if !is_true { 41| 0| countdown = 20; 42| 0| } 43| 0|} + 44| | + 45| 0|fn unused_private_function() { + 46| 0| let is_true = std::env::args().len() == 1; + 47| 0| let mut countdown = 2; + 48| 0| if !is_true { + 49| 0| countdown = 20; + 50| 0| } + 51| 0|} + 52| | + 53| 1|fn use_this_lib_crate() { + 54| 1| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + 55| 1| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + 56| 1| "used from library used_crate.rs", + 57| 1| ); + 58| 1| let some_vec = vec![5, 6, 7, 8]; + 59| 1| used_only_from_this_lib_crate_generic_function(some_vec); + 60| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); + 61| 1|} + ------------------ + | Unexecuted instantiation: used_crate::use_this_lib_crate + ------------------ + 62| | + 63| |// FIXME(#79651): `used_from_bin_crate_and_lib_crate_generic_function()` is covered and executed + 64| |// `2` times, but the coverage output also shows (at the bottom of the coverage report): + 65| |// ------------------ + 66| |// | Unexecuted instantiation: + 67| |// ------------------ + 68| |// + 69| |// Note, the function name shown in the error seems to change depending on the structure of the + 70| |// code, for some reason, including: + 71| |// + 72| |// * used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str> + 73| |// * used_crate::use_this_lib_crate + 74| |// + 75| |// The `Unexecuted instantiation` error may be related to more than one generic function. Since the + 76| |// reporting is not consistent, it may not be obvious if there are multiple problems here; however, + 77| |// `used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>` (which I have seen + 78| |// with this error) is the only generic function missing instantiaion coverage counts. + 79| |// + 80| |// The `&str` variant was called from within this `lib` crate, and the `bin` crate also calls this + 81| |// function, but with `T` type `&Vec`. + 82| |// + 83| |// I believe the reason is that one or both crates are generating `Zero` counters for what it + 84| |// believes are "Unreachable" instantiations, but those instantiations are counted from the + 85| |// coverage map in the other crate. + 86| |// + 87| |// See `add_unreachable_coverage()` in `mapgen.rs` for more on how these `Zero` counters are added + 88| |// for what the funciton believes are `DefId`s that did not get codegenned. I suspect the issue + 89| |// may be related to this process, but this needs to be confirmed. It may not be possible to know + 90| |// for sure if a function is truly unused and should be reported with `Zero` coverage if it may + 91| |// still get used from an external crate. (Something to look at: If the `DefId` in MIR corresponds + 92| |// _only_ to the generic function without type parameters, is the `DefId` in the codegenned set, + 93| |// instantiated with one of the type parameters (in either or both crates) a *different* `DefId`? + 94| |// If so, `add_unreachable_coverage()` would assume the MIR `DefId` was uncovered, and would add + 95| |// unreachable coverage. + 96| |// + 97| |// I didn't think they could be different, but if they can, we would need to find the `DefId` for + 98| |// the generic function MIR and include it in the set of "codegenned" DefIds if any instantiation + 99| |// of that generic function does exist. + 100| |// + 101| |// Note, however, for `used_with_same_type_from_bin_crate_and_lib_crate_generic_function()` both + 102| |// crates use this function with the same type variant. The function does not have multiple + 103| |// instantiations, so the coverage analysis is not confused. No "Unexecuted instantiations" errors + 104| |// are reported. diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt index 2fac0fea84b..82a4457b6ef 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt @@ -28,16 +28,18 @@ Counter in file 0 79:14 -> 79:16, 0 Counter in file 0 81:1 -> 81:2, 0 Counter in file 0 91:25 -> 91:34, 0 Counter in file 0 5:1 -> 5:25, #1 -Counter in file 0 5:25 -> 6:14, #1 -Counter in file 0 7:9 -> 7:10, #2 -Counter in file 0 9:9 -> 9:10, (#1 - #2) -Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) Counter in file 0 21:1 -> 21:23, #1 +Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 67:5 -> 67:23, #1 Counter in file 0 38:1 -> 38:19, #1 +Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 29:1 -> 29:22, #1 Counter in file 0 93:1 -> 101:2, #1 Counter in file 0 91:1 -> 91:25, #1 +Counter in file 0 5:25 -> 6:14, #1 +Counter in file 0 7:9 -> 7:10, #2 +Counter in file 0 9:9 -> 9:10, (#1 - #2) +Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) Counter in file 0 38:19 -> 42:12, #1 Counter in file 0 43:9 -> 43:10, #3 Counter in file 0 43:14 -> 43:18, (#1 + 0) @@ -53,7 +55,6 @@ Counter in file 0 51:5 -> 52:18, #1 Counter in file 0 53:13 -> 53:14, #2 Counter in file 0 63:13 -> 63:14, (#1 - #2) Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2)) -Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 49:1 -> 68:12, #1 Counter in file 0 69:9 -> 69:10, #2 Counter in file 0 69:14 -> 69:27, (#1 + 0) @@ -69,7 +70,6 @@ Counter in file 0 86:14 -> 86:16, #2 Counter in file 0 87:14 -> 87:16, #3 Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2)))) Counter in file 0 17:1 -> 17:20, #1 -Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 66:5 -> 66:23, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 17:9 -> 17:10, #1 diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt index e8be1e685e6..b0319cd9e18 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt @@ -1,39 +1,48 @@ Counter in file 0 17:1 -> 19:2, #1 -Counter in file 0 25:1 -> 27:2, 0 -Counter in file 0 29:1 -> 32:16, 0 -Counter in file 0 32:17 -> 34:6, 0 -Counter in file 0 34:6 -> 34:7, 0 -Counter in file 0 35:1 -> 35:2, 0 -Counter in file 0 37:1 -> 40:16, 0 -Counter in file 0 40:17 -> 42:6, 0 -Counter in file 0 42:6 -> 42:7, 0 -Counter in file 0 43:1 -> 43:2, 0 +Counter in file 0 25:1 -> 27:2, #1 +Counter in file 0 17:1 -> 19:2, #1 +Counter in file 0 5:1 -> 12:2, #1 +Counter in file 0 17:1 -> 19:2, 0 +Counter in file 0 33:1 -> 35:2, 0 +Counter in file 0 45:1 -> 48:16, 0 +Counter in file 0 48:17 -> 50:6, 0 +Counter in file 0 50:6 -> 50:7, 0 +Counter in file 0 51:1 -> 51:2, 0 +Counter in file 0 53:1 -> 61:2, #1 +Counter in file 0 25:1 -> 27:2, #1 +Counter in file 0 29:1 -> 31:2, #1 +Counter in file 0 21:1 -> 23:2, #1 Counter in file 0 5:1 -> 5:24, #1 Counter in file 0 9:9 -> 11:15, (#1 + 0) Counter in file 0 11:16 -> 13:6, #2 Counter in file 0 13:6 -> 13:7, (#1 - #2) Counter in file 0 14:5 -> 15:2, (#2 + (#1 - #2)) Counter in file 0 21:1 -> 23:2, #1 -Counter in file 0 21:1 -> 23:2, #1 -Counter in file 0 5:1 -> 10:2, #1 -Emitting segments for file: ../coverage/used_crate/mod.rs +Counter in file 0 37:1 -> 40:16, #1 +Counter in file 0 40:17 -> 42:6, #2 +Counter in file 0 42:6 -> 42:7, (#1 - #2) +Counter in file 0 43:1 -> 43:2, (#2 + (#1 - #2)) +Emitting segments for file: ../coverage/lib/used_crate.rs Combined regions: 5:1 -> 5:24 (count=1) 9:9 -> 11:15 (count=1) 11:16 -> 13:6 (count=1) 13:6 -> 13:7 (count=0) 14:5 -> 15:2 (count=1) - 17:1 -> 19:2 (count=1) + 17:1 -> 19:2 (count=2) 21:1 -> 23:2 (count=2) - 25:1 -> 27:2 (count=0) - 29:1 -> 32:16 (count=0) - 32:17 -> 34:6 (count=0) - 34:6 -> 34:7 (count=0) - 35:1 -> 35:2 (count=0) + 25:1 -> 27:2 (count=2) + 29:1 -> 31:2 (count=2) + 33:1 -> 35:2 (count=0) 37:1 -> 40:16 (count=0) 40:17 -> 42:6 (count=0) 42:6 -> 42:7 (count=0) 43:1 -> 43:2 (count=0) + 45:1 -> 48:16 (count=0) + 48:17 -> 50:6 (count=0) + 50:6 -> 50:7 (count=0) + 51:1 -> 51:2 (count=0) + 53:1 -> 61:2 (count=1) Segment at 5:1 (count = 1), RegionEntry Segment at 5:24 (count = 0), Skipped Segment at 9:9 (count = 1), RegionEntry @@ -43,18 +52,15 @@ Segment at 13:6 (count = 0), RegionEntry Segment at 13:7 (count = 0), Skipped Segment at 14:5 (count = 1), RegionEntry Segment at 15:2 (count = 0), Skipped -Segment at 17:1 (count = 1), RegionEntry +Segment at 17:1 (count = 2), RegionEntry Segment at 19:2 (count = 0), Skipped Segment at 21:1 (count = 2), RegionEntry Segment at 23:2 (count = 0), Skipped -Segment at 25:1 (count = 0), RegionEntry +Segment at 25:1 (count = 2), RegionEntry Segment at 27:2 (count = 0), Skipped -Segment at 29:1 (count = 0), RegionEntry -Segment at 32:16 (count = 0), Skipped -Segment at 32:17 (count = 0), RegionEntry -Segment at 34:6 (count = 0), RegionEntry -Segment at 34:7 (count = 0), Skipped -Segment at 35:1 (count = 0), RegionEntry +Segment at 29:1 (count = 2), RegionEntry +Segment at 31:2 (count = 0), Skipped +Segment at 33:1 (count = 0), RegionEntry Segment at 35:2 (count = 0), Skipped Segment at 37:1 (count = 0), RegionEntry Segment at 40:16 (count = 0), Skipped @@ -63,13 +69,42 @@ Segment at 42:6 (count = 0), RegionEntry Segment at 42:7 (count = 0), Skipped Segment at 43:1 (count = 0), RegionEntry Segment at 43:2 (count = 0), Skipped -Emitting segments for function: _RINvNtCs4fqI2P2rA04_10uses_crate10used_crate27used_twice_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEEB4_ +Segment at 45:1 (count = 0), RegionEntry +Segment at 48:16 (count = 0), Skipped +Segment at 48:17 (count = 0), RegionEntry +Segment at 50:6 (count = 0), RegionEntry +Segment at 50:7 (count = 0), Skipped +Segment at 51:1 (count = 0), RegionEntry +Segment at 51:2 (count = 0), Skipped +Segment at 53:1 (count = 1), RegionEntry +Segment at 61:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionReECs4fqI2P2rA04_10uses_crate +Combined regions: + 17:1 -> 19:2 (count=1) +Segment at 17:1 (count = 1), RegionEntry +Segment at 19:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionRINtNtCs3QflaznQylx_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate +Combined regions: + 17:1 -> 19:2 (count=1) +Segment at 17:1 (count = 1), RegionEntry +Segment at 19:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEEB2_ Combined regions: 21:1 -> 23:2 (count=1) Segment at 21:1 (count = 1), RegionEntry Segment at 23:2 (count = 0), Skipped -Emitting segments for function: _RINvNtCs4fqI2P2rA04_10uses_crate10used_crate27used_twice_generic_functionReEB4_ +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionReEB2_ Combined regions: 21:1 -> 23:2 (count=1) Segment at 21:1 (count = 1), RegionEntry Segment at 23:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate +Combined regions: + 25:1 -> 27:2 (count=1) +Segment at 25:1 (count = 1), RegionEntry +Segment at 27:2 (count = 0), Skipped +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionReEB2_ +Combined regions: + 25:1 -> 27:2 (count=1) +Segment at 25:1 (count = 1), RegionEntry +Segment at 27:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-spanview/Makefile b/src/test/run-make-fulldeps/coverage-spanview/Makefile index f414fe89eb9..84b5d0e522f 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/Makefile +++ b/src/test/run-make-fulldeps/coverage-spanview/Makefile @@ -21,7 +21,7 @@ endef export SPANVIEW_HEADER ifeq ($(LLVM_VERSION_11_PLUS),true) -all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) +all: $(patsubst $(SOURCEDIR)/lib/%.rs,%,$(wildcard $(SOURCEDIR)/lib/*.rs)) $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) else $(info Rust option `-Z instrument-coverage` requires LLVM 11 or higher. Test skipped.) all: @@ -36,12 +36,47 @@ endif -include clear_expected_if_blessed +# FIXME(richkadel): The actions for these two types of targets (libraries and binaries) should be +# combined. + +%: $(SOURCEDIR)/lib/%.rs + # Compile the test library with coverage instrumentation + $(RUSTC) $(SOURCEDIR)/lib/$@.rs \ + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/lib/$@.rs && \ + echo "--edition=2018" \ + ) \ + --crate-type rlib \ + -Zinstrument-coverage \ + -Zdump-mir=InstrumentCoverage \ + -Zdump-mir-spanview \ + -Zdump-mir-dir="$(TMPDIR)"/mir_dump.$@ + + for path in "$(TMPDIR)"/mir_dump.$@/*; do \ + file="$$(basename "$$path")"; \ + urlescaped="$$("$(PYTHON)" $(BASEDIR)/escape_url.py $$file)" || exit $$?; \ + printf "$$SPANVIEW_HEADER\n" "$@" "$$urlescaped" > "$$path".modified; \ + tail -n +2 "$$path" >> "$$path".modified; \ + mv "$$path".modified "$$path"; \ + done && true # for/done ends in non-zero status + +ifdef RUSTC_BLESS_TEST + mkdir -p expected_mir_dump.$@ + cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html expected_mir_dump.$@/ +else + # Check that the selected `mir_dump` files match what we expect (`--bless` refreshes `expected`) + mkdir -p "$(TMPDIR)"/actual_mir_dump.$@ + rm -f "$(TMPDIR)"/actual_mir_dump.$@/* + cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html "$(TMPDIR)"/actual_mir_dump.$@/ + $(DIFF) -r expected_mir_dump.$@/ "$(TMPDIR)"/actual_mir_dump.$@/ +endif + %: $(SOURCEDIR)/%.rs - # Compile the test program with coverage instrumentation and generate relevant MIR. + # Compile the test program with coverage instrumentation $(RUSTC) $(SOURCEDIR)/$@.rs \ $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && \ echo "--edition=2018" \ ) \ + -L "$(TMPDIR)" \ -Zinstrument-coverage \ -Zdump-mir=InstrumentCoverage \ -Zdump-mir-spanview \ diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_function.-------.InstrumentCoverage.0.html similarity index 95% rename from src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_function.-------.InstrumentCoverage.0.html index 10e71152c53..47fe96eebd1 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_function.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -uses_crate.used_crate-unused_private_function - Coverage Spans +used_crate.unused_function - Coverage Spans + + +
@0,1,2,3,4⦊pub fn unused_generic_function<T: Debug>(arg: T) { + println!("unused_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_private_function.-------.InstrumentCoverage.0.html similarity index 53% rename from src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_private_function.-------.InstrumentCoverage.0.html index 42ba0458349..361c5793022 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.unused_private_function.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -uses_crate.used_crate-unused_function - Coverage Spans +used_crate.unused_private_function - Coverage Spans -
@0,1,2,3⦊pub fn unused_function() { - let is_true = std::env::args().len() == 1; - let mut countdown = 2; - if !is_true⦉@0,1,2,3 @4,6⦊{ - countdown = 20; - }⦉@4,6@5⦊⦉@5 -}@7⦊⦉@7
+
@0,1,2,3⦊fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 20; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..bed5e7bb7ce --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html @@ -0,0 +1,190 @@ + + + + +used_crate.use_this_lib_crate - Coverage Spans + + + +
@0,1,2,3,4,5,6,7,8⦊fn use_this_lib_crate() { + used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + "used from library used_crate.rs", + ); + let some_vec = vec![5, 6, 7, 8]; + used_only_from_this_lib_crate_generic_function(some_vec); + used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); +}⦉@0,1,2,3,4,5,6,7,8
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..8b994a6962b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +used_crate.used_from_bin_crate_and_lib_crate_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) { + println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_function.-------.InstrumentCoverage.0.html similarity index 91% rename from src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html rename to src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_function.-------.InstrumentCoverage.0.html index 15dce97e742..2ffd9bfb823 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_function.-------.InstrumentCoverage.0.html @@ -2,7 +2,7 @@ -uses_crate.used_crate-used_function - Coverage Spans +used_crate.used_function - Coverage Spans + + +
@0,1,2,3,4⦊pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { + println!("used_only_from_bin_crate_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_this_lib_crate_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_this_lib_crate_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..76bc057dd00 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_only_from_this_lib_crate_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +used_crate.used_only_from_this_lib_crate_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { + println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 00000000000..a2f4b7e19eb --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +used_crate.used_with_same_type_from_bin_crate_and_lib_crate_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) { + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html index 52c99558de6..acb2c7d63f5 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html @@ -69,83 +69,125 @@ -
@0,1,2,3,4,5,6,7⦊fn main() { -@0,1,2,3,4,5,6,7,8,9⦊fn main() { + used_crate::used_function(); - used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; - let some_vec = vec![1, 2, 3, 4]; + used_crate::used_generic_function(&some_vec); - used_crate::used_only_from_bin_crate_generic_function(&some_vec); + used_crate::used_twice_generic_function(some_vec); - used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); +}⦉@0,1,2,3,4,5,6,7
+8:59-8:68: @4[4]: _7 = &_2 +8:5-8:69: @4.Call: _6 = used_only_from_bin_crate_generic_function::<&Vec<i32>>(move _7) -> [return: bb5, unwind: bb11] +9:5-9:89: @5.Call: _8 = used_only_from_bin_crate_generic_function::<&str>(const "used from bin uses_crate.rs") -> [return: bb6, unwind: bb11] +10:68-10:76: @6[3]: _10 = move _2 +10:5-10:77: @6.Call: _9 = used_from_bin_crate_and_lib_crate_generic_function::<Vec<i32>>(move _10) -> [return: bb7, unwind: bb10] +11:5-11:98: @7.Call: _11 = used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>(const "interesting?") -> [return: bb8, unwind: bb11] +5:11-12:2: @8[1]: _0 = const () +12:2-12:2: @9.Return: return"> used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); +}⦉@0,1,2,3,4,5,6,7,8,9
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html deleted file mode 100644 index d89963a32ce..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -uses_crate.used_crate-unused_generic_function - Coverage Spans - - - -
@0,1,2,3,4⦊pub fn unused_generic_function<T: Debug>(arg: T) { - println!("unused_generic_function with {:?}", arg); -}⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html deleted file mode 100644 index e47ed0b3817..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -uses_crate.used_crate-used_generic_function - Coverage Spans - - - -
@0,1,2,3,4⦊pub fn used_generic_function<T: Debug>(arg: T) { - println!("used_generic_function with {:?}", arg); -}⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html deleted file mode 100644 index ef63db45cc0..00000000000 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - -uses_crate.used_crate-used_twice_generic_function - Coverage Spans - - - -
@0,1,2,3,4⦊pub fn used_twice_generic_function<T: Debug>(arg: T) { - println!("used_twice_generic_function with {:?}", arg); -}⦉@0,1,2,3,4
- - diff --git a/src/test/run-make-fulldeps/coverage/async.rs b/src/test/run-make-fulldeps/coverage/async.rs index 491d2746543..5553af92465 100644 --- a/src/test/run-make-fulldeps/coverage/async.rs +++ b/src/test/run-make-fulldeps/coverage/async.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, dead_code)] // require-rust-edition-2018 diff --git a/src/test/run-make-fulldeps/coverage/if_else.rs b/src/test/run-make-fulldeps/coverage/if_else.rs index 3ae4b7a7316..3244e1e3afd 100644 --- a/src/test/run-make-fulldeps/coverage/if_else.rs +++ b/src/test/run-make-fulldeps/coverage/if_else.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, unused_variables)] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure diff --git a/src/test/run-make-fulldeps/coverage/inner_items.rs b/src/test/run-make-fulldeps/coverage/inner_items.rs index 66e76513e26..bcb62b3031c 100644 --- a/src/test/run-make-fulldeps/coverage/inner_items.rs +++ b/src/test/run-make-fulldeps/coverage/inner_items.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments, unused_variables)] +#![allow(unused_assignments, unused_variables, dead_code)] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure diff --git a/src/test/run-make-fulldeps/coverage/lib/used_crate.rs b/src/test/run-make-fulldeps/coverage/lib/used_crate.rs new file mode 100644 index 00000000000..e5555f91935 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/lib/used_crate.rs @@ -0,0 +1,104 @@ +#![allow(unused_assignments, unused_variables)] + +use std::fmt::Debug; + +pub fn used_function() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true { + countdown = 10; + } + use_this_lib_crate(); +} + +pub fn used_only_from_bin_crate_generic_function(arg: T) { + println!("used_only_from_bin_crate_generic_function with {:?}", arg); +} + +pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); +} + +pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +} + +pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +} + +pub fn unused_generic_function(arg: T) { + println!("unused_generic_function with {:?}", arg); +} + +pub fn unused_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +fn use_this_lib_crate() { + used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + "used from library used_crate.rs", + ); + let some_vec = vec![5, 6, 7, 8]; + used_only_from_this_lib_crate_generic_function(some_vec); + used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); +} + +// FIXME(#79651): `used_from_bin_crate_and_lib_crate_generic_function()` is covered and executed +// `2` times, but the coverage output also shows (at the bottom of the coverage report): +// ------------------ +// | Unexecuted instantiation: +// ------------------ +// +// Note, the function name shown in the error seems to change depending on the structure of the +// code, for some reason, including: +// +// * used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str> +// * used_crate::use_this_lib_crate +// +// The `Unexecuted instantiation` error may be related to more than one generic function. Since the +// reporting is not consistent, it may not be obvious if there are multiple problems here; however, +// `used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>` (which I have seen +// with this error) is the only generic function missing instantiaion coverage counts. +// +// The `&str` variant was called from within this `lib` crate, and the `bin` crate also calls this +// function, but with `T` type `&Vec`. +// +// I believe the reason is that one or both crates are generating `Zero` counters for what it +// believes are "Unreachable" instantiations, but those instantiations are counted from the +// coverage map in the other crate. +// +// See `add_unreachable_coverage()` in `mapgen.rs` for more on how these `Zero` counters are added +// for what the funciton believes are `DefId`s that did not get codegenned. I suspect the issue +// may be related to this process, but this needs to be confirmed. It may not be possible to know +// for sure if a function is truly unused and should be reported with `Zero` coverage if it may +// still get used from an external crate. (Something to look at: If the `DefId` in MIR corresponds +// _only_ to the generic function without type parameters, is the `DefId` in the codegenned set, +// instantiated with one of the type parameters (in either or both crates) a *different* `DefId`? +// If so, `add_unreachable_coverage()` would assume the MIR `DefId` was uncovered, and would add +// unreachable coverage. +// +// I didn't think they could be different, but if they can, we would need to find the `DefId` for +// the generic function MIR and include it in the set of "codegenned" DefIds if any instantiation +// of that generic function does exist. +// +// Note, however, for `used_with_same_type_from_bin_crate_and_lib_crate_generic_function()` both +// crates use this function with the same type variant. The function does not have multiple +// instantiations, so the coverage analysis is not confused. No "Unexecuted instantiations" errors +// are reported. diff --git a/src/test/run-make-fulldeps/coverage/loop_break_value.rs b/src/test/run-make-fulldeps/coverage/loop_break_value.rs index ba66d136de1..dbc4fad7a23 100644 --- a/src/test/run-make-fulldeps/coverage/loop_break_value.rs +++ b/src/test/run-make-fulldeps/coverage/loop_break_value.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, unused_variables)] fn main() { let result diff --git a/src/test/run-make-fulldeps/coverage/loops_branches.rs b/src/test/run-make-fulldeps/coverage/loops_branches.rs index a9df7e0fab7..938421d32e7 100644 --- a/src/test/run-make-fulldeps/coverage/loops_branches.rs +++ b/src/test/run-make-fulldeps/coverage/loops_branches.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, unused_variables, while_true)] // This test confirms an earlier problem was resolved, supporting the MIR graph generated by the // structure of this `fmt` function. diff --git a/src/test/run-make-fulldeps/coverage/simple_match.rs b/src/test/run-make-fulldeps/coverage/simple_match.rs index c9a24f7a9d3..be99e59a826 100644 --- a/src/test/run-make-fulldeps/coverage/simple_match.rs +++ b/src/test/run-make-fulldeps/coverage/simple_match.rs @@ -1,4 +1,4 @@ -#![allow(unused_assignments)] +#![allow(unused_assignments, unused_variables)] fn main() { // Initialize test constants in a way that cannot be determined at compile time, to ensure diff --git a/src/test/run-make-fulldeps/coverage/used_crate/mod.rs b/src/test/run-make-fulldeps/coverage/used_crate/mod.rs deleted file mode 100644 index 825eff4d352..00000000000 --- a/src/test/run-make-fulldeps/coverage/used_crate/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -use std::fmt::Debug; - -pub fn used_function() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - let mut countdown = 0; - if is_true { - countdown = 10; - } - used_twice_generic_function("some str"); -} - -pub fn used_generic_function(arg: T) { - println!("used_generic_function with {:?}", arg); -} - -pub fn used_twice_generic_function(arg: T) { - println!("used_twice_generic_function with {:?}", arg); -} - -pub fn unused_generic_function(arg: T) { - println!("unused_generic_function with {:?}", arg); -} - -pub fn unused_function() { - let is_true = std::env::args().len() == 1; - let mut countdown = 2; - if !is_true { - countdown = 20; - } -} - -fn unused_private_function() { - let is_true = std::env::args().len() == 1; - let mut countdown = 2; - if !is_true { - countdown = 20; - } -} diff --git a/src/test/run-make-fulldeps/coverage/uses_crate.rs b/src/test/run-make-fulldeps/coverage/uses_crate.rs index 473d43217a9..8d24b1ca3e6 100644 --- a/src/test/run-make-fulldeps/coverage/uses_crate.rs +++ b/src/test/run-make-fulldeps/coverage/uses_crate.rs @@ -1,10 +1,12 @@ #![allow(unused_assignments, unused_variables)] -mod used_crate; +extern crate used_crate; fn main() { used_crate::used_function(); let some_vec = vec![1, 2, 3, 4]; - used_crate::used_generic_function(&some_vec); - used_crate::used_twice_generic_function(some_vec); + used_crate::used_only_from_bin_crate_generic_function(&some_vec); + used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); } From dc4bd9067eda1df118fc48cb6b828d72e916e1bb Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Thu, 3 Dec 2020 12:00:33 -0800 Subject: [PATCH 173/274] Tweak to Makefile to overcome MacOS make corruption bug --- .../run-make-fulldeps/coverage-reports/Makefile | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 89d5974d73c..302f09ae422 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -87,20 +87,14 @@ endif %: $(SOURCEDIR)/lib/%.rs # Compile the test library with coverage instrumentation $(RUSTC) $(SOURCEDIR)/lib/$@.rs \ - $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/lib/$@.rs && \ - echo "--edition=2018" \ - ) \ - --crate-type rlib \ - -Zinstrument-coverage + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/lib/$@.rs && echo "--edition=2018" ) \ + --crate-type rlib -Zinstrument-coverage %: $(SOURCEDIR)/%.rs # Compile the test program with coverage instrumentation $(RUSTC) $(SOURCEDIR)/$@.rs \ - $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && \ - echo "--edition=2018" \ - ) \ - -L "$(TMPDIR)" \ - -Zinstrument-coverage + $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && echo "--edition=2018" ) \ + -L "$(TMPDIR)" -Zinstrument-coverage # Run it in order to generate some profiling data, # with `LLVM_PROFILE_FILE=` environment variable set to From 8135ab8a22f4aa6ad071574798397aa131377ca2 Mon Sep 17 00:00:00 2001 From: Ricky Date: Thu, 3 Dec 2020 16:11:52 -0500 Subject: [PATCH 174/274] Moved map_err_ignore to restriction and updated help message --- clippy_lints/src/map_err_ignore.rs | 4 ++-- tests/ui/map_err.stderr | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 5298e16a04d..324a11f140a 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -99,7 +99,7 @@ declare_clippy_lint! { /// } /// ``` pub MAP_ERR_IGNORE, - pedantic, + restriction, "`map_err` should not ignore the original error" } @@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { body_span, "`map_err(|_|...` ignores the original error", None, - "Consider wrapping the error in an enum variant", + "Consider wrapping the error in an enum variant for more error context, or using a named wildcard (`.map_err(|_ignored| ...`) to intentionally ignore the error", ); } } diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index 390d7ce2e4e..8193f7cfb8e 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -5,7 +5,7 @@ LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | ^^^ | = note: `-D clippy::map-err-ignore` implied by `-D warnings` - = help: Consider wrapping the error in an enum variant + = help: Consider wrapping the error in an enum variant for more error context, or using a named wildcard (`.map_err(|_ignored| ...`) to intentionally ignore the error error: aborting due to previous error From 0ad3dce83a4506875e6b1381f5261e458b5c5d98 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 3 Dec 2020 17:06:58 -0500 Subject: [PATCH 175/274] Fix some clippy lints --- compiler/rustc_expand/src/base.rs | 10 ++++------ compiler/rustc_expand/src/expand.rs | 8 ++++++-- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_lexer/src/lib.rs | 10 +++++----- compiler/rustc_serialize/src/json.rs | 2 +- compiler/rustc_span/src/analyze_source_file.rs | 4 ++-- compiler/rustc_span/src/lib.rs | 5 +---- compiler/rustc_span/src/source_map.rs | 6 ++---- compiler/rustc_span/src/symbol.rs | 14 ++++++-------- 9 files changed, 28 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b1071bf4308..335f3b7a9a0 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -235,12 +235,10 @@ impl Annotatable { pub fn derive_allowed(&self) -> bool { match *self { Annotatable::Stmt(ref stmt) => match stmt.kind { - ast::StmtKind::Item(ref item) => match item.kind { - ast::ItemKind::Struct(..) - | ast::ItemKind::Enum(..) - | ast::ItemKind::Union(..) => true, - _ => false, - }, + ast::StmtKind::Item(ref item) => matches!( + item.kind, + ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) + ), _ => false, }, Annotatable::Item(ref item) => match item.kind { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 4ba75c21cf0..7870252231a 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1134,7 +1134,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let Some(attr) = self.take_first_attr_no_derive(&mut expr) { // Collect the invoc regardless of whether or not attributes are permitted here // expansion will eat the attribute so it won't error later. - attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr)); + if let Some(attr) = attr.0.as_ref() { + self.cfg.maybe_emit_expr_attr_err(attr) + } // AstFragmentKind::Expr requires the macro to emit an expression. return self @@ -1231,7 +1233,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.cfg.configure_expr_kind(&mut expr.kind); if let Some(attr) = self.take_first_attr_no_derive(&mut expr) { - attr.0.as_ref().map(|attr| self.cfg.maybe_emit_expr_attr_err(attr)); + if let Some(attr) = attr.0.as_ref() { + self.cfg.maybe_emit_expr_attr_err(attr) + } return self .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f01d4417105..44dc6673564 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2401,7 +2401,7 @@ impl StructField<'_> { // Still necessary in couple of places pub fn is_positional(&self) -> bool { let first = self.ident.as_str().as_bytes()[0]; - first >= b'0' && first <= b'9' + (b'0'..=b'9').contains(&first) } } diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 6539419aefb..44fc4db7dc1 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -267,8 +267,8 @@ pub fn is_whitespace(c: char) -> bool { pub fn is_id_start(c: char) -> bool { // This is XID_Start OR '_' (which formally is not a XID_Start). // We also add fast-path for ascii idents - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') + ('a'..='z').contains(&c) + || ('A'..='Z').contains(&c) || c == '_' || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_start(c)) } @@ -279,9 +279,9 @@ pub fn is_id_start(c: char) -> bool { pub fn is_id_continue(c: char) -> bool { // This is exactly XID_Continue. // We also add fast-path for ascii idents - ('a' <= c && c <= 'z') - || ('A' <= c && c <= 'Z') - || ('0' <= c && c <= '9') + ('a'..='z').contains(&c) + || ('A'..='Z').contains(&c) + || ('0'..='9').contains(&c) || c == '_' || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c)) } diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs index 6c8965aa2e3..bbbe568f17a 100644 --- a/compiler/rustc_serialize/src/json.rs +++ b/compiler/rustc_serialize/src/json.rs @@ -1859,7 +1859,7 @@ impl> Parser { } let n2 = self.decode_hex_escape()?; - if n2 < 0xDC00 || n2 > 0xDFFF { + if !(0xDC00..=0xDFFF).contains(&n2) { return self.error(LoneLeadingSurrogateInHexEscape); } let c = diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index b4beb3dc376..5987fb2a198 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -97,7 +97,7 @@ cfg_if::cfg_if! { let ptr = src_bytes.as_ptr() as *const __m128i; // We don't know if the pointer is aligned to 16 bytes, so we // use `loadu`, which supports unaligned loading. - let chunk = _mm_loadu_si128(ptr.offset(chunk_index as isize)); + let chunk = _mm_loadu_si128(ptr.add(chunk_index)); // For character in the chunk, see if its byte value is < 0, which // indicates that it's part of a UTF-8 char. @@ -253,7 +253,7 @@ fn analyze_source_file_generic( let pos = BytePos::from_usize(i) + output_offset; if char_len > 1 { - assert!(char_len >= 2 && char_len <= 4); + assert!((2..=4).contains(&char_len)); let mbc = MultiByteChar { pos, bytes: char_len as u8 }; multi_byte_chars.push(mbc); } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 11a49d1ab88..f63a73acbf4 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1015,10 +1015,7 @@ pub enum ExternalSourceKind { impl ExternalSource { pub fn is_absent(&self) -> bool { - match self { - ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. } => false, - _ => true, - } + !matches!(self, ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. }) } pub fn get_source(&self) -> Option<&Lrc> { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index f067cdb7308..e9b4eb6e4ab 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -623,7 +623,7 @@ impl SourceMap { self.span_to_source(sp, |src, start_index, end_index| { src.get(start_index..end_index) .map(|s| s.to_string()) - .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp)) + .ok_or(SpanSnippetError::IllFormedSpan(sp)) }) } @@ -640,9 +640,7 @@ impl SourceMap { /// Returns the source snippet as `String` before the given `Span`. pub fn span_to_prev_source(&self, sp: Span) -> Result { self.span_to_source(sp, |src, start_index, _| { - src.get(..start_index) - .map(|s| s.to_string()) - .ok_or_else(|| SpanSnippetError::IllFormedSpan(sp)) + src.get(..start_index).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp)) }) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 523628b7058..00854d9a3fc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1362,15 +1362,13 @@ impl fmt::Display for IdentPrinter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.is_raw { f.write_str("r#")?; - } else { - if self.symbol == kw::DollarCrate { - if let Some(span) = self.convert_dollar_crate { - let converted = span.ctxt().dollar_crate_name(); - if !converted.is_path_segment_keyword() { - f.write_str("::")?; - } - return fmt::Display::fmt(&converted, f); + } else if self.symbol == kw::DollarCrate { + if let Some(span) = self.convert_dollar_crate { + let converted = span.ctxt().dollar_crate_name(); + if !converted.is_path_segment_keyword() { + f.write_str("::")?; } + return fmt::Display::fmt(&converted, f); } } fmt::Display::fmt(&self.symbol, f) From 5d4a7128d9929723769a7c674f49e9fe3fc0ff13 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 4 Oct 2020 20:42:34 -0700 Subject: [PATCH 176/274] Render Markdown in search results Previously Markdown documentation was not rendered to HTML for search results, which led to the output not being very readable, particularly for inline code. This PR fixes that by rendering Markdown to HTML with the help of pulldown-cmark (the library rustdoc uses to parse Markdown for the main text of documentation). However, the text for the title attribute (the text shown when you hover over an element) still uses the plain-text rendering since it is displayed in browsers as plain-text. Only these styles will be rendered; everything else is stripped away: * *italics* * **bold** * `inline code` --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/formats/cache.rs | 8 +- src/librustdoc/html/markdown.rs | 92 ++++++++++++++++++- src/librustdoc/html/markdown/tests.rs | 33 ++++++- src/librustdoc/html/render/cache.rs | 6 +- src/librustdoc/html/render/mod.rs | 41 ++------- src/librustdoc/html/static/main.js | 25 ++++- ...ext-summaries.rs => markdown-summaries.rs} | 9 +- 8 files changed, 166 insertions(+), 50 deletions(-) rename src/test/rustdoc/{plain-text-summaries.rs => markdown-summaries.rs} (55%) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d294d8f02a8..40218022a19 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1015,7 +1015,7 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { .iter() .map(|t| Argument { type_: t.clean(cx), - name: names.next().map_or(String::new(), |name| name.to_string()), + name: names.next().map_or_else(|| String::new(), |name| name.to_string()), }) .collect(), }, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index c3153f2d4b6..e82bc540e95 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -14,13 +14,13 @@ use crate::config::RenderInfo; use crate::fold::DocFolder; use crate::formats::item_type::ItemType; use crate::formats::Impl; +use crate::html::markdown::short_markdown_summary; use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation}; use crate::html::render::IndexItem; -use crate::html::render::{plain_text_summary, shorten}; thread_local!(crate static CACHE_KEY: RefCell> = Default::default()); -/// This cache is used to store information about the `clean::Crate` being +/// This cache is used to store information about the [`clean::Crate`] being /// rendered in order to provide more useful documentation. This contains /// information like all implementors of a trait, all traits a type implements, /// documentation for all known traits, etc. @@ -313,7 +313,9 @@ impl DocFolder for Cache { ty: item.type_(), name: s.to_string(), path: path.join("::"), - desc: shorten(plain_text_summary(item.doc_value())), + desc: item + .doc_value() + .map_or_else(|| String::new(), short_markdown_summary), parent, parent_idx: None, search_type: get_index_search_type(&item), diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 8ce686c6550..6bba5036191 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -17,8 +17,6 @@ //! // ... something using html //! ``` -#![allow(non_camel_case_types)] - use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_hir::HirId; @@ -1037,7 +1035,97 @@ impl MarkdownSummaryLine<'_> { } } +/// Renders a subset of Markdown in the first paragraph of the provided Markdown. +/// +/// - *Italics*, **bold**, and `inline code` styles **are** rendered. +/// - Headings and links are stripped (though the text *is* rendered). +/// - HTML, code blocks, and everything else are ignored. +/// +/// Returns a tuple of the rendered HTML string and whether the output was shortened +/// due to the provided `length_limit`. +fn markdown_summary_with_limit(md: &str, length_limit: Option) -> (String, bool) { + if md.is_empty() { + return (String::new(), false); + } + + let length_limit = length_limit.unwrap_or(u16::MAX) as usize; + + let mut s = String::with_capacity(md.len() * 3 / 2); + let mut text_length = 0; + let mut stopped_early = false; + + fn push(s: &mut String, text_length: &mut usize, text: &str) { + s.push_str(text); + *text_length += text.len(); + }; + + 'outer: for event in Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH) { + match &event { + Event::Text(text) => { + for word in text.split_inclusive(char::is_whitespace) { + if text_length + word.len() >= length_limit { + stopped_early = true; + break 'outer; + } + + push(&mut s, &mut text_length, word); + } + } + Event::Code(code) => { + if text_length + code.len() >= length_limit { + stopped_early = true; + break; + } + + s.push_str(""); + push(&mut s, &mut text_length, code); + s.push_str(""); + } + Event::Start(tag) => match tag { + Tag::Emphasis => s.push_str(""), + Tag::Strong => s.push_str(""), + Tag::CodeBlock(..) => break, + _ => {} + }, + Event::End(tag) => match tag { + Tag::Emphasis => s.push_str(""), + Tag::Strong => s.push_str(""), + Tag::Paragraph => break, + _ => {} + }, + Event::HardBreak | Event::SoftBreak => { + if text_length + 1 >= length_limit { + stopped_early = true; + break; + } + + push(&mut s, &mut text_length, " "); + } + _ => {} + } + } + + (s, stopped_early) +} + +/// Renders a shortened first paragraph of the given Markdown as a subset of Markdown, +/// making it suitable for contexts like the search index. +/// +/// Will shorten to 59 or 60 characters, including an ellipsis (…) if it was shortened. +/// +/// See [`markdown_summary_with_limit`] for details about what is rendered and what is not. +crate fn short_markdown_summary(markdown: &str) -> String { + let (mut s, was_shortened) = markdown_summary_with_limit(markdown, Some(59)); + + if was_shortened { + s.push('…'); + } + + s +} + /// Renders the first paragraph of the provided markdown as plain text. +/// Useful for alt-text. /// /// - Headings, links, and formatting are stripped. /// - Inline code is rendered as-is, surrounded by backticks. diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 8e618733f07..9807d8632c7 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -1,4 +1,4 @@ -use super::plain_text_summary; +use super::{plain_text_summary, short_markdown_summary}; use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use std::cell::RefCell; @@ -204,6 +204,33 @@ fn test_header_ids_multiple_blocks() { ); } +#[test] +fn test_short_markdown_summary() { + fn t(input: &str, expect: &str) { + let output = short_markdown_summary(input); + assert_eq!(output, expect, "original: {}", input); + } + + t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); + t("*italic*", "italic"); + t("**bold**", "bold"); + t("Multi-line\nsummary", "Multi-line summary"); + t("Hard-break \nsummary", "Hard-break summary"); + t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)"); + t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); + t("code `let x = i32;` ...", "code let x = i32; ..."); + t("type `Type<'static>` ...", "type Type<'static> ..."); + t("# top header", "top header"); + t("## header", "header"); + t("first paragraph\n\nsecond paragraph", "first paragraph"); + t("```\nfn main() {}\n```", ""); + t("
hello
", ""); + t( + "a *very*, **very** long first paragraph. it has lots of `inline code: Vec`. and it has a [link](https://www.rust-lang.org).\nthat was a soft line break! \nthat was a hard one\n\nsecond paragraph.", + "a very, very long first paragraph. it has lots of …", + ); +} + #[test] fn test_plain_text_summary() { fn t(input: &str, expect: &str) { @@ -224,6 +251,10 @@ fn test_plain_text_summary() { t("first paragraph\n\nsecond paragraph", "first paragraph"); t("```\nfn main() {}\n```", ""); t("
hello
", ""); + t( + "a *very*, **very** long first paragraph. it has lots of `inline code: Vec`. and it has a [link](https://www.rust-lang.org).\nthat was a soft line break! \nthat was a hard one\n\nsecond paragraph.", + "a very, very long first paragraph. it has lots of `inline code: Vec`. and it has a link. that was a soft line break! that was a hard one", + ); } #[test] diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 085ca01f58d..97f764517fa 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -9,7 +9,7 @@ use crate::clean::types::GetDefId; use crate::clean::{self, AttributesExt}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::html::render::{plain_text_summary, shorten}; +use crate::html::markdown::short_markdown_summary; use crate::html::render::{Generic, IndexItem, IndexItemFunctionType, RenderType, TypeWithKind}; /// Indicates where an external crate can be found. @@ -78,7 +78,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { ty: item.type_(), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), - desc: shorten(plain_text_summary(item.doc_value())), + desc: item.doc_value().map_or_else(|| String::new(), short_markdown_summary), parent: Some(did), parent_idx: None, search_type: get_index_search_type(&item), @@ -127,7 +127,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let crate_doc = krate .module .as_ref() - .map(|module| shorten(plain_text_summary(module.doc_value()))) + .map(|module| module.doc_value().map_or_else(|| String::new(), short_markdown_summary)) .unwrap_or_default(); #[derive(Serialize)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index de620a35c80..901f00b21da 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -76,7 +76,9 @@ use crate::html::format::fmt_impl_for_trait_page; use crate::html::format::Function; use crate::html::format::{href, print_default_space, print_generic_bounds, WhereClause}; use crate::html::format::{print_abi_with_space, Buffer, PrintWithSpace}; -use crate::html::markdown::{self, ErrorCodes, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine}; +use crate::html::markdown::{ + self, plain_text_summary, ErrorCodes, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine, +}; use crate::html::sources; use crate::html::{highlight, layout, static_files}; use cache::{build_index, ExternalLocation}; @@ -1604,9 +1606,10 @@ impl Context { Some(ref s) => s.to_string(), }; let short = short.to_string(); - map.entry(short) - .or_default() - .push((myname, Some(plain_text_summary(item.doc_value())))); + map.entry(short).or_default().push(( + myname, + Some(item.doc_value().map_or_else(|| String::new(), plain_text_summary)), + )); } if self.shared.sort_modules_alphabetically { @@ -1810,36 +1813,6 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } -/// Renders the first paragraph of the given markdown as plain text, making it suitable for -/// contexts like alt-text or the search index. -/// -/// If no markdown is supplied, the empty string is returned. -/// -/// See [`markdown::plain_text_summary`] for further details. -#[inline] -crate fn plain_text_summary(s: Option<&str>) -> String { - s.map(markdown::plain_text_summary).unwrap_or_default() -} - -crate fn shorten(s: String) -> String { - if s.chars().count() > 60 { - let mut len = 0; - let mut ret = s - .split_whitespace() - .take_while(|p| { - // + 1 for the added character after the word. - len += p.chars().count() + 1; - len < 60 - }) - .collect::>() - .join(" "); - ret.push('…'); - ret - } else { - s - } -} - fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) { if let Some(ref name) = item.name { info!("Documenting {}", name); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 69984be5eb6..712ea044e48 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1611,7 +1611,7 @@ function defocusSearchBar() { item.displayPath + "" + name + "
"; }); output += "
" + "" + - "" + escape(item.desc) + + "" + item.desc + " 
"; @@ -2013,7 +2013,9 @@ function defocusSearchBar() { } var link = document.createElement("a"); link.href = rootPath + crates[i] + "/index.html"; - link.title = rawSearchIndex[crates[i]].doc; + // The summary in the search index has HTML, so we need to + // dynamically render it as plaintext. + link.title = convertHTMLToPlaintext(rawSearchIndex[crates[i]].doc); link.className = klass; link.textContent = crates[i]; @@ -2026,6 +2028,25 @@ function defocusSearchBar() { } }; + /** + * Convert HTML to plaintext: + * + * * Replace "foo" with "`foo`" + * * Strip all other HTML tags + * + * Used by the dynamic sidebar crate list renderer. + * + * @param {[string]} html [The HTML to convert] + * @return {[string]} [The resulting plaintext] + */ + function convertHTMLToPlaintext(html) { + var dom = new DOMParser().parseFromString( + html.replace('', '`').replace('', '`'), + 'text/html', + ); + return dom.body.innerText; + } + // delayed sidebar rendering. window.initSidebarItems = function(items) { diff --git a/src/test/rustdoc/plain-text-summaries.rs b/src/test/rustdoc/markdown-summaries.rs similarity index 55% rename from src/test/rustdoc/plain-text-summaries.rs rename to src/test/rustdoc/markdown-summaries.rs index c995ccbf0af..b843e28e7b0 100644 --- a/src/test/rustdoc/plain-text-summaries.rs +++ b/src/test/rustdoc/markdown-summaries.rs @@ -1,21 +1,22 @@ #![crate_type = "lib"] #![crate_name = "summaries"] -//! This summary has a [link] and `code`. +//! This *summary* has a [link] and `code`. //! //! This is the second paragraph. //! //! [link]: https://example.com -// @has search-index.js 'This summary has a link and `code`.' +// @has search-index.js 'This summary has a link and code.' // @!has - 'second paragraph' -/// This `code` should be in backticks. +/// This `code` will be rendered in a code tag. /// /// This text should not be rendered. pub struct Sidebar; -// @has summaries/sidebar-items.js 'This `code` should be in backticks.' +// @has search-index.js 'This code will be rendered in a code tag.' +// @has summaries/sidebar-items.js 'This `code` will be rendered in a code tag.' // @!has - 'text should not be rendered' /// ```text From e178030ea4d1b3a1e38cc53141188d2249d33cf5 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 17 Nov 2020 12:24:16 -0800 Subject: [PATCH 177/274] Use `createElement` and `innerHTML` instead of `DOMParser` @GuillaumeGomez was concerned about browser compatibility. --- src/librustdoc/html/static/main.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 712ea044e48..0884351a9fd 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2040,11 +2040,9 @@ function defocusSearchBar() { * @return {[string]} [The resulting plaintext] */ function convertHTMLToPlaintext(html) { - var dom = new DOMParser().parseFromString( - html.replace('', '`').replace('', '`'), - 'text/html', - ); - return dom.body.innerText; + var x = document.createElement("div"); + x.innerHTML = html.replace('', '`').replace('', '`'); + return x.innerText; } From 07e9426efba69e8b662f2a896326b157f5d0ba2d Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 23 Nov 2020 19:26:15 -0800 Subject: [PATCH 178/274] Make `length_limit` a `usize` --- src/librustdoc/html/markdown.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 6bba5036191..0e4c5410abe 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1043,13 +1043,11 @@ impl MarkdownSummaryLine<'_> { /// /// Returns a tuple of the rendered HTML string and whether the output was shortened /// due to the provided `length_limit`. -fn markdown_summary_with_limit(md: &str, length_limit: Option) -> (String, bool) { +fn markdown_summary_with_limit(md: &str, length_limit: usize) -> (String, bool) { if md.is_empty() { return (String::new(), false); } - let length_limit = length_limit.unwrap_or(u16::MAX) as usize; - let mut s = String::with_capacity(md.len() * 3 / 2); let mut text_length = 0; let mut stopped_early = false; @@ -1115,7 +1113,7 @@ fn markdown_summary_with_limit(md: &str, length_limit: Option) -> (String, /// /// See [`markdown_summary_with_limit`] for details about what is rendered and what is not. crate fn short_markdown_summary(markdown: &str) -> String { - let (mut s, was_shortened) = markdown_summary_with_limit(markdown, Some(59)); + let (mut s, was_shortened) = markdown_summary_with_limit(markdown, 59); if was_shortened { s.push('…'); From b9035194c0c434d89ec776176a88406cc4af66cc Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 23 Nov 2020 20:33:41 -0800 Subject: [PATCH 179/274] Add rustdoc-js test Finally! --- src/test/rustdoc-js/basic.rs | 2 +- src/test/rustdoc-js/summaries.js | 7 +++++++ src/test/rustdoc-js/summaries.rs | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc-js/summaries.js create mode 100644 src/test/rustdoc-js/summaries.rs diff --git a/src/test/rustdoc-js/basic.rs b/src/test/rustdoc-js/basic.rs index 1b4963fcebe..da946a58b1c 100644 --- a/src/test/rustdoc-js/basic.rs +++ b/src/test/rustdoc-js/basic.rs @@ -1,2 +1,2 @@ -/// Foo +/// Docs for Foo pub struct Foo; diff --git a/src/test/rustdoc-js/summaries.js b/src/test/rustdoc-js/summaries.js new file mode 100644 index 00000000000..773357610d7 --- /dev/null +++ b/src/test/rustdoc-js/summaries.js @@ -0,0 +1,7 @@ +const QUERY = 'summaries'; + +const EXPECTED = { + 'others': [ + { 'path': '', 'name': 'summaries', 'desc': 'This summary has a link and code.' }, + ], +}; diff --git a/src/test/rustdoc-js/summaries.rs b/src/test/rustdoc-js/summaries.rs new file mode 100644 index 00000000000..beb91e286b6 --- /dev/null +++ b/src/test/rustdoc-js/summaries.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![crate_name = "summaries"] + +//! This *summary* has a [link] and `code`. +//! +//! This is the second paragraph. +//! +//! [link]: https://example.com + +/// This `code` will be rendered in a code tag. +/// +/// This text should not be rendered. +pub struct Sidebar; + +/// ```text +/// this block should not be rendered +/// ``` +pub struct Sidebar2; From f0cf5a974ec0730a512fa241dacf6e2c5659625f Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 24 Nov 2020 11:18:45 -0800 Subject: [PATCH 180/274] Add more rustdoc-js test cases --- src/test/rustdoc-js/summaries.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/test/rustdoc-js/summaries.js b/src/test/rustdoc-js/summaries.js index 773357610d7..f175e47342d 100644 --- a/src/test/rustdoc-js/summaries.js +++ b/src/test/rustdoc-js/summaries.js @@ -1,7 +1,21 @@ -const QUERY = 'summaries'; +// ignore-tidy-linelength -const EXPECTED = { - 'others': [ - { 'path': '', 'name': 'summaries', 'desc': 'This summary has a link and code.' }, - ], -}; +const QUERY = ['summaries', 'summaries::Sidebar', 'summaries::Sidebar2']; + +const EXPECTED = [ + { + 'others': [ + { 'path': '', 'name': 'summaries', 'desc': 'This summary has a link and code.' }, + ], + }, + { + 'others': [ + { 'path': 'summaries', 'name': 'Sidebar', 'desc': 'This code will be rendered in a code tag.' }, + ], + }, + { + 'others': [ + { 'path': 'summaries', 'name': 'Sidebar2', 'desc': '' }, + ], + }, +]; From 376507f47b5f16c0a9c210005de2bcdb270d8920 Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 3 Dec 2020 13:08:40 -0800 Subject: [PATCH 181/274] Add missing feature flag Accidentally removed in rebase. --- src/librustdoc/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 80a9c3811cf..26bf4b569ff 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -15,6 +15,7 @@ #![feature(never_type)] #![feature(once_cell)] #![feature(type_ascription)] +#![feature(split_inclusive)] #![recursion_limit = "256"] #[macro_use] From f633ef6bba70b91f0415316fe10bb1f9c016ba33 Mon Sep 17 00:00:00 2001 From: Ricky Date: Thu, 3 Dec 2020 17:22:03 -0500 Subject: [PATCH 182/274] didn't update lint correctly --- clippy_lints/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 167e5b6b87f..013406347f2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1214,6 +1214,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&integer_division::INTEGER_DIVISION), LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION), + LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), LintId::of(&mem_forget::MEM_FORGET), @@ -1280,7 +1281,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EXPLICIT_ITER_LOOP), LintId::of(¯o_use::MACRO_USE_IMPORTS), LintId::of(&manual_ok_or::MANUAL_OK_OR), - LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_SAME_ARMS), From 75482f917d7fc65190274bd577dcc2e30ba34aff Mon Sep 17 00:00:00 2001 From: Ricky Date: Thu, 3 Dec 2020 17:44:50 -0500 Subject: [PATCH 183/274] Apply suggestions from code review updated help message for the user Co-authored-by: Jane Lusby --- clippy_lints/src/map_err_ignore.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 324a11f140a..f3c0515b9bc 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -133,9 +133,9 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { cx, MAP_ERR_IGNORE, body_span, - "`map_err(|_|...` ignores the original error", + "`map_err(|_|...` wildcard pattern discards the original error", None, - "Consider wrapping the error in an enum variant for more error context, or using a named wildcard (`.map_err(|_ignored| ...`) to intentionally ignore the error", + "Consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", ); } } From 4bc33d37225db3dd3ab68bb53e855fcf794047db Mon Sep 17 00:00:00 2001 From: Ricky Date: Thu, 3 Dec 2020 17:49:27 -0500 Subject: [PATCH 184/274] Update the stderr message in ui tests --- tests/ui/map_err.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index 8193f7cfb8e..8ee2941790d 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -1,11 +1,11 @@ -error: `map_err(|_|...` ignores the original error +error: `map_err(|_|...` wildcard pattern discards the original error --> $DIR/map_err.rs:23:32 | LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | ^^^ | = note: `-D clippy::map-err-ignore` implied by `-D warnings` - = help: Consider wrapping the error in an enum variant for more error context, or using a named wildcard (`.map_err(|_ignored| ...`) to intentionally ignore the error + = help: Consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`) error: aborting due to previous error From b6113066429bc3108f62b920ccbfc79accfef2dd Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Nov 2020 22:44:02 -0300 Subject: [PATCH 185/274] Add lint unsafe_sizeof_count_copies --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 5 + .../src/unsafe_sizeof_count_copies.rs | 98 +++++++++++++ clippy_lints/src/utils/paths.rs | 4 + tests/ui/unsafe_sizeof_count_copies.rs | 54 ++++++++ tests/ui/unsafe_sizeof_count_copies.stderr | 131 ++++++++++++++++++ 6 files changed, 293 insertions(+) create mode 100644 clippy_lints/src/unsafe_sizeof_count_copies.rs create mode 100644 tests/ui/unsafe_sizeof_count_copies.rs create mode 100644 tests/ui/unsafe_sizeof_count_copies.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index e65e7cc639f..e0f3b82ad25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2124,6 +2124,7 @@ Released 2018-09-13 [`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal [`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize [`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name +[`unsafe_sizeof_count_copies`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_sizeof_count_copies [`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization [`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix [`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 167e5b6b87f..1bce0130b40 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -329,6 +329,7 @@ mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; +mod unsafe_sizeof_count_copies; mod unused_io_amount; mod unused_self; mod unused_unit; @@ -916,6 +917,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnecessary_wraps::UNNECESSARY_WRAPS, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + &unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, &unused_unit::UNUSED_UNIT, @@ -998,6 +1000,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box matches::Matches::new(msrv)); store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); + store.register_late_pass(|| box unsafe_sizeof_count_copies::UnsafeSizeofCountCopies); store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); @@ -1605,6 +1608,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(&unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), LintId::of(&unwrap::PANICKING_UNWRAP), @@ -1883,6 +1887,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(&unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), diff --git a/clippy_lints/src/unsafe_sizeof_count_copies.rs b/clippy_lints/src/unsafe_sizeof_count_copies.rs new file mode 100644 index 00000000000..2422df8feba --- /dev/null +++ b/clippy_lints/src/unsafe_sizeof_count_copies.rs @@ -0,0 +1,98 @@ +//! Lint on unsafe memory copying that use the `size_of` of the pointee type instead of a pointee +//! count + +use crate::utils::{match_def_path, paths, span_lint_and_help}; +use if_chain::if_chain; +use rustc_hir::BinOpKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{Ty as TyM, TyS}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Detects expressions where + /// size_of:: is used as the count argument to unsafe + /// memory copying functions like ptr::copy and + /// ptr::copy_nonoverlapping where T is the pointee type + /// of the pointers used + /// + /// **Why is this bad?** These functions expect a count + /// of T and not a number of bytes, which can lead to + /// copying the incorrect amount of bytes, which can + /// result in Undefined Behaviour + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,no_run + /// # use std::ptr::copy_nonoverlapping; + /// # use std::mem::size_of; + /// + /// const SIZE: usize = 128; + /// let x = [2u8; SIZE]; + /// let mut y = [2u8; SIZE]; + /// unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + /// ``` + pub UNSAFE_SIZEOF_COUNT_COPIES, + correctness, + "unsafe memory copying using a byte count instead of a count of T" +} + +declare_lint_pass!(UnsafeSizeofCountCopies => [UNSAFE_SIZEOF_COUNT_COPIES]); + +fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { + match &expr.kind { + ExprKind::Call(ref count_func, _func_args) => { + if_chain! { + if let ExprKind::Path(ref count_func_qpath) = count_func.kind; + if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::MEM_SIZE_OF) + || match_def_path(cx, def_id, &paths::MEM_SIZE_OF_VAL); + then { + cx.typeck_results().node_substs(count_func.hir_id).types().next() + } else { + None + } + } + }, + ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node || BinOpKind::Div == op.node => { + get_size_of_ty(cx, &*left).or_else(|| get_size_of_ty(cx, &*right)) + }, + _ => None, + } +} + +impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + // Find calls to ptr::copy and copy_nonoverlapping + if let ExprKind::Call(ref func, ref func_args) = expr.kind; + if let ExprKind::Path(ref func_qpath) = func.kind; + if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) + || match_def_path(cx, def_id, &paths::COPY); + + // Get the pointee type + let _substs = cx.typeck_results().node_substs(func.hir_id); + if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); + + // Find a size_of call in the count parameter expression and + // check that it's the same type + if let [_src, _dest, count] = &**func_args; + if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count); + if TyS::same_type(pointee_ty, ty_used_for_size_of); + then { + span_lint_and_help( + cx, + UNSAFE_SIZEOF_COUNT_COPIES, + expr.span, + "unsafe memory copying using a byte count (Multiplied by size_of::) \ + instead of a count of T", + None, + "use a count of elements instead of a count of bytes for the count parameter, \ + it already gets multiplied by the size of the pointed to type" + ); + } + }; + } +} diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 16e6a016c9e..fe763d4bfbb 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -20,6 +20,8 @@ pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"]; pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"]; pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"]; +pub const COPY: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; +pub const COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy"]; pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"]; @@ -73,6 +75,8 @@ pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "Manua pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"]; pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]; pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"]; +pub const MEM_SIZE_OF: [&str; 3] = ["core", "mem", "size_of"]; +pub const MEM_SIZE_OF_VAL: [&str; 3] = ["core", "mem", "size_of_val"]; pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OPS_MODULE: [&str; 2] = ["core", "ops"]; diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/unsafe_sizeof_count_copies.rs new file mode 100644 index 00000000000..0077ed07fce --- /dev/null +++ b/tests/ui/unsafe_sizeof_count_copies.rs @@ -0,0 +1,54 @@ +#![warn(clippy::unsafe_sizeof_count_copies)] + +use std::mem::{size_of, size_of_val}; +use std::ptr::{copy, copy_nonoverlapping}; + +fn main() { + const SIZE: usize = 128; + const HALF_SIZE: usize = SIZE / 2; + const DOUBLE_SIZE: usize = SIZE * 2; + let mut x = [2u8; SIZE]; + let mut y = [2u8; SIZE]; + + // Count is size_of (Should trigger the lint) + unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + + // Count expression involving multiplication of size_of (Should trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; + + // Count expression involving nested multiplications of size_of (Should trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; + + // Count expression involving divisions of size_of (Should trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; + + // No size_of calls (Should not trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), SIZE) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), SIZE) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; + + // Different types for pointee and size_of (Should not trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() / 2 * SIZE) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&0u16) / 2 * SIZE) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() / 2 * SIZE) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&0u16) / 2 * SIZE) }; +} diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr new file mode 100644 index 00000000000..6804df8cdfc --- /dev/null +++ b/tests/ui/unsafe_sizeof_count_copies.stderr @@ -0,0 +1,131 @@ +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:14:14 + | +LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unsafe-sizeof-count-copies` implied by `-D warnings` + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:15:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:17:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:18:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:21:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:22:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:24:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:25:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:28:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:29:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:31:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:32:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:35:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:36:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:38:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:39:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: aborting due to 16 previous errors + From 0f954babef41b16e26b900d3858ceac4005a4506 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 29 Nov 2020 01:47:32 -0300 Subject: [PATCH 186/274] Make the unsafe_sizeof_count_copies lint find copy_{from,to} method calls --- .../src/unsafe_sizeof_count_copies.rs | 66 ++++++++++++++----- tests/ui/unsafe_sizeof_count_copies.rs | 5 ++ tests/ui/unsafe_sizeof_count_copies.stderr | 60 +++++++++++++---- 3 files changed, 99 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/unsafe_sizeof_count_copies.rs b/clippy_lints/src/unsafe_sizeof_count_copies.rs index 2422df8feba..5df7d72564e 100644 --- a/clippy_lints/src/unsafe_sizeof_count_copies.rs +++ b/clippy_lints/src/unsafe_sizeof_count_copies.rs @@ -6,7 +6,7 @@ use if_chain::if_chain; use rustc_hir::BinOpKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{Ty as TyM, TyS}; +use rustc_middle::ty::{self, Ty, TyS, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -40,7 +40,7 @@ declare_clippy_lint! { declare_lint_pass!(UnsafeSizeofCountCopies => [UNSAFE_SIZEOF_COUNT_COPIES]); -fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { +fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { match &expr.kind { ExprKind::Call(ref count_func, _func_args) => { if_chain! { @@ -62,35 +62,65 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { + if_chain! { + // Find calls to ptr::copy and copy_nonoverlapping + if let ExprKind::Call(ref func, ref args) = expr.kind; + if let [_src, _dest, count] = &**args; + if let ExprKind::Path(ref func_qpath) = func.kind; + if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) + || match_def_path(cx, def_id, &paths::COPY); + + // Get the pointee type + if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); + then { + return Some((pointee_ty, count)); + } + }; + if_chain! { + // Find calls to copy_{from,to}{,_nonoverlapping} + if let ExprKind::MethodCall(ref method_path, _, ref args, _) = expr.kind; + if let [ptr_self, _, count] = &**args; + let method_ident = method_path.ident.as_str(); + if method_ident== "copy_to" || method_ident == "copy_from" + || method_ident == "copy_to_nonoverlapping" || method_ident == "copy_from_nonoverlapping"; + + // Get the pointee type + if let ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl:_mutability }) = + cx.typeck_results().expr_ty(ptr_self).kind(); + then { + return Some((pointee_ty, count)); + } + }; + None +} + impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - // Find calls to ptr::copy and copy_nonoverlapping - if let ExprKind::Call(ref func, ref func_args) = expr.kind; - if let ExprKind::Path(ref func_qpath) = func.kind; - if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) - || match_def_path(cx, def_id, &paths::COPY); + const HELP_MSG: &str = "use a count of elements instead of a count of bytes \ + for the count parameter, it already gets multiplied by the size of the pointed to type"; + + const LINT_MSG: &str = "unsafe memory copying using a byte count \ + (Multiplied by size_of::) instead of a count of T"; - // Get the pointee type - let _substs = cx.typeck_results().node_substs(func.hir_id); - if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); + if_chain! { + // Find calls to unsafe copy functions and get + // the pointee type and count parameter expression + if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr); // Find a size_of call in the count parameter expression and // check that it's the same type - if let [_src, _dest, count] = &**func_args; - if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count); + if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr); if TyS::same_type(pointee_ty, ty_used_for_size_of); then { span_lint_and_help( cx, UNSAFE_SIZEOF_COUNT_COPIES, expr.span, - "unsafe memory copying using a byte count (Multiplied by size_of::) \ - instead of a count of T", + LINT_MSG, None, - "use a count of elements instead of a count of bytes for the count parameter, \ - it already gets multiplied by the size of the pointed to type" + HELP_MSG ); } }; diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/unsafe_sizeof_count_copies.rs index 0077ed07fce..0bb22314cc0 100644 --- a/tests/ui/unsafe_sizeof_count_copies.rs +++ b/tests/ui/unsafe_sizeof_count_copies.rs @@ -14,6 +14,11 @@ fn main() { unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; + unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; + unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; + unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr index 6804df8cdfc..14ca04617c2 100644 --- a/tests/ui/unsafe_sizeof_count_copies.stderr +++ b/tests/ui/unsafe_sizeof_count_copies.stderr @@ -18,13 +18,45 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T --> $DIR/unsafe_sizeof_count_copies.rs:17:14 | +LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:18:14 + | +LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:19:14 + | +LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:20:14 + | +LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:22:14 + | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:18:14 + --> $DIR/unsafe_sizeof_count_copies.rs:23:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +64,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:21:14 + --> $DIR/unsafe_sizeof_count_copies.rs:26:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +72,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:22:14 + --> $DIR/unsafe_sizeof_count_copies.rs:27:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +80,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:24:14 + --> $DIR/unsafe_sizeof_count_copies.rs:29:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +88,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:25:14 + --> $DIR/unsafe_sizeof_count_copies.rs:30:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +96,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:28:14 + --> $DIR/unsafe_sizeof_count_copies.rs:33:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +104,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:29:14 + --> $DIR/unsafe_sizeof_count_copies.rs:34:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +112,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * si = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:31:14 + --> $DIR/unsafe_sizeof_count_copies.rs:36:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +120,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:32:14 + --> $DIR/unsafe_sizeof_count_copies.rs:37:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +128,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZ = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:35:14 + --> $DIR/unsafe_sizeof_count_copies.rs:40:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +136,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:36:14 + --> $DIR/unsafe_sizeof_count_copies.rs:41:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +144,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:38:14 + --> $DIR/unsafe_sizeof_count_copies.rs:43:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,12 +152,12 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:39:14 + --> $DIR/unsafe_sizeof_count_copies.rs:44:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: aborting due to 16 previous errors +error: aborting due to 20 previous errors From 1b80990fe01646868f85245f608203e23f64184a Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 29 Nov 2020 14:23:59 -0300 Subject: [PATCH 187/274] Make the unsafe_sizeof_count_copies lint work with more functions Specifically: - find std::ptr::write_bytes - find std::ptr::swap_nonoverlapping - find std::ptr::slice_from_raw_parts - find std::ptr::slice_from_raw_parts_mut - pointer_primitive::write_bytes --- .../src/unsafe_sizeof_count_copies.rs | 42 ++++-- clippy_lints/src/utils/paths.rs | 4 + tests/ui/unsafe_sizeof_count_copies.rs | 12 +- tests/ui/unsafe_sizeof_count_copies.stderr | 122 ++++++++++++------ 4 files changed, 126 insertions(+), 54 deletions(-) diff --git a/clippy_lints/src/unsafe_sizeof_count_copies.rs b/clippy_lints/src/unsafe_sizeof_count_copies.rs index 5df7d72564e..8a4538091e7 100644 --- a/clippy_lints/src/unsafe_sizeof_count_copies.rs +++ b/clippy_lints/src/unsafe_sizeof_count_copies.rs @@ -41,8 +41,8 @@ declare_clippy_lint! { declare_lint_pass!(UnsafeSizeofCountCopies => [UNSAFE_SIZEOF_COUNT_COPIES]); fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { - match &expr.kind { - ExprKind::Call(ref count_func, _func_args) => { + match expr.kind { + ExprKind::Call(count_func, _func_args) => { if_chain! { if let ExprKind::Path(ref count_func_qpath) = count_func.kind; if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); @@ -56,7 +56,7 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { - get_size_of_ty(cx, &*left).or_else(|| get_size_of_ty(cx, &*right)) + get_size_of_ty(cx, left).or_else(|| get_size_of_ty(cx, right)) }, _ => None, } @@ -64,13 +64,16 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { if_chain! { - // Find calls to ptr::copy and copy_nonoverlapping - if let ExprKind::Call(ref func, ref args) = expr.kind; - if let [_src, _dest, count] = &**args; + // Find calls to ptr::{copy, copy_nonoverlapping} + // and ptr::{swap_nonoverlapping, write_bytes}, + if let ExprKind::Call(func, args) = expr.kind; + if let [_, _, count] = args; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) - || match_def_path(cx, def_id, &paths::COPY); + || match_def_path(cx, def_id, &paths::COPY) + || match_def_path(cx, def_id, &paths::WRITE_BYTES) + || match_def_path(cx, def_id, &paths::PTR_SWAP_NONOVERLAPPING); // Get the pointee type if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); @@ -79,11 +82,11 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - } }; if_chain! { - // Find calls to copy_{from,to}{,_nonoverlapping} - if let ExprKind::MethodCall(ref method_path, _, ref args, _) = expr.kind; - if let [ptr_self, _, count] = &**args; + // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods + if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind; + if let [ptr_self, _, count] = args; let method_ident = method_path.ident.as_str(); - if method_ident== "copy_to" || method_ident == "copy_from" + if method_ident == "write_bytes" || method_ident == "copy_to" || method_ident == "copy_from" || method_ident == "copy_to_nonoverlapping" || method_ident == "copy_from_nonoverlapping"; // Get the pointee type @@ -93,6 +96,21 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - return Some((pointee_ty, count)); } }; + if_chain! { + // Find calls to ptr::copy and copy_nonoverlapping + if let ExprKind::Call(func, args) = expr.kind; + if let [_data, count] = args; + if let ExprKind::Path(ref func_qpath) = func.kind; + if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::PTR_SLICE_FROM_RAW_PARTS) + || match_def_path(cx, def_id, &paths::PTR_SLICE_FROM_RAW_PARTS_MUT); + + // Get the pointee type + if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); + then { + return Some((pointee_ty, count)); + } + }; None } @@ -102,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { for the count parameter, it already gets multiplied by the size of the pointed to type"; const LINT_MSG: &str = "unsafe memory copying using a byte count \ - (Multiplied by size_of::) instead of a count of T"; + (multiplied by size_of/size_of_val::) instead of a count of T"; if_chain! { // Find calls to unsafe copy functions and get diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index fe763d4bfbb..87c020a99db 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -104,6 +104,9 @@ pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"]; pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; pub const PTR_NULL: [&str; 3] = ["core", "ptr", "null"]; pub const PTR_NULL_MUT: [&str; 3] = ["core", "ptr", "null_mut"]; +pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"]; +pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"]; +pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"]; pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"]; pub const RC: [&str; 3] = ["alloc", "rc", "Rc"]; @@ -158,3 +161,4 @@ pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; +pub const WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"]; diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/unsafe_sizeof_count_copies.rs index 0bb22314cc0..6aed8c31f7e 100644 --- a/tests/ui/unsafe_sizeof_count_copies.rs +++ b/tests/ui/unsafe_sizeof_count_copies.rs @@ -1,7 +1,9 @@ #![warn(clippy::unsafe_sizeof_count_copies)] use std::mem::{size_of, size_of_val}; -use std::ptr::{copy, copy_nonoverlapping}; +use std::ptr::{ + copy, copy_nonoverlapping, slice_from_raw_parts, slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, +}; fn main() { const SIZE: usize = 128; @@ -22,6 +24,14 @@ fn main() { unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; + unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; + + unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; + + unsafe { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + unsafe { slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + // Count expression involving multiplication of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr index 14ca04617c2..6f491bc4e4a 100644 --- a/tests/ui/unsafe_sizeof_count_copies.stderr +++ b/tests/ui/unsafe_sizeof_count_copies.stderr @@ -1,5 +1,5 @@ -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:14:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:16:14 | LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,157 +7,197 @@ LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of: = note: `-D clippy::unsafe-sizeof-count-copies` implied by `-D warnings` = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:15:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:17:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:17:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:19:14 | LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:18:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:20:14 | LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:19:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:21:14 | LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:20:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:22:14 | LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:22:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:24:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:23:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:25:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:26:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:27:14 + | +LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:28:14 + | +LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:30:14 + | +LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:32:14 + | +LL | unsafe { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:33:14 + | +LL | unsafe { slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:36:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:27:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:37:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:29:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:39:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:30:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:40:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:33:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:43:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:34:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:44:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:36:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:46:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:37:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:47:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:40:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:50:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:41:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:51:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:43:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:53:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:44:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:54:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: aborting due to 20 previous errors +error: aborting due to 25 previous errors From 63a3c44060b9b06e10e7a854abcdbb853f6938c3 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 29 Nov 2020 14:32:11 -0300 Subject: [PATCH 188/274] Remove unnecessary unsafe_size_count_copies tests --- tests/ui/unsafe_sizeof_count_copies.rs | 22 +------ tests/ui/unsafe_sizeof_count_copies.stderr | 76 +--------------------- 2 files changed, 3 insertions(+), 95 deletions(-) diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/unsafe_sizeof_count_copies.rs index 6aed8c31f7e..2a9adeb6bd9 100644 --- a/tests/ui/unsafe_sizeof_count_copies.rs +++ b/tests/ui/unsafe_sizeof_count_copies.rs @@ -34,36 +34,16 @@ fn main() { // Count expression involving multiplication of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; - - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; // Count expression involving nested multiplications of size_of (Should trigger the lint) - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; - // Count expression involving divisions of size_of (Should trigger the lint) - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; // No size_of calls (Should not trigger the lint) - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), SIZE) }; - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), SIZE) }; - - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; // Different types for pointee and size_of (Should not trigger the lint) - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() / 2 * SIZE) }; - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&0u16) / 2 * SIZE) }; - - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() / 2 * SIZE) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&0u16) / 2 * SIZE) }; + unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() / 2 * SIZE) }; } diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr index 6f491bc4e4a..7989e96dd21 100644 --- a/tests/ui/unsafe_sizeof_count_copies.stderr +++ b/tests/ui/unsafe_sizeof_count_copies.stderr @@ -111,93 +111,21 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:37:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T --> $DIR/unsafe_sizeof_count_copies.rs:39:14 | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:40:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:43:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:44:14 - | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:46:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:47:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:50:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:51:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:53:14 + --> $DIR/unsafe_sizeof_count_copies.rs:42:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:54:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: aborting due to 25 previous errors +error: aborting due to 16 previous errors From af9685bb1e7e27a7b21d9939a42c1e9dce8c4df5 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Dec 2020 20:55:38 -0300 Subject: [PATCH 189/274] Rename unsafe_sizeof_count_copies to size_of_in_element_count Also fix review comments: - Use const arrays and iterate them for the method/function names - merge 2 if_chain's into one using a rest pattern - remove unnecessary unsafe block in test And make the lint only point to the count expression instead of the entire function call --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 10 +- ..._copies.rs => size_of_in_element_count.rs} | 74 +++++----- ..._copies.rs => size_of_in_element_count.rs} | 9 +- tests/ui/size_of_in_element_count.stderr | 131 ++++++++++++++++++ tests/ui/unsafe_sizeof_count_copies.stderr | 131 ------------------ 6 files changed, 175 insertions(+), 182 deletions(-) rename clippy_lints/src/{unsafe_sizeof_count_copies.rs => size_of_in_element_count.rs} (63%) rename tests/ui/{unsafe_sizeof_count_copies.rs => size_of_in_element_count.rs} (86%) create mode 100644 tests/ui/size_of_in_element_count.stderr delete mode 100644 tests/ui/unsafe_sizeof_count_copies.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index e0f3b82ad25..c7e02aaf4e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2057,6 +2057,7 @@ Released 2018-09-13 [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else +[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive @@ -2124,7 +2125,6 @@ Released 2018-09-13 [`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal [`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize [`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name -[`unsafe_sizeof_count_copies`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_sizeof_count_copies [`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization [`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix [`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1bce0130b40..06961064a4b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -306,6 +306,7 @@ mod self_assignment; mod serde_api; mod shadow; mod single_component_path_imports; +mod size_of_in_element_count; mod slow_vector_initialization; mod stable_sort_primitive; mod strings; @@ -329,7 +330,6 @@ mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; -mod unsafe_sizeof_count_copies; mod unused_io_amount; mod unused_self; mod unused_unit; @@ -917,7 +917,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnecessary_wraps::UNNECESSARY_WRAPS, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - &unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES, + &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, &unused_unit::UNUSED_UNIT, @@ -1000,7 +1000,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box matches::Matches::new(msrv)); store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); - store.register_late_pass(|| box unsafe_sizeof_count_copies::UnsafeSizeofCountCopies); + store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount); store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); @@ -1608,7 +1608,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(&unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), LintId::of(&unwrap::PANICKING_UNWRAP), @@ -1887,7 +1887,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(&unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), diff --git a/clippy_lints/src/unsafe_sizeof_count_copies.rs b/clippy_lints/src/size_of_in_element_count.rs similarity index 63% rename from clippy_lints/src/unsafe_sizeof_count_copies.rs rename to clippy_lints/src/size_of_in_element_count.rs index 8a4538091e7..9701e793700 100644 --- a/clippy_lints/src/unsafe_sizeof_count_copies.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -1,5 +1,5 @@ -//! Lint on unsafe memory copying that use the `size_of` of the pointee type instead of a pointee -//! count +//! Lint on use of `size_of` or `size_of_val` of T in an expression +//! expecting a count of T use crate::utils::{match_def_path, paths, span_lint_and_help}; use if_chain::if_chain; @@ -11,15 +11,11 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** Detects expressions where - /// size_of:: is used as the count argument to unsafe - /// memory copying functions like ptr::copy and - /// ptr::copy_nonoverlapping where T is the pointee type - /// of the pointers used + /// size_of:: or size_of_val:: is used as a + /// count of elements of type T /// /// **Why is this bad?** These functions expect a count - /// of T and not a number of bytes, which can lead to - /// copying the incorrect amount of bytes, which can - /// result in Undefined Behaviour + /// of T and not a number of bytes /// /// **Known problems:** None. /// @@ -33,12 +29,12 @@ declare_clippy_lint! { /// let mut y = [2u8; SIZE]; /// unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; /// ``` - pub UNSAFE_SIZEOF_COUNT_COPIES, + pub SIZE_OF_IN_ELEMENT_COUNT, correctness, - "unsafe memory copying using a byte count instead of a count of T" + "using size_of:: or size_of_val:: where a count of elements of T is expected" } -declare_lint_pass!(UnsafeSizeofCountCopies => [UNSAFE_SIZEOF_COUNT_COPIES]); +declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]); fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { match expr.kind { @@ -62,18 +58,30 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { if_chain! { // Find calls to ptr::{copy, copy_nonoverlapping} // and ptr::{swap_nonoverlapping, write_bytes}, if let ExprKind::Call(func, args) = expr.kind; - if let [_, _, count] = args; + if let [.., count] = args; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) - || match_def_path(cx, def_id, &paths::COPY) - || match_def_path(cx, def_id, &paths::WRITE_BYTES) - || match_def_path(cx, def_id, &paths::PTR_SWAP_NONOVERLAPPING); + if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path)); // Get the pointee type if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); @@ -86,8 +94,7 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind; if let [ptr_self, _, count] = args; let method_ident = method_path.ident.as_str(); - if method_ident == "write_bytes" || method_ident == "copy_to" || method_ident == "copy_from" - || method_ident == "copy_to_nonoverlapping" || method_ident == "copy_from_nonoverlapping"; + if METHODS.iter().any(|m| *m == &*method_ident); // Get the pointee type if let ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl:_mutability }) = @@ -96,31 +103,16 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - return Some((pointee_ty, count)); } }; - if_chain! { - // Find calls to ptr::copy and copy_nonoverlapping - if let ExprKind::Call(func, args) = expr.kind; - if let [_data, count] = args; - if let ExprKind::Path(ref func_qpath) = func.kind; - if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::PTR_SLICE_FROM_RAW_PARTS) - || match_def_path(cx, def_id, &paths::PTR_SLICE_FROM_RAW_PARTS_MUT); - - // Get the pointee type - if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); - then { - return Some((pointee_ty, count)); - } - }; None } -impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { +impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - const HELP_MSG: &str = "use a count of elements instead of a count of bytes \ - for the count parameter, it already gets multiplied by the size of the pointed to type"; + const HELP_MSG: &str = "use a count of elements instead of a count of bytes\ + , it already gets multiplied by the size of the type"; - const LINT_MSG: &str = "unsafe memory copying using a byte count \ - (multiplied by size_of/size_of_val::) instead of a count of T"; + const LINT_MSG: &str = "found a count of bytes \ + instead of a count of elements of T"; if_chain! { // Find calls to unsafe copy functions and get @@ -134,8 +126,8 @@ impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { then { span_lint_and_help( cx, - UNSAFE_SIZEOF_COUNT_COPIES, - expr.span, + SIZE_OF_IN_ELEMENT_COUNT, + count_expr.span, LINT_MSG, None, HELP_MSG diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/size_of_in_element_count.rs similarity index 86% rename from tests/ui/unsafe_sizeof_count_copies.rs rename to tests/ui/size_of_in_element_count.rs index 2a9adeb6bd9..d4658ebf72d 100644 --- a/tests/ui/unsafe_sizeof_count_copies.rs +++ b/tests/ui/size_of_in_element_count.rs @@ -1,8 +1,9 @@ -#![warn(clippy::unsafe_sizeof_count_copies)] +#![warn(clippy::size_of_in_element_count)] use std::mem::{size_of, size_of_val}; use std::ptr::{ - copy, copy_nonoverlapping, slice_from_raw_parts, slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, + copy, copy_nonoverlapping, slice_from_raw_parts, + slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, }; fn main() { @@ -29,8 +30,8 @@ fn main() { unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; - unsafe { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; - unsafe { slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); + slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); // Count expression involving multiplication of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; diff --git a/tests/ui/size_of_in_element_count.stderr b/tests/ui/size_of_in_element_count.stderr new file mode 100644 index 00000000000..80c3fec1b05 --- /dev/null +++ b/tests/ui/size_of_in_element_count.stderr @@ -0,0 +1,131 @@ +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:17:68 + | +LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:18:62 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:20:49 + | +LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:21:64 + | +LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:22:51 + | +LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:23:66 + | +LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:25:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:26:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:28:46 + | +LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:29:47 + | +LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:31:66 + | +LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:33:46 + | +LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:34:38 + | +LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:37:62 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:40:62 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:43:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: aborting due to 16 previous errors + diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr deleted file mode 100644 index 7989e96dd21..00000000000 --- a/tests/ui/unsafe_sizeof_count_copies.stderr +++ /dev/null @@ -1,131 +0,0 @@ -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:16:14 - | -LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unsafe-sizeof-count-copies` implied by `-D warnings` - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:17:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:19:14 - | -LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:20:14 - | -LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:21:14 - | -LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:22:14 - | -LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:24:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:25:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:27:14 - | -LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:28:14 - | -LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:30:14 - | -LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:32:14 - | -LL | unsafe { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:33:14 - | -LL | unsafe { slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:36:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:39:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:42:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: aborting due to 16 previous errors - From c1a5329475d041dbeb077ecda6ae71f690b4bcc1 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Nov 2020 21:54:50 -0300 Subject: [PATCH 190/274] Add more functions to size_of_in_element_count Specifically ptr::{sub, wrapping_sub, add, wrapping_add, offset, wrapping_offset} and slice::{from_raw_parts, from_raw_parts_mut} The lint now also looks for size_of calls through casts (Since offset takes an isize) --- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/size_of_in_element_count.rs | 48 ++++++---- clippy_lints/src/utils/paths.rs | 2 + tests/ui/size_of_in_element_count.rs | 15 ++- tests/ui/size_of_in_element_count.stderr | 98 ++++++++++++++++---- 5 files changed, 127 insertions(+), 42 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 06961064a4b..4ef595bcffd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -848,6 +848,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &shadow::SHADOW_SAME, &shadow::SHADOW_UNRELATED, &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, + &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, &stable_sort_primitive::STABLE_SORT_PRIMITIVE, &strings::STRING_ADD, @@ -917,7 +918,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnecessary_wraps::UNNECESSARY_WRAPS, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, &unused_unit::UNUSED_UNIT, @@ -1562,6 +1562,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&self_assignment::SELF_ASSIGNMENT), LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), @@ -1608,7 +1609,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), LintId::of(&unwrap::PANICKING_UNWRAP), @@ -1872,6 +1872,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(®ex::INVALID_REGEX), LintId::of(&self_assignment::SELF_ASSIGNMENT), LintId::of(&serde_api::SERDE_API_MISUSE), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), @@ -1887,7 +1888,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 9701e793700..210cf5773e1 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -54,31 +54,40 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { get_size_of_ty(cx, left).or_else(|| get_size_of_ty(cx, right)) }, + ExprKind::Cast(expr, _) => get_size_of_ty(cx, expr), _ => None, } } -const FUNCTIONS: [[&str; 3]; 6] = [ - paths::COPY_NONOVERLAPPING, - paths::COPY, - paths::WRITE_BYTES, - paths::PTR_SWAP_NONOVERLAPPING, - paths::PTR_SLICE_FROM_RAW_PARTS, - paths::PTR_SLICE_FROM_RAW_PARTS_MUT, +fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { + const FUNCTIONS: [&[&str]; 8] = [ + &paths::COPY_NONOVERLAPPING, + &paths::COPY, + &paths::WRITE_BYTES, + &paths::PTR_SWAP_NONOVERLAPPING, + &paths::PTR_SLICE_FROM_RAW_PARTS, + &paths::PTR_SLICE_FROM_RAW_PARTS_MUT, + &paths::SLICE_FROM_RAW_PARTS, + &paths::SLICE_FROM_RAW_PARTS_MUT, ]; -const METHODS: [&str; 5] = [ - "write_bytes", - "copy_to", - "copy_from", - "copy_to_nonoverlapping", - "copy_from_nonoverlapping", + const METHODS: [&str; 11] = [ + "write_bytes", + "copy_to", + "copy_from", + "copy_to_nonoverlapping", + "copy_from_nonoverlapping", + "add", + "wrapping_add", + "sub", + "wrapping_sub", + "offset", + "wrapping_offset", ]; -fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { + if_chain! { // Find calls to ptr::{copy, copy_nonoverlapping} // and ptr::{swap_nonoverlapping, write_bytes}, - if let ExprKind::Call(func, args) = expr.kind; - if let [.., count] = args; + if let ExprKind::Call(func, [.., count]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path)); @@ -91,13 +100,12 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - }; if_chain! { // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods - if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind; - if let [ptr_self, _, count] = args; + if let ExprKind::MethodCall(method_path, _, [ptr_self, .., count], _) = expr.kind; let method_ident = method_path.ident.as_str(); if METHODS.iter().any(|m| *m == &*method_ident); // Get the pointee type - if let ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl:_mutability }) = + if let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) = cx.typeck_results().expr_ty(ptr_self).kind(); then { return Some((pointee_ty, count)); @@ -115,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount { instead of a count of elements of T"; if_chain! { - // Find calls to unsafe copy functions and get + // Find calls to functions with an element count parameter and get // the pointee type and count parameter expression if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr); diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 87c020a99db..6fdc7b4587f 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -128,6 +128,8 @@ pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGu pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; +pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"]; +pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; diff --git a/tests/ui/size_of_in_element_count.rs b/tests/ui/size_of_in_element_count.rs index d4658ebf72d..b13e390705a 100644 --- a/tests/ui/size_of_in_element_count.rs +++ b/tests/ui/size_of_in_element_count.rs @@ -1,10 +1,11 @@ #![warn(clippy::size_of_in_element_count)] +#![allow(clippy::ptr_offset_with_cast)] use std::mem::{size_of, size_of_val}; use std::ptr::{ - copy, copy_nonoverlapping, slice_from_raw_parts, - slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, + copy, copy_nonoverlapping, slice_from_raw_parts, slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, }; +use std::slice::{from_raw_parts, from_raw_parts_mut}; fn main() { const SIZE: usize = 128; @@ -33,6 +34,16 @@ fn main() { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); + unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + + unsafe { y.as_mut_ptr().sub(size_of::()) }; + y.as_ptr().wrapping_sub(size_of::()); + unsafe { y.as_ptr().add(size_of::()) }; + y.as_mut_ptr().wrapping_add(size_of::()); + unsafe { y.as_ptr().offset(size_of::() as isize) }; + y.as_mut_ptr().wrapping_offset(size_of::() as isize); + // Count expression involving multiplication of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; diff --git a/tests/ui/size_of_in_element_count.stderr b/tests/ui/size_of_in_element_count.stderr index 80c3fec1b05..b7f421ec997 100644 --- a/tests/ui/size_of_in_element_count.stderr +++ b/tests/ui/size_of_in_element_count.stderr @@ -1,5 +1,5 @@ error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:17:68 + --> $DIR/size_of_in_element_count.rs:18:68 | LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of: = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:18:62 + --> $DIR/size_of_in_element_count.rs:19:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:20:49 + --> $DIR/size_of_in_element_count.rs:21:49 | LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:21:64 + --> $DIR/size_of_in_element_count.rs:22:64 | LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of:: $DIR/size_of_in_element_count.rs:22:51 + --> $DIR/size_of_in_element_count.rs:23:51 | LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:23:66 + --> $DIR/size_of_in_element_count.rs:24:66 | LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::< = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:25:47 + --> $DIR/size_of_in_element_count.rs:26:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:26:47 + --> $DIR/size_of_in_element_count.rs:27:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:28:46 + --> $DIR/size_of_in_element_count.rs:29:46 | LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:29:47 + --> $DIR/size_of_in_element_count.rs:30:47 | LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:31:66 + --> $DIR/size_of_in_element_count.rs:32:66 | LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::< = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:33:46 + --> $DIR/size_of_in_element_count.rs:34:46 | LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:34:38 + --> $DIR/size_of_in_element_count.rs:35:38 | LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,71 @@ LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:37:62 + --> $DIR/size_of_in_element_count.rs:37:49 + | +LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:38:41 + | +LL | unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:40:33 + | +LL | unsafe { y.as_mut_ptr().sub(size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:41:29 + | +LL | y.as_ptr().wrapping_sub(size_of::()); + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:42:29 + | +LL | unsafe { y.as_ptr().add(size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:43:33 + | +LL | y.as_mut_ptr().wrapping_add(size_of::()); + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:44:32 + | +LL | unsafe { y.as_ptr().offset(size_of::() as isize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:45:36 + | +LL | y.as_mut_ptr().wrapping_offset(size_of::() as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:48:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +176,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:40:62 + --> $DIR/size_of_in_element_count.rs:51:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,12 +184,12 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * si = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:43:47 + --> $DIR/size_of_in_element_count.rs:54:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: aborting due to 16 previous errors +error: aborting due to 24 previous errors From 5f821fbcf1687c4476c117bcab5a3b2a4a977d4c Mon Sep 17 00:00:00 2001 From: Ricky Date: Thu, 3 Dec 2020 19:41:44 -0500 Subject: [PATCH 191/274] Added test to make sure ignoring the error with a named wildcard value works --- tests/ui/map_err.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/ui/map_err.rs b/tests/ui/map_err.rs index 05b9949f102..00e037843f8 100644 --- a/tests/ui/map_err.rs +++ b/tests/ui/map_err.rs @@ -22,5 +22,9 @@ fn main() -> Result<(), Errors> { println!("{:?}", x.map_err(|_| Errors::Ignored)); + // Should not warn you because you explicitly ignore the parameter + // using a named wildcard value + println!("{:?}", x.map_err(|_foo| Errors::Ignored)); + Ok(()) } From 793c40e0bdf0778dfa979e757e3cbf9f62eeb22c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 3 Dec 2020 22:22:57 +0000 Subject: [PATCH 192/274] Inline `is_covered_by` --- compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 3b2eef5a905..8b21a9b24e6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -697,6 +697,8 @@ impl<'tcx> Constructor<'tcx> { /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`. /// For the simple cases, this is simply checking for equality. For the "grouped" constructors, /// this checks for inclusion. + // We inline because this has a single call site in `Matrix::specialize_constructor`. + #[inline] pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool { // This must be kept in sync with `is_covered_by_any`. match (self, other) { From 957061bb977751767e2b543b29d65581283a94fe Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Thu, 3 Dec 2020 18:07:29 -0800 Subject: [PATCH 193/274] Fix src/test/ui/env-vars.rs on 128-core machines on Windows On Windows, the environment variable NUMBER_OF_PROCESSORS has special meaning. Unfortunately, you can get different answers, depending on whether you are enumerating all environment variables or querying a specific variable. This was causing the src/test/ui/env-vars.rs test to fail on machines with more than 64 processors when run on Windows. --- src/test/ui/env-vars.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/ui/env-vars.rs b/src/test/ui/env-vars.rs index f73902c4006..f5035bb2c69 100644 --- a/src/test/ui/env-vars.rs +++ b/src/test/ui/env-vars.rs @@ -5,6 +5,14 @@ use std::env::*; fn main() { for (k, v) in vars_os() { + // On Windows, the environment variable NUMBER_OF_PROCESSORS has special meaning. + // Unfortunately, you can get different answers, depending on whether you are + // enumerating all environment variables or querying a specific variable. + // This was causing this test to fail on machines with more than 64 processors. + if cfg!(target_os = "windows") && k == "NUMBER_OF_PROCESSORS" { + continue; + } + let v2 = var_os(&k); assert!(v2.as_ref().map(|s| &**s) == Some(&*v), "bad vars->var transition: {:?} {:?} {:?}", k, v, v2); From cb56b1a7e99735238908206b6a5febf8fd6a29c0 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Sun, 20 Sep 2020 10:40:30 -0500 Subject: [PATCH 194/274] Fix comment that refers to dead enforce_object_limitations function. --- compiler/rustc_typeck/src/check/method/probe.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 39a79893b64..891dd8b2f02 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -765,13 +765,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ) }); - // It is illegal to invoke a method on a trait instance that - // refers to the `Self` type. An error will be reported by - // `enforce_object_limitations()` if the method refers to the - // `Self` type anywhere other than the receiver. Here, we use - // a substitution that replaces `Self` with the object type - // itself. Hence, a `&self` method will wind up with an - // argument type like `&Trait`. + // It is illegal to invoke a method on a trait instance that refers to + // the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error + // will be reported by `object_safety.rs` if the method refers to the + // `Self` type anywhere other than the receiver. Here, we use a + // substitution that replaces `Self` with the object type itself. Hence, + // a `&self` method will wind up with an argument type like `&Trait`. let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); From 4d8a7c282935ccb4452e371c1f572e75b7fd180e Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Tue, 20 Oct 2020 23:10:47 -0500 Subject: [PATCH 195/274] Unnest some .chain calls, so it's clearer what's going on. --- compiler/rustc_typeck/src/bounds.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 683707470f4..497754f20e4 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -67,22 +67,18 @@ impl<'tcx> Bounds<'tcx> { sized_predicate .into_iter() + .chain(self.region_bounds.iter().map(|&(region_bound, span)| { + let outlives = ty::OutlivesPredicate(param_ty, region_bound); + (ty::Binder::bind(outlives).to_predicate(tcx), span) + })) + .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { + let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); + (predicate, span) + })) .chain( - self.region_bounds + self.projection_bounds .iter() - .map(|&(region_bound, span)| { - let outlives = ty::OutlivesPredicate(param_ty, region_bound); - (ty::Binder::bind(outlives).to_predicate(tcx), span) - }) - .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { - let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); - (predicate, span) - })) - .chain( - self.projection_bounds - .iter() - .map(|&(projection, span)| (projection.to_predicate(tcx), span)), - ), + .map(|&(projection, span)| (projection.to_predicate(tcx), span)), ) .collect() } From 76ff0f408ac46d4b22b9a09898ccece3a7ca92ac Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Tue, 20 Oct 2020 23:22:34 -0500 Subject: [PATCH 196/274] The details of higher-rank sub are in the rustc book not a doc module. --- compiler/rustc_infer/src/infer/higher_ranked/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index 9d9ecf5b384..39043980dc4 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -24,9 +24,9 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // as-is, we need to do some extra work here in order to make sure // that function subtyping works correctly with respect to regions // - // Note: this is a subtle algorithm. For a full explanation, - // please see the large comment at the end of the file in the (inlined) module - // `doc`. + // Note: this is a subtle algorithm. For a full explanation, please see + // the rustc dev guide: + // let span = self.trace.cause.span; From 504f136c74fb48967e0cddc8c05481b7fc1bac52 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Tue, 20 Oct 2020 23:22:43 -0500 Subject: [PATCH 197/274] Writeback walks the HIR not the AST. --- compiler/rustc_typeck/src/check/writeback.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index d1ada123c0d..68b85a4da34 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -88,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /////////////////////////////////////////////////////////////////////////// -// The Writeback context. This visitor walks the AST, checking the +// The Writeback context. This visitor walks the HIR, checking the // fn-specific typeck results to find references to types or regions. It // resolves those regions to remove inference variables and writes the // final result back into the master typeck results in the tcx. Here and From 01f32116028a127b4a946c72b8ed5de3e03be477 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 4 Dec 2020 10:01:09 +0100 Subject: [PATCH 198/274] Turn unnecessary_wraps applicability to MaybeIncorrect --- clippy_lints/src/unnecessary_wraps.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 360df2a6752..5d801511a0b 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { diag.multipart_suggestion( "...and change the returning expressions", suggs, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); }, ); From 823f64532c2f234db14d09ab51bf73a6b71d8e0e Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Fri, 4 Dec 2020 11:33:30 +0100 Subject: [PATCH 199/274] A slightly clearer diagnostic when misusing --- compiler/rustc_parse/src/parser/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b746256f5fe..22f308ff36d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -264,7 +264,7 @@ impl TokenType { TokenType::Ident => "identifier".to_string(), TokenType::Path => "path".to_string(), TokenType::Type => "type".to_string(), - TokenType::Const => "const".to_string(), + TokenType::Const => "a const expression".to_string(), } } } From 19003517cea93d337df071e191ecd57259543cd4 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Fri, 4 Dec 2020 12:21:33 +0100 Subject: [PATCH 200/274] Fix UI tests for 'const expression' change --- .../parse/trait-path-missing-gen_arg.rs | 4 ++-- .../parse/trait-path-missing-gen_arg.stderr | 8 ++++---- src/test/ui/issues/issue-20616-3.rs | 2 +- src/test/ui/issues/issue-20616-3.stderr | 4 ++-- src/test/ui/issues/issue-20616-4.rs | 2 +- src/test/ui/issues/issue-20616-4.stderr | 4 ++-- src/test/ui/issues/issue-20616-5.rs | 2 +- src/test/ui/issues/issue-20616-5.stderr | 4 ++-- src/test/ui/issues/issue-20616-6.rs | 2 +- src/test/ui/issues/issue-20616-6.stderr | 4 ++-- src/test/ui/issues/issue-20616-7.rs | 2 +- src/test/ui/issues/issue-20616-7.stderr | 4 ++-- src/test/ui/parser/removed-syntax-uniq-mut-ty.rs | 2 +- src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr | 4 ++-- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs index dad8c2a2909..94dda17aad7 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs @@ -7,7 +7,7 @@ trait X { const _: () = { fn f1<'a>(arg : Box>) {} - //~^ ERROR: expected one of `>`, const, lifetime, or type, found `:` + //~^ ERROR: expected one of `>`, a const expression, lifetime, or type, found `:` //~| ERROR: expected parameter name, found `>` //~| ERROR: expected one of `!`, `)`, `+`, `,`, or `::`, found `>` //~| ERROR: constant provided when a type was expected @@ -15,7 +15,7 @@ const _: () = { const _: () = { fn f1<'a>(arg : Box>) {} - //~^ ERROR: expected one of `>`, const, lifetime, or type, found `=` + //~^ ERROR: expected one of `>`, a const expression, lifetime, or type, found `=` }; fn main() {} diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr index 583697f0b67..8a5e2c29c36 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, lifetime, or type, found `:` +error: expected one of `>`, a const expression, lifetime, or type, found `:` --> $DIR/trait-path-missing-gen_arg.rs:9:30 | LL | fn f1<'a>(arg : Box>) {} - | ^ expected one of `>`, const, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type | help: expressions must be enclosed in braces to be used as const generic arguments | @@ -24,11 +24,11 @@ LL | fn f1<'a>(arg : Box>) {} | expected one of `!`, `)`, `+`, `,`, or `::` | help: missing `,` -error: expected one of `>`, const, lifetime, or type, found `=` +error: expected one of `>`, a const expression, lifetime, or type, found `=` --> $DIR/trait-path-missing-gen_arg.rs:17:30 | LL | fn f1<'a>(arg : Box>) {} - | ^ expected one of `>`, const, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/trait-path-missing-gen_arg.rs:1:12 diff --git a/src/test/ui/issues/issue-20616-3.rs b/src/test/ui/issues/issue-20616-3.rs index 780038c11b8..b2371051c78 100644 --- a/src/test/ui/issues/issue-20616-3.rs +++ b/src/test/ui/issues/issue-20616-3.rs @@ -11,7 +11,7 @@ type Type_1_<'a, T> = &'a T; type Type_3 = Box; -//~^ error: expected one of `>`, const, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` //type Type_4 = Type_1_<'static,, T>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-3.stderr b/src/test/ui/issues/issue-20616-3.stderr index 2f8cf8a79ed..b535c7a3267 100644 --- a/src/test/ui/issues/issue-20616-3.stderr +++ b/src/test/ui/issues/issue-20616-3.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-3.rs:13:24 | LL | type Type_3 = Box; - | ^ expected one of `>`, const, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-4.rs b/src/test/ui/issues/issue-20616-4.rs index 85aa9c1146d..a71f47ca4bf 100644 --- a/src/test/ui/issues/issue-20616-4.rs +++ b/src/test/ui/issues/issue-20616-4.rs @@ -14,7 +14,7 @@ type Type_1_<'a, T> = &'a T; type Type_4 = Type_1_<'static,, T>; -//~^ error: expected one of `>`, const, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` type Type_5_<'a> = Type_1_<'a, ()>; diff --git a/src/test/ui/issues/issue-20616-4.stderr b/src/test/ui/issues/issue-20616-4.stderr index 3be6c2e78ce..2b3b75f3119 100644 --- a/src/test/ui/issues/issue-20616-4.stderr +++ b/src/test/ui/issues/issue-20616-4.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-4.rs:16:34 | LL | type Type_4 = Type_1_<'static,, T>; - | ^ expected one of `>`, const, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-5.rs b/src/test/ui/issues/issue-20616-5.rs index c0c6bc6dd97..b96d09d59ae 100644 --- a/src/test/ui/issues/issue-20616-5.rs +++ b/src/test/ui/issues/issue-20616-5.rs @@ -20,7 +20,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_5<'a> = Type_1_<'a, (),,>; -//~^ error: expected one of `>`, const, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-5.stderr b/src/test/ui/issues/issue-20616-5.stderr index b90fbf60051..1ec1dbde695 100644 --- a/src/test/ui/issues/issue-20616-5.stderr +++ b/src/test/ui/issues/issue-20616-5.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-5.rs:22:34 | LL | type Type_5<'a> = Type_1_<'a, (),,>; - | ^ expected one of `>`, const, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-6.rs b/src/test/ui/issues/issue-20616-6.rs index 73c75bdc45f..a2c45ecec7a 100644 --- a/src/test/ui/issues/issue-20616-6.rs +++ b/src/test/ui/issues/issue-20616-6.rs @@ -23,7 +23,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_6 = Type_5_<'a,,>; -//~^ error: expected one of `>`, const, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` //type Type_7 = Box<(),,>; // error: expected type, found `,` diff --git a/src/test/ui/issues/issue-20616-6.stderr b/src/test/ui/issues/issue-20616-6.stderr index ea1c15ba423..7401abdd091 100644 --- a/src/test/ui/issues/issue-20616-6.stderr +++ b/src/test/ui/issues/issue-20616-6.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-6.rs:25:26 | LL | type Type_6 = Type_5_<'a,,>; - | ^ expected one of `>`, const, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-7.rs b/src/test/ui/issues/issue-20616-7.rs index 8beeebd7a95..67209c02adf 100644 --- a/src/test/ui/issues/issue-20616-7.rs +++ b/src/test/ui/issues/issue-20616-7.rs @@ -26,7 +26,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_7 = Box<(),,>; -//~^ error: expected one of `>`, const, lifetime, or type, found `,` +//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,` //type Type_8<'a,,> = &'a (); // error: expected ident, found `,` diff --git a/src/test/ui/issues/issue-20616-7.stderr b/src/test/ui/issues/issue-20616-7.stderr index dcd199902fc..e2c3efe8447 100644 --- a/src/test/ui/issues/issue-20616-7.stderr +++ b/src/test/ui/issues/issue-20616-7.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, lifetime, or type, found `,` +error: expected one of `>`, a const expression, lifetime, or type, found `,` --> $DIR/issue-20616-7.rs:28:22 | LL | type Type_7 = Box<(),,>; - | ^ expected one of `>`, const, lifetime, or type + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs b/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs index f9a9d071a3d..a8dee5bbda4 100644 --- a/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs +++ b/src/test/ui/parser/removed-syntax-uniq-mut-ty.rs @@ -1,2 +1,2 @@ type mut_box = Box; -//~^ ERROR expected one of `>`, const, lifetime, or type, found keyword `mut` +//~^ ERROR expected one of `>`, a const expression, lifetime, or type, found keyword `mut` diff --git a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr index 0703caf5bed..39db0be9fbb 100644 --- a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr +++ b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, const, lifetime, or type, found keyword `mut` +error: expected one of `>`, a const expression, lifetime, or type, found keyword `mut` --> $DIR/removed-syntax-uniq-mut-ty.rs:1:20 | LL | type mut_box = Box; - | ^^^ expected one of `>`, const, lifetime, or type + | ^^^ expected one of `>`, a const expression, lifetime, or type error: aborting due to previous error From 356ea6b5aa76df23f12a3f11725517c29872a31e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 4 Dec 2020 16:22:36 +0300 Subject: [PATCH 201/274] Move format machinery tests to where they belong --- src/test/ui/{expr/if => fmt}/ifmt-bad-arg.rs | 0 src/test/ui/{expr/if => fmt}/ifmt-bad-arg.stderr | 0 src/test/ui/{expr/if => fmt}/ifmt-bad-format-args.rs | 0 src/test/ui/{expr/if => fmt}/ifmt-bad-format-args.stderr | 0 src/test/ui/{expr/if => fmt}/ifmt-unimpl.rs | 0 src/test/ui/{expr/if => fmt}/ifmt-unimpl.stderr | 0 src/test/ui/{expr/if => fmt}/ifmt-unknown-trait.rs | 0 src/test/ui/{expr/if => fmt}/ifmt-unknown-trait.stderr | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{expr/if => fmt}/ifmt-bad-arg.rs (100%) rename src/test/ui/{expr/if => fmt}/ifmt-bad-arg.stderr (100%) rename src/test/ui/{expr/if => fmt}/ifmt-bad-format-args.rs (100%) rename src/test/ui/{expr/if => fmt}/ifmt-bad-format-args.stderr (100%) rename src/test/ui/{expr/if => fmt}/ifmt-unimpl.rs (100%) rename src/test/ui/{expr/if => fmt}/ifmt-unimpl.stderr (100%) rename src/test/ui/{expr/if => fmt}/ifmt-unknown-trait.rs (100%) rename src/test/ui/{expr/if => fmt}/ifmt-unknown-trait.stderr (100%) diff --git a/src/test/ui/expr/if/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs similarity index 100% rename from src/test/ui/expr/if/ifmt-bad-arg.rs rename to src/test/ui/fmt/ifmt-bad-arg.rs diff --git a/src/test/ui/expr/if/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr similarity index 100% rename from src/test/ui/expr/if/ifmt-bad-arg.stderr rename to src/test/ui/fmt/ifmt-bad-arg.stderr diff --git a/src/test/ui/expr/if/ifmt-bad-format-args.rs b/src/test/ui/fmt/ifmt-bad-format-args.rs similarity index 100% rename from src/test/ui/expr/if/ifmt-bad-format-args.rs rename to src/test/ui/fmt/ifmt-bad-format-args.rs diff --git a/src/test/ui/expr/if/ifmt-bad-format-args.stderr b/src/test/ui/fmt/ifmt-bad-format-args.stderr similarity index 100% rename from src/test/ui/expr/if/ifmt-bad-format-args.stderr rename to src/test/ui/fmt/ifmt-bad-format-args.stderr diff --git a/src/test/ui/expr/if/ifmt-unimpl.rs b/src/test/ui/fmt/ifmt-unimpl.rs similarity index 100% rename from src/test/ui/expr/if/ifmt-unimpl.rs rename to src/test/ui/fmt/ifmt-unimpl.rs diff --git a/src/test/ui/expr/if/ifmt-unimpl.stderr b/src/test/ui/fmt/ifmt-unimpl.stderr similarity index 100% rename from src/test/ui/expr/if/ifmt-unimpl.stderr rename to src/test/ui/fmt/ifmt-unimpl.stderr diff --git a/src/test/ui/expr/if/ifmt-unknown-trait.rs b/src/test/ui/fmt/ifmt-unknown-trait.rs similarity index 100% rename from src/test/ui/expr/if/ifmt-unknown-trait.rs rename to src/test/ui/fmt/ifmt-unknown-trait.rs diff --git a/src/test/ui/expr/if/ifmt-unknown-trait.stderr b/src/test/ui/fmt/ifmt-unknown-trait.stderr similarity index 100% rename from src/test/ui/expr/if/ifmt-unknown-trait.stderr rename to src/test/ui/fmt/ifmt-unknown-trait.stderr From 9274b37d99f608e5fde569788ee79bd72fc3cf13 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Fri, 4 Dec 2020 14:47:15 +0100 Subject: [PATCH 202/274] Rename `AllocRef` to `Allocator` and `(de)alloc` to `(de)allocate` --- library/alloc/src/alloc.rs | 40 ++-- library/alloc/src/alloc/tests.rs | 4 +- library/alloc/src/boxed.rs | 133 +++++------ library/alloc/src/collections/btree/node.rs | 10 +- library/alloc/src/raw_vec.rs | 24 +- library/alloc/src/raw_vec/tests.rs | 10 +- library/alloc/src/rc.rs | 18 +- library/alloc/src/slice.rs | 24 +- library/alloc/src/sync.rs | 16 +- library/alloc/src/vec.rs | 224 +++++++++--------- library/alloc/tests/heap.rs | 8 +- library/core/src/alloc/layout.rs | 2 +- library/core/src/alloc/mod.rs | 64 ++--- library/core/src/ptr/non_null.rs | 4 +- library/std/src/alloc.rs | 20 +- src/test/ui/allocator/custom.rs | 15 +- src/test/ui/allocator/xcrate-use.rs | 10 +- .../ui/associated-types/defaults-wf.stderr | 2 +- src/test/ui/bad/bad-sized.stderr | 2 +- src/test/ui/box/leak-alloc.rs | 16 +- .../e0119/conflict-with-std.stderr | 2 +- src/test/ui/issues/issue-20433.stderr | 2 +- src/test/ui/issues/issue-41974.stderr | 2 +- src/test/ui/realloc-16687.rs | 6 +- src/test/ui/regions/regions-mock-codegen.rs | 10 +- src/test/ui/unique-object-noncopyable.stderr | 2 +- src/test/ui/unique-pinned-nocopy.stderr | 2 +- 27 files changed, 337 insertions(+), 335 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index b1bfc2abe44..4fbcc4590f1 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -38,7 +38,7 @@ extern "Rust" { /// The global memory allocator. /// -/// This type implements the [`AllocRef`] trait by forwarding calls +/// This type implements the [`Allocator`] trait by forwarding calls /// to the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crate’s default. /// @@ -59,7 +59,7 @@ pub use std::alloc::Global; /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `alloc` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -93,7 +93,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `dealloc` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -111,7 +111,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `realloc` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -129,7 +129,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 /// if there is one, or the `std` crate’s default. /// /// This function is expected to be deprecated in favor of the `alloc_zeroed` method -/// of the [`Global`] type when it and the [`AllocRef`] trait become stable. +/// of the [`Global`] type when it and the [`Allocator`] trait become stable. /// /// # Safety /// @@ -170,7 +170,7 @@ impl Global { } } - // SAFETY: Same as `AllocRef::grow` + // SAFETY: Same as `Allocator::grow` #[inline] unsafe fn grow_impl( &self, @@ -211,7 +211,7 @@ impl Global { old_size => unsafe { let new_ptr = self.alloc_impl(new_layout, zeroed)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); Ok(new_ptr) }, } @@ -220,19 +220,19 @@ impl Global { #[unstable(feature = "allocator_api", issue = "32838")] #[cfg(not(test))] -unsafe impl AllocRef for Global { +unsafe impl Allocator for Global { #[inline] - fn alloc(&self, layout: Layout) -> Result, AllocError> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -277,7 +277,7 @@ unsafe impl AllocRef for Global { match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, @@ -297,9 +297,9 @@ unsafe impl AllocRef for Global { // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller. new_size => unsafe { - let new_ptr = self.alloc(new_layout)?; + let new_ptr = self.allocate(new_layout)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); Ok(new_ptr) }, } @@ -313,7 +313,7 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; - match Global.alloc(layout) { + match Global.allocate(layout) { Ok(ptr) => ptr.as_mut_ptr(), Err(_) => handle_alloc_error(layout), } @@ -322,16 +322,16 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { #[cfg_attr(not(test), lang = "box_free")] #[inline] // This signature has to be the same as `Box`, otherwise an ICE will happen. -// When an additional parameter to `Box` is added (like `A: AllocRef`), this has to be added here as +// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as // well. -// For example if `Box` is changed to `struct Box(Unique, A)`, -// this function has to be changed to `fn box_free(Unique, A)` as well. -pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { +// For example if `Box` is changed to `struct Box(Unique, A)`, +// this function has to be changed to `fn box_free(Unique, A)` as well. +pub(crate) unsafe fn box_free(ptr: Unique, alloc: A) { unsafe { let size = size_of_val(ptr.as_ref()); let align = min_align_of_val(ptr.as_ref()); let layout = Layout::from_size_align_unchecked(size, align); - alloc.dealloc(ptr.cast().into(), layout) + alloc.deallocate(ptr.cast().into(), layout) } } diff --git a/library/alloc/src/alloc/tests.rs b/library/alloc/src/alloc/tests.rs index f7463d0daac..94e05fa448f 100644 --- a/library/alloc/src/alloc/tests.rs +++ b/library/alloc/src/alloc/tests.rs @@ -9,7 +9,7 @@ fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = - Global.alloc_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout)); + Global.allocate_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout)); let mut i = ptr.as_non_null_ptr().as_ptr(); let end = i.add(layout.size()); @@ -17,7 +17,7 @@ fn allocate_zeroed() { assert_eq!(*i, 0); i = i.offset(1); } - Global.dealloc(ptr.as_non_null_ptr(), layout); + Global.deallocate(ptr.as_non_null_ptr(), layout); } } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index d814c525ceb..a6360f25eca 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -153,7 +153,7 @@ use core::pin::Pin; use core::ptr::{self, Unique}; use core::task::{Context, Poll}; -use crate::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{handle_alloc_error, Allocator, Global, Layout}; use crate::borrow::Cow; use crate::raw_vec::RawVec; use crate::str::from_boxed_utf8_unchecked; @@ -167,7 +167,7 @@ use crate::vec::Vec; #[stable(feature = "rust1", since = "1.0.0")] pub struct Box< T: ?Sized, - #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, >(Unique, A); impl Box { @@ -243,7 +243,7 @@ impl Box { } } -impl Box { +impl Box { /// Allocates memory in the given allocator then places `x` into it. /// /// This doesn't actually allocate if `T` is zero-sized. @@ -291,7 +291,7 @@ impl Box { // #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); - let ptr = alloc.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); + let ptr = alloc.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); unsafe { Box::from_raw_in(ptr.as_ptr(), alloc) } } @@ -319,7 +319,8 @@ impl Box { // #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); - let ptr = alloc.alloc_zeroed(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); + let ptr = + alloc.allocate_zeroed(layout).unwrap_or_else(|_| handle_alloc_error(layout)).cast(); unsafe { Box::from_raw_in(ptr.as_ptr(), alloc) } } @@ -339,7 +340,7 @@ impl Box { /// This conversion does not allocate on the heap and happens in place. #[unstable(feature = "box_into_boxed_slice", issue = "71582")] pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> { - let (raw, alloc) = Box::into_raw_with_alloc(boxed); + let (raw, alloc) = Box::into_raw_with_allocator(boxed); unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) } } } @@ -394,7 +395,7 @@ impl Box<[T]> { } } -impl Box<[T], A> { +impl Box<[T], A> { /// Constructs a new boxed slice with uninitialized contents in the provided allocator. /// /// # Examples @@ -450,7 +451,7 @@ impl Box<[T], A> { } } -impl Box, A> { +impl Box, A> { /// Converts to `Box`. /// /// # Safety @@ -482,12 +483,12 @@ impl Box, A> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box { - let (raw, alloc) = Box::into_raw_with_alloc(self); + let (raw, alloc) = Box::into_raw_with_allocator(self); unsafe { Box::from_raw_in(raw as *mut T, alloc) } } } -impl Box<[mem::MaybeUninit], A> { +impl Box<[mem::MaybeUninit], A> { /// Converts to `Box<[T], A>`. /// /// # Safety @@ -521,7 +522,7 @@ impl Box<[mem::MaybeUninit], A> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box<[T], A> { - let (raw, alloc) = Box::into_raw_with_alloc(self); + let (raw, alloc) = Box::into_raw_with_allocator(self); unsafe { Box::from_raw_in(raw as *mut [T], alloc) } } } @@ -575,7 +576,7 @@ impl Box { } } -impl Box { +impl Box { /// Constructs a box from a raw pointer in the given allocator. /// /// After calling this function, the raw pointer is owned by the @@ -594,24 +595,24 @@ impl Box { /// # Examples /// /// Recreate a `Box` which was previously converted to a raw pointer - /// using [`Box::into_raw_with_alloc`]: + /// using [`Box::into_raw_with_allocator`]: /// ``` /// #![feature(allocator_api)] /// /// use std::alloc::System; /// /// let x = Box::new_in(5, System); - /// let (ptr, alloc) = Box::into_raw_with_alloc(x); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; /// ``` /// Manually create a `Box` from scratch by using the system allocator: /// ``` /// #![feature(allocator_api, slice_ptr_get)] /// - /// use std::alloc::{AllocRef, Layout, System}; + /// use std::alloc::{Allocator, Layout, System}; /// /// unsafe { - /// let ptr = System.alloc(Layout::new::())?.as_mut_ptr(); + /// let ptr = System.allocate(Layout::new::())?.as_mut_ptr(); /// // In general .write is required to avoid attempting to destruct /// // the (uninitialized) previous contents of `ptr`, though for this /// // simple example `*ptr = 5` would have worked as well. @@ -671,7 +672,7 @@ impl Box { #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Self) -> *mut T { - Self::into_raw_with_alloc(b).0 + Self::into_raw_with_allocator(b).0 } /// Consumes the `Box`, returning a wrapped raw pointer and the allocator. @@ -687,7 +688,7 @@ impl Box { /// the cleanup. /// /// Note: this is an associated function, which means that you have - /// to call it as `Box::into_raw_with_alloc(b)` instead of `b.into_raw_with_alloc()`. This + /// to call it as `Box::into_raw_with_allocator(b)` instead of `b.into_raw_with_allocator()`. This /// is so that there is no conflict with a method on the inner type. /// /// # Examples @@ -699,7 +700,7 @@ impl Box { /// use std::alloc::System; /// /// let x = Box::new_in(String::from("Hello"), System); - /// let (ptr, alloc) = Box::into_raw_with_alloc(x); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; /// ``` /// Manual cleanup by explicitly running the destructor and deallocating @@ -707,22 +708,22 @@ impl Box { /// ``` /// #![feature(allocator_api)] /// - /// use std::alloc::{AllocRef, Layout, System}; + /// use std::alloc::{Allocator, Layout, System}; /// use std::ptr::{self, NonNull}; /// /// let x = Box::new_in(String::from("Hello"), System); - /// let (ptr, alloc) = Box::into_raw_with_alloc(x); + /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// unsafe { /// ptr::drop_in_place(ptr); /// let non_null = NonNull::new_unchecked(ptr); - /// alloc.dealloc(non_null.cast(), Layout::new::()); + /// alloc.deallocate(non_null.cast(), Layout::new::()); /// } /// ``` /// /// [memory layout]: self#memory-layout #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn into_raw_with_alloc(b: Self) -> (*mut T, A) { + pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) { let (leaked, alloc) = Box::into_unique(b); (leaked.as_ptr(), alloc) } @@ -747,11 +748,11 @@ impl Box { /// Returns a reference to the underlying allocator. /// /// Note: this is an associated function, which means that you have - /// to call it as `Box::alloc_ref(&b)` instead of `b.alloc_ref()`. This + /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This /// is so that there is no conflict with a method on the inner type. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(b: &Self) -> &A { + pub fn allocator(b: &Self) -> &A { &b.1 } @@ -817,7 +818,7 @@ impl Box { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized, A: AllocRef> Drop for Box { +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { fn drop(&mut self) { // FIXME: Do nothing, drop is currently performed by compiler. } @@ -846,7 +847,7 @@ impl Default for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Box { +impl Clone for Box { /// Returns a new box with a `clone()` of this box's contents. /// /// # Examples @@ -900,7 +901,7 @@ impl Clone for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Box { +impl PartialEq for Box { #[inline] fn eq(&self, other: &Self) -> bool { PartialEq::eq(&**self, &**other) @@ -911,7 +912,7 @@ impl PartialEq for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Box { +impl PartialOrd for Box { #[inline] fn partial_cmp(&self, other: &Self) -> Option { PartialOrd::partial_cmp(&**self, &**other) @@ -934,24 +935,24 @@ impl PartialOrd for Box { } } #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Box { +impl Ord for Box { #[inline] fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(&**self, &**other) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Box {} +impl Eq for Box {} #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Box { +impl Hash for Box { fn hash(&self, state: &mut H) { (**self).hash(state); } } #[stable(feature = "indirect_hasher_impl", since = "1.22.0")] -impl Hasher for Box { +impl Hasher for Box { fn finish(&self) -> u64 { (**self).finish() } @@ -1016,7 +1017,7 @@ impl From for Box { } #[stable(feature = "pin", since = "1.33.0")] -impl From> for Pin> +impl From> for Pin> where A: 'static, { @@ -1094,7 +1095,7 @@ impl From> for Box { } #[stable(feature = "boxed_str_conv", since = "1.19.0")] -impl From> for Box<[u8], A> { +impl From> for Box<[u8], A> { /// Converts a `Box` into a `Box<[u8]>` /// /// This conversion does not allocate on the heap and happens in place. @@ -1113,7 +1114,7 @@ impl From> for Box<[u8], A> { /// ``` #[inline] fn from(s: Box) -> Self { - let (raw, alloc) = Box::into_raw_with_alloc(s); + let (raw, alloc) = Box::into_raw_with_allocator(s); unsafe { Box::from_raw_in(raw as *mut [u8], alloc) } } } @@ -1147,7 +1148,7 @@ impl TryFrom> for Box<[T; N]> { } } -impl Box { +impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. @@ -1170,7 +1171,7 @@ impl Box { pub fn downcast(self) -> Result, Self> { if self.is::() { unsafe { - let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_alloc(self); + let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); Ok(Box::from_raw_in(raw as *mut T, alloc)) } } else { @@ -1179,7 +1180,7 @@ impl Box { } } -impl Box { +impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. @@ -1202,7 +1203,7 @@ impl Box { pub fn downcast(self) -> Result, Self> { if self.is::() { unsafe { - let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_alloc(self); + let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); Ok(Box::from_raw_in(raw as *mut T, alloc)) } } else { @@ -1212,21 +1213,21 @@ impl Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Box { +impl fmt::Display for Box { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Box { +impl fmt::Debug for Box { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Pointer for Box { +impl fmt::Pointer for Box { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // It's not possible to extract the inner Uniq directly from the Box, // instead we cast it to a *const which aliases the Unique @@ -1236,7 +1237,7 @@ impl fmt::Pointer for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Box { +impl Deref for Box { type Target = T; fn deref(&self) -> &T { @@ -1245,17 +1246,17 @@ impl Deref for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl DerefMut for Box { +impl DerefMut for Box { fn deref_mut(&mut self) -> &mut T { &mut **self } } #[unstable(feature = "receiver_trait", issue = "none")] -impl Receiver for Box {} +impl Receiver for Box {} #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Box { +impl Iterator for Box { type Item = I::Item; fn next(&mut self) -> Option { (**self).next() @@ -1276,7 +1277,7 @@ trait BoxIter { fn last(self) -> Option; } -impl BoxIter for Box { +impl BoxIter for Box { type Item = I::Item; default fn last(self) -> Option { #[inline] @@ -1291,14 +1292,14 @@ impl BoxIter for Box { /// Specialization for sized `I`s that uses `I`s implementation of `last()` /// instead of the default. #[stable(feature = "rust1", since = "1.0.0")] -impl BoxIter for Box { +impl BoxIter for Box { fn last(self) -> Option { (*self).last() } } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Box { +impl DoubleEndedIterator for Box { fn next_back(&mut self) -> Option { (**self).next_back() } @@ -1307,7 +1308,7 @@ impl DoubleEndedIterator for Box ExactSizeIterator for Box { +impl ExactSizeIterator for Box { fn len(&self) -> usize { (**self).len() } @@ -1317,10 +1318,10 @@ impl ExactSizeIterator for Box } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Box {} +impl FusedIterator for Box {} #[stable(feature = "boxed_closure_impls", since = "1.35.0")] -impl + ?Sized, A: AllocRef> FnOnce for Box { +impl + ?Sized, A: Allocator> FnOnce for Box { type Output = >::Output; extern "rust-call" fn call_once(self, args: Args) -> Self::Output { @@ -1329,21 +1330,21 @@ impl + ?Sized, A: AllocRef> FnOnce for Box { } #[stable(feature = "boxed_closure_impls", since = "1.35.0")] -impl + ?Sized, A: AllocRef> FnMut for Box { +impl + ?Sized, A: Allocator> FnMut for Box { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { >::call_mut(self, args) } } #[stable(feature = "boxed_closure_impls", since = "1.35.0")] -impl + ?Sized, A: AllocRef> Fn for Box { +impl + ?Sized, A: Allocator> Fn for Box { extern "rust-call" fn call(&self, args: Args) -> Self::Output { >::call(self, args) } } #[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized, A: AllocRef> CoerceUnsized> for Box {} +impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U: ?Sized> DispatchFromDyn> for Box {} @@ -1356,9 +1357,9 @@ impl FromIterator for Box<[I]> { } #[stable(feature = "box_slice_clone", since = "1.3.0")] -impl Clone for Box<[T], A> { +impl Clone for Box<[T], A> { fn clone(&self) -> Self { - let alloc = Box::alloc_ref(self).clone(); + let alloc = Box::allocator(self).clone(); self.to_vec_in(alloc).into_boxed_slice() } @@ -1372,28 +1373,28 @@ impl Clone for Box<[T], A> { } #[stable(feature = "box_borrow", since = "1.1.0")] -impl borrow::Borrow for Box { +impl borrow::Borrow for Box { fn borrow(&self) -> &T { &**self } } #[stable(feature = "box_borrow", since = "1.1.0")] -impl borrow::BorrowMut for Box { +impl borrow::BorrowMut for Box { fn borrow_mut(&mut self) -> &mut T { &mut **self } } #[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsRef for Box { +impl AsRef for Box { fn as_ref(&self) -> &T { &**self } } #[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsMut for Box { +impl AsMut for Box { fn as_mut(&mut self) -> &mut T { &mut **self } @@ -1422,10 +1423,10 @@ impl AsMut for Box { * could have a method to project a Pin from it. */ #[stable(feature = "pin", since = "1.33.0")] -impl Unpin for Box where A: 'static {} +impl Unpin for Box where A: 'static {} #[unstable(feature = "generator_trait", issue = "43122")] -impl + Unpin, R, A: AllocRef> Generator for Box +impl + Unpin, R, A: Allocator> Generator for Box where A: 'static, { @@ -1438,7 +1439,7 @@ where } #[unstable(feature = "generator_trait", issue = "43122")] -impl, R, A: AllocRef> Generator for Pin> +impl, R, A: Allocator> Generator for Pin> where A: 'static, { @@ -1451,7 +1452,7 @@ where } #[stable(feature = "futures_api", since = "1.36.0")] -impl Future for Box +impl Future for Box where A: 'static, { diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 78be070a983..31809fde57b 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -36,7 +36,7 @@ use core::marker::PhantomData; use core::mem::{self, MaybeUninit}; use core::ptr::{self, NonNull}; -use crate::alloc::{AllocRef, Global, Layout}; +use crate::alloc::{Allocator, Global, Layout}; use crate::boxed::Box; const B: usize = 6; @@ -195,7 +195,7 @@ impl NodeRef { self.borrow_mut().clear_parent_link(); unsafe { - Global.dealloc(top.cast(), Layout::new::>()); + Global.deallocate(top.cast(), Layout::new::>()); } } } @@ -449,7 +449,7 @@ impl NodeRef { let node = self.node; let ret = self.ascend().ok(); unsafe { - Global.dealloc( + Global.deallocate( node.cast(), if height > 0 { Layout::new::>() @@ -1407,9 +1407,9 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { left_node.correct_childrens_parent_links(left_len + 1..=left_len + 1 + right_len); - Global.dealloc(right_node.node.cast(), Layout::new::>()); + Global.deallocate(right_node.node.cast(), Layout::new::>()); } else { - Global.dealloc(right_node.node.cast(), Layout::new::>()); + Global.deallocate(right_node.node.cast(), Layout::new::>()); } let new_idx = match track_edge_idx { diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index edab576bea8..edee439ad8d 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -9,7 +9,7 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use crate::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{handle_alloc_error, Allocator, Global, Layout}; use crate::boxed::Box; use crate::collections::TryReserveError::{self, *}; @@ -46,7 +46,7 @@ enum AllocInit { /// `usize::MAX`. This means that you need to be careful when round-tripping this type with a /// `Box<[T]>`, since `capacity()` won't yield the length. #[allow(missing_debug_implementations)] -pub struct RawVec { +pub struct RawVec { ptr: Unique, cap: usize, alloc: A, @@ -113,7 +113,7 @@ impl RawVec { } } -impl RawVec { +impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. #[rustc_allow_const_fn_unstable(const_fn)] @@ -139,7 +139,7 @@ impl RawVec { /// Converts a `Box<[T]>` into a `RawVec`. pub fn from_box(slice: Box<[T], A>) -> Self { unsafe { - let (slice, alloc) = Box::into_raw_with_alloc(slice); + let (slice, alloc) = Box::into_raw_with_allocator(slice); RawVec::from_raw_parts_in(slice.as_mut_ptr(), slice.len(), alloc) } } @@ -185,8 +185,8 @@ impl RawVec { Err(_) => capacity_overflow(), } let result = match init { - AllocInit::Uninitialized => alloc.alloc(layout), - AllocInit::Zeroed => alloc.alloc_zeroed(layout), + AllocInit::Uninitialized => alloc.allocate(layout), + AllocInit::Zeroed => alloc.allocate_zeroed(layout), }; let ptr = match result { Ok(ptr) => ptr, @@ -232,7 +232,7 @@ impl RawVec { } /// Returns a shared reference to the allocator backing this `RawVec`. - pub fn alloc_ref(&self) -> &A { + pub fn allocator(&self) -> &A { &self.alloc } @@ -359,7 +359,7 @@ impl RawVec { } } -impl RawVec { +impl RawVec { /// Returns if the buffer needs to grow to fulfill the needed extra capacity. /// Mainly used to make inlining reserve-calls possible without inlining `grow`. fn needs_to_grow(&self, len: usize, additional: usize) -> bool { @@ -471,7 +471,7 @@ fn finish_grow
( alloc: &mut A, ) -> Result, TryReserveError> where - A: AllocRef, + A: Allocator, { // Check for the error here to minimize the size of `RawVec::grow_*`. let new_layout = new_layout.map_err(|_| CapacityOverflow)?; @@ -486,17 +486,17 @@ where alloc.grow(ptr, old_layout, new_layout) } } else { - alloc.alloc(new_layout) + alloc.allocate(new_layout) }; memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }) } -unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. fn drop(&mut self) { if let Some((ptr, layout)) = self.current_memory() { - unsafe { self.alloc.dealloc(ptr, layout) } + unsafe { self.alloc.deallocate(ptr, layout) } } } } diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index cb4fe1b46cd..8c15a24409b 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -20,13 +20,13 @@ fn allocator_param() { struct BoundedAlloc { fuel: Cell, } - unsafe impl AllocRef for BoundedAlloc { - fn alloc(&self, layout: Layout) -> Result, AllocError> { + unsafe impl Allocator for BoundedAlloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { let size = layout.size(); if size > self.fuel.get() { return Err(AllocError); } - match Global.alloc(layout) { + match Global.allocate(layout) { ok @ Ok(_) => { self.fuel.set(self.fuel.get() - size); ok @@ -34,8 +34,8 @@ fn allocator_param() { err @ Err(_) => err, } } - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { - unsafe { Global.dealloc(ptr, layout) } + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { Global.deallocate(ptr, layout) } } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 6dcd0c6056c..a96be57143d 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -262,7 +262,7 @@ use core::pin::Pin; use core::ptr::{self, NonNull}; use core::slice::from_raw_parts_mut; -use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::string::String; use crate::vec::Vec; @@ -416,7 +416,7 @@ impl Rc { unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| mem as *mut RcBox>, )) } @@ -447,7 +447,7 @@ impl Rc { unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| mem as *mut RcBox>, )) } @@ -555,7 +555,7 @@ impl Rc<[T]> { unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| { ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[mem::MaybeUninit]> @@ -1040,7 +1040,7 @@ impl Rc { unsafe { Self::allocate_for_layout( Layout::for_value(&*ptr), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox, ) } @@ -1075,7 +1075,7 @@ impl Rc<[T]> { unsafe { Self::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>, ) } @@ -1125,7 +1125,7 @@ impl Rc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem, self.layout); + Global.deallocate(self.mem, self.layout); } } } @@ -1225,7 +1225,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.inner().dec_weak(); if self.inner().weak() == 0 { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -2040,7 +2040,7 @@ impl Drop for Weak { // the strong pointers have disappeared. if inner.weak() == 0 { unsafe { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 949a3bb1d70..064700fc72c 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -87,7 +87,7 @@ use core::cmp::Ordering::{self, Less}; use core::mem::{self, size_of}; use core::ptr; -use crate::alloc::{AllocRef, Global}; +use crate::alloc::{Allocator, Global}; use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; @@ -138,7 +138,7 @@ pub use hack::to_vec; // `core::slice::SliceExt` - we need to supply these functions for the // `test_permutations` test mod hack { - use core::alloc::AllocRef; + use core::alloc::Allocator; use crate::boxed::Box; use crate::vec::Vec; @@ -146,33 +146,33 @@ mod hack { // We shouldn't add inline attribute to this since this is used in // `vec!` macro mostly and causes perf regression. See #71204 for // discussion and perf results. - pub fn into_vec(b: Box<[T], A>) -> Vec { + pub fn into_vec(b: Box<[T], A>) -> Vec { unsafe { let len = b.len(); - let (b, alloc) = Box::into_raw_with_alloc(b); + let (b, alloc) = Box::into_raw_with_allocator(b); Vec::from_raw_parts_in(b as *mut T, len, len, alloc) } } #[inline] - pub fn to_vec(s: &[T], alloc: A) -> Vec { + pub fn to_vec(s: &[T], alloc: A) -> Vec { T::to_vec(s, alloc) } pub trait ConvertVec { - fn to_vec(s: &[Self], alloc: A) -> Vec + fn to_vec(s: &[Self], alloc: A) -> Vec where Self: Sized; } impl ConvertVec for T { #[inline] - default fn to_vec(s: &[Self], alloc: A) -> Vec { - struct DropGuard<'a, T, A: AllocRef> { + default fn to_vec(s: &[Self], alloc: A) -> Vec { + struct DropGuard<'a, T, A: Allocator> { vec: &'a mut Vec, num_init: usize, } - impl<'a, T, A: AllocRef> Drop for DropGuard<'a, T, A> { + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { #[inline] fn drop(&mut self) { // SAFETY: @@ -203,7 +203,7 @@ mod hack { impl ConvertVec for T { #[inline] - fn to_vec(s: &[Self], alloc: A) -> Vec { + fn to_vec(s: &[Self], alloc: A) -> Vec { let mut v = Vec::with_capacity_in(s.len(), alloc); // SAFETY: // allocated above with the capacity of `s`, and initialize to `s.len()` in @@ -464,7 +464,7 @@ impl [T] { /// ``` #[inline] #[unstable(feature = "allocator_api", issue = "32838")] - pub fn to_vec_in(&self, alloc: A) -> Vec + pub fn to_vec_in(&self, alloc: A) -> Vec where T: Clone, { @@ -488,7 +488,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn into_vec(self: Box) -> Vec { + pub fn into_vec(self: Box) -> Vec { // N.B., see the `hack` module in this file for more details. hack::into_vec(self) } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 5ab930a5208..9d478a302e9 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -22,7 +22,7 @@ use core::slice::from_raw_parts_mut; use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -434,7 +434,7 @@ impl Arc { unsafe { Arc::from_ptr(Arc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| mem as *mut ArcInner>, )) } @@ -465,7 +465,7 @@ impl Arc { unsafe { Arc::from_ptr(Arc::allocate_for_layout( Layout::new::(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| mem as *mut ArcInner>, )) } @@ -572,7 +572,7 @@ impl Arc<[T]> { unsafe { Arc::from_ptr(Arc::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc_zeroed(layout), + |layout| Global.allocate_zeroed(layout), |mem| { ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[mem::MaybeUninit]> @@ -1015,7 +1015,7 @@ impl Arc { unsafe { Self::allocate_for_layout( Layout::for_value(&*ptr), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner, ) } @@ -1050,7 +1050,7 @@ impl Arc<[T]> { unsafe { Self::allocate_for_layout( Layout::array::(len).unwrap(), - |layout| Global.alloc(layout), + |layout| Global.allocate(layout), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>, ) } @@ -1102,7 +1102,7 @@ impl Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem, self.layout); + Global.deallocate(self.mem, self.layout); } } } @@ -1925,7 +1925,7 @@ impl Drop for Weak { if inner.weak.fetch_sub(1, Release) == 1 { acquire!(inner.weak); - unsafe { Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } + unsafe { Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } } } } diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 51687920928..9fffb47aa59 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -68,7 +68,7 @@ use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; -use crate::alloc::{AllocRef, Global}; +use crate::alloc::{Allocator, Global}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; @@ -298,7 +298,7 @@ use crate::raw_vec::RawVec; /// [`&`]: ../../std/primitive.reference.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] -pub struct Vec { +pub struct Vec { buf: RawVec, len: usize, } @@ -433,7 +433,7 @@ impl Vec { } } -impl Vec { +impl Vec { /// Constructs a new, empty `Vec`. /// /// The vector will not allocate until elements are pushed onto it. @@ -555,7 +555,7 @@ impl Vec { /// let p = v.as_mut_ptr(); /// let len = v.len(); /// let cap = v.capacity(); - /// let alloc = v.alloc_ref(); + /// let alloc = v.allocator(); /// /// unsafe { /// // Overwrite memory with 4, 5, 6 @@ -656,7 +656,7 @@ impl Vec { let len = me.len(); let capacity = me.capacity(); let ptr = me.as_mut_ptr(); - let alloc = unsafe { ptr::read(me.alloc_ref()) }; + let alloc = unsafe { ptr::read(me.allocator()) }; (ptr, len, capacity, alloc) } @@ -1058,8 +1058,8 @@ impl Vec { /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(&self) -> &A { - self.buf.alloc_ref() + pub fn allocator(&self) -> &A { + self.buf.allocator() } /// Forces the length of the vector to `new_len`. @@ -1620,12 +1620,12 @@ impl Vec { // the new vector can take over the original buffer and avoid the copy return mem::replace( self, - Vec::with_capacity_in(self.capacity(), self.alloc_ref().clone()), + Vec::with_capacity_in(self.capacity(), self.allocator().clone()), ); } let other_len = self.len - at; - let mut other = Vec::with_capacity_in(other_len, self.alloc_ref().clone()); + let mut other = Vec::with_capacity_in(other_len, self.allocator().clone()); // Unsafely `set_len` and copy items to `other`. unsafe { @@ -1749,7 +1749,7 @@ impl Vec { } } -impl Vec { +impl Vec { /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. /// /// If `new_len` is greater than `len`, the `Vec` is extended by the @@ -1844,7 +1844,7 @@ impl T> ExtendWith for ExtendFunc { } } -impl Vec { +impl Vec { /// Extend the vector by `n` values, using the given generator. fn extend_with>(&mut self, n: usize, mut value: E) { self.reserve(n); @@ -1904,7 +1904,7 @@ impl Drop for SetLenOnDrop<'_> { } } -impl Vec { +impl Vec { /// Removes consecutive repeated elements in the vector according to the /// [`PartialEq`] trait implementation. /// @@ -1926,7 +1926,7 @@ impl Vec { } } -impl Vec { +impl Vec { /// Removes the first instance of `item` from the vector if the item exists. /// /// This method will be removed soon. @@ -1959,17 +1959,17 @@ pub fn from_elem(elem: T, n: usize) -> Vec { #[doc(hidden)] #[unstable(feature = "allocator_api", issue = "32838")] -pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec { +pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec { ::from_elem(elem, n, alloc) } // Specialization trait used for Vec::from_elem trait SpecFromElem: Sized { - fn from_elem(elem: Self, n: usize, alloc: A) -> Vec; + fn from_elem(elem: Self, n: usize, alloc: A) -> Vec; } impl SpecFromElem for T { - default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { + default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { let mut v = Vec::with_capacity_in(n, alloc); v.extend_with(n, ExtendElement(elem)); v @@ -1978,7 +1978,7 @@ impl SpecFromElem for T { impl SpecFromElem for i8 { #[inline] - fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { + fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { if elem == 0 { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } @@ -1993,7 +1993,7 @@ impl SpecFromElem for i8 { impl SpecFromElem for u8 { #[inline] - fn from_elem(elem: u8, n: usize, alloc: A) -> Vec { + fn from_elem(elem: u8, n: usize, alloc: A) -> Vec { if elem == 0 { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } @@ -2008,7 +2008,7 @@ impl SpecFromElem for u8 { impl SpecFromElem for T { #[inline] - fn from_elem(elem: T, n: usize, alloc: A) -> Vec { + fn from_elem(elem: T, n: usize, alloc: A) -> Vec { if elem.is_zero() { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } @@ -2093,7 +2093,7 @@ unsafe impl IsZero for Option> { //////////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for Vec { +impl ops::Deref for Vec { type Target = [T]; fn deref(&self) -> &[T] { @@ -2102,17 +2102,17 @@ impl ops::Deref for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::DerefMut for Vec { +impl ops::DerefMut for Vec { fn deref_mut(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } } } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Vec { +impl Clone for Vec { #[cfg(not(test))] fn clone(&self) -> Self { - let alloc = self.alloc_ref().clone(); + let alloc = self.allocator().clone(); <[T]>::to_vec_in(&**self, alloc) } @@ -2122,7 +2122,7 @@ impl Clone for Vec { // NB see the slice::hack module in slice.rs for more information #[cfg(test)] fn clone(&self) -> Self { - let alloc = self.alloc_ref().clone(); + let alloc = self.allocator().clone(); crate::slice::to_vec(&**self, alloc) } @@ -2141,7 +2141,7 @@ impl Clone for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Vec { +impl Hash for Vec { #[inline] fn hash(&self, state: &mut H) { Hash::hash(&**self, state) @@ -2153,7 +2153,7 @@ impl Hash for Vec { message = "vector indices are of type `usize` or ranges of `usize`", label = "vector indices are of type `usize` or ranges of `usize`" )] -impl, A: AllocRef> Index for Vec { +impl, A: Allocator> Index for Vec { type Output = I::Output; #[inline] @@ -2167,7 +2167,7 @@ impl, A: AllocRef> Index for Vec { message = "vector indices are of type `usize` or ranges of `usize`", label = "vector indices are of type `usize` or ranges of `usize`" )] -impl, A: AllocRef> IndexMut for Vec { +impl, A: Allocator> IndexMut for Vec { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { IndexMut::index_mut(&mut **self, index) @@ -2183,7 +2183,7 @@ impl FromIterator for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for Vec { +impl IntoIterator for Vec { type Item = T; type IntoIter = IntoIter; @@ -2204,7 +2204,7 @@ impl IntoIterator for Vec { fn into_iter(self) -> IntoIter { unsafe { let mut me = ManuallyDrop::new(self); - let alloc = ptr::read(me.alloc_ref()); + let alloc = ptr::read(me.allocator()); let begin = me.as_mut_ptr(); let end = if mem::size_of::() == 0 { arith_offset(begin as *const i8, me.len() as isize) as *const T @@ -2225,7 +2225,7 @@ impl IntoIterator for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, A: AllocRef> IntoIterator for &'a Vec { +impl<'a, T, A: Allocator> IntoIterator for &'a Vec { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; @@ -2235,7 +2235,7 @@ impl<'a, T, A: AllocRef> IntoIterator for &'a Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, A: AllocRef> IntoIterator for &'a mut Vec { +impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; @@ -2245,7 +2245,7 @@ impl<'a, T, A: AllocRef> IntoIterator for &'a mut Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl Extend for Vec { +impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { >::spec_extend(self, iter.into_iter()) @@ -2533,7 +2533,7 @@ trait SpecExtend { fn spec_extend(&mut self, iter: I); } -impl SpecExtend for Vec +impl SpecExtend for Vec where I: Iterator, { @@ -2542,7 +2542,7 @@ where } } -impl SpecExtend for Vec +impl SpecExtend for Vec where I: TrustedLen, { @@ -2575,7 +2575,7 @@ where } } -impl SpecExtend> for Vec { +impl SpecExtend> for Vec { fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); @@ -2584,7 +2584,7 @@ impl SpecExtend> for Vec { } } -impl<'a, T: 'a, I, A: AllocRef + 'a> SpecExtend<&'a T, I> for Vec +impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec where I: Iterator, T: Clone, @@ -2594,7 +2594,7 @@ where } } -impl<'a, T: 'a, A: AllocRef + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec +impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec where T: Copy, { @@ -2604,7 +2604,7 @@ where } } -impl Vec { +impl Vec { // leaf method to which various SpecFrom/SpecExtend implementations delegate when // they have no further optimizations to apply fn extend_desugared>(&mut self, mut iterator: I) { @@ -2739,7 +2739,7 @@ impl Vec { /// /// [`copy_from_slice`]: ../../std/primitive.slice.html#method.copy_from_slice #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: Copy + 'a, A: AllocRef + 'a> Extend<&'a T> for Vec { +impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { self.spec_extend(iter.into_iter()) } @@ -2771,18 +2771,18 @@ macro_rules! __impl_slice_eq1 { } } -__impl_slice_eq1! { [A: AllocRef] Vec, Vec, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef] Vec, &[U], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef] Vec, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef] &[T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } -__impl_slice_eq1! { [A: AllocRef] &mut [T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } -__impl_slice_eq1! { [A: AllocRef] Vec, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } -__impl_slice_eq1! { [A: AllocRef] [T], Vec, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } -__impl_slice_eq1! { [A: AllocRef] Cow<'_, [T]>, Vec where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, Vec, #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, &[U], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, &mut [U], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator] &[T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } +__impl_slice_eq1! { [A: Allocator] &mut [T], Vec, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] } +__impl_slice_eq1! { [A: Allocator] Vec, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } +__impl_slice_eq1! { [A: Allocator] [T], Vec, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")] } +__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } __impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } __impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef, const N: usize] Vec, [U; N], #[stable(feature = "rust1", since = "1.0.0")] } -__impl_slice_eq1! { [A: AllocRef, const N: usize] Vec, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, [U; N], #[stable(feature = "rust1", since = "1.0.0")] } +__impl_slice_eq1! { [A: Allocator, const N: usize] Vec, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] } // NOTE: some less important impls are omitted to reduce code bloat // FIXME(Centril): Reconsider this? @@ -2796,7 +2796,7 @@ __impl_slice_eq1! { [A: AllocRef, const N: usize] Vec, &[U; N], #[stable(f /// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Vec { +impl PartialOrd for Vec { #[inline] fn partial_cmp(&self, other: &Self) -> Option { PartialOrd::partial_cmp(&**self, &**other) @@ -2804,11 +2804,11 @@ impl PartialOrd for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Vec {} +impl Eq for Vec {} /// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Vec { +impl Ord for Vec { #[inline] fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(&**self, &**other) @@ -2816,7 +2816,7 @@ impl Ord for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T, A: AllocRef> Drop for Vec { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec { fn drop(&mut self) { unsafe { // use drop for [T] @@ -2837,35 +2837,35 @@ impl Default for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Vec { +impl fmt::Debug for Vec { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef> for Vec { +impl AsRef> for Vec { fn as_ref(&self) -> &Vec { self } } #[stable(feature = "vec_as_mut", since = "1.5.0")] -impl AsMut> for Vec { +impl AsMut> for Vec { fn as_mut(&mut self) -> &mut Vec { self } } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRef<[T]> for Vec { +impl AsRef<[T]> for Vec { fn as_ref(&self) -> &[T] { self } } #[stable(feature = "vec_as_mut", since = "1.5.0")] -impl AsMut<[T]> for Vec { +impl AsMut<[T]> for Vec { fn as_mut(&mut self) -> &mut [T] { self } @@ -2920,7 +2920,7 @@ where // note: test pulls in libstd, which causes errors here #[cfg(not(test))] #[stable(feature = "vec_from_box", since = "1.18.0")] -impl From> for Vec { +impl From> for Vec { fn from(s: Box<[T], A>) -> Self { let len = s.len(); Self { buf: RawVec::from_box(s), len } @@ -2930,7 +2930,7 @@ impl From> for Vec { // note: test pulls in libstd, which causes errors here #[cfg(not(test))] #[stable(feature = "box_from_vec", since = "1.20.0")] -impl From> for Box<[T], A> { +impl From> for Box<[T], A> { fn from(v: Vec) -> Self { v.into_boxed_slice() } @@ -2944,7 +2944,7 @@ impl From<&str> for Vec { } #[stable(feature = "array_try_from_vec", since = "1.48.0")] -impl TryFrom> for [T; N] { +impl TryFrom> for [T; N] { type Error = Vec; /// Gets the entire contents of the `Vec` as an array, @@ -3045,8 +3045,10 @@ where /// let iter: std::vec::IntoIter<_> = v.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter -{ +pub struct IntoIter< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { buf: NonNull, phantom: PhantomData, cap: usize, @@ -3056,13 +3058,13 @@ pub struct IntoIter fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter").field(&self.as_slice()).finish() } } -impl IntoIter { +impl IntoIter { /// Returns the remaining items of this iterator as a slice. /// /// # Examples @@ -3100,7 +3102,7 @@ impl IntoIter { /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(&self) -> &A { + pub fn allocator(&self) -> &A { &self.alloc } @@ -3126,19 +3128,19 @@ impl IntoIter { } #[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] -impl AsRef<[T]> for IntoIter { +impl AsRef<[T]> for IntoIter { fn as_ref(&self) -> &[T] { self.as_slice() } } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for IntoIter {} +unsafe impl Send for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for IntoIter {} +unsafe impl Sync for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = T; #[inline] @@ -3195,7 +3197,7 @@ impl Iterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { +impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { if self.end == self.ptr { @@ -3215,23 +3217,23 @@ impl DoubleEndedIterator for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { fn is_empty(&self) -> bool { self.ptr == self.end } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for IntoIter {} +unsafe impl TrustedLen for IntoIter {} #[doc(hidden)] #[unstable(issue = "none", feature = "std_internals")] // T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr // and thus we can't implement drop-handling -unsafe impl TrustedRandomAccess for IntoIter +unsafe impl TrustedRandomAccess for IntoIter where T: Copy, { @@ -3241,7 +3243,7 @@ where } #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] -impl Clone for IntoIter { +impl Clone for IntoIter { #[cfg(not(test))] fn clone(&self) -> Self { self.as_slice().to_vec_in(self.alloc.clone()).into_iter() @@ -3253,11 +3255,11 @@ impl Clone for IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T, A: AllocRef> Drop for IntoIter { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter { fn drop(&mut self) { - struct DropGuard<'a, T, A: AllocRef>(&'a mut IntoIter); + struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter); - impl Drop for DropGuard<'_, T, A> { + impl Drop for DropGuard<'_, T, A> { fn drop(&mut self) { unsafe { // `IntoIter::alloc` is not used anymore after this @@ -3278,10 +3280,10 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for IntoIter { } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl InPlaceIterable for IntoIter {} +unsafe impl InPlaceIterable for IntoIter {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for IntoIter { +unsafe impl SourceIter for IntoIter { type Source = Self; #[inline] @@ -3320,7 +3322,7 @@ impl AsIntoIter for IntoIter { pub struct Drain< 'a, T: 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef + 'a = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, > { /// Index of tail to preserve tail_start: usize, @@ -3332,13 +3334,13 @@ pub struct Drain< } #[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for Drain<'_, T, A> { +impl fmt::Debug for Drain<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() } } -impl<'a, T, A: AllocRef> Drain<'a, T, A> { +impl<'a, T, A: Allocator> Drain<'a, T, A> { /// Returns the remaining items of this iterator as a slice. /// /// # Examples @@ -3358,25 +3360,25 @@ impl<'a, T, A: AllocRef> Drain<'a, T, A> { /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(&self) -> &A { - unsafe { self.vec.as_ref().alloc_ref() } + pub fn allocator(&self) -> &A { + unsafe { self.vec.as_ref().allocator() } } } #[stable(feature = "vec_drain_as_slice", since = "1.46.0")] -impl<'a, T, A: AllocRef> AsRef<[T]> for Drain<'a, T, A> { +impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> { fn as_ref(&self) -> &[T] { self.as_slice() } } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Sync for Drain<'_, T, A> {} +unsafe impl Sync for Drain<'_, T, A> {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl Send for Drain<'_, T, A> {} +unsafe impl Send for Drain<'_, T, A> {} #[stable(feature = "drain", since = "1.6.0")] -impl Iterator for Drain<'_, T, A> { +impl Iterator for Drain<'_, T, A> { type Item = T; #[inline] @@ -3390,7 +3392,7 @@ impl Iterator for Drain<'_, T, A> { } #[stable(feature = "drain", since = "1.6.0")] -impl DoubleEndedIterator for Drain<'_, T, A> { +impl DoubleEndedIterator for Drain<'_, T, A> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) @@ -3398,13 +3400,13 @@ impl DoubleEndedIterator for Drain<'_, T, A> { } #[stable(feature = "drain", since = "1.6.0")] -impl Drop for Drain<'_, T, A> { +impl Drop for Drain<'_, T, A> { fn drop(&mut self) { /// Continues dropping the remaining elements in the `Drain`, then moves back the /// un-`Drain`ed elements to restore the original `Vec`. - struct DropGuard<'r, 'a, T, A: AllocRef>(&'r mut Drain<'a, T, A>); + struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); - impl<'r, 'a, T, A: AllocRef> Drop for DropGuard<'r, 'a, T, A> { + impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { fn drop(&mut self) { // Continue the same loop we have below. If the loop already finished, this does // nothing. @@ -3440,17 +3442,17 @@ impl Drop for Drain<'_, T, A> { } #[stable(feature = "drain", since = "1.6.0")] -impl ExactSizeIterator for Drain<'_, T, A> { +impl ExactSizeIterator for Drain<'_, T, A> { fn is_empty(&self) -> bool { self.iter.is_empty() } } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Drain<'_, T, A> {} +unsafe impl TrustedLen for Drain<'_, T, A> {} #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, T, A> {} +impl FusedIterator for Drain<'_, T, A> {} /// A splicing iterator for `Vec`. /// @@ -3469,14 +3471,14 @@ impl FusedIterator for Drain<'_, T, A> {} pub struct Splice< 'a, I: Iterator + 'a, - #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef + 'a = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global, > { drain: Drain<'a, I::Item, A>, replace_with: I, } #[stable(feature = "vec_splice", since = "1.21.0")] -impl Iterator for Splice<'_, I, A> { +impl Iterator for Splice<'_, I, A> { type Item = I::Item; fn next(&mut self) -> Option { @@ -3489,17 +3491,17 @@ impl Iterator for Splice<'_, I, A> { } #[stable(feature = "vec_splice", since = "1.21.0")] -impl DoubleEndedIterator for Splice<'_, I, A> { +impl DoubleEndedIterator for Splice<'_, I, A> { fn next_back(&mut self) -> Option { self.drain.next_back() } } #[stable(feature = "vec_splice", since = "1.21.0")] -impl ExactSizeIterator for Splice<'_, I, A> {} +impl ExactSizeIterator for Splice<'_, I, A> {} #[stable(feature = "vec_splice", since = "1.21.0")] -impl Drop for Splice<'_, I, A> { +impl Drop for Splice<'_, I, A> { fn drop(&mut self) { self.drain.by_ref().for_each(drop); @@ -3540,7 +3542,7 @@ impl Drop for Splice<'_, I, A> { } /// Private helper methods for `Splice::drop` -impl Drain<'_, T, A> { +impl Drain<'_, T, A> { /// The range from `self.vec.len` to `self.tail_start` contains elements /// that have been moved out. /// Fill that range as much as possible with new elements from the `replace_with` iterator. @@ -3599,7 +3601,7 @@ pub struct DrainFilter< 'a, T, F, - #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > where F: FnMut(&mut T) -> bool, { @@ -3620,20 +3622,20 @@ pub struct DrainFilter< panic_flag: bool, } -impl DrainFilter<'_, T, F, A> +impl DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn alloc_ref(&self) -> &A { - self.vec.alloc_ref() + pub fn allocator(&self) -> &A { + self.vec.allocator() } } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Iterator for DrainFilter<'_, T, F, A> +impl Iterator for DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -3671,19 +3673,19 @@ where } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl Drop for DrainFilter<'_, T, F, A> +impl Drop for DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - struct BackshiftOnDrop<'a, 'b, T, F, A: AllocRef> + struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator> where F: FnMut(&mut T) -> bool, { drain: &'b mut DrainFilter<'a, T, F, A>, } - impl<'a, 'b, T, F, A: AllocRef> Drop for BackshiftOnDrop<'a, 'b, T, F, A> + impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A> where F: FnMut(&mut T) -> bool, { diff --git a/library/alloc/tests/heap.rs b/library/alloc/tests/heap.rs index a7239a4b14f..246b341eeb3 100644 --- a/library/alloc/tests/heap.rs +++ b/library/alloc/tests/heap.rs @@ -1,4 +1,4 @@ -use std::alloc::{AllocRef, Global, Layout, System}; +use std::alloc::{Allocator, Global, Layout, System}; /// Issue #45955 and #62251. #[test] @@ -11,7 +11,7 @@ fn std_heap_overaligned_request() { check_overalign_requests(Global) } -fn check_overalign_requests(allocator: T) { +fn check_overalign_requests(allocator: T) { for &align in &[4, 8, 16, 32] { // less than and bigger than `MIN_ALIGN` for &size in &[align / 2, align - 1] { @@ -20,7 +20,7 @@ fn check_overalign_requests(allocator: T) { unsafe { let pointers: Vec<_> = (0..iterations) .map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap() }) .collect(); for &ptr in &pointers { @@ -33,7 +33,7 @@ fn check_overalign_requests(allocator: T) { // Clean up for &ptr in &pointers { - allocator.dealloc( + allocator.deallocate( ptr.as_non_null_ptr(), Layout::from_size_align(size, align).unwrap(), ) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 339d85902b8..57c6624b64f 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -19,7 +19,7 @@ const fn size_align() -> (usize, usize) { /// even though `GlobalAlloc` requires that all memory requests /// be non-zero in size. A caller must either ensure that conditions /// like this are met, use specific allocators with looser -/// requirements, or use the more lenient `AllocRef` interface.) +/// requirements, or use the more lenient `Allocator` interface.) #[stable(feature = "alloc_layout", since = "1.28.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[lang = "alloc_layout"] diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index bc874e2e522..045eb58d013 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -40,14 +40,14 @@ impl fmt::Display for AllocError { } } -/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of +/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of /// data described via [`Layout`][]. /// -/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having +/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having /// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the /// allocated memory. /// -/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying +/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying /// allocator does not support this (like jemalloc) or return a null pointer (such as /// `libc::malloc`), this must be caught by the implementation. /// @@ -56,18 +56,18 @@ impl fmt::Display for AllocError { /// Some of the methods require that a memory block be *currently allocated* via an allocator. This /// means that: /// -/// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or +/// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or /// [`shrink`], and /// /// * the memory block has not been subsequently deallocated, where blocks are either deallocated -/// directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or +/// directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or /// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer /// remains valid. /// -/// [`alloc`]: AllocRef::alloc -/// [`grow`]: AllocRef::grow -/// [`shrink`]: AllocRef::shrink -/// [`dealloc`]: AllocRef::dealloc +/// [`allocate`]: Allocator::allocate +/// [`grow`]: Allocator::grow +/// [`shrink`]: Allocator::shrink +/// [`deallocate`]: Allocator::deallocate /// /// ### Memory fitting /// @@ -79,7 +79,7 @@ impl fmt::Display for AllocError { /// /// * The provided [`layout.size()`] must fall in the range `min ..= max`, where: /// - `min` is the size of the layout most recently used to allocate the block, and -/// - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`]. +/// - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`]. /// /// [`layout.align()`]: Layout::align /// [`layout.size()`]: Layout::size @@ -97,7 +97,7 @@ impl fmt::Display for AllocError { /// /// [*currently allocated*]: #currently-allocated-memory #[unstable(feature = "allocator_api", issue = "32838")] -pub unsafe trait AllocRef { +pub unsafe trait Allocator { /// Attempts to allocate a block of memory. /// /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. @@ -118,9 +118,9 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc(&self, layout: Layout) -> Result, AllocError>; + fn allocate(&self, layout: Layout) -> Result, AllocError>; - /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized. + /// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized. /// /// # Errors /// @@ -135,8 +135,8 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { - let ptr = self.alloc(layout)?; + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + let ptr = self.allocate(layout)?; // SAFETY: `alloc` returns a valid memory block unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) } Ok(ptr) @@ -151,7 +151,7 @@ pub unsafe trait AllocRef { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout); + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); /// Attempts to extend the memory block. /// @@ -200,7 +200,7 @@ pub unsafe trait AllocRef { "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - let new_ptr = self.alloc(new_layout)?; + let new_ptr = self.allocate(new_layout)?; // SAFETY: because `new_layout.size()` must be greater than or equal to // `old_layout.size()`, both the old and new memory allocation are valid for reads and @@ -209,7 +209,7 @@ pub unsafe trait AllocRef { // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); } Ok(new_ptr) @@ -261,7 +261,7 @@ pub unsafe trait AllocRef { "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - let new_ptr = self.alloc_zeroed(new_layout)?; + let new_ptr = self.allocate_zeroed(new_layout)?; // SAFETY: because `new_layout.size()` must be greater than or equal to // `old_layout.size()`, both the old and new memory allocation are valid for reads and @@ -270,7 +270,7 @@ pub unsafe trait AllocRef { // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); } Ok(new_ptr) @@ -323,7 +323,7 @@ pub unsafe trait AllocRef { "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - let new_ptr = self.alloc(new_layout)?; + let new_ptr = self.allocate(new_layout)?; // SAFETY: because `new_layout.size()` must be lower than or equal to // `old_layout.size()`, both the old and new memory allocation are valid for reads and @@ -332,15 +332,15 @@ pub unsafe trait AllocRef { // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size()); - self.dealloc(ptr, old_layout); + self.deallocate(ptr, old_layout); } Ok(new_ptr) } - /// Creates a "by reference" adaptor for this instance of `AllocRef`. + /// Creates a "by reference" adaptor for this instance of `Allocator`. /// - /// The returned adaptor also implements `AllocRef` and will simply borrow this. + /// The returned adaptor also implements `Allocator` and will simply borrow this. #[inline(always)] fn by_ref(&self) -> &Self { self @@ -348,24 +348,24 @@ pub unsafe trait AllocRef { } #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl AllocRef for &A +unsafe impl Allocator for &A where - A: AllocRef + ?Sized, + A: Allocator + ?Sized, { #[inline] - fn alloc(&self, layout: Layout) -> Result, AllocError> { - (**self).alloc(layout) + fn allocate(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate(layout) } #[inline] - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { - (**self).alloc_zeroed(layout) + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + (**self).allocate_zeroed(layout) } #[inline] - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).dealloc(ptr, layout) } + unsafe { (**self).deallocate(ptr, layout) } } #[inline] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 5dc7171a7dc..d849008b880 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -439,11 +439,11 @@ impl NonNull<[T]> { /// ```rust /// #![feature(allocator_api, ptr_as_uninit)] /// - /// use std::alloc::{AllocRef, Layout, Global}; + /// use std::alloc::{Allocator, Layout, Global}; /// use std::mem::MaybeUninit; /// use std::ptr::NonNull; /// - /// let memory: NonNull<[u8]> = Global.alloc(Layout::new::<[u8; 32]>())?; + /// let memory: NonNull<[u8]> = Global.allocate(Layout::new::<[u8; 32]>())?; /// // This is safe as `memory` is valid for reads and writes for `memory.len()` many bytes. /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized. /// # #[allow(unused_variables)] diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 375b015ccc8..819d57a934d 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -149,7 +149,7 @@ impl System { } } - // SAFETY: Same as `AllocRef::grow` + // SAFETY: Same as `Allocator::grow` #[inline] unsafe fn grow_impl( &self, @@ -190,29 +190,29 @@ impl System { old_size => unsafe { let new_ptr = self.alloc_impl(new_layout, zeroed)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); - AllocRef::dealloc(&self, ptr, old_layout); + Allocator::deallocate(&self, ptr, old_layout); Ok(new_ptr) }, } } } -// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl, +// The Allocator impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl, // which is in `std::sys::*::alloc`. #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl AllocRef for System { +unsafe impl Allocator for System { #[inline] - fn alloc(&self, layout: Layout) -> Result, AllocError> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -257,7 +257,7 @@ unsafe impl AllocRef for System { match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - AllocRef::dealloc(&self, ptr, old_layout); + Allocator::deallocate(&self, ptr, old_layout); Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, @@ -277,9 +277,9 @@ unsafe impl AllocRef for System { // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller. new_size => unsafe { - let new_ptr = AllocRef::alloc(&self, new_layout)?; + let new_ptr = Allocator::allocate(&self, new_layout)?; ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); - AllocRef::dealloc(&self, ptr, old_layout); + Allocator::deallocate(&self, ptr, old_layout); Ok(new_ptr) }, } diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index dfb5d3e9e38..10cbc23c427 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -8,9 +8,8 @@ extern crate helper; -use std::alloc::{self, AllocRef, Global, Layout, System}; +use std::alloc::{self, Allocator, Global, Layout, System}; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::ptr::NonNull; static HITS: AtomicUsize = AtomicUsize::new(0); @@ -24,7 +23,7 @@ unsafe impl alloc::GlobalAlloc for A { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); - AllocRef::dealloc(&System, NonNull::new(ptr).unwrap(), layout) + alloc::GlobalAlloc::dealloc(&System, ptr, layout) } } @@ -39,10 +38,10 @@ fn main() { unsafe { let layout = Layout::from_size_align(4, 2).unwrap(); - let memory = Global.alloc(layout.clone()).unwrap(); + let memory = Global.allocate(layout.clone()).unwrap(); helper::work_with(&memory); assert_eq!(HITS.load(Ordering::SeqCst), n + 1); - Global.dealloc(memory.as_non_null_ptr(), layout); + Global.deallocate(memory.as_non_null_ptr(), layout); assert_eq!(HITS.load(Ordering::SeqCst), n + 2); let s = String::with_capacity(10); @@ -51,10 +50,10 @@ fn main() { drop(s); assert_eq!(HITS.load(Ordering::SeqCst), n + 4); - let memory = System.alloc(layout.clone()).unwrap(); - assert_eq!(HITS.load(Ordering::SeqCst), n + 4); + let memory = System.allocate(layout.clone()).unwrap(); helper::work_with(&memory); - System.dealloc(memory.as_non_null_ptr(), layout); + assert_eq!(HITS.load(Ordering::SeqCst), n + 4); + System.deallocate(memory.as_non_null_ptr(), layout); assert_eq!(HITS.load(Ordering::SeqCst), n + 4); } } diff --git a/src/test/ui/allocator/xcrate-use.rs b/src/test/ui/allocator/xcrate-use.rs index a1446b3664d..edd4df75e8b 100644 --- a/src/test/ui/allocator/xcrate-use.rs +++ b/src/test/ui/allocator/xcrate-use.rs @@ -10,7 +10,7 @@ extern crate custom; extern crate helper; -use std::alloc::{AllocRef, Global, Layout, System}; +use std::alloc::{Allocator, Global, Layout, System}; use std::sync::atomic::{AtomicUsize, Ordering}; #[global_allocator] @@ -21,16 +21,16 @@ fn main() { let n = GLOBAL.0.load(Ordering::SeqCst); let layout = Layout::from_size_align(4, 2).unwrap(); - let memory = Global.alloc(layout.clone()).unwrap(); + let memory = Global.allocate(layout.clone()).unwrap(); helper::work_with(&memory); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); - Global.dealloc(memory.as_non_null_ptr(), layout); + Global.deallocate(memory.as_non_null_ptr(), layout); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); - let memory = System.alloc(layout.clone()).unwrap(); + let memory = System.allocate(layout.clone()).unwrap(); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); helper::work_with(&memory); - System.dealloc(memory.as_non_null_ptr(), layout); + System.deallocate(memory.as_non_null_ptr(), layout); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); } } diff --git a/src/test/ui/associated-types/defaults-wf.stderr b/src/test/ui/associated-types/defaults-wf.stderr index 26c85260194..4c43e6a182d 100644 --- a/src/test/ui/associated-types/defaults-wf.stderr +++ b/src/test/ui/associated-types/defaults-wf.stderr @@ -6,7 +6,7 @@ LL | type Ty = Vec<[u8]>; | ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | -LL | pub struct Vec { +LL | pub struct Vec { | - required by this bound in `Vec` | = help: the trait `Sized` is not implemented for `[u8]` diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr index 10d12a09b25..60a5bb9f786 100644 --- a/src/test/ui/bad/bad-sized.stderr +++ b/src/test/ui/bad/bad-sized.stderr @@ -17,7 +17,7 @@ LL | let x: Vec = Vec::new(); | ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | -LL | pub struct Vec { +LL | pub struct Vec { | - required by this bound in `Vec` | = help: the trait `Sized` is not implemented for `dyn Trait` diff --git a/src/test/ui/box/leak-alloc.rs b/src/test/ui/box/leak-alloc.rs index 2e73d6f1432..3f0f39f448b 100644 --- a/src/test/ui/box/leak-alloc.rs +++ b/src/test/ui/box/leak-alloc.rs @@ -1,26 +1,26 @@ #![feature(allocator_api)] -use std::alloc::{AllocError, AllocRef, Layout, System}; +use std::alloc::{AllocError, Allocator, Layout, System}; use std::ptr::NonNull; use std::boxed::Box; -struct Allocator {} +struct Alloc {} -unsafe impl AllocRef for Allocator { - fn alloc(&self, layout: Layout) -> Result, AllocError> { - System.alloc(layout) +unsafe impl Allocator for Alloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + System.allocate(layout) } - unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { - System.dealloc(ptr, layout) + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + System.deallocate(ptr, layout) } } fn use_value(_: u32) {} fn main() { - let alloc = Allocator {}; + let alloc = Alloc {}; let boxed = Box::new_in(10, alloc.by_ref()); let theref = Box::leak(boxed); drop(alloc); diff --git a/src/test/ui/error-codes/e0119/conflict-with-std.stderr b/src/test/ui/error-codes/e0119/conflict-with-std.stderr index 9dc1a509cd0..68551f43775 100644 --- a/src/test/ui/error-codes/e0119/conflict-with-std.stderr +++ b/src/test/ui/error-codes/e0119/conflict-with-std.stderr @@ -6,7 +6,7 @@ LL | impl AsRef for Box { | = note: conflicting implementation in crate `alloc`: - impl AsRef for Box - where A: AllocRef, T: ?Sized; + where A: Allocator, T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: --> $DIR/conflict-with-std.rs:12:1 diff --git a/src/test/ui/issues/issue-20433.stderr b/src/test/ui/issues/issue-20433.stderr index d40946ae03f..3f7226c79bf 100644 --- a/src/test/ui/issues/issue-20433.stderr +++ b/src/test/ui/issues/issue-20433.stderr @@ -6,7 +6,7 @@ LL | fn iceman(c: Vec<[i32]>) {} | ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | -LL | pub struct Vec { +LL | pub struct Vec { | - required by this bound in `Vec` | = help: the trait `Sized` is not implemented for `[i32]` diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr index cc4b3707dd6..cde285f73d6 100644 --- a/src/test/ui/issues/issue-41974.stderr +++ b/src/test/ui/issues/issue-41974.stderr @@ -6,7 +6,7 @@ LL | impl Drop for T where T: A { | = note: conflicting implementation in crate `alloc`: - impl Drop for Box - where A: AllocRef, T: ?Sized; + where A: Allocator, T: ?Sized; = note: downstream crates may implement trait `A` for type `std::boxed::Box<_, _>` error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions diff --git a/src/test/ui/realloc-16687.rs b/src/test/ui/realloc-16687.rs index 2e07fdcbe83..92d98c16c60 100644 --- a/src/test/ui/realloc-16687.rs +++ b/src/test/ui/realloc-16687.rs @@ -7,7 +7,7 @@ #![feature(allocator_api)] #![feature(slice_ptr_get)] -use std::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use std::alloc::{handle_alloc_error, Allocator, Global, Layout}; use std::ptr::{self, NonNull}; fn main() { @@ -42,7 +42,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = Global.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); if PRINT { println!("allocate({:?}) = {:?}", layout, ptr); @@ -56,7 +56,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Global.dealloc(NonNull::new_unchecked(ptr), layout); + Global.deallocate(NonNull::new_unchecked(ptr), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { diff --git a/src/test/ui/regions/regions-mock-codegen.rs b/src/test/ui/regions/regions-mock-codegen.rs index ad4b9c352ae..9d0ca76e409 100644 --- a/src/test/ui/regions/regions-mock-codegen.rs +++ b/src/test/ui/regions/regions-mock-codegen.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 #![feature(allocator_api)] -use std::alloc::{handle_alloc_error, AllocRef, Global, Layout}; +use std::alloc::{handle_alloc_error, Allocator, Global, Layout}; use std::ptr::NonNull; struct arena(()); @@ -22,23 +22,23 @@ struct Ccx { x: isize, } -fn alloc(_bcx: &arena) -> &Bcx<'_> { +fn allocate(_bcx: &arena) -> &Bcx<'_> { unsafe { let layout = Layout::new::(); - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = Global.allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); &*(ptr.as_ptr() as *const _) } } fn h<'a>(bcx: &'a Bcx<'a>) -> &'a Bcx<'a> { - return alloc(bcx.fcx.arena); + return allocate(bcx.fcx.arena); } fn g(fcx: &Fcx) { let bcx = Bcx { fcx }; let bcx2 = h(&bcx); unsafe { - Global.dealloc(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); + Global.deallocate(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); } } diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 2e23ddd9053..09cbb875338 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -22,7 +22,7 @@ LL | fn clone(&self) -> Self; | LL | / pub struct Box< LL | | T: ?Sized, -LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, +LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, LL | | >(Unique, A); | |________________- doesn't satisfy `Box: Clone` | diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index d533724a009..bc081024182 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -19,7 +19,7 @@ LL | fn clone(&self) -> Self; | LL | / pub struct Box< LL | | T: ?Sized, -LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: AllocRef = Global, +LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, LL | | >(Unique, A); | |________________- doesn't satisfy `Box: Clone` | From 75140e813f3701e76ab64e091653395ec397f68d Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Fri, 4 Dec 2020 23:36:07 +0900 Subject: [PATCH 203/274] Fix a style of texts in `size_of_in_element_count` --- clippy_lints/src/size_of_in_element_count.rs | 11 ++--- tests/ui/size_of_in_element_count.stderr | 48 ++++++++++---------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 210cf5773e1..ea7a76146f5 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -11,11 +11,11 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** Detects expressions where - /// size_of:: or size_of_val:: is used as a - /// count of elements of type T + /// `size_of::` or `size_of_val::` is used as a + /// count of elements of type `T` /// /// **Why is this bad?** These functions expect a count - /// of T and not a number of bytes + /// of `T` and not a number of bytes /// /// **Known problems:** None. /// @@ -23,7 +23,6 @@ declare_clippy_lint! { /// ```rust,no_run /// # use std::ptr::copy_nonoverlapping; /// # use std::mem::size_of; - /// /// const SIZE: usize = 128; /// let x = [2u8; SIZE]; /// let mut y = [2u8; SIZE]; @@ -31,7 +30,7 @@ declare_clippy_lint! { /// ``` pub SIZE_OF_IN_ELEMENT_COUNT, correctness, - "using size_of:: or size_of_val:: where a count of elements of T is expected" + "using `size_of::` or `size_of_val::` where a count of elements of `T` is expected" } declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]); @@ -120,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount { , it already gets multiplied by the size of the type"; const LINT_MSG: &str = "found a count of bytes \ - instead of a count of elements of T"; + instead of a count of elements of `T`"; if_chain! { // Find calls to functions with an element count parameter and get diff --git a/tests/ui/size_of_in_element_count.stderr b/tests/ui/size_of_in_element_count.stderr index b7f421ec997..8cf3612abda 100644 --- a/tests/ui/size_of_in_element_count.stderr +++ b/tests/ui/size_of_in_element_count.stderr @@ -1,4 +1,4 @@ -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:18:68 | LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; @@ -7,7 +7,7 @@ LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of: = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:19:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; @@ -15,7 +15,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:21:49 | LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; @@ -23,7 +23,7 @@ LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:22:64 | LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; @@ -31,7 +31,7 @@ LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of:: $DIR/size_of_in_element_count.rs:23:51 | LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; @@ -39,7 +39,7 @@ LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:24:66 | LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; @@ -47,7 +47,7 @@ LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::< | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:26:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; @@ -55,7 +55,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:27:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; @@ -63,7 +63,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:29:46 | LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; @@ -71,7 +71,7 @@ LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:30:47 | LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; @@ -79,7 +79,7 @@ LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:32:66 | LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; @@ -87,7 +87,7 @@ LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::< | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:34:46 | LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); @@ -95,7 +95,7 @@ LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:35:38 | LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); @@ -103,7 +103,7 @@ LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:37:49 | LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; @@ -111,7 +111,7 @@ LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:38:41 | LL | unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; @@ -119,7 +119,7 @@ LL | unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:40:33 | LL | unsafe { y.as_mut_ptr().sub(size_of::()) }; @@ -127,7 +127,7 @@ LL | unsafe { y.as_mut_ptr().sub(size_of::()) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:41:29 | LL | y.as_ptr().wrapping_sub(size_of::()); @@ -135,7 +135,7 @@ LL | y.as_ptr().wrapping_sub(size_of::()); | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:42:29 | LL | unsafe { y.as_ptr().add(size_of::()) }; @@ -143,7 +143,7 @@ LL | unsafe { y.as_ptr().add(size_of::()) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:43:33 | LL | y.as_mut_ptr().wrapping_add(size_of::()); @@ -151,7 +151,7 @@ LL | y.as_mut_ptr().wrapping_add(size_of::()); | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:44:32 | LL | unsafe { y.as_ptr().offset(size_of::() as isize) }; @@ -159,7 +159,7 @@ LL | unsafe { y.as_ptr().offset(size_of::() as isize) }; | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:45:36 | LL | y.as_mut_ptr().wrapping_offset(size_of::() as isize); @@ -167,7 +167,7 @@ LL | y.as_mut_ptr().wrapping_offset(size_of::() as isize); | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:48:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; @@ -175,7 +175,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:51:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; @@ -183,7 +183,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * si | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: found a count of bytes instead of a count of elements of T +error: found a count of bytes instead of a count of elements of `T` --> $DIR/size_of_in_element_count.rs:54:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; From 98fc02d6faeb39c7a4264af8ffdedc6a5a157f89 Mon Sep 17 00:00:00 2001 From: SNCPlay42 Date: Thu, 26 Nov 2020 15:32:41 +0000 Subject: [PATCH 204/274] check the recursion limit when finding struct tail --- compiler/rustc_middle/src/ty/util.rs | 10 ++++++-- src/test/ui/infinite/infinite-struct.rs | 10 ++++++++ src/test/ui/infinite/infinite-struct.stderr | 27 +++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/infinite/infinite-struct.rs create mode 100644 src/test/ui/infinite/infinite-struct.stderr diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e23c3f51967..25787f005aa 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -18,7 +18,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, TargetDataLayout}; use smallvec::SmallVec; use std::{cmp, fmt}; @@ -221,7 +221,13 @@ impl<'tcx> TyCtxt<'tcx> { mut ty: Ty<'tcx>, normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>, ) -> Ty<'tcx> { - loop { + for iteration in 0.. { + if !self.sess.recursion_limit().value_within_limit(iteration) { + return self.ty_error_with_message( + DUMMY_SP, + &format!("reached the recursion limit finding the struct tail for {}", ty), + ); + } match *ty.kind() { ty::Adt(def, substs) => { if !def.is_struct() { diff --git a/src/test/ui/infinite/infinite-struct.rs b/src/test/ui/infinite/infinite-struct.rs new file mode 100644 index 00000000000..70a203ea6e8 --- /dev/null +++ b/src/test/ui/infinite/infinite-struct.rs @@ -0,0 +1,10 @@ +struct Take(Take); +//~^ ERROR has infinite size +//~| ERROR cycle detected + +// check that we don't hang trying to find the tail of a recursive struct (#79437) +fn foo() -> Take { + Take(loop {}) +} + +fn main() {} diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr new file mode 100644 index 00000000000..d180670e38f --- /dev/null +++ b/src/test/ui/infinite/infinite-struct.stderr @@ -0,0 +1,27 @@ +error[E0072]: recursive type `Take` has infinite size + --> $DIR/infinite-struct.rs:1:1 + | +LL | struct Take(Take); + | ^^^^^^^^^^^^----^^ + | | | + | | recursive without indirection + | recursive type has infinite size + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Take` representable + | +LL | struct Take(Box); + | ^^^^ ^ + +error[E0391]: cycle detected when computing drop-check constraints for `Take` + --> $DIR/infinite-struct.rs:1:1 + | +LL | struct Take(Take); + | ^^^^^^^^^^^^^^^^^^ + | + = note: ...which again requires computing drop-check constraints for `Take`, completing the cycle + = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: Take } }` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0072, E0391. +For more information about an error, try `rustc --explain E0072`. From db5d697004d8bf3ce783d02f2e4a1c8354281d78 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Thu, 3 Dec 2020 20:13:51 +0000 Subject: [PATCH 205/274] std: impl of `Write` for `&mut [u8]`: document the buffer full error Signed-off-by: Ian Jackson --- library/std/src/io/impls.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 6b3c86cb0df..00bf8b9af73 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -306,6 +306,10 @@ impl BufRead for &[u8] { /// /// Note that writing updates the slice to point to the yet unwritten part. /// The slice will be empty when it has been completely overwritten. +/// +/// If the number of bytes to be written exceeds the size of the slice, write operations will +/// return short writes: ultimately, `Ok(0)`; in this situation, `write_all` returns an error of +/// kind `ErrorKind::WriteZero`. #[stable(feature = "rust1", since = "1.0.0")] impl Write for &mut [u8] { #[inline] From 19c7619dcda902acafa927b0b8511ca8ecce13a4 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 2 Nov 2020 20:58:12 +0000 Subject: [PATCH 206/274] IntoInnerError: Provide into_parts In particular, IntoIneerError only currently provides .error() which returns a reference, not an owned value. This is not helpful and means that a caller of BufWriter::into_inner cannot acquire an owned io::Error which seems quite wrong. Signed-off-by: Ian Jackson --- library/std/src/io/buffered/mod.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index f9caeaf98e2..0b58e55ed17 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -126,6 +126,30 @@ impl IntoInnerError { pub fn into_inner(self) -> W { self.0 } + + /// Consumes the [`IntoInnerError`] and returns the error which caused the call to + /// [`BufWriter::into_inner()`] to fail, and the underlying writer. + /// + /// This can be used to simply obtain ownership of the underlying error; it can also be used for + /// advanced error recovery. + /// + /// # Example + /// ``` + /// #![feature(io_into_inner_error_parts)] + /// use std::io::{BufWriter, ErrorKind, Write}; + /// + /// let mut not_enough_space = [0u8; 10]; + /// let mut stream = BufWriter::new(not_enough_space.as_mut()); + /// write!(stream, "this cannot be actually written").unwrap(); + /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); + /// let (err, recovered_writer) = into_inner_err.into_parts(); + /// assert_eq!(err.kind(), ErrorKind::WriteZero); + /// assert_eq!(recovered_writer.buffer(), b"t be actually written"); + /// ``` + #[unstable(feature = "io_into_inner_error_parts", issue = "79704")] + pub fn into_parts(self) -> (Error, W) { + (self.1, self.0) + } } #[stable(feature = "rust1", since = "1.0.0")] From b777552167d2651ceb13437f9fde4dca95045912 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Fri, 4 Dec 2020 17:32:26 +0000 Subject: [PATCH 207/274] IntoInnerError: Provide into_error Signed-off-by: Ian Jackson --- library/std/src/io/buffered/mod.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs index 0b58e55ed17..65497817f81 100644 --- a/library/std/src/io/buffered/mod.rs +++ b/library/std/src/io/buffered/mod.rs @@ -127,6 +127,27 @@ impl IntoInnerError { self.0 } + /// Consumes the [`IntoInnerError`] and returns the error which caused the call to + /// [`BufWriter::into_inner()`] to fail. Unlike `error`, this can be used to + /// obtain ownership of the underlying error. + /// + /// # Example + /// ``` + /// #![feature(io_into_inner_error_parts)] + /// use std::io::{BufWriter, ErrorKind, Write}; + /// + /// let mut not_enough_space = [0u8; 10]; + /// let mut stream = BufWriter::new(not_enough_space.as_mut()); + /// write!(stream, "this cannot be actually written").unwrap(); + /// let into_inner_err = stream.into_inner().expect_err("now we discover it's too small"); + /// let err = into_inner_err.into_error(); + /// assert_eq!(err.kind(), ErrorKind::WriteZero); + /// ``` + #[unstable(feature = "io_into_inner_error_parts", issue = "79704")] + pub fn into_error(self) -> Error { + self.1 + } + /// Consumes the [`IntoInnerError`] and returns the error which caused the call to /// [`BufWriter::into_inner()`] to fail, and the underlying writer. /// From 6edd59885605d2cf0aa8727cf2cd30cd13098804 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 4 Dec 2020 21:26:47 +0000 Subject: [PATCH 208/274] Added a lint-fraction-readability flag to the configuration --- clippy_lints/src/lib.rs | 3 +- clippy_lints/src/literal_representation.rs | 37 ++++++++++++---- clippy_lints/src/utils/conf.rs | 2 + .../lint_decimal_readability/clippy.toml | 1 + .../ui-toml/lint_decimal_readability/test.rs | 22 ++++++++++ .../lint_decimal_readability/test.stderr | 10 +++++ .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/unreadable_literal.fixed | 18 ++++++-- tests/ui/unreadable_literal.rs | 18 ++++++-- tests/ui/unreadable_literal.stderr | 42 +++++++++++-------- 10 files changed, 118 insertions(+), 37 deletions(-) create mode 100644 tests/ui-toml/lint_decimal_readability/clippy.toml create mode 100644 tests/ui-toml/lint_decimal_readability/test.rs create mode 100644 tests/ui-toml/lint_decimal_readability/test.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a861a34aeb7..58e91dd32bd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1138,7 +1138,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); - store.register_early_pass(|| box literal_representation::LiteralDigitGrouping); + let literal_representation_lint_fraction_readability = conf.lint_fraction_readability; + store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability)); let literal_representation_threshold = conf.literal_representation_threshold; store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)); let enum_variant_name_threshold = conf.enum_variant_name_threshold; diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index e8a741683da..3920e5b6e83 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -11,7 +11,7 @@ use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// **What it does:** Warns if a long integral or floating-point constant does @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ``` pub UNREADABLE_LITERAL, pedantic, - "long integer literal without underscores" + "long literal without underscores" } declare_clippy_lint! { @@ -208,7 +208,13 @@ impl WarningType { } } -declare_lint_pass!(LiteralDigitGrouping => [ +#[allow(clippy::module_name_repetitions)] +#[derive(Copy, Clone)] +pub struct LiteralDigitGrouping { + lint_fraction_readability: bool, +} + +impl_lint_pass!(LiteralDigitGrouping => [ UNREADABLE_LITERAL, INCONSISTENT_DIGIT_GROUPING, LARGE_DIGIT_GROUPS, @@ -223,7 +229,7 @@ impl EarlyLintPass for LiteralDigitGrouping { } if let ExprKind::Lit(ref lit) = expr.kind { - Self::check_lit(cx, lit) + self.check_lit(cx, lit) } } } @@ -232,7 +238,13 @@ impl EarlyLintPass for LiteralDigitGrouping { const UUID_GROUP_LENS: [usize; 5] = [8, 4, 4, 4, 12]; impl LiteralDigitGrouping { - fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) { + pub fn new(lint_fraction_readability: bool) -> Self { + Self { + lint_fraction_readability, + } + } + + fn check_lit(&self, cx: &EarlyContext<'_>, lit: &Lit) { if_chain! { if let Some(src) = snippet_opt(cx, lit.span); if let Some(mut num_lit) = NumericLiteral::from_lit(&src, &lit); @@ -247,9 +259,12 @@ impl LiteralDigitGrouping { let result = (|| { - let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix)?; + let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix, true)?; if let Some(fraction) = num_lit.fraction { - let fractional_group_size = Self::get_group_size(fraction.rsplit('_'), num_lit.radix)?; + let fractional_group_size = Self::get_group_size( + fraction.rsplit('_'), + num_lit.radix, + self.lint_fraction_readability)?; let consistent = Self::parts_consistent(integral_group_size, fractional_group_size, @@ -363,7 +378,11 @@ impl LiteralDigitGrouping { /// Returns the size of the digit groups (or None if ungrouped) if successful, /// otherwise returns a `WarningType` for linting. - fn get_group_size<'a>(groups: impl Iterator, radix: Radix) -> Result, WarningType> { + fn get_group_size<'a>( + groups: impl Iterator, + radix: Radix, + lint_unreadable: bool, + ) -> Result, WarningType> { let mut groups = groups.map(str::len); let first = groups.next().expect("At least one group"); @@ -380,7 +399,7 @@ impl LiteralDigitGrouping { } else { Ok(Some(second)) } - } else if first > 5 { + } else if first > 5 && lint_unreadable { Err(WarningType::UnreadableLiteral) } else { Ok(None) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index fc6304118d9..c9d5f781f1b 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -170,6 +170,8 @@ define_Conf! { (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false), /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses (disallowed_methods, "disallowed_methods": Vec, Vec::::new()), + /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators. + (lint_fraction_readability, "lint_fraction_readability": bool, true), } impl Default for Conf { diff --git a/tests/ui-toml/lint_decimal_readability/clippy.toml b/tests/ui-toml/lint_decimal_readability/clippy.toml new file mode 100644 index 00000000000..635e282dc06 --- /dev/null +++ b/tests/ui-toml/lint_decimal_readability/clippy.toml @@ -0,0 +1 @@ +lint-fraction-readability = false \ No newline at end of file diff --git a/tests/ui-toml/lint_decimal_readability/test.rs b/tests/ui-toml/lint_decimal_readability/test.rs new file mode 100644 index 00000000000..9377eb69b23 --- /dev/null +++ b/tests/ui-toml/lint_decimal_readability/test.rs @@ -0,0 +1,22 @@ +#[deny(clippy::unreadable_literal)] + +fn allow_inconsistent_digit_grouping() { + #![allow(clippy::inconsistent_digit_grouping)] + let _pass1 = 100_200_300.123456789; +} + +fn main() { + allow_inconsistent_digit_grouping(); + + let _pass1 = 100_200_300.100_200_300; + let _pass2 = 1.123456789; + let _pass3 = 1.0; + let _pass4 = 10000.00001; + let _pass5 = 1.123456789e1; + + // due to clippy::inconsistent-digit-grouping + let _fail1 = 100_200_300.123456789; + + // fail due to the integer part + let _fail2 = 100200300.300200100; +} diff --git a/tests/ui-toml/lint_decimal_readability/test.stderr b/tests/ui-toml/lint_decimal_readability/test.stderr new file mode 100644 index 00000000000..9119ef19a7b --- /dev/null +++ b/tests/ui-toml/lint_decimal_readability/test.stderr @@ -0,0 +1,10 @@ +error: digits grouped inconsistently by underscores + --> $DIR/test.rs:18:18 + | +LL | let _fail1 = 100_200_300.123456789; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.123_456_789` + | + = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index af3d9ecf6e8..eff4da7e658 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `lint-fraction-readability`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui/unreadable_literal.fixed b/tests/ui/unreadable_literal.fixed index 4043d53299f..c2e38037add 100644 --- a/tests/ui/unreadable_literal.fixed +++ b/tests/ui/unreadable_literal.fixed @@ -10,6 +10,14 @@ macro_rules! foo { }; } +struct Bar(f32); + +macro_rules! bar { + () => { + Bar(100200300400.100200300400500) + }; +} + fn main() { let _good = ( 0b1011_i64, @@ -26,10 +34,12 @@ fn main() { let _good_sci = 1.1234e1; let _bad_sci = 1.123_456e1; - let _fail9 = 0x00ab_cdef; - let _fail10: u32 = 0xBAFE_BAFE; - let _fail11 = 0x0abc_deff; - let _fail12: i128 = 0x00ab_cabc_abca_bcab_cabc; + let _fail1 = 0x00ab_cdef; + let _fail2: u32 = 0xBAFE_BAFE; + let _fail3 = 0x0abc_deff; + let _fail4: i128 = 0x00ab_cabc_abca_bcab_cabc; + let _fail5 = 1.100_300_400; let _ = foo!(); + let _ = bar!(); } diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index e658a5f28c9..8296945b25e 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -10,6 +10,14 @@ macro_rules! foo { }; } +struct Bar(f32); + +macro_rules! bar { + () => { + Bar(100200300400.100200300400500) + }; +} + fn main() { let _good = ( 0b1011_i64, @@ -26,10 +34,12 @@ fn main() { let _good_sci = 1.1234e1; let _bad_sci = 1.123456e1; - let _fail9 = 0xabcdef; - let _fail10: u32 = 0xBAFEBAFE; - let _fail11 = 0xabcdeff; - let _fail12: i128 = 0xabcabcabcabcabcabc; + let _fail1 = 0xabcdef; + let _fail2: u32 = 0xBAFEBAFE; + let _fail3 = 0xabcdeff; + let _fail4: i128 = 0xabcabcabcabcabcabc; + let _fail5 = 1.100300400; let _ = foo!(); + let _ = bar!(); } diff --git a/tests/ui/unreadable_literal.stderr b/tests/ui/unreadable_literal.stderr index 8645cabeabb..8436aac17ac 100644 --- a/tests/ui/unreadable_literal.stderr +++ b/tests/ui/unreadable_literal.stderr @@ -1,5 +1,5 @@ error: digits of hex or binary literal not grouped by four - --> $DIR/unreadable_literal.rs:17:9 + --> $DIR/unreadable_literal.rs:25:9 | LL | 0x1_234_567, | ^^^^^^^^^^^ help: consider: `0x0123_4567` @@ -7,7 +7,7 @@ LL | 0x1_234_567, = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:25:17 + --> $DIR/unreadable_literal.rs:33:17 | LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `0b11_0110_i64` @@ -15,52 +15,58 @@ LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); = note: `-D clippy::unreadable-literal` implied by `-D warnings` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:25:31 + --> $DIR/unreadable_literal.rs:33:31 | LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^^^^^ help: consider: `0xcafe_babe_usize` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:25:49 + --> $DIR/unreadable_literal.rs:33:49 | LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^ help: consider: `123_456_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:25:61 + --> $DIR/unreadable_literal.rs:33:61 | LL | let _bad = (0b110110_i64, 0xcafebabe_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `1.234_567_f32` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:27:20 + --> $DIR/unreadable_literal.rs:35:20 | LL | let _bad_sci = 1.123456e1; | ^^^^^^^^^^ help: consider: `1.123_456e1` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:29:18 + --> $DIR/unreadable_literal.rs:37:18 | -LL | let _fail9 = 0xabcdef; +LL | let _fail1 = 0xabcdef; | ^^^^^^^^ help: consider: `0x00ab_cdef` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:30:24 + --> $DIR/unreadable_literal.rs:38:23 | -LL | let _fail10: u32 = 0xBAFEBAFE; - | ^^^^^^^^^^ help: consider: `0xBAFE_BAFE` +LL | let _fail2: u32 = 0xBAFEBAFE; + | ^^^^^^^^^^ help: consider: `0xBAFE_BAFE` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:31:19 + --> $DIR/unreadable_literal.rs:39:18 | -LL | let _fail11 = 0xabcdeff; - | ^^^^^^^^^ help: consider: `0x0abc_deff` +LL | let _fail3 = 0xabcdeff; + | ^^^^^^^^^ help: consider: `0x0abc_deff` error: long literal lacking separators - --> $DIR/unreadable_literal.rs:32:25 + --> $DIR/unreadable_literal.rs:40:24 | -LL | let _fail12: i128 = 0xabcabcabcabcabcabc; - | ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc` +LL | let _fail4: i128 = 0xabcabcabcabcabcabc; + | ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc` -error: aborting due to 10 previous errors +error: long literal lacking separators + --> $DIR/unreadable_literal.rs:41:18 + | +LL | let _fail5 = 1.100300400; + | ^^^^^^^^^^^ help: consider: `1.100_300_400` + +error: aborting due to 11 previous errors From 18383c69c1ebf0b6bc0f1ecdeee062f0767a69e8 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 4 Dec 2020 22:05:52 +0000 Subject: [PATCH 209/274] Updated code for CI --- clippy_lints/src/literal_representation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 3920e5b6e83..87a957a9bd2 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -244,7 +244,7 @@ impl LiteralDigitGrouping { } } - fn check_lit(&self, cx: &EarlyContext<'_>, lit: &Lit) { + fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { if_chain! { if let Some(src) = snippet_opt(cx, lit.span); if let Some(mut num_lit) = NumericLiteral::from_lit(&src, &lit); From b766abc88f78f36193ddefb1079dbc832346b358 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 5 Oct 2020 22:10:37 +0100 Subject: [PATCH 210/274] Simplify unscheduling of drops after moves --- compiler/rustc_mir_build/src/build/scope.rs | 52 +++++++++------------ 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index e91227d8357..5967c6fc80e 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -121,8 +121,6 @@ struct Scope { /// end of the vector (top of the stack) first. drops: Vec, - moved_locals: Vec, - /// The drop index that will drop everything in and below this scope on an /// unwind path. cached_unwind_block: Option, @@ -406,7 +404,6 @@ impl<'tcx> Scopes<'tcx> { region_scope: region_scope.0, region_scope_span: region_scope.1.span, drops: vec![], - moved_locals: vec![], cached_unwind_block: None, cached_generator_drop_block: None, }); @@ -904,29 +901,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return; } - Some(local_scope) => self - .scopes - .scopes - .iter_mut() - .rfind(|scope| scope.region_scope == local_scope) - .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)), + Some(local_scope) => { + let top_scope = self.scopes.scopes.last_mut().unwrap(); + assert!( + top_scope.region_scope == local_scope, + "local scope ({:?}) is not the topmost scope!", + local_scope + ); + + top_scope + } }; // look for moves of a local variable, like `MOVE(_X)` - let locals_moved = operands.iter().flat_map(|operand| match operand { - Operand::Copy(_) | Operand::Constant(_) => None, - Operand::Move(place) => place.as_local(), - }); + let locals_moved = operands + .iter() + .filter_map(|operand| match operand { + Operand::Copy(_) | Operand::Constant(_) => None, + Operand::Move(place) => place.as_local(), + }) + .collect::>(); - for local in locals_moved { - // check if we have a Drop for this operand and -- if so - // -- add it to the list of moved operands. Note that this - // local might not have been an operand created for this - // call, it could come from other places too. - if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) { - scope.moved_locals.push(local); - } - } + // Remove the drops for the moved operands. + scope + .drops + .retain(|drop| drop.kind == DropKind::Storage || !locals_moved.contains(&drop.local)); + scope.invalidate_cache(); } // Other @@ -1174,14 +1174,6 @@ fn build_scope_drops<'tcx>( debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind); unwind_to = unwind_drops.drops[unwind_to].1; - // If the operand has been moved, and we are not on an unwind - // path, then don't generate the drop. (We only take this into - // account for non-unwind paths so as not to disturb the - // caching mechanism.) - if scope.moved_locals.iter().any(|&o| o == local) { - continue; - } - unwind_drops.add_entry(block, unwind_to); let next = cfg.start_new_block(); From 7f3e8551dde7f14641618cdb8fda2f99ff1d74b6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 24 Oct 2020 11:18:32 +0100 Subject: [PATCH 211/274] Use `record_operands_moved` more aggresively --- .../src/build/expr/as_rvalue.rs | 9 ++- .../rustc_mir_build/src/build/expr/into.rs | 7 +- .../rustc_mir_build/src/build/expr/stmt.rs | 2 + compiler/rustc_mir_build/src/build/scope.rs | 4 +- ...ignment.main.SimplifyCfg-initial.after.mir | 28 +++---- .../box_expr.main.ElaborateDrops.before.mir | 28 +++---- .../issue_41110.main.ElaborateDrops.after.mir | 27 +------ .../issue_41110.test.ElaborateDrops.after.mir | 48 +++++------- .../issue_41888.main.ElaborateDrops.after.mir | 74 +++++++++---------- ...issue_62289.test.ElaborateDrops.before.mir | 40 ++++------ ..._after_call.main.ElaborateDrops.before.mir | 10 +-- ...ove_out.move_out_by_subslice.mir_map.0.mir | 38 ++-------- ...y_move_out.move_out_from_end.mir_map.0.mir | 38 ++-------- 13 files changed, 120 insertions(+), 233 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 7c34b996055..4e96ae38015 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -11,6 +11,8 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; +use std::slice; + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Returns an rvalue suitable for use until the end of the current /// scope expression. @@ -117,7 +119,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value) ); - block.and(Rvalue::Use(Operand::Move(Place::from(result)))) + let result_operand = Operand::Move(Place::from(result)); + this.record_operands_moved(slice::from_ref(&result_operand)); + block.and(Rvalue::Use(result_operand)) } ExprKind::Cast { source } => { let source = unpack!(block = this.as_operand(block, scope, source)); @@ -161,6 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); + this.record_operands_moved(&fields); block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields)) } ExprKind::Tuple { fields } => { @@ -171,6 +176,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); + this.record_operands_moved(&fields); block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) } ExprKind::Closure { closure_id, substs, upvars, movability } => { @@ -222,6 +228,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs), }; + this.record_operands_moved(&operands); block.and(Rvalue::Aggregate(result, operands)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 50001c38dc7..ce2ebb8b83b 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -10,9 +10,10 @@ use rustc_hir as hir; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; use rustc_span::symbol::sym; - use rustc_target::spec::abi::Abi; +use std::slice; + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. @@ -271,7 +272,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let field_names = this.hir.all_fields(adt_def, variant_index); - let fields = if let Some(FruInfo { base, field_types }) = base { + let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base { let base = unpack!(block = this.as_place(block, base)); // MIR does not natively support FRU, so for each @@ -306,6 +307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { user_ty, active_field_index, ); + this.record_operands_moved(&fields); this.cfg.push_assign( block, source_info, @@ -432,6 +434,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = this.local_scope(); let value = unpack!(block = this.as_operand(block, scope, value)); let resume = this.cfg.start_new_block(); + this.record_operands_moved(slice::from_ref(&value)); this.cfg.terminate( block, source_info, diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index f117689d940..a974ea0db5f 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -3,6 +3,7 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::thir::*; use rustc_middle::middle::region; use rustc_middle::mir::*; +use std::slice; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Builds a block of MIR statements to evaluate the THIR `expr`. @@ -46,6 +47,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if this.hir.needs_drop(lhs.ty) { let rhs = unpack!(block = this.as_local_operand(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); + this.record_operands_moved(slice::from_ref(&rhs)); unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs)); } else { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 5967c6fc80e..695b884abbd 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -83,7 +83,7 @@ that contains only loops and breakable blocks. It tracks where a `break`, use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; use crate::thir::{Expr, ExprRef, LintLevel}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_index::vec::IndexVec; use rustc_middle::middle::region; @@ -1379,7 +1379,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind { | TerminatorKind::Yield { .. } | TerminatorKind::GeneratorDrop | TerminatorKind::FalseEdge { .. } - | TerminatorKind::InlineAsm {.. } => { + | TerminatorKind::InlineAsm { .. } => { span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind) } } diff --git a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 7e0ca3dea4b..0c7b64cb97f 100644 --- a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -41,44 +41,36 @@ fn main() -> () { StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15 StorageLive(_6); // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 _6 = move _4; // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 - replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11 + replace(_5 <- move _6) -> [return: bb1, unwind: bb4]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11 } bb1: { - drop(_6) -> [return: bb2, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 - } - - bb2: { StorageDead(_6); // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 _0 = const (); // scope 0 at $DIR/basic_assignment.rs:10:11: 24:2 - drop(_5) -> [return: bb3, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_5) -> [return: bb2, unwind: bb5]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb3: { + bb2: { StorageDead(_5); // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 - drop(_4) -> [return: bb4, unwind: bb8]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_4) -> [return: bb3, unwind: bb6]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb4: { + bb3: { StorageDead(_4); // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 StorageDead(_2); // scope 1 at $DIR/basic_assignment.rs:24:1: 24:2 StorageDead(_1); // scope 0 at $DIR/basic_assignment.rs:24:1: 24:2 return; // scope 0 at $DIR/basic_assignment.rs:24:2: 24:2 } - bb5 (cleanup): { - drop(_6) -> bb6; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 - } - - bb6 (cleanup): { - drop(_5) -> bb7; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 + bb4 (cleanup): { + drop(_5) -> bb5; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb7 (cleanup): { - drop(_4) -> bb8; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + bb5 (cleanup): { + drop(_4) -> bb6; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb8 (cleanup): { + bb6 (cleanup): { resume; // scope 0 at $DIR/basic_assignment.rs:10:1: 24:2 } } diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index cfbd3a58637..20ea7b026bc 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -14,7 +14,7 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10 StorageLive(_2); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 _2 = Box(S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - (*_2) = S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + (*_2) = S::new() -> [return: bb1, unwind: bb5]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 // mir::Constant // + span: $DIR/box_expr.rs:7:17: 7:23 // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } @@ -22,45 +22,37 @@ fn main() -> () { bb1: { _1 = move _2; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - drop(_2) -> bb2; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 - } - - bb2: { StorageDead(_2); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _3 = std::mem::drop::>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + _3 = std::mem::drop::>(move _4) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 // + literal: Const { ty: fn(std::boxed::Box) {std::mem::drop::>}, val: Value(Scalar()) } } - bb3: { + bb2: { StorageDead(_4); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 StorageDead(_3); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 _0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2 - drop(_1) -> bb4; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_1) -> bb3; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb4: { + bb3: { StorageDead(_1); // scope 0 at $DIR/box_expr.rs:9:1: 9:2 return; // scope 0 at $DIR/box_expr.rs:9:2: 9:2 } - bb5 (cleanup): { - drop(_4) -> bb6; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 - } - - bb6 (cleanup): { - drop(_1) -> bb8; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + bb4 (cleanup): { + drop(_1) -> bb6; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb7 (cleanup): { - drop(_2) -> bb8; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + bb5 (cleanup): { + drop(_2) -> bb6; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 } - bb8 (cleanup): { + bb6 (cleanup): { resume; // scope 0 at $DIR/box_expr.rs:6:1: 9:2 } } diff --git a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir index 7113c42b9c7..bbbd2bcf128 100644 --- a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir @@ -6,21 +6,18 @@ fn main() -> () { let mut _2: S; // in scope 0 at $DIR/issue-41110.rs:8:13: 8:14 let mut _3: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:27 let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:22 - let mut _5: bool; // in scope 0 at $DIR/issue-41110.rs:8:27: 8:28 scope 1 { debug x => _1; // in scope 1 at $DIR/issue-41110.rs:8:9: 8:10 } bb0: { - _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 StorageLive(_2); // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 - _5 = const true; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 _2 = S; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 StorageLive(_3); // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 StorageLive(_4); // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 _4 = S; // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 - _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 + _3 = S::id(move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 // mir::Constant // + span: $DIR/issue-41110.rs:8:23: 8:25 // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(Scalar()) } @@ -28,8 +25,7 @@ fn main() -> () { bb1: { StorageDead(_4); // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 - _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 - _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 + _1 = S::other(move _2, move _3) -> bb2; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 // mir::Constant // + span: $DIR/issue-41110.rs:8:15: 8:20 // + literal: Const { ty: fn(S, S) {S::other}, val: Value(Scalar()) } @@ -37,7 +33,6 @@ fn main() -> () { bb2: { StorageDead(_3); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 StorageDead(_2); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 _0 = const (); // scope 0 at $DIR/issue-41110.rs:7:11: 9:2 StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:9:1: 9:2 @@ -45,26 +40,10 @@ fn main() -> () { } bb3 (cleanup): { - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + drop(_2) -> bb4; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 } bb4 (cleanup): { - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 - } - - bb5 (cleanup): { - goto -> bb8; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - } - - bb6 (cleanup): { resume; // scope 0 at $DIR/issue-41110.rs:7:1: 9:2 } - - bb7 (cleanup): { - drop(_2) -> bb6; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - } - - bb8 (cleanup): { - switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 - } } diff --git a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir index c4e852ca321..b0c7260f0f4 100644 --- a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir @@ -25,7 +25,7 @@ fn test() -> () { StorageLive(_3); // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 StorageLive(_4); // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 _4 = move _2; // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 - _3 = std::mem::drop::(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 + _3 = std::mem::drop::(move _4) -> [return: bb1, unwind: bb5]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 // mir::Constant // + span: $DIR/issue-41110.rs:17:5: 17:9 // + literal: Const { ty: fn(S) {std::mem::drop::}, val: Value(Scalar()) } @@ -37,65 +37,53 @@ fn test() -> () { StorageLive(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _6 = const false; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _5 = move _1; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - goto -> bb12; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb9; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } bb2: { - goto -> bb3; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - } - - bb3: { StorageDead(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _0 = const (); // scope 0 at $DIR/issue-41110.rs:14:15: 19:2 - drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 + drop(_2) -> [return: bb3, unwind: bb6]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } - bb4: { + bb3: { StorageDead(_2); // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 - goto -> bb5; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + goto -> bb4; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb5: { + bb4: { _6 = const false; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 return; // scope 0 at $DIR/issue-41110.rs:19:2: 19:2 } - bb6 (cleanup): { - goto -> bb8; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - } - - bb7 (cleanup): { - goto -> bb8; // scope 2 at $DIR/issue-41110.rs:17:11: 17:12 - } - - bb8 (cleanup): { - goto -> bb9; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 + bb5 (cleanup): { + goto -> bb6; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } - bb9 (cleanup): { - goto -> bb14; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb6 (cleanup): { + goto -> bb11; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb10 (cleanup): { + bb7 (cleanup): { resume; // scope 0 at $DIR/issue-41110.rs:14:1: 19:2 } - bb11 (cleanup): { + bb8 (cleanup): { _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 - goto -> bb6; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } - bb12: { + bb9: { _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 goto -> bb2; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } - bb13 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb10 (cleanup): { + drop(_1) -> bb7; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb14 (cleanup): { - switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb11 (cleanup): { + switchInt(_6) -> [false: bb7, otherwise: bb10]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } } diff --git a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir index 453886f3eff..5011c2adfa5 100644 --- a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir @@ -26,7 +26,7 @@ fn main() -> () { _8 = const false; // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 StorageLive(_1); // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 StorageLive(_2); // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 - _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 + _2 = cond() -> [return: bb1, unwind: bb9]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 // mir::Constant // + span: $DIR/issue-41888.rs:8:8: 8:12 // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar()) } @@ -38,7 +38,7 @@ fn main() -> () { bb2: { _0 = const (); // scope 1 at $DIR/issue-41888.rs:14:6: 14:6 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 + goto -> bb7; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 } bb3: { @@ -47,38 +47,34 @@ fn main() -> () { _4 = K; // scope 1 at $DIR/issue-41888.rs:9:18: 9:19 _3 = E::F(move _4); // scope 1 at $DIR/issue-41888.rs:9:13: 9:20 StorageDead(_4); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - goto -> bb14; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb12; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } bb4: { - goto -> bb5; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - } - - bb5: { StorageDead(_3); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 _5 = discriminant(_1); // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 - switchInt(move _5) -> [0_isize: bb7, otherwise: bb6]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 + switchInt(move _5) -> [0_isize: bb6, otherwise: bb5]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 } - bb6: { + bb5: { _0 = const (); // scope 1 at $DIR/issue-41888.rs:13:10: 13:10 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 + goto -> bb7; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } - bb7: { + bb6: { StorageLive(_6); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _9 = const false; // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _6 = move ((_1 as F).0: K); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _0 = const (); // scope 2 at $DIR/issue-41888.rs:10:29: 13:10 StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:13:9: 13:10 - goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 + goto -> bb7; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } - bb8: { - goto -> bb20; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb7: { + goto -> bb18; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb9: { + bb8: { _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 _8 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 _9 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 @@ -87,27 +83,23 @@ fn main() -> () { return; // scope 0 at $DIR/issue-41888.rs:15:2: 15:2 } - bb10 (cleanup): { - goto -> bb11; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - } - - bb11 (cleanup): { - goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb9 (cleanup): { + goto -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb12 (cleanup): { + bb10 (cleanup): { resume; // scope 0 at $DIR/issue-41888.rs:6:1: 15:2 } - bb13 (cleanup): { + bb11 (cleanup): { _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _1 = move _3; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 - goto -> bb10; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb9; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } - bb14: { + bb12: { _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 @@ -115,38 +107,38 @@ fn main() -> () { goto -> bb4; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } - bb15: { + bb13: { _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - goto -> bb9; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + goto -> bb8; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb16 (cleanup): { - goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb14 (cleanup): { + goto -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb17: { - drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb15: { + drop(_1) -> [return: bb13, unwind: bb10]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb18 (cleanup): { - drop(_1) -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb16 (cleanup): { + drop(_1) -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb19: { + bb17: { _10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _10) -> [0_isize: bb13, otherwise: bb15]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb20: { - switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb18: { + switchInt(_7) -> [false: bb13, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb21 (cleanup): { + bb19 (cleanup): { _11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _11) -> [0_isize: bb14, otherwise: bb16]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb22 (cleanup): { - switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb20 (cleanup): { + switchInt(_7) -> [false: bb10, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } } diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index c1421f20a0b..ab6e7ea7b38 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -30,7 +30,7 @@ fn test() -> Option> { StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _3 = as Try>::into_result(move _4) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result}, val: Value(Scalar()) } @@ -48,7 +48,11 @@ fn test() -> Option> { (*_2) = _10; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 StorageDead(_10); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - drop(_2) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb8; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb3: { @@ -61,7 +65,7 @@ fn test() -> Option> { StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = >::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = >::from(move _9) -> [return: bb5, unwind: bb9]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {>::from}, val: Value(Scalar()) } @@ -69,7 +73,7 @@ fn test() -> Option> { bb5: { StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 + _0 = > as Try>::from_error(move _8) -> [return: bb6, unwind: bb9]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error}, val: Value(Scalar()) } @@ -78,41 +82,25 @@ fn test() -> Option> { bb6: { StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 - _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - } - - bb8: { - StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 - } - - bb9: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + goto -> bb8; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb10: { + bb8: { return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb11 (cleanup): { - drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - } - - bb12 (cleanup): { - drop(_2) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + bb9 (cleanup): { + drop(_2) -> bb10; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } - bb13 (cleanup): { + bb10 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir index bbb433dbe25..2f95931d2b2 100644 --- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir @@ -28,7 +28,7 @@ fn main() -> () { bb1: { StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34 - _1 = std::mem::drop::(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 + _1 = std::mem::drop::(move _2) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19 // + literal: Const { ty: fn(std::string::String) {std::mem::drop::}, val: Value(Scalar()) } @@ -41,12 +41,4 @@ fn main() -> () { _0 = const (); // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:11: 10:2 return; // scope 0 at $DIR/no-spurious-drop-after-call.rs:10:2: 10:2 } - - bb3 (cleanup): { - drop(_2) -> bb4; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:34: 9:35 - } - - bb4 (cleanup): { - resume; // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:1: 10:2 - } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index d18f6308ded..9bca5d24605 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -22,62 +22,38 @@ fn move_out_by_subslice() -> () { _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 - } - - bb1: { StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 - } - - bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_6) -> [return: bb1, unwind: bb3]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb5: { + bb1: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb6: { + bb2: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - } - - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - } - - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + bb3 (cleanup): { + drop(_1) -> bb4; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb10 (cleanup): { + bb4 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir index eda8e5fd3af..c9004416f2e 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir @@ -22,62 +22,38 @@ fn move_out_from_end() -> () { _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 - } - - bb1: { StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 - } - - bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_6) -> [return: bb1, unwind: bb3]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb5: { + bb1: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb6: { + bb2: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - } - - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - } - - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + bb3 (cleanup): { + drop(_1) -> bb4; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb10 (cleanup): { + bb4 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2 } } From ab121e3afef7b54b5621547b0b5c01d9554fe026 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 5 Dec 2020 08:02:56 +0900 Subject: [PATCH 212/274] Add a regression test for issue-66286 --- src/test/ui/proc-macro/auxiliary/issue-66286.rs | 14 ++++++++++++++ src/test/ui/proc-macro/issue-66286.rs | 13 +++++++++++++ src/test/ui/proc-macro/issue-66286.stderr | 12 ++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/test/ui/proc-macro/auxiliary/issue-66286.rs create mode 100644 src/test/ui/proc-macro/issue-66286.rs create mode 100644 src/test/ui/proc-macro/issue-66286.stderr diff --git a/src/test/ui/proc-macro/auxiliary/issue-66286.rs b/src/test/ui/proc-macro/auxiliary/issue-66286.rs new file mode 100644 index 00000000000..6217f1c7e61 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/issue-66286.rs @@ -0,0 +1,14 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn vec_ice(_attr: TokenStream, input: TokenStream) -> TokenStream { + // This redundant convert is necessary to reproduce ICE. + input.into_iter().collect() +} diff --git a/src/test/ui/proc-macro/issue-66286.rs b/src/test/ui/proc-macro/issue-66286.rs new file mode 100644 index 00000000000..2a67aeab44e --- /dev/null +++ b/src/test/ui/proc-macro/issue-66286.rs @@ -0,0 +1,13 @@ +// aux-build:issue-66286.rs + +// Regression test for #66286. + +extern crate issue_66286; + +#[issue_66286::vec_ice] +pub extern fn foo(_: Vec(u32)) -> u32 { + //~^ ERROR: parenthesized type parameters may only be used with a `Fn` trait + 0 +} + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-66286.stderr b/src/test/ui/proc-macro/issue-66286.stderr new file mode 100644 index 00000000000..2854dd7d59c --- /dev/null +++ b/src/test/ui/proc-macro/issue-66286.stderr @@ -0,0 +1,12 @@ +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/issue-66286.rs:8:22 + | +LL | pub extern fn foo(_: Vec(u32)) -> u32 { + | ^^^^^^^^ + | | + | only `Fn` traits may use parentheses + | help: use angle brackets instead: `Vec` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0214`. From 4fef39113a514bb270f5661a82fdba17d3e41dbb Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 24 Oct 2020 22:30:57 +0100 Subject: [PATCH 213/274] Avoid leaking block expression values --- compiler/rustc_mir_build/src/build/block.rs | 10 +- .../src/build/expr/as_rvalue.rs | 11 +- .../rustc_mir_build/src/build/expr/as_temp.rs | 6 +- .../rustc_mir_build/src/build/expr/into.rs | 92 +- compiler/rustc_mir_build/src/build/into.rs | 11 +- .../rustc_mir_build/src/build/matches/mod.rs | 97 +- compiler/rustc_mir_build/src/build/mod.rs | 34 +- compiler/rustc_mir_build/src/build/scope.rs | 176 +- .../alloc/src/collections/btree/map/tests.rs | 2 +- .../inline/inline_diverging.h.Inline.diff | 11 +- ...issue_62289.test.ElaborateDrops.before.mir | 14 +- .../expected_show_coverage.uses_crate.txt | 4 +- .../expected_show_coverage_counters.async.txt | 12 +- ...pected_show_coverage_counters.generics.txt | 4 +- ...cted_show_coverage_counters.uses_crate.txt | 10 +- ...block_on.-------.InstrumentCoverage.0.html | 114 +- ...ync.main.-------.InstrumentCoverage.0.html | 54 +- ...osure#2}.-------.InstrumentCoverage.0.html | 12 +- ...ure.main.-------.InstrumentCoverage.0.html | 19992 ++++++++-------- ...ib_crate.-------.InstrumentCoverage.0.html | 162 +- ...ate.main.-------.InstrumentCoverage.0.html | 176 +- src/test/ui/drop/dynamic-drop-async.rs | 165 +- src/test/ui/drop/dynamic-drop.rs | 437 +- 23 files changed, 10953 insertions(+), 10653 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index d5f72e6f22d..82f38ac0e76 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -3,6 +3,7 @@ use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::thir::*; use rustc_hir as hir; +use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_session::lint::Level; @@ -12,6 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn ast_block( &mut self, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ast_block: &'tcx hir::Block<'tcx>, source_info: SourceInfo, @@ -28,9 +30,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| { this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { if targeted_by_break { - this.in_breakable_scope(None, destination, span, |this| { + this.in_breakable_scope(None, destination, scope, span, |this| { Some(this.ast_block_stmts( destination, + scope, block, span, stmts, @@ -39,7 +42,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { )) }) } else { - this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode) + this.ast_block_stmts(destination, scope, block, span, stmts, expr, safety_mode) } }) }) @@ -48,6 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn ast_block_stmts( &mut self, destination: Place<'tcx>, + scope: Option, mut block: BasicBlock, span: Span, stmts: Vec>, @@ -182,7 +186,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span }); - unpack!(block = this.into(destination, block, expr)); + unpack!(block = this.into(destination, scope, block, expr)); let popped = this.block_context.pop(); assert!(popped.map_or(false, |bf| bf.is_tail_expr())); diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 4e96ae38015..c0e4141a558 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -114,10 +114,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); this.cfg.push_assign(block, source_info, Place::from(result), box_); - // initialize the box contents: + // Initialize the box contents. No scope is needed since the + // `Box` is already scheduled to be dropped. unpack!( - block = - this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value) + block = this.into( + this.hir.tcx().mk_place_deref(Place::from(result)), + None, + block, + value, + ) ); let result_operand = Operand::Move(Place::from(result)); this.record_operands_moved(slice::from_ref(&result_operand)); diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 9984b527ffd..241330d96e7 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -114,11 +114,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - unpack!(block = this.into(temp_place, block, expr)); - - if let Some(temp_lifetime) = temp_lifetime { - this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); - } + unpack!(block = this.into(temp_place, temp_lifetime, block, expr)); block.and(temp) } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index ce2ebb8b83b..5f9743b7f59 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -1,12 +1,14 @@ //! See docs in build/expr/mod.rs use crate::build::expr::category::{Category, RvalueFunc}; +use crate::build::scope::DropKind; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::thir::*; use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; +use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; use rustc_span::symbol::sym; @@ -17,13 +19,19 @@ use std::slice; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. + /// If a `drop_scope` is provided, `destination` is scheduled to be dropped + /// in `scope` once it has been initialized. crate fn into_expr( &mut self, destination: Place<'tcx>, + scope: Option, mut block: BasicBlock, expr: Expr<'tcx>, ) -> BlockAnd<()> { - debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr); + debug!( + "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})", + destination, scope, block, expr + ); // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to @@ -38,6 +46,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => false, }; + let schedule_drop = move |this: &mut Self| { + if let Some(drop_scope) = scope { + let local = + destination.as_local().expect("cannot schedule drop of non-Local place"); + this.schedule_drop(expr_span, drop_scope, local, DropKind::Value); + } + }; + if !expr_is_block_or_scope { this.block_context.push(BlockFrame::SubExpr); } @@ -47,15 +63,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let region_scope = (region_scope, source_info); ensure_sufficient_stack(|| { this.in_scope(region_scope, lint_level, |this| { - this.into(destination, block, value) + this.into(destination, scope, block, value) }) }) } ExprKind::Block { body: ast_block } => { - this.ast_block(destination, block, ast_block, source_info) + this.ast_block(destination, scope, block, ast_block, source_info) } ExprKind::Match { scrutinee, arms } => { - this.match_expr(destination, expr_span, block, scrutinee, arms) + this.match_expr(destination, scope, expr_span, block, scrutinee, arms) } ExprKind::NeverToAny { source } => { let source = this.hir.mirror(source); @@ -67,6 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This is an optimization. If the expression was a call then we already have an // unreachable block. Don't bother to terminate it and create a new one. + schedule_drop(this); if is_call { block.unit() } else { @@ -142,26 +159,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Start the loop. this.cfg.goto(block, source_info, loop_block); - this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| { - // conduct the test, if necessary - let body_block = this.cfg.start_new_block(); - this.cfg.terminate( - loop_block, - source_info, - TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, - ); - this.diverge_from(loop_block); - - // The “return” value of the loop body must always be an unit. We therefore - // introduce a unit temporary as the destination for the loop body. - let tmp = this.get_unit_temp(); - // Execute the body, branching back to the test. - let body_block_end = unpack!(this.into(tmp, body_block, body)); - this.cfg.goto(body_block_end, source_info, loop_block); - - // Loops are only exited by `break` expressions. - None - }) + this.in_breakable_scope( + Some(loop_block), + destination, + scope, + expr_span, + move |this| { + // conduct the test, if necessary + let body_block = this.cfg.start_new_block(); + this.cfg.terminate( + loop_block, + source_info, + TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, + ); + this.diverge_from(loop_block); + + // The “return” value of the loop body must always be an unit. We therefore + // introduce a unit temporary as the destination for the loop body. + let tmp = this.get_unit_temp(); + // Execute the body, branching back to the test. + // We don't need to provide a drop scope because `tmp` + // has type `()`. + let body_block_end = unpack!(this.into(tmp, None, body_block, body)); + this.cfg.goto(body_block_end, source_info, loop_block); + schedule_drop(this); + + // Loops are only exited by `break` expressions. + None + }, + ) } ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => { let intrinsic = match *ty.kind() { @@ -193,8 +219,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .local_decls .push(LocalDecl::with_source_info(ptr_ty, source_info).internal()); let ptr_temp = Place::from(ptr_temp); - let block = unpack!(this.into(ptr_temp, block, ptr)); - this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val) + // No need for a scope, ptr_temp doesn't need drop + let block = unpack!(this.into(ptr_temp, None, block, ptr)); + // Maybe we should provide a scope here so that + // `move_val_init` wouldn't leak on panic even with an + // arbitrary `val` expression, but `schedule_drop`, + // borrowck and drop elaboration all prevent us from + // dropping `ptr_temp.deref()`. + this.into(this.hir.tcx().mk_place_deref(ptr_temp), None, block, val) } else { let args: Vec<_> = args .into_iter() @@ -227,10 +259,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); this.diverge_from(block); + schedule_drop(this); success.unit() } } - ExprKind::Use { source } => this.into(destination, block, source), + ExprKind::Use { source } => this.into(destination, scope, block, source), ExprKind::Borrow { arg, borrow_kind } => { // We don't do this in `as_rvalue` because we use `as_place` // for borrow expressions, so we cannot create an `RValue` that @@ -314,6 +347,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination, Rvalue::Aggregate(adt, fields), ); + schedule_drop(this); block.unit() } ExprKind::InlineAsm { template, operands, options, line_spans } => { @@ -410,6 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); + schedule_drop(this); block.unit() } ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => { @@ -427,6 +462,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); + schedule_drop(this); block.unit() } @@ -441,6 +477,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None }, ); this.generator_drop_cleanup(block); + schedule_drop(this); resume.unit() } @@ -472,6 +509,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); this.cfg.push_assign(block, source_info, destination, rvalue); + schedule_drop(this); block.unit() } }; diff --git a/compiler/rustc_mir_build/src/build/into.rs b/compiler/rustc_mir_build/src/build/into.rs index 7264e495b84..ee1838ddea6 100644 --- a/compiler/rustc_mir_build/src/build/into.rs +++ b/compiler/rustc_mir_build/src/build/into.rs @@ -6,6 +6,7 @@ use crate::build::{BlockAnd, Builder}; use crate::thir::*; +use rustc_middle::middle::region; use rustc_middle::mir::*; pub(in crate::build) trait EvalInto<'tcx> { @@ -13,6 +14,7 @@ pub(in crate::build) trait EvalInto<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ) -> BlockAnd<()>; } @@ -21,13 +23,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn into( &mut self, destination: Place<'tcx>, + scope: Option, block: BasicBlock, expr: E, ) -> BlockAnd<()> where E: EvalInto<'tcx>, { - expr.eval_into(self, destination, block) + expr.eval_into(self, destination, scope, block) } } @@ -36,10 +39,11 @@ impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ) -> BlockAnd<()> { let expr = builder.hir.mirror(self); - builder.into_expr(destination, block, expr) + builder.into_expr(destination, scope, block, expr) } } @@ -48,8 +52,9 @@ impl<'tcx> EvalInto<'tcx> for Expr<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, + scope: Option, block: BasicBlock, ) -> BlockAnd<()> { - builder.into_expr(destination, block, self) + builder.into_expr(destination, scope, block, self) } } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 3ee15248ae2..7ffdb7e33fb 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -87,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn match_expr( &mut self, destination: Place<'tcx>, + destination_scope: Option, span: Span, mut block: BasicBlock, scrutinee: ExprRef<'tcx>, @@ -107,6 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.lower_match_arms( destination, + destination_scope, scrutinee_place, scrutinee_span, arm_candidates, @@ -213,75 +215,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - /// Lower the bindings, guards and arm bodies of a `match` expression. - /// - /// The decision tree should have already been created - /// (by [Builder::lower_match_tree]). - /// - /// `outer_source_info` is the SourceInfo for the whole match. - fn lower_match_arms( - &mut self, - destination: Place<'tcx>, - scrutinee_place: Place<'tcx>, - scrutinee_span: Span, - arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, - outer_source_info: SourceInfo, - fake_borrow_temps: Vec<(Place<'tcx>, Local)>, - ) -> BlockAnd<()> { - let arm_end_blocks: Vec<_> = arm_candidates - .into_iter() - .map(|(arm, candidate)| { - debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); - - let arm_source_info = self.source_info(arm.span); - let arm_scope = (arm.scope, arm_source_info); - self.in_scope(arm_scope, arm.lint_level, |this| { - let body = this.hir.mirror(arm.body.clone()); - let scope = this.declare_bindings( - None, - arm.span, - &arm.pattern, - ArmHasGuard(arm.guard.is_some()), - Some((Some(&scrutinee_place), scrutinee_span)), - ); - - let arm_block = this.bind_pattern( - outer_source_info, - candidate, - arm.guard.as_ref(), - &fake_borrow_temps, - scrutinee_span, - Some(arm.scope), - ); - - if let Some(source_scope) = scope { - this.source_scope = source_scope; - } - - this.into(destination, arm_block, body) - }) - }) - .collect(); - - // all the arm blocks will rejoin here - let end_block = self.cfg.start_new_block(); - - for arm_block in arm_end_blocks { - self.cfg.goto(unpack!(arm_block), outer_source_info, end_block); - } - - self.source_scope = outer_source_info.scope; - - end_block.unit() - } - /// Binds the variables and ascribes types for a given `match` arm or /// `let` binding. /// /// Also check if the guard matches, if it's provided. /// `arm_scope` should be `Some` if and only if this is called for a /// `match` arm. - fn bind_pattern( + crate fn bind_pattern( &mut self, outer_source_info: SourceInfo, candidate: Candidate<'_, 'tcx>, @@ -365,13 +305,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - unpack!(block = self.into(place, block, initializer)); + let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); + + unpack!(block = self.into(place, Some(region_scope), block, initializer)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let source_info = self.source_info(irrefutable_pat.span); self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place); - self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } @@ -398,9 +339,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription: thir::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span }, } => { + let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - unpack!(block = self.into(place, block, initializer)); + unpack!(block = self.into(place, Some(region_scope), block, initializer)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let pattern_source_info = self.source_info(irrefutable_pat.span); @@ -438,7 +380,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); - self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } @@ -684,7 +625,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } #[derive(Debug)] -struct Candidate<'pat, 'tcx> { +pub(super) struct Candidate<'pat, 'tcx> { /// `Span` of the original pattern that gave rise to this candidate span: Span, @@ -1394,12 +1335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match test.kind { TestKind::SwitchInt { switch_ty, ref mut options } => { for candidate in candidates.iter() { - if !self.add_cases_to_switch( - &match_place, - candidate, - switch_ty, - options, - ) { + if !self.add_cases_to_switch(&match_place, candidate, switch_ty, options) { break; } } @@ -1780,14 +1716,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // and that is clearly not correct. - let by_value_bindings = - parent_bindings - .iter() - .flat_map(|(bindings, _)| bindings) - .chain(&candidate.bindings) - .filter(|binding| { - matches!(binding.binding_mode, BindingMode::ByValue ) - }); + let by_value_bindings = parent_bindings + .iter() + .flat_map(|(bindings, _)| bindings) + .chain(&candidate.bindings) + .filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue)); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index c50389a850e..34ef4ed78fd 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -75,7 +75,9 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ kind: hir::TraitItemKind::Const(ty, Some(body_id)), .. }) => (*body_id, ty.span, None), - Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => (*body, tcx.hir().span(*hir_id), None), + Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => { + (*body, tcx.hir().span(*hir_id), None) + } _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def.did), }; @@ -183,7 +185,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ return_ty, return_ty_span, body, - span_with_body + span_with_body, ); mir.yield_ty = yield_ty; mir @@ -581,7 +583,7 @@ fn construct_fn<'a, 'tcx, A>( return_ty: Ty<'tcx>, return_ty_span: Span, body: &'tcx hir::Body<'tcx>, - span_with_body: Span + span_with_body: Span, ) -> Body<'tcx> where A: Iterator>, @@ -615,8 +617,12 @@ where let arg_scope_s = (arg_scope, source_info); // Attribute epilogue to function's closing brace let fn_end = span_with_body.shrink_to_hi(); - let return_block = - unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { + let return_block = unpack!(builder.in_breakable_scope( + None, + Place::return_place(), + Some(call_site_scope), + fn_end, + |builder| { Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body( START_BLOCK, @@ -626,11 +632,13 @@ where &body.value, ) })) - })); + }, + )); let source_info = builder.source_info(fn_end); builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); let should_abort = should_abort_on_panic(tcx, fn_def_id, abi); builder.build_drop_trees(should_abort); + builder.unschedule_return_place_drop(); return_block.unit() })); @@ -657,12 +665,15 @@ fn construct_const<'a, 'tcx>( let owner_id = tcx.hir().body_owner(body_id); let def_id = tcx.hir().local_def_id(owner_id); let span = tcx.hir().span(owner_id); - let mut builder = Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None); + let mut builder = + Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None); let mut block = START_BLOCK; let ast_expr = &tcx.hir().body(body_id).value; let expr = builder.hir.mirror(ast_expr); - unpack!(block = builder.into_expr(Place::return_place(), block, expr)); + // We don't provide a scope because we can't unwind in constants, so won't + // need to drop the return place. + unpack!(block = builder.into_expr(Place::return_place(), None, block, expr)); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -697,7 +708,8 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t hir::BodyOwnerKind::Const => 0, hir::BodyOwnerKind::Static(_) => 0, }; - let mut builder = Builder::new(hir, def_id.to_def_id(), span, num_params, Safety::Safe, ty, span, None); + let mut builder = + Builder::new(hir, def_id.to_def_id(), span, num_params, Safety::Safe, ty, span, None); let source_info = builder.source_info(span); // Some MIR passes will expect the number of parameters to match the // function declaration. @@ -941,7 +953,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let body = self.hir.mirror(ast_body); - self.into(Place::return_place(), block, body) + let call_site = + region::Scope { id: ast_body.hir_id.local_id, data: region::ScopeData::CallSite }; + self.into(Place::return_place(), Some(call_site), block, body) } fn set_correct_source_scope_for_arg( diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 695b884abbd..468b3484ca5 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -81,8 +81,9 @@ that contains only loops and breakable blocks. It tracks where a `break`, */ +use crate::build::matches::{ArmHasGuard, Candidate}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; -use crate::thir::{Expr, ExprRef, LintLevel}; +use crate::thir::{Arm, Expr, ExprRef, LintLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_index::vec::IndexVec; @@ -156,6 +157,8 @@ struct BreakableScope<'tcx> { /// The destination of the loop/block expression itself (i.e., where to put /// the result of a `break` or `return` expression) break_destination: Place<'tcx>, + /// The scope that the destination should have its drop scheduled in. + destination_scope: Option, /// Drops that happen on the `break`/`return` path. break_drops: DropTree, /// Drops that happen on the `continue` path. @@ -438,6 +441,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, loop_block: Option, break_destination: Place<'tcx>, + destination_scope: Option, span: Span, f: F, ) -> BlockAnd<()> @@ -448,15 +452,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = BreakableScope { region_scope, break_destination, + destination_scope, break_drops: DropTree::new(), continue_drops: loop_block.map(|_| DropTree::new()), }; + let continue_block = loop_block.map(|block| (block, self.diverge_cleanup())); self.scopes.breakable_scopes.push(scope); let normal_exit_block = f(self); let breakable_scope = self.scopes.breakable_scopes.pop().unwrap(); assert!(breakable_scope.region_scope == region_scope); + if let Some(drops) = breakable_scope.continue_drops { + self.build_exit_tree(drops, continue_block); + } let break_block = self.build_exit_tree(breakable_scope.break_drops, None); - if let Some(drops) = breakable_scope.continue_drops { self.build_exit_tree(drops, loop_block); } match (normal_exit_block, break_block) { (Some(block), None) | (None, Some(block)) => block, (None, None) => self.cfg.start_new_block().unit(), @@ -585,22 +593,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .rposition(|breakable_scope| breakable_scope.region_scope == scope) .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found")) }; - let (break_index, destination) = match target { + let (break_index, destination, dest_scope) = match target { BreakableTarget::Return => { let scope = &self.scopes.breakable_scopes[0]; if scope.break_destination != Place::return_place() { span_bug!(span, "`return` in item with no return scope"); } - (0, Some(scope.break_destination)) + (0, Some(scope.break_destination), scope.destination_scope) } BreakableTarget::Break(scope) => { let break_index = get_scope_index(scope); let scope = &self.scopes.breakable_scopes[break_index]; - (break_index, Some(scope.break_destination)) + (break_index, Some(scope.break_destination), scope.destination_scope) } BreakableTarget::Continue(scope) => { let break_index = get_scope_index(scope); - (break_index, None) + (break_index, None, None) } }; @@ -608,7 +616,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(value) = value { debug!("stmt_expr Break val block_context.push(SubExpr)"); self.block_context.push(BlockFrame::SubExpr); - unpack!(block = self.into(destination, block, value)); + unpack!(block = self.into(destination, dest_scope, block, value)); + dest_scope + .map(|scope| self.unschedule_drop(scope, destination.as_local().unwrap())); self.block_context.pop(); } else { self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx()) @@ -858,14 +868,47 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); } - /// Indicates that the "local operand" stored in `local` is + /// Unschedule a drop. Used for `break`, `return` and `match` expressions, + /// where `record_operands_moved` is not powerful enough. + /// + /// The given local is expected to have a value drop scheduled in the given + /// scope and for that drop to be the most recent thing scheduled in that + /// scope. + fn unschedule_drop(&mut self, region_scope: region::Scope, local: Local) { + if !self.hir.needs_drop(self.local_decls[local].ty) { + return; + } + for scope in self.scopes.scopes.iter_mut().rev() { + scope.invalidate_cache(); + + if scope.region_scope == region_scope { + let drop = scope.drops.pop(); + + match drop { + Some(DropData { local: removed_local, kind: DropKind::Value, .. }) + if removed_local == local => + { + return; + } + _ => bug!( + "found wrong drop, expected value drop of {:?}, found {:?}", + local, + drop, + ), + } + } + } + + bug!("region scope {:?} not in scope to unschedule drop of {:?}", region_scope, local); + } + + /// Indicates that the "local operands" stored in `local` is /// *moved* at some point during execution (see `local_scope` for /// more information about what a "local operand" is -- in short, /// it's an intermediate operand created as part of preparing some /// MIR instruction). We use this information to suppress - /// redundant drops on the non-unwind paths. This results in less - /// MIR, but also avoids spurious borrow check errors - /// (c.f. #64391). + /// redundant drops. This results in less MIR, but also avoids spurious + /// borrow check errors (c.f. #64391). /// /// Example: when compiling the call to `foo` here: /// @@ -1116,11 +1159,96 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { success_block } + /// Lower the arms and guards of a match. + /// + /// The decision tree should have already been created (by + /// [Builder::lower_match_tree]). + /// + /// This is this module, and not in `build::matches` because we have to do + /// some careful scope manipulation to have the drop of the destination be + /// scheduled at the end of each arm and then cleared for the next arm. + crate fn lower_match_arms( + &mut self, + destination: Place<'tcx>, + destination_scope: Option, + scrutinee_place: Place<'tcx>, + scrutinee_span: Span, + arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, + outer_source_info: SourceInfo, + fake_borrow_temps: Vec<(Place<'tcx>, Local)>, + ) -> BlockAnd<()> { + if arm_candidates.is_empty() { + // If there are no arms to schedule drops, then we have to do it + // manually. + if let Some(scope) = destination_scope { + self.schedule_drop( + outer_source_info.span, + scope, + destination.as_local().unwrap(), + DropKind::Value, + ); + } + return self.cfg.start_new_block().unit(); + } + let mut first_arm = true; + let arm_end_blocks: Vec<_> = arm_candidates + .into_iter() + .map(|(arm, candidate)| { + debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); + + if first_arm { + first_arm = false; + } else if let Some(scope) = destination_scope { + self.unschedule_drop(scope, destination.as_local().unwrap()); + } + + let arm_source_info = self.source_info(arm.span); + let arm_scope = (arm.scope, arm_source_info); + self.in_scope(arm_scope, arm.lint_level, |this| { + let body = this.hir.mirror(arm.body.clone()); + let scope = this.declare_bindings( + None, + arm.span, + &arm.pattern, + ArmHasGuard(arm.guard.is_some()), + Some((Some(&scrutinee_place), scrutinee_span)), + ); + + let arm_block = this.bind_pattern( + outer_source_info, + candidate, + arm.guard.as_ref(), + &fake_borrow_temps, + scrutinee_span, + Some(arm.scope), + ); + + if let Some(source_scope) = scope { + this.source_scope = source_scope; + } + + this.into(destination, destination_scope, arm_block, body) + }) + }) + .collect(); + + // all the arm blocks will rejoin here + let end_block = self.cfg.start_new_block(); + + for arm_block in arm_end_blocks { + self.cfg.goto(unpack!(arm_block), outer_source_info, end_block); + } + + self.source_scope = outer_source_info.scope; + + end_block.unit() + } + /// Unschedules any drops in the top scope. /// /// This is only needed for `match` arm scopes, because they have one /// entrance per pattern, but only one exit. - crate fn clear_top_scope(&mut self, region_scope: region::Scope) { + pub(super) fn clear_top_scope(&mut self, region_scope: region::Scope) { let top_scope = self.scopes.scopes.last_mut().unwrap(); assert_eq!(top_scope.region_scope, region_scope); @@ -1128,6 +1256,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { top_scope.drops.clear(); top_scope.invalidate_cache(); } + + /// Unschedules the drop of the return place. + /// + /// If the return type of a function requires drop, then we schedule it + /// in the outermost scope so that it's dropped if there's a panic while + /// we drop any local variables. But we don't want to drop it if we + /// return normally. + crate fn unschedule_return_place_drop(&mut self) { + assert_eq!(self.scopes.scopes.len(), 1); + assert!(self.scopes.scopes[0].drops.len() <= 1); + self.scopes.scopes[0].drops.clear(); + } } /// Builds drops for `pop_scope` and `leave_top_scope`. @@ -1203,20 +1343,24 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { /// Build a drop tree for a breakable scope. /// /// If `continue_block` is `Some`, then the tree is for `continue` inside a - /// loop. Otherwise this is for `break` or `return`. + /// loop. Otherwise this is for `break` or `return`. The `DropIdx` is the + /// next drop in the case that the drop tree unwinds. This is needed + /// because the drop of the break destination has already been scheduled + /// but it hasn't been initialized on the `continue` paths. fn build_exit_tree( &mut self, mut drops: DropTree, - continue_block: Option, + continue_block: Option<(BasicBlock, DropIdx)>, ) -> Option> { let mut blocks = IndexVec::from_elem(None, &drops.drops); - blocks[ROOT_NODE] = continue_block; + blocks[ROOT_NODE] = continue_block.map(|(block, _)| block); drops.build_mir::(&mut self.cfg, &mut blocks); // Link the exit drop tree to unwind drop tree. if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) { - let unwind_target = self.diverge_cleanup(); + let unwind_target = continue_block + .map_or_else(|| self.diverge_cleanup(), |(_, unwind_target)| unwind_target); let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1); for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) { match drop_data.0.kind { diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 23cd4f3d83d..97df8ea07d2 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1772,7 +1772,7 @@ fn test_append_drop_leak() { catch_unwind(move || left.append(&mut right)).unwrap_err(); - assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy + assert_eq!(DROPS.load(SeqCst), 5); } #[test] diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff index 07994eb3c16..22737381c71 100644 --- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff @@ -5,18 +5,19 @@ let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12 let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 -+ let mut _7: (); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _8: (); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ let mut _9: (); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 1 (inlined call_twice:: ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22 + debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let _3: !; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _6: !; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 ++ let mut _7: !; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 2 { + debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 3 { -+ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:22:5: 22:22 ++ debug b => _7; // in scope 3 at $DIR/inline-diverging.rs:22:5: 22:22 + } + scope 6 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:22:5: 22:22 + scope 7 (inlined sleep) { // at $DIR/inline-diverging.rs:22:5: 22:22 @@ -40,12 +41,12 @@ - // mir::Constant // + span: $DIR/inline-diverging.rs:22:16: 22:21 // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar()) } -+ StorageLive(_6); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ StorageLive(_7); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 -+ StorageLive(_7); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 -+ _7 = const (); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 ++ StorageLive(_8); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 ++ _8 = const (); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:22:5: 22:22 } diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index ab6e7ea7b38..f74cdd71919 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -30,7 +30,7 @@ fn test() -> Option> { StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as Try>::into_result(move _4) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _3 = as Try>::into_result(move _4) -> [return: bb1, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result}, val: Value(Scalar()) } @@ -65,7 +65,7 @@ fn test() -> Option> { StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = >::from(move _9) -> [return: bb5, unwind: bb9]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = >::from(move _9) -> [return: bb5, unwind: bb10]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {>::from}, val: Value(Scalar()) } @@ -73,7 +73,7 @@ fn test() -> Option> { bb5: { StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as Try>::from_error(move _8) -> [return: bb6, unwind: bb9]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 + _0 = > as Try>::from_error(move _8) -> [return: bb6, unwind: bb10]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error}, val: Value(Scalar()) } @@ -82,7 +82,7 @@ fn test() -> Option> { bb6: { StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> [return: bb7, unwind: bb9]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { @@ -97,10 +97,14 @@ fn test() -> Option> { } bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_0) -> bb11; // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 } bb10 (cleanup): { + drop(_2) -> bb11; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + } + + bb11 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index e14e733fff6..4c03e950af0 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -19,12 +19,12 @@ 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 19| 2|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_crate::used_only_from_bin_crate_generic_function::<&str>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt index 82a4457b6ef..abc2d32a897 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt @@ -28,18 +28,16 @@ Counter in file 0 79:14 -> 79:16, 0 Counter in file 0 81:1 -> 81:2, 0 Counter in file 0 91:25 -> 91:34, 0 Counter in file 0 5:1 -> 5:25, #1 +Counter in file 0 5:25 -> 6:14, #1 +Counter in file 0 7:9 -> 7:10, #2 +Counter in file 0 9:9 -> 9:10, (#1 - #2) +Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) Counter in file 0 21:1 -> 21:23, #1 -Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 67:5 -> 67:23, #1 Counter in file 0 38:1 -> 38:19, #1 -Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 29:1 -> 29:22, #1 Counter in file 0 93:1 -> 101:2, #1 Counter in file 0 91:1 -> 91:25, #1 -Counter in file 0 5:25 -> 6:14, #1 -Counter in file 0 7:9 -> 7:10, #2 -Counter in file 0 9:9 -> 9:10, (#1 - #2) -Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) Counter in file 0 38:19 -> 42:12, #1 Counter in file 0 43:9 -> 43:10, #3 Counter in file 0 43:14 -> 43:18, (#1 + 0) @@ -55,6 +53,7 @@ Counter in file 0 51:5 -> 52:18, #1 Counter in file 0 53:13 -> 53:14, #2 Counter in file 0 63:13 -> 63:14, (#1 - #2) Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2)) +Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 49:1 -> 68:12, #1 Counter in file 0 69:9 -> 69:10, #2 Counter in file 0 69:14 -> 69:27, (#1 + 0) @@ -70,6 +69,7 @@ Counter in file 0 86:14 -> 86:16, #2 Counter in file 0 87:14 -> 87:16, #3 Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2)))) Counter in file 0 17:1 -> 17:20, #1 +Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 66:5 -> 66:23, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 17:9 -> 17:10, #1 diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt index e2cbf6f709e..b41f482173b 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt @@ -32,12 +32,12 @@ Combined regions: 10:5 -> 12:6 (count=1) Segment at 10:5 (count = 1), RegionEntry Segment at 12:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworklENtNtNtCs3rFBWs28XFJ_4core3ops4drop4Drop4dropB4_ +Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworklENtNtNtCs6HRHKMTmAen_4core3ops4drop4Drop4dropB4_ Combined regions: 17:5 -> 19:6 (count=1) Segment at 17:5 (count = 1), RegionEntry Segment at 19:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworkdENtNtNtCs3rFBWs28XFJ_4core3ops4drop4Drop4dropB4_ +Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworkdENtNtNtCs6HRHKMTmAen_4core3ops4drop4Drop4dropB4_ Combined regions: 17:5 -> 19:6 (count=1) Segment at 17:5 (count = 1), RegionEntry diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt index b0319cd9e18..42cc4904e5f 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt @@ -1,6 +1,6 @@ -Counter in file 0 17:1 -> 19:2, #1 Counter in file 0 25:1 -> 27:2, #1 Counter in file 0 17:1 -> 19:2, #1 +Counter in file 0 17:1 -> 19:2, #1 Counter in file 0 5:1 -> 12:2, #1 Counter in file 0 17:1 -> 19:2, 0 Counter in file 0 33:1 -> 35:2, 0 @@ -78,17 +78,17 @@ Segment at 51:1 (count = 0), RegionEntry Segment at 51:2 (count = 0), Skipped Segment at 53:1 (count = 1), RegionEntry Segment at 61:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionReECs4fqI2P2rA04_10uses_crate +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionRINtNtCsFAjihUSTht_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate Combined regions: 17:1 -> 19:2 (count=1) Segment at 17:1 (count = 1), RegionEntry Segment at 19:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionRINtNtCs3QflaznQylx_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionReECs4fqI2P2rA04_10uses_crate Combined regions: 17:1 -> 19:2 (count=1) Segment at 17:1 (count = 1), RegionEntry Segment at 19:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEEB2_ +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionINtNtCsFAjihUSTht_5alloc3vec3VeclEEB2_ Combined regions: 21:1 -> 23:2 (count=1) Segment at 21:1 (count = 1), RegionEntry @@ -98,7 +98,7 @@ Combined regions: 21:1 -> 23:2 (count=1) Segment at 21:1 (count = 1), RegionEntry Segment at 23:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionINtNtCsFAjihUSTht_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate Combined regions: 25:1 -> 27:2 (count=1) Segment at 25:1 (count = 1), RegionEntry diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html index 81310c8cb25..19707255d07 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html @@ -70,166 +70,166 @@
@0,1,2,3,4,5⦊pub fn block_on<F: Future>(mut future: F) -> F::Output { let mut future = unsafe { Pin::new_unchecked(&mut future) }; static VTABLE: RawWakerVTable = RawWakerVTable::new( |_| unimplemented!("clone"), |_| unimplemented!("wake"), |_| unimplemented!("wake_by_ref"), |_| (), ); let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; loop { if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; }@11,13⦊⦉@11,13 diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html index 313a36ed6c2..611799161d3 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html @@ -69,9 +69,9 @@ -
@0,1,2,3,4,5,6,7,8,9,10,11,12,13⦊fn main() { - let _ = g(10); - let _ = h(9); - let mut future = Box::pin(i(8)); - j(7); - l(6); - let _ = m(5); - executor::block_on(future.as_mut()); -@4,5,6,7,8⦊format!("'{}'", val) @@ -117,13 +117,13 @@ 103:9-103:29: @4[23]: _18 = (_16.0: &&str) 103:9-103:29: @4[26]: _20 = &(*_18) 103:9-103:29: @4[28]: _21 = <&str as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r &str, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) -103:9-103:29: @4.Call: _19 = ArgumentV1::new::<&str>(move _20, move _21) -> [return: bb5, unwind: bb9] +103:9-103:29: @4.Call: _19 = ArgumentV1::new::<&str>(move _20, move _21) -> [return: bb5, unwind: bb10] 103:9-103:29: @5[2]: _15 = [move _19] 103:9-103:29: @5[5]: _14 = &_15 103:9-103:29: @5[6]: _13 = &(*_14) 103:9-103:29: @5[7]: _12 = move _13 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) -103:9-103:29: @5.Call: _7 = Arguments::new_v1(move _8, move _12) -> [return: bb6, unwind: bb9] -103:9-103:29: @6.Call: _6 = format(move _7) -> [return: bb7, unwind: bb9] +103:9-103:29: @5.Call: _7 = Arguments::new_v1(move _8, move _12) -> [return: bb6, unwind: bb10] +103:9-103:29: @6.Call: _6 = format(move _7) -> [return: bb7, unwind: bb10] 103:9-103:29: @7[1]: FakeRead(ForLet, _6) 103:9-103:29: @7[6]: _0 = move _6 104:6-104:6: @8.Return: return"> }⦉@4,5,6,7,8
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html index 702c7937064..3bd446b0e04 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html @@ -69,7079 +69,7079 @@ -
@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊fn main() { -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure - // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. - // dependent conditions. + let is_true = std::env::args().len() == 1; - let is_true = std::env::args().len() == 1; + let is_false = ! is_true; - let is_false = ! is_true; + - + let mut some_string = Some(String::from("the string content")); - let mut some_string = Some(String::from("the string content")); + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| +10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +3:11-155:2: @36[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 1".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊ -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊ + ) - ) + ); - ); + - + some_string = Some(String::from("the string content")); - some_string = Some(String::from("the string content")); + let - let + a - a + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| +10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +29:24-29:58: @9.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb10, unwind: bb43] +29:19-29:59: @10[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @11[3]: _33 = &_5 +31:9-31:10: @11[6]: FakeRead(ForLet, _32) +3:11-155:2: @36[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 2".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + a - a + ) - ) + ); - ); + - + some_string = None; - some_string = None; + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| +10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +29:24-29:58: @9.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb10, unwind: bb43] +29:19-29:59: @10[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @11[3]: _33 = &_5 +31:9-31:10: @11[6]: FakeRead(ForLet, _32) +42:9-42:32: @11[13]: _136 = const main::promoted[3] +42:9-42:32: @11[14]: _39 = &(*_136) +42:9-42:32: @11[15]: _38 = &(*_39) +42:9-42:32: @11[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @11[26]: _48 = move _7 +48:13-48:14: @11[28]: _49 = _32 +44:9-49:10: @11.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb12, unwind: bb43] +44:9-49:10: @12[2]: _46 = &_47 +41:5-50:7: @12[3]: _45 = (move _46,) +41:5-50:7: @12[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @12[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @12[10]: _52 = &(*_50) +41:5-50:7: @12[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @12.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb13, unwind: bb41] +41:5-50:7: @13[2]: _44 = [move _51] +41:5-50:7: @13[5]: _43 = &_44 +41:5-50:7: @13[6]: _42 = &(*_43) +41:5-50:7: @13[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @13.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb14, unwind: bb41] +41:5-50:7: @14.Call: _35 = _print(move _36) -> [return: bb15, unwind: bb41] +41:5-50:7: @16[6]: _34 = const () +52:19-52:23: @16[9]: _54 = Option::<String>::None +54:9-54:32: @17[7]: _135 = const main::promoted[2] +54:9-54:32: @17[8]: _60 = &(*_135) +54:9-54:32: @17[9]: _59 = &(*_60) +54:9-54:32: @17[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @17[20]: _69 = move _7 +56:9-68:10: @17.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb18, unwind: bb43] +56:9-68:10: @18[2]: _67 = &_68 +53:5-69:7: @18[3]: _66 = (move _67,) +53:5-69:7: @18[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @18[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @18[10]: _74 = &(*_72) +53:5-69:7: @18[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @18.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb19, unwind: bb40] +53:5-69:7: @19[2]: _65 = [move _73] +53:5-69:7: @19[5]: _64 = &_65 +53:5-69:7: @19[6]: _63 = &(*_64) +53:5-69:7: @19[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @19.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb20, unwind: bb40] +53:5-69:7: @20.Call: _56 = _print(move _57) -> [return: bb21, unwind: bb40] +53:5-69:7: @22[6]: _55 = const () +3:11-155:2: @36[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 3".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊ -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊ + ) - ) + ); - ); + - + some_string = None; - some_string = None; + let - let + a - a + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| +10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +29:24-29:58: @9.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb10, unwind: bb43] +29:19-29:59: @10[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @11[3]: _33 = &_5 +31:9-31:10: @11[6]: FakeRead(ForLet, _32) +42:9-42:32: @11[13]: _136 = const main::promoted[3] +42:9-42:32: @11[14]: _39 = &(*_136) +42:9-42:32: @11[15]: _38 = &(*_39) +42:9-42:32: @11[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @11[26]: _48 = move _7 +48:13-48:14: @11[28]: _49 = _32 +44:9-49:10: @11.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb12, unwind: bb43] +44:9-49:10: @12[2]: _46 = &_47 +41:5-50:7: @12[3]: _45 = (move _46,) +41:5-50:7: @12[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @12[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @12[10]: _52 = &(*_50) +41:5-50:7: @12[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @12.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb13, unwind: bb41] +41:5-50:7: @13[2]: _44 = [move _51] +41:5-50:7: @13[5]: _43 = &_44 +41:5-50:7: @13[6]: _42 = &(*_43) +41:5-50:7: @13[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @13.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb14, unwind: bb41] +41:5-50:7: @14.Call: _35 = _print(move _36) -> [return: bb15, unwind: bb41] +41:5-50:7: @16[6]: _34 = const () +52:19-52:23: @16[9]: _54 = Option::<String>::None +54:9-54:32: @17[7]: _135 = const main::promoted[2] +54:9-54:32: @17[8]: _60 = &(*_135) +54:9-54:32: @17[9]: _59 = &(*_60) +54:9-54:32: @17[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @17[20]: _69 = move _7 +56:9-68:10: @17.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb18, unwind: bb43] +56:9-68:10: @18[2]: _67 = &_68 +53:5-69:7: @18[3]: _66 = (move _67,) +53:5-69:7: @18[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @18[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @18[10]: _74 = &(*_72) +53:5-69:7: @18[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @18.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb19, unwind: bb40] +53:5-69:7: @19[2]: _65 = [move _73] +53:5-69:7: @19[5]: _64 = &_65 +53:5-69:7: @19[6]: _63 = &(*_64) +53:5-69:7: @19[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @19.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb20, unwind: bb40] +53:5-69:7: @20.Call: _56 = _print(move _57) -> [return: bb21, unwind: bb40] +53:5-69:7: @22[6]: _55 = const () +71:19-71:23: @22[9]: _76 = Option::<String>::None +75:9-82:6: @23[3]: _78 = &_5 +73:9-73:10: @23[6]: FakeRead(ForLet, _77) +3:11-155:2: @36[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 4".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + a - a + ) - ) + ); - ); + - + let - let + quote_closure - quote_closure + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|val| +10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +29:24-29:58: @9.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb10, unwind: bb43] +29:19-29:59: @10[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @11[3]: _33 = &_5 +31:9-31:10: @11[6]: FakeRead(ForLet, _32) +42:9-42:32: @11[13]: _136 = const main::promoted[3] +42:9-42:32: @11[14]: _39 = &(*_136) +42:9-42:32: @11[15]: _38 = &(*_39) +42:9-42:32: @11[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @11[26]: _48 = move _7 +48:13-48:14: @11[28]: _49 = _32 +44:9-49:10: @11.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb12, unwind: bb43] +44:9-49:10: @12[2]: _46 = &_47 +41:5-50:7: @12[3]: _45 = (move _46,) +41:5-50:7: @12[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @12[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @12[10]: _52 = &(*_50) +41:5-50:7: @12[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @12.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb13, unwind: bb41] +41:5-50:7: @13[2]: _44 = [move _51] +41:5-50:7: @13[5]: _43 = &_44 +41:5-50:7: @13[6]: _42 = &(*_43) +41:5-50:7: @13[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @13.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb14, unwind: bb41] +41:5-50:7: @14.Call: _35 = _print(move _36) -> [return: bb15, unwind: bb41] +41:5-50:7: @16[6]: _34 = const () +52:19-52:23: @16[9]: _54 = Option::<String>::None +54:9-54:32: @17[7]: _135 = const main::promoted[2] +54:9-54:32: @17[8]: _60 = &(*_135) +54:9-54:32: @17[9]: _59 = &(*_60) +54:9-54:32: @17[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @17[20]: _69 = move _7 +56:9-68:10: @17.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb18, unwind: bb43] +56:9-68:10: @18[2]: _67 = &_68 +53:5-69:7: @18[3]: _66 = (move _67,) +53:5-69:7: @18[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @18[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @18[10]: _74 = &(*_72) +53:5-69:7: @18[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @18.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb19, unwind: bb40] +53:5-69:7: @19[2]: _65 = [move _73] +53:5-69:7: @19[5]: _64 = &_65 +53:5-69:7: @19[6]: _63 = &(*_64) +53:5-69:7: @19[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @19.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb20, unwind: bb40] +53:5-69:7: @20.Call: _56 = _print(move _57) -> [return: bb21, unwind: bb40] +53:5-69:7: @22[6]: _55 = const () +71:19-71:23: @22[9]: _76 = Option::<String>::None +75:9-82:6: @23[3]: _78 = &_5 +73:9-73:10: @23[6]: FakeRead(ForLet, _77) +84:9-84:32: @23[13]: _134 = const main::promoted[1] +84:9-84:32: @23[14]: _84 = &(*_134) +84:9-84:32: @23[15]: _83 = &(*_84) +84:9-84:32: @23[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @23[26]: _93 = move _7 +90:13-90:14: @23[28]: _94 = _77 +86:9-91:10: @23.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb24, unwind: bb43] +86:9-91:10: @24[2]: _91 = &_92 +83:5-92:7: @24[3]: _90 = (move _91,) +83:5-92:7: @24[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @24[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @24[10]: _97 = &(*_95) +83:5-92:7: @24[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @24.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb25, unwind: bb39] +83:5-92:7: @25[2]: _89 = [move _96] +83:5-92:7: @25[5]: _88 = &_89 +83:5-92:7: @25[6]: _87 = &(*_88) +83:5-92:7: @25[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @25.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb26, unwind: bb39] +83:5-92:7: @26.Call: _80 = _print(move _81) -> [return: bb27, unwind: bb39] +83:5-92:7: @28[6]: _79 = const () +97:9-104:6: @28[10]: _100 = &_5 +95:9-95:22: @28[13]: FakeRead(ForLet, _99) +3:11-155:2: @36[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|val| { let mut countdown = 0; if is_false { countdown = 10; } format!("'{}'", val) - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + println!( - println!( + "Repeated, quoted string: {:?}" - "Repeated, quoted string: {:?}" + , - , + std::iter::repeat("repeat me") - std::iter::repeat("repeat me") + .take(5) - .take(5) + .map - .map + ( - ( + quote_closure - quote_closure + ) - ) + .collect::<Vec<_>>() - .collect::<Vec<_>>() + ); - ); + - + let - let + _unused_closure - _unused_closure + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| +10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +29:24-29:58: @9.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb10, unwind: bb43] +29:19-29:59: @10[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @11[3]: _33 = &_5 +31:9-31:10: @11[6]: FakeRead(ForLet, _32) +42:9-42:32: @11[13]: _136 = const main::promoted[3] +42:9-42:32: @11[14]: _39 = &(*_136) +42:9-42:32: @11[15]: _38 = &(*_39) +42:9-42:32: @11[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @11[26]: _48 = move _7 +48:13-48:14: @11[28]: _49 = _32 +44:9-49:10: @11.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb12, unwind: bb43] +44:9-49:10: @12[2]: _46 = &_47 +41:5-50:7: @12[3]: _45 = (move _46,) +41:5-50:7: @12[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @12[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @12[10]: _52 = &(*_50) +41:5-50:7: @12[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @12.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb13, unwind: bb41] +41:5-50:7: @13[2]: _44 = [move _51] +41:5-50:7: @13[5]: _43 = &_44 +41:5-50:7: @13[6]: _42 = &(*_43) +41:5-50:7: @13[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @13.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb14, unwind: bb41] +41:5-50:7: @14.Call: _35 = _print(move _36) -> [return: bb15, unwind: bb41] +41:5-50:7: @16[6]: _34 = const () +52:19-52:23: @16[9]: _54 = Option::<String>::None +54:9-54:32: @17[7]: _135 = const main::promoted[2] +54:9-54:32: @17[8]: _60 = &(*_135) +54:9-54:32: @17[9]: _59 = &(*_60) +54:9-54:32: @17[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @17[20]: _69 = move _7 +56:9-68:10: @17.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb18, unwind: bb43] +56:9-68:10: @18[2]: _67 = &_68 +53:5-69:7: @18[3]: _66 = (move _67,) +53:5-69:7: @18[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @18[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @18[10]: _74 = &(*_72) +53:5-69:7: @18[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @18.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb19, unwind: bb40] +53:5-69:7: @19[2]: _65 = [move _73] +53:5-69:7: @19[5]: _64 = &_65 +53:5-69:7: @19[6]: _63 = &(*_64) +53:5-69:7: @19[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @19.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb20, unwind: bb40] +53:5-69:7: @20.Call: _56 = _print(move _57) -> [return: bb21, unwind: bb40] +53:5-69:7: @22[6]: _55 = const () +71:19-71:23: @22[9]: _76 = Option::<String>::None +75:9-82:6: @23[3]: _78 = &_5 +73:9-73:10: @23[6]: FakeRead(ForLet, _77) +84:9-84:32: @23[13]: _134 = const main::promoted[1] +84:9-84:32: @23[14]: _84 = &(*_134) +84:9-84:32: @23[15]: _83 = &(*_84) +84:9-84:32: @23[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @23[26]: _93 = move _7 +90:13-90:14: @23[28]: _94 = _77 +86:9-91:10: @23.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb24, unwind: bb43] +86:9-91:10: @24[2]: _91 = &_92 +83:5-92:7: @24[3]: _90 = (move _91,) +83:5-92:7: @24[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @24[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @24[10]: _97 = &(*_95) +83:5-92:7: @24[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @24.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb25, unwind: bb39] +83:5-92:7: @25[2]: _89 = [move _96] +83:5-92:7: @25[5]: _88 = &_89 +83:5-92:7: @25[6]: _87 = &(*_88) +83:5-92:7: @25[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @25.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb26, unwind: bb39] +83:5-92:7: @26.Call: _80 = _print(move _81) -> [return: bb27, unwind: bb39] +83:5-92:7: @28[6]: _79 = const () +97:9-104:6: @28[10]: _100 = &_5 +95:9-95:22: @28[13]: FakeRead(ForLet, _99) +106:9-106:40: @28[20]: _133 = const main::promoted[0] +106:9-106:40: @28[21]: _106 = &(*_133) +106:9-106:40: @28[22]: _105 = &(*_106) +106:9-106:40: @28[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @28.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb29, unwind: bb43] +108:9-109:21: @29.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb30, unwind: bb43] +112:13-112:26: @30[2]: _118 = _99 +108:9-113:10: @30.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb31, unwind: bb43] +108:9-114:33: @31.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb32, unwind: bb43] +108:9-114:33: @32[1]: _113 = &_114 +105:5-115:7: @32[2]: _112 = (move _113,) +105:5-115:7: @32[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @32[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @32[9]: _121 = &(*_119) +105:5-115:7: @32[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @32.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb33, unwind: bb38] +105:5-115:7: @33[2]: _111 = [move _120] +105:5-115:7: @33[5]: _110 = &_111 +105:5-115:7: @33[6]: _109 = &(*_110) +105:5-115:7: @33[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @33.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb34, unwind: bb38] +105:5-115:7: @34.Call: _102 = _print(move _103) -> [return: bb35, unwind: bb38] +105:5-115:7: @36[6]: _101 = const () +118:9-118:24: @36[13]: FakeRead(ForLet, _123) +3:11-155:2: @36[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| mut countdown | { @@ -7149,3773 +7149,3773 @@ countdown = 10; } "closure should be unused".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + - + let mut countdown = 10; - let mut countdown = 10; + let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | countdown += 1 let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | countdown += 1@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + - + // Macros can sometimes confuse the coverage results. Compare this next assignment, with an - // Macros can sometimes confuse the coverage results. Compare this next assignment, with an + // unused closure that invokes the `println!()` macro, with the closure assignment above, that - // unused closure that invokes the `println!()` macro, with the closure assignment above, that + // does not use a macro. The closure above correctly shows `0` executions. - // does not use a macro. The closure above correctly shows `0` executions. + let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | println!("not called") let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | println!("not called")@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + // The closure assignment above is executed, with a line count of `1`, but the `println!()` - // The closure assignment above is executed, with a line count of `1`, but the `println!()` + // could not have been called, and yet, there is no indication that it wasn't... - // could not have been called, and yet, there is no indication that it wasn't... + - + // ...but adding block braces gives the expected result, showing the block was not executed. - // ...but adding block braces gives the expected result, showing the block was not executed. + let _short_unused_closure_block = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | { println!("not called") } let _short_unused_closure_block = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + - + let _shortish_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | { +10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +29:24-29:58: @9.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb10, unwind: bb43] +29:19-29:59: @10[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @11[3]: _33 = &_5 +31:9-31:10: @11[6]: FakeRead(ForLet, _32) +42:9-42:32: @11[13]: _136 = const main::promoted[3] +42:9-42:32: @11[14]: _39 = &(*_136) +42:9-42:32: @11[15]: _38 = &(*_39) +42:9-42:32: @11[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @11[26]: _48 = move _7 +48:13-48:14: @11[28]: _49 = _32 +44:9-49:10: @11.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb12, unwind: bb43] +44:9-49:10: @12[2]: _46 = &_47 +41:5-50:7: @12[3]: _45 = (move _46,) +41:5-50:7: @12[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @12[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @12[10]: _52 = &(*_50) +41:5-50:7: @12[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @12.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb13, unwind: bb41] +41:5-50:7: @13[2]: _44 = [move _51] +41:5-50:7: @13[5]: _43 = &_44 +41:5-50:7: @13[6]: _42 = &(*_43) +41:5-50:7: @13[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @13.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb14, unwind: bb41] +41:5-50:7: @14.Call: _35 = _print(move _36) -> [return: bb15, unwind: bb41] +41:5-50:7: @16[6]: _34 = const () +52:19-52:23: @16[9]: _54 = Option::<String>::None +54:9-54:32: @17[7]: _135 = const main::promoted[2] +54:9-54:32: @17[8]: _60 = &(*_135) +54:9-54:32: @17[9]: _59 = &(*_60) +54:9-54:32: @17[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @17[20]: _69 = move _7 +56:9-68:10: @17.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb18, unwind: bb43] +56:9-68:10: @18[2]: _67 = &_68 +53:5-69:7: @18[3]: _66 = (move _67,) +53:5-69:7: @18[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @18[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @18[10]: _74 = &(*_72) +53:5-69:7: @18[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @18.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb19, unwind: bb40] +53:5-69:7: @19[2]: _65 = [move _73] +53:5-69:7: @19[5]: _64 = &_65 +53:5-69:7: @19[6]: _63 = &(*_64) +53:5-69:7: @19[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @19.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb20, unwind: bb40] +53:5-69:7: @20.Call: _56 = _print(move _57) -> [return: bb21, unwind: bb40] +53:5-69:7: @22[6]: _55 = const () +71:19-71:23: @22[9]: _76 = Option::<String>::None +75:9-82:6: @23[3]: _78 = &_5 +73:9-73:10: @23[6]: FakeRead(ForLet, _77) +84:9-84:32: @23[13]: _134 = const main::promoted[1] +84:9-84:32: @23[14]: _84 = &(*_134) +84:9-84:32: @23[15]: _83 = &(*_84) +84:9-84:32: @23[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @23[26]: _93 = move _7 +90:13-90:14: @23[28]: _94 = _77 +86:9-91:10: @23.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb24, unwind: bb43] +86:9-91:10: @24[2]: _91 = &_92 +83:5-92:7: @24[3]: _90 = (move _91,) +83:5-92:7: @24[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @24[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @24[10]: _97 = &(*_95) +83:5-92:7: @24[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @24.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb25, unwind: bb39] +83:5-92:7: @25[2]: _89 = [move _96] +83:5-92:7: @25[5]: _88 = &_89 +83:5-92:7: @25[6]: _87 = &(*_88) +83:5-92:7: @25[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @25.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb26, unwind: bb39] +83:5-92:7: @26.Call: _80 = _print(move _81) -> [return: bb27, unwind: bb39] +83:5-92:7: @28[6]: _79 = const () +97:9-104:6: @28[10]: _100 = &_5 +95:9-95:22: @28[13]: FakeRead(ForLet, _99) +106:9-106:40: @28[20]: _133 = const main::promoted[0] +106:9-106:40: @28[21]: _106 = &(*_133) +106:9-106:40: @28[22]: _105 = &(*_106) +106:9-106:40: @28[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @28.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb29, unwind: bb43] +108:9-109:21: @29.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb30, unwind: bb43] +112:13-112:26: @30[2]: _118 = _99 +108:9-113:10: @30.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb31, unwind: bb43] +108:9-114:33: @31.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb32, unwind: bb43] +108:9-114:33: @32[1]: _113 = &_114 +105:5-115:7: @32[2]: _112 = (move _113,) +105:5-115:7: @32[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @32[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @32[9]: _121 = &(*_119) +105:5-115:7: @32[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @32.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb33, unwind: bb38] +105:5-115:7: @33[2]: _111 = [move _120] +105:5-115:7: @33[5]: _110 = &_111 +105:5-115:7: @33[6]: _109 = &(*_110) +105:5-115:7: @33[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @33.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb34, unwind: bb38] +105:5-115:7: @34.Call: _102 = _print(move _103) -> [return: bb35, unwind: bb38] +105:5-115:7: @36[6]: _101 = const () +118:9-118:24: @36[13]: FakeRead(ForLet, _123) +130:25-130:27: @36[15]: _125 = const 10_i32 +130:9-130:22: @36[16]: FakeRead(ForLet, _125) +131:33-131:67: @36[19]: _127 = &mut _125 +131:9-131:30: @36[22]: FakeRead(ForLet, _126) +136:9-136:30: @36[25]: FakeRead(ForLet, _128) +141:9-141:36: @36[28]: FakeRead(ForLet, _129) +143:9-143:33: @36[31]: FakeRead(ForLet, _130) +3:11-155:2: @36[38]: _0 = const ()"> let _shortish_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | { println!("not called") - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + - + let _as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| +10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +29:24-29:58: @9.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb10, unwind: bb43] +29:19-29:59: @10[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @11[3]: _33 = &_5 +31:9-31:10: @11[6]: FakeRead(ForLet, _32) +42:9-42:32: @11[13]: _136 = const main::promoted[3] +42:9-42:32: @11[14]: _39 = &(*_136) +42:9-42:32: @11[15]: _38 = &(*_39) +42:9-42:32: @11[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @11[26]: _48 = move _7 +48:13-48:14: @11[28]: _49 = _32 +44:9-49:10: @11.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb12, unwind: bb43] +44:9-49:10: @12[2]: _46 = &_47 +41:5-50:7: @12[3]: _45 = (move _46,) +41:5-50:7: @12[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @12[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @12[10]: _52 = &(*_50) +41:5-50:7: @12[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @12.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb13, unwind: bb41] +41:5-50:7: @13[2]: _44 = [move _51] +41:5-50:7: @13[5]: _43 = &_44 +41:5-50:7: @13[6]: _42 = &(*_43) +41:5-50:7: @13[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @13.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb14, unwind: bb41] +41:5-50:7: @14.Call: _35 = _print(move _36) -> [return: bb15, unwind: bb41] +41:5-50:7: @16[6]: _34 = const () +52:19-52:23: @16[9]: _54 = Option::<String>::None +54:9-54:32: @17[7]: _135 = const main::promoted[2] +54:9-54:32: @17[8]: _60 = &(*_135) +54:9-54:32: @17[9]: _59 = &(*_60) +54:9-54:32: @17[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @17[20]: _69 = move _7 +56:9-68:10: @17.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb18, unwind: bb43] +56:9-68:10: @18[2]: _67 = &_68 +53:5-69:7: @18[3]: _66 = (move _67,) +53:5-69:7: @18[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @18[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @18[10]: _74 = &(*_72) +53:5-69:7: @18[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @18.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb19, unwind: bb40] +53:5-69:7: @19[2]: _65 = [move _73] +53:5-69:7: @19[5]: _64 = &_65 +53:5-69:7: @19[6]: _63 = &(*_64) +53:5-69:7: @19[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @19.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb20, unwind: bb40] +53:5-69:7: @20.Call: _56 = _print(move _57) -> [return: bb21, unwind: bb40] +53:5-69:7: @22[6]: _55 = const () +71:19-71:23: @22[9]: _76 = Option::<String>::None +75:9-82:6: @23[3]: _78 = &_5 +73:9-73:10: @23[6]: FakeRead(ForLet, _77) +84:9-84:32: @23[13]: _134 = const main::promoted[1] +84:9-84:32: @23[14]: _84 = &(*_134) +84:9-84:32: @23[15]: _83 = &(*_84) +84:9-84:32: @23[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @23[26]: _93 = move _7 +90:13-90:14: @23[28]: _94 = _77 +86:9-91:10: @23.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb24, unwind: bb43] +86:9-91:10: @24[2]: _91 = &_92 +83:5-92:7: @24[3]: _90 = (move _91,) +83:5-92:7: @24[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @24[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @24[10]: _97 = &(*_95) +83:5-92:7: @24[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @24.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb25, unwind: bb39] +83:5-92:7: @25[2]: _89 = [move _96] +83:5-92:7: @25[5]: _88 = &_89 +83:5-92:7: @25[6]: _87 = &(*_88) +83:5-92:7: @25[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @25.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb26, unwind: bb39] +83:5-92:7: @26.Call: _80 = _print(move _81) -> [return: bb27, unwind: bb39] +83:5-92:7: @28[6]: _79 = const () +97:9-104:6: @28[10]: _100 = &_5 +95:9-95:22: @28[13]: FakeRead(ForLet, _99) +106:9-106:40: @28[20]: _133 = const main::promoted[0] +106:9-106:40: @28[21]: _106 = &(*_133) +106:9-106:40: @28[22]: _105 = &(*_106) +106:9-106:40: @28[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @28.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb29, unwind: bb43] +108:9-109:21: @29.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb30, unwind: bb43] +112:13-112:26: @30[2]: _118 = _99 +108:9-113:10: @30.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb31, unwind: bb43] +108:9-114:33: @31.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb32, unwind: bb43] +108:9-114:33: @32[1]: _113 = &_114 +105:5-115:7: @32[2]: _112 = (move _113,) +105:5-115:7: @32[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @32[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @32[9]: _121 = &(*_119) +105:5-115:7: @32[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @32.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb33, unwind: bb38] +105:5-115:7: @33[2]: _111 = [move _120] +105:5-115:7: @33[5]: _110 = &_111 +105:5-115:7: @33[6]: _109 = &(*_110) +105:5-115:7: @33[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @33.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb34, unwind: bb38] +105:5-115:7: @34.Call: _102 = _print(move _103) -> [return: bb35, unwind: bb38] +105:5-115:7: @36[6]: _101 = const () +118:9-118:24: @36[13]: FakeRead(ForLet, _123) +130:25-130:27: @36[15]: _125 = const 10_i32 +130:9-130:22: @36[16]: FakeRead(ForLet, _125) +131:33-131:67: @36[19]: _127 = &mut _125 +131:9-131:30: @36[22]: FakeRead(ForLet, _126) +136:9-136:30: @36[25]: FakeRead(ForLet, _128) +141:9-141:36: @36[28]: FakeRead(ForLet, _129) +143:9-143:33: @36[31]: FakeRead(ForLet, _130) +147:9-147:33: @36[34]: FakeRead(ForLet, _131) +3:11-155:2: @36[38]: _0 = const ()"> let _as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 - | { println!("not called") } | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; + - + let _almost_as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| +10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +29:24-29:58: @9.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb10, unwind: bb43] +29:19-29:59: @10[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @11[3]: _33 = &_5 +31:9-31:10: @11[6]: FakeRead(ForLet, _32) +42:9-42:32: @11[13]: _136 = const main::promoted[3] +42:9-42:32: @11[14]: _39 = &(*_136) +42:9-42:32: @11[15]: _38 = &(*_39) +42:9-42:32: @11[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @11[26]: _48 = move _7 +48:13-48:14: @11[28]: _49 = _32 +44:9-49:10: @11.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb12, unwind: bb43] +44:9-49:10: @12[2]: _46 = &_47 +41:5-50:7: @12[3]: _45 = (move _46,) +41:5-50:7: @12[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @12[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @12[10]: _52 = &(*_50) +41:5-50:7: @12[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @12.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb13, unwind: bb41] +41:5-50:7: @13[2]: _44 = [move _51] +41:5-50:7: @13[5]: _43 = &_44 +41:5-50:7: @13[6]: _42 = &(*_43) +41:5-50:7: @13[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @13.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb14, unwind: bb41] +41:5-50:7: @14.Call: _35 = _print(move _36) -> [return: bb15, unwind: bb41] +41:5-50:7: @16[6]: _34 = const () +52:19-52:23: @16[9]: _54 = Option::<String>::None +54:9-54:32: @17[7]: _135 = const main::promoted[2] +54:9-54:32: @17[8]: _60 = &(*_135) +54:9-54:32: @17[9]: _59 = &(*_60) +54:9-54:32: @17[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @17[20]: _69 = move _7 +56:9-68:10: @17.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb18, unwind: bb43] +56:9-68:10: @18[2]: _67 = &_68 +53:5-69:7: @18[3]: _66 = (move _67,) +53:5-69:7: @18[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @18[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @18[10]: _74 = &(*_72) +53:5-69:7: @18[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @18.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb19, unwind: bb40] +53:5-69:7: @19[2]: _65 = [move _73] +53:5-69:7: @19[5]: _64 = &_65 +53:5-69:7: @19[6]: _63 = &(*_64) +53:5-69:7: @19[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @19.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb20, unwind: bb40] +53:5-69:7: @20.Call: _56 = _print(move _57) -> [return: bb21, unwind: bb40] +53:5-69:7: @22[6]: _55 = const () +71:19-71:23: @22[9]: _76 = Option::<String>::None +75:9-82:6: @23[3]: _78 = &_5 +73:9-73:10: @23[6]: FakeRead(ForLet, _77) +84:9-84:32: @23[13]: _134 = const main::promoted[1] +84:9-84:32: @23[14]: _84 = &(*_134) +84:9-84:32: @23[15]: _83 = &(*_84) +84:9-84:32: @23[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @23[26]: _93 = move _7 +90:13-90:14: @23[28]: _94 = _77 +86:9-91:10: @23.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb24, unwind: bb43] +86:9-91:10: @24[2]: _91 = &_92 +83:5-92:7: @24[3]: _90 = (move _91,) +83:5-92:7: @24[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @24[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @24[10]: _97 = &(*_95) +83:5-92:7: @24[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @24.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb25, unwind: bb39] +83:5-92:7: @25[2]: _89 = [move _96] +83:5-92:7: @25[5]: _88 = &_89 +83:5-92:7: @25[6]: _87 = &(*_88) +83:5-92:7: @25[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @25.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb26, unwind: bb39] +83:5-92:7: @26.Call: _80 = _print(move _81) -> [return: bb27, unwind: bb39] +83:5-92:7: @28[6]: _79 = const () +97:9-104:6: @28[10]: _100 = &_5 +95:9-95:22: @28[13]: FakeRead(ForLet, _99) +106:9-106:40: @28[20]: _133 = const main::promoted[0] +106:9-106:40: @28[21]: _106 = &(*_133) +106:9-106:40: @28[22]: _105 = &(*_106) +106:9-106:40: @28[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @28.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb29, unwind: bb43] +108:9-109:21: @29.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb30, unwind: bb43] +112:13-112:26: @30[2]: _118 = _99 +108:9-113:10: @30.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb31, unwind: bb43] +108:9-114:33: @31.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb32, unwind: bb43] +108:9-114:33: @32[1]: _113 = &_114 +105:5-115:7: @32[2]: _112 = (move _113,) +105:5-115:7: @32[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @32[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @32[9]: _121 = &(*_119) +105:5-115:7: @32[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @32.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb33, unwind: bb38] +105:5-115:7: @33[2]: _111 = [move _120] +105:5-115:7: @33[5]: _110 = &_111 +105:5-115:7: @33[6]: _109 = &(*_110) +105:5-115:7: @33[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @33.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb34, unwind: bb38] +105:5-115:7: @34.Call: _102 = _print(move _103) -> [return: bb35, unwind: bb38] +105:5-115:7: @36[6]: _101 = const () +118:9-118:24: @36[13]: FakeRead(ForLet, _123) +130:25-130:27: @36[15]: _125 = const 10_i32 +130:9-130:22: @36[16]: FakeRead(ForLet, _125) +131:33-131:67: @36[19]: _127 = &mut _125 +131:9-131:30: @36[22]: FakeRead(ForLet, _126) +136:9-136:30: @36[25]: FakeRead(ForLet, _128) +141:9-141:36: @36[28]: FakeRead(ForLet, _129) +143:9-143:33: @36[31]: FakeRead(ForLet, _130) +147:9-147:33: @36[34]: FakeRead(ForLet, _131) +151:9-151:40: @36[37]: FakeRead(ForLet, _132) +3:11-155:2: @36[38]: _0 = const ()"> let _almost_as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 - | { println!("not called") } | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊ -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊ + ; - ; +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42
+10:9-10:24: @4[2]: FakeRead(ForLet, _7) +12:9-12:32: @4[9]: _137 = const main::promoted[4] +12:9-12:32: @4[10]: _14 = &(*_137) +12:9-12:32: @4[11]: _13 = &(*_14) +12:9-12:32: @4[12]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @4[22]: _23 = move _7 +14:9-26:10: @4.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb5, unwind: bb43] +14:9-26:10: @5[2]: _21 = &_22 +11:5-27:7: @5[3]: _20 = (move _21,) +11:5-27:7: @5[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @5[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @5[10]: _28 = &(*_26) +11:5-27:7: @5[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @5.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb6, unwind: bb42] +11:5-27:7: @6[2]: _19 = [move _27] +11:5-27:7: @6[5]: _18 = &_19 +11:5-27:7: @6[6]: _17 = &(*_18) +11:5-27:7: @6[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @6.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb7, unwind: bb42] +11:5-27:7: @7.Call: _10 = _print(move _11) -> [return: bb8, unwind: bb42] +11:5-27:7: @9[6]: _9 = const () +29:24-29:58: @9.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb10, unwind: bb43] +29:19-29:59: @10[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @11[3]: _33 = &_5 +31:9-31:10: @11[6]: FakeRead(ForLet, _32) +42:9-42:32: @11[13]: _136 = const main::promoted[3] +42:9-42:32: @11[14]: _39 = &(*_136) +42:9-42:32: @11[15]: _38 = &(*_39) +42:9-42:32: @11[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @11[26]: _48 = move _7 +48:13-48:14: @11[28]: _49 = _32 +44:9-49:10: @11.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb12, unwind: bb43] +44:9-49:10: @12[2]: _46 = &_47 +41:5-50:7: @12[3]: _45 = (move _46,) +41:5-50:7: @12[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @12[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @12[10]: _52 = &(*_50) +41:5-50:7: @12[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @12.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb13, unwind: bb41] +41:5-50:7: @13[2]: _44 = [move _51] +41:5-50:7: @13[5]: _43 = &_44 +41:5-50:7: @13[6]: _42 = &(*_43) +41:5-50:7: @13[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @13.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb14, unwind: bb41] +41:5-50:7: @14.Call: _35 = _print(move _36) -> [return: bb15, unwind: bb41] +41:5-50:7: @16[6]: _34 = const () +52:19-52:23: @16[9]: _54 = Option::<String>::None +54:9-54:32: @17[7]: _135 = const main::promoted[2] +54:9-54:32: @17[8]: _60 = &(*_135) +54:9-54:32: @17[9]: _59 = &(*_60) +54:9-54:32: @17[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @17[20]: _69 = move _7 +56:9-68:10: @17.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb18, unwind: bb43] +56:9-68:10: @18[2]: _67 = &_68 +53:5-69:7: @18[3]: _66 = (move _67,) +53:5-69:7: @18[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @18[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @18[10]: _74 = &(*_72) +53:5-69:7: @18[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @18.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb19, unwind: bb40] +53:5-69:7: @19[2]: _65 = [move _73] +53:5-69:7: @19[5]: _64 = &_65 +53:5-69:7: @19[6]: _63 = &(*_64) +53:5-69:7: @19[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @19.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb20, unwind: bb40] +53:5-69:7: @20.Call: _56 = _print(move _57) -> [return: bb21, unwind: bb40] +53:5-69:7: @22[6]: _55 = const () +71:19-71:23: @22[9]: _76 = Option::<String>::None +75:9-82:6: @23[3]: _78 = &_5 +73:9-73:10: @23[6]: FakeRead(ForLet, _77) +84:9-84:32: @23[13]: _134 = const main::promoted[1] +84:9-84:32: @23[14]: _84 = &(*_134) +84:9-84:32: @23[15]: _83 = &(*_84) +84:9-84:32: @23[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @23[26]: _93 = move _7 +90:13-90:14: @23[28]: _94 = _77 +86:9-91:10: @23.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb24, unwind: bb43] +86:9-91:10: @24[2]: _91 = &_92 +83:5-92:7: @24[3]: _90 = (move _91,) +83:5-92:7: @24[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @24[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @24[10]: _97 = &(*_95) +83:5-92:7: @24[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @24.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb25, unwind: bb39] +83:5-92:7: @25[2]: _89 = [move _96] +83:5-92:7: @25[5]: _88 = &_89 +83:5-92:7: @25[6]: _87 = &(*_88) +83:5-92:7: @25[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @25.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb26, unwind: bb39] +83:5-92:7: @26.Call: _80 = _print(move _81) -> [return: bb27, unwind: bb39] +83:5-92:7: @28[6]: _79 = const () +97:9-104:6: @28[10]: _100 = &_5 +95:9-95:22: @28[13]: FakeRead(ForLet, _99) +106:9-106:40: @28[20]: _133 = const main::promoted[0] +106:9-106:40: @28[21]: _106 = &(*_133) +106:9-106:40: @28[22]: _105 = &(*_106) +106:9-106:40: @28[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @28.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb29, unwind: bb43] +108:9-109:21: @29.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb30, unwind: bb43] +112:13-112:26: @30[2]: _118 = _99 +108:9-113:10: @30.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb31, unwind: bb43] +108:9-114:33: @31.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb32, unwind: bb43] +108:9-114:33: @32[1]: _113 = &_114 +105:5-115:7: @32[2]: _112 = (move _113,) +105:5-115:7: @32[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @32[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @32[9]: _121 = &(*_119) +105:5-115:7: @32[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @32.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb33, unwind: bb38] +105:5-115:7: @33[2]: _111 = [move _120] +105:5-115:7: @33[5]: _110 = &_111 +105:5-115:7: @33[6]: _109 = &(*_110) +105:5-115:7: @33[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @33.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb34, unwind: bb38] +105:5-115:7: @34.Call: _102 = _print(move _103) -> [return: bb35, unwind: bb38] +105:5-115:7: @36[6]: _101 = const () +118:9-118:24: @36[13]: FakeRead(ForLet, _123) +130:25-130:27: @36[15]: _125 = const 10_i32 +130:9-130:22: @36[16]: FakeRead(ForLet, _125) +131:33-131:67: @36[19]: _127 = &mut _125 +131:9-131:30: @36[22]: FakeRead(ForLet, _126) +136:9-136:30: @36[25]: FakeRead(ForLet, _128) +141:9-141:36: @36[28]: FakeRead(ForLet, _129) +143:9-143:33: @36[31]: FakeRead(ForLet, _130) +147:9-147:33: @36[34]: FakeRead(ForLet, _131) +151:9-151:40: @36[37]: FakeRead(ForLet, _132) +3:11-155:2: @36[38]: _0 = const () +155:2-155:2: @37.Return: return">}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html index bed5e7bb7ce..7c44c536379 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html @@ -69,122 +69,122 @@ -
@0,1,2,3,4,5,6,7,8⦊fn use_this_lib_crate() { -@0,1,2,3,4,5,6,7⦊fn use_this_lib_crate() { + used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); - used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + "used from library used_crate.rs", - "used from library used_crate.rs", + ); - ); + let some_vec = vec![5, 6, 7, 8]; - let some_vec = vec![5, 6, 7, 8]; + used_only_from_this_lib_crate_generic_function(some_vec); - used_only_from_this_lib_crate_generic_function(some_vec); + used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); - used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); +}⦉@0,1,2,3,4,5,6,7,8
+58:20-58:36: @3.Call: _3 = slice::<impl [i32]>::into_vec::<std::alloc::Global>(move _4) -> [return: bb4, unwind: bb10] +58:9-58:17: @4[1]: FakeRead(ForLet, _3) +59:52-59:60: @4[4]: _8 = move _3 +59:5-59:61: @4.Call: _7 = used_only_from_this_lib_crate_generic_function::<Vec<i32>>(move _8) -> [return: bb5, unwind: bb8] +60:5-60:91: @5.Call: _9 = used_only_from_this_lib_crate_generic_function::<&str>(const "used ONLY from library used_crate.rs") -> [return: bb6, unwind: bb8] +53:25-61:2: @6[1]: _0 = const () +61:2-61:2: @7.Return: return">}⦉@0,1,2,3,4,5,6,7
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html index acb2c7d63f5..ba6af60fa5c 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html @@ -69,125 +69,125 @@ -
@0,1,2,3,4,5,6,7,8,9⦊fn main() { -@0,1,2,3,4,5,6,7,8⦊fn main() { + used_crate::used_function(); - used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; - let some_vec = vec![1, 2, 3, 4]; + used_crate::used_only_from_bin_crate_generic_function(&some_vec); - used_crate::used_only_from_bin_crate_generic_function(&some_vec); + used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); - used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); - used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); - used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); +}⦉@0,1,2,3,4,5,6,7,8,9
+7:20-7:36: @2.Call: _2 = slice::<impl [i32]>::into_vec::<std::alloc::Global>(move _3) -> [return: bb3, unwind: bb11] +7:9-7:17: @3[1]: FakeRead(ForLet, _2) +8:59-8:68: @3[4]: _7 = &_2 +8:5-8:69: @3.Call: _6 = used_only_from_bin_crate_generic_function::<&Vec<i32>>(move _7) -> [return: bb4, unwind: bb9] +9:5-9:89: @4.Call: _8 = used_only_from_bin_crate_generic_function::<&str>(const "used from bin uses_crate.rs") -> [return: bb5, unwind: bb9] +10:68-10:76: @5[3]: _10 = move _2 +10:5-10:77: @5.Call: _9 = used_from_bin_crate_and_lib_crate_generic_function::<Vec<i32>>(move _10) -> [return: bb6, unwind: bb9] +11:5-11:98: @6.Call: _11 = used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>(const "interesting?") -> [return: bb7, unwind: bb9] +5:11-12:2: @7[1]: _0 = const () +12:2-12:2: @8.Return: return">}⦉@0,1,2,3,4,5,6,7,8 diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index c4f7c378616..a952fe8e76e 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -43,6 +43,7 @@ impl Future for Defer { /// The `failing_op`-th operation will panic. struct Allocator { data: RefCell>, + name: &'static str, failing_op: usize, cur_ops: Cell, } @@ -54,23 +55,28 @@ impl Drop for Allocator { fn drop(&mut self) { let data = self.data.borrow(); if data.iter().any(|d| *d) { - panic!("missing free: {:?}", data); + panic!("missing free in {:?}: {:?}", self.name, data); } } } impl Allocator { - fn new(failing_op: usize) -> Self { - Allocator { failing_op, cur_ops: Cell::new(0), data: RefCell::new(vec![]) } + fn new(failing_op: usize, name: &'static str) -> Self { + Allocator { + failing_op, + name, + cur_ops: Cell::new(0), + data: RefCell::new(vec![]), + } } - fn alloc(&self) -> impl Future> + '_ { + fn alloc(self: &Rc) -> impl Future + 'static { self.fallible_operation(); let mut data = self.data.borrow_mut(); let addr = data.len(); data.push(true); - Defer { ready: false, value: Some(Ptr(addr, self)) } + Defer { ready: false, value: Some(Ptr(addr, self.clone())) } } fn fallible_operation(&self) { self.cur_ops.set(self.cur_ops.get() + 1); @@ -83,11 +89,11 @@ impl Allocator { // Type that tracks whether it was dropped and can panic when it's created or // destroyed. -struct Ptr<'a>(usize, &'a Allocator); -impl<'a> Drop for Ptr<'a> { +struct Ptr(usize, Rc); +impl Drop for Ptr { fn drop(&mut self) { match self.1.data.borrow_mut()[self.0] { - false => panic!("double free at index {:?}", self.0), + false => panic!("double free in {:?} at index {:?}", self.1.name, self.0), ref mut d => *d = false, } @@ -111,7 +117,7 @@ async fn dynamic_drop(a: Rc, c: bool) { }; } -struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>); +struct TwoPtrs(Ptr, Ptr); async fn struct_dynamic_drop(a: Rc, c0: bool, c1: bool, c: bool) { for i in 0..2 { let x; @@ -232,21 +238,62 @@ async fn move_ref_pattern(a: Rc) { a.alloc().await; } -fn run_test(cx: &mut Context<'_>, ref f: F) +async fn panic_after_return(a: Rc, c: bool) -> (Ptr,) { + a.alloc().await; + let p = a.alloc().await; + if c { + a.alloc().await; + let q = a.alloc().await; + // We use a return type that isn't used anywhere else to make sure that + // the return place doesn't incorrectly end up in the generator state. + return (a.alloc().await,); + } + (a.alloc().await,) +} + + +async fn panic_after_init_by_loop(a: Rc) { + a.alloc().await; + let p = a.alloc().await; + let q = loop { + a.alloc().await; + let r = a.alloc().await; + break a.alloc().await; + }; +} + +async fn panic_after_init_by_match_with_bindings_and_guard(a: Rc, b: bool) { + a.alloc().await; + let p = a.alloc().await; + let q = match a.alloc().await { + ref _x if b => { + a.alloc().await; + let r = a.alloc().await; + a.alloc().await + } + _x => { + a.alloc().await; + let r = a.alloc().await; + a.alloc().await + }, + }; +} + +fn run_test(cx: &mut Context<'_>, ref f: F, name: &'static str) where F: Fn(Rc) -> G, - G: Future, + G: Future, { for polls in 0.. { // Run without any panics to find which operations happen after the // penultimate `poll`. - let first_alloc = Rc::new(Allocator::new(usize::MAX)); + let first_alloc = Rc::new(Allocator::new(usize::MAX, name)); let mut fut = Box::pin(f(first_alloc.clone())); let mut ops_before_last_poll = 0; let mut completed = false; for _ in 0..polls { ops_before_last_poll = first_alloc.cur_ops.get(); - if let Poll::Ready(()) = fut.as_mut().poll(cx) { + if let Poll::Ready(_) = fut.as_mut().poll(cx) { completed = true; } } @@ -255,7 +302,7 @@ where // Start at `ops_before_last_poll` so that we will always be able to // `poll` the expected number of times. for failing_op in ops_before_last_poll..first_alloc.cur_ops.get() { - let alloc = Rc::new(Allocator::new(failing_op + 1)); + let alloc = Rc::new(Allocator::new(failing_op + 1, name)); let f = &f; let cx = &mut *cx; let result = panic::catch_unwind(panic::AssertUnwindSafe(move || { @@ -285,48 +332,58 @@ fn clone_waker(data: *const ()) -> RawWaker { RawWaker::new(data, &RawWakerVTable::new(clone_waker, drop, drop, drop)) } +macro_rules! run_test { + ($ctxt:expr, $e:expr) => { run_test($ctxt, $e, stringify!($e)); }; +} + fn main() { let waker = unsafe { Waker::from_raw(clone_waker(ptr::null())) }; let context = &mut Context::from_waker(&waker); - run_test(context, |a| dynamic_init(a, false)); - run_test(context, |a| dynamic_init(a, true)); - run_test(context, |a| dynamic_drop(a, false)); - run_test(context, |a| dynamic_drop(a, true)); - - run_test(context, |a| assignment(a, false, false)); - run_test(context, |a| assignment(a, false, true)); - run_test(context, |a| assignment(a, true, false)); - run_test(context, |a| assignment(a, true, true)); - - run_test(context, |a| array_simple(a)); - run_test(context, |a| vec_simple(a)); - run_test(context, |a| vec_unreachable(a)); - - run_test(context, |a| struct_dynamic_drop(a, false, false, false)); - run_test(context, |a| struct_dynamic_drop(a, false, false, true)); - run_test(context, |a| struct_dynamic_drop(a, false, true, false)); - run_test(context, |a| struct_dynamic_drop(a, false, true, true)); - run_test(context, |a| struct_dynamic_drop(a, true, false, false)); - run_test(context, |a| struct_dynamic_drop(a, true, false, true)); - run_test(context, |a| struct_dynamic_drop(a, true, true, false)); - run_test(context, |a| struct_dynamic_drop(a, true, true, true)); - - run_test(context, |a| field_assignment(a, false)); - run_test(context, |a| field_assignment(a, true)); - - run_test(context, |a| mixed_drop_and_nondrop(a)); - - run_test(context, |a| slice_pattern_one_of(a, 0)); - run_test(context, |a| slice_pattern_one_of(a, 1)); - run_test(context, |a| slice_pattern_one_of(a, 2)); - run_test(context, |a| slice_pattern_one_of(a, 3)); - - run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, true)); - run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, false)); - run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, true)); - run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, false)); - run_test(context, |a| subslice_pattern_reassign(a)); - - run_test(context, |a| move_ref_pattern(a)); + run_test!(context, |a| dynamic_init(a, false)); + run_test!(context, |a| dynamic_init(a, true)); + run_test!(context, |a| dynamic_drop(a, false)); + run_test!(context, |a| dynamic_drop(a, true)); + + run_test!(context, |a| assignment(a, false, false)); + run_test!(context, |a| assignment(a, false, true)); + run_test!(context, |a| assignment(a, true, false)); + run_test!(context, |a| assignment(a, true, true)); + + run_test!(context, |a| array_simple(a)); + run_test!(context, |a| vec_simple(a)); + run_test!(context, |a| vec_unreachable(a)); + + run_test!(context, |a| struct_dynamic_drop(a, false, false, false)); + run_test!(context, |a| struct_dynamic_drop(a, false, false, true)); + run_test!(context, |a| struct_dynamic_drop(a, false, true, false)); + run_test!(context, |a| struct_dynamic_drop(a, false, true, true)); + run_test!(context, |a| struct_dynamic_drop(a, true, false, false)); + run_test!(context, |a| struct_dynamic_drop(a, true, false, true)); + run_test!(context, |a| struct_dynamic_drop(a, true, true, false)); + run_test!(context, |a| struct_dynamic_drop(a, true, true, true)); + + run_test!(context, |a| field_assignment(a, false)); + run_test!(context, |a| field_assignment(a, true)); + + run_test!(context, |a| mixed_drop_and_nondrop(a)); + + run_test!(context, |a| slice_pattern_one_of(a, 0)); + run_test!(context, |a| slice_pattern_one_of(a, 1)); + run_test!(context, |a| slice_pattern_one_of(a, 2)); + run_test!(context, |a| slice_pattern_one_of(a, 3)); + + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test!(context, |a| subslice_pattern_reassign(a)); + + run_test!(context, |a| move_ref_pattern(a)); + + run_test!(context, |a| panic_after_return(a, false)); + run_test!(context, |a| panic_after_return(a, true)); + run_test!(context, |a| panic_after_init_by_loop(a)); + run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, false)); + run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, true)); } diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index 88f557055f3..ddccee20e12 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -3,7 +3,6 @@ #![feature(generators, generator_trait)] #![feature(bindings_after_at)] - #![allow(unused_assignments)] #![allow(unused_variables)] @@ -17,6 +16,7 @@ struct InjectedFailure; struct Allocator { data: RefCell>, + name: &'static str, failing_op: usize, cur_ops: Cell, } @@ -28,17 +28,18 @@ impl Drop for Allocator { fn drop(&mut self) { let data = self.data.borrow(); if data.iter().any(|d| *d) { - panic!("missing free: {:?}", data); + panic!("missing free in {:?}: {:?}", self.name, data); } } } impl Allocator { - fn new(failing_op: usize) -> Self { + fn new(failing_op: usize, name: &'static str) -> Self { Allocator { failing_op: failing_op, cur_ops: Cell::new(0), - data: RefCell::new(vec![]) + data: RefCell::new(vec![]), + name, } } fn alloc(&self) -> Ptr<'_> { @@ -53,33 +54,17 @@ impl Allocator { data.push(true); Ptr(addr, self) } - // FIXME(#47949) Any use of this indicates a bug in rustc: we should never - // be leaking values in the cases here. - // - // Creates a `Ptr<'_>` and checks that the allocated value is leaked if the - // `failing_op` is in the list of exception. - fn alloc_leaked(&self, exceptions: Vec) -> Ptr<'_> { - let ptr = self.alloc(); - - if exceptions.iter().any(|operation| *operation == self.failing_op) { - let mut data = self.data.borrow_mut(); - data[ptr.0] = false; - } - ptr - } } struct Ptr<'a>(usize, &'a Allocator); impl<'a> Drop for Ptr<'a> { fn drop(&mut self) { match self.1.data.borrow_mut()[self.0] { - false => { - panic!("double free at index {:?}", self.0) - } - ref mut d => *d = false + false => panic!("double free in {:?} at index {:?}", self.1.name, self.0), + ref mut d => *d = false, } - self.1.cur_ops.set(self.1.cur_ops.get()+1); + self.1.cur_ops.set(self.1.cur_ops.get() + 1); if self.1.cur_ops.get() == self.1.failing_op { panic!(InjectedFailure); @@ -177,11 +162,7 @@ fn generator(a: &Allocator, run_count: usize) { assert!(run_count < 4); let mut gen = || { - (a.alloc(), - yield a.alloc(), - a.alloc(), - yield a.alloc() - ); + (a.alloc(), yield a.alloc(), a.alloc(), yield a.alloc()); }; for _ in 0..run_count { Pin::new(&mut gen).resume(()); @@ -205,28 +186,40 @@ fn vec_unreachable(a: &Allocator) { } fn slice_pattern_first(a: &Allocator) { - let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()]; + let [_x, ..] = [a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_middle(a: &Allocator) { - let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()]; + let [_, _x, _] = [a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_two(a: &Allocator) { - let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + let [_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_last(a: &Allocator) { - let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + let [.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_one_of(a: &Allocator, i: usize) { let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; let _x = match i { - 0 => { let [a, ..] = array; a } - 1 => { let [_, a, ..] = array; a } - 2 => { let [_, _, a, _] = array; a } - 3 => { let [_, _, _, a] = array; a } + 0 => { + let [a, ..] = array; + a + } + 1 => { + let [_, a, ..] = array; + a + } + 2 => { + let [_, _, a, _] = array; + a + } + 3 => { + let [_, _, _, a] = array; + a + } _ => panic!("unmatched"), }; } @@ -234,9 +227,9 @@ fn slice_pattern_one_of(a: &Allocator, i: usize) { fn subslice_pattern_from_end(a: &Allocator, arg: bool) { let a = [a.alloc(), a.alloc(), a.alloc()]; if arg { - let[.., _x, _] = a; + let [.., _x, _] = a; } else { - let[_, _y @ ..] = a; + let [_, _y @ ..] = a; } } @@ -248,45 +241,61 @@ fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) { } if arg { - let[.., _x, _] = a; + let [.., _x, _] = a; } else { - let[_, _y @ ..] = a; + let [_, _y @ ..] = a; } } fn slice_pattern_reassign(a: &Allocator) { let mut ar = [a.alloc(), a.alloc()]; - let[_, _x] = ar; + let [_, _x] = ar; ar = [a.alloc(), a.alloc()]; - let[.., _y] = ar; + let [.., _y] = ar; } fn subslice_pattern_reassign(a: &Allocator) { let mut ar = [a.alloc(), a.alloc(), a.alloc()]; - let[_, _, _x] = ar; + let [_, _, _x] = ar; ar = [a.alloc(), a.alloc(), a.alloc()]; - let[_, _y @ ..] = ar; + let [_, _y @ ..] = ar; } fn index_field_mixed_ends(a: &Allocator) { let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; - let[(_x, _), ..] = ar; - let[(_, _y), _] = ar; - let[_, (_, _w)] = ar; - let[.., (_z, _)] = ar; + let [(_x, _), ..] = ar; + let [(_, _y), _] = ar; + let [_, (_, _w)] = ar; + let [.., (_z, _)] = ar; } fn subslice_mixed_min_lengths(a: &Allocator, c: i32) { let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; match c { - 0 => { let[_x, ..] = ar; } - 1 => { let[_x, _, ..] = ar; } - 2 => { let[_x, _] = ar; } - 3 => { let[(_x, _), _, ..] = ar; } - 4 => { let[.., (_x, _)] = ar; } - 5 => { let[.., (_x, _), _] = ar; } - 6 => { let [_y @ ..] = ar; } - _ => { let [_y @ .., _] = ar; } + 0 => { + let [_x, ..] = ar; + } + 1 => { + let [_x, _, ..] = ar; + } + 2 => { + let [_x, _] = ar; + } + 3 => { + let [(_x, _), _, ..] = ar; + } + 4 => { + let [.., (_x, _)] = ar; + } + 5 => { + let [.., (_x, _), _] = ar; + } + 6 => { + let [_y @ ..] = ar; + } + _ => { + let [_y @ .., _] = ar; + } } } @@ -334,87 +343,160 @@ fn move_ref_pattern(a: &Allocator) { } fn panic_after_return(a: &Allocator) -> Ptr<'_> { - // Panic in the drop of `p` or `q` can leak - let exceptions = vec![8, 9]; a.alloc(); let p = a.alloc(); { a.alloc(); let p = a.alloc(); - // FIXME (#47949) We leak values when we panic in a destructor after - // evaluating an expression with `rustc_mir::build::Builder::into`. - a.alloc_leaked(exceptions) + a.alloc() } } fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> { - // Panic in the drop of `p` or `q` can leak - let exceptions = vec![8, 9]; a.alloc(); let p = a.alloc(); { a.alloc(); let q = a.alloc(); - // FIXME (#47949) - return a.alloc_leaked(exceptions); + return a.alloc(); } } fn panic_after_init(a: &Allocator) { - // Panic in the drop of `r` can leak - let exceptions = vec![8]; a.alloc(); let p = a.alloc(); let q = { a.alloc(); let r = a.alloc(); - // FIXME (#47949) - a.alloc_leaked(exceptions) + a.alloc() }; } fn panic_after_init_temp(a: &Allocator) { - // Panic in the drop of `r` can leak - let exceptions = vec![8]; a.alloc(); let p = a.alloc(); { a.alloc(); let r = a.alloc(); - // FIXME (#47949) - a.alloc_leaked(exceptions) + a.alloc() }; } fn panic_after_init_by_loop(a: &Allocator) { - // Panic in the drop of `r` can leak - let exceptions = vec![8]; a.alloc(); let p = a.alloc(); let q = loop { a.alloc(); let r = a.alloc(); - // FIXME (#47949) - break a.alloc_leaked(exceptions); + break a.alloc(); + }; +} + +fn panic_after_init_by_match(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let _ = loop { + let q = match b { + true => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + false => { + a.alloc(); + let r = a.alloc(); + break a.alloc(); + } + }; + return; + }; +} + +fn panic_after_init_by_match_with_guard(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = match a.alloc() { + _ if b => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + _ => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + }; +} + +fn panic_after_init_by_match_with_bindings_and_guard(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = match a.alloc() { + _x if b => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + _x => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + }; +} + +fn panic_after_init_by_match_with_ref_bindings_and_guard(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = match a.alloc() { + ref _x if b => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + ref _x => { + a.alloc(); + let r = a.alloc(); + a.alloc() + } + }; +} + +fn panic_after_init_by_break_if(a: &Allocator, b: bool) { + a.alloc(); + let p = a.alloc(); + let q = loop { + let r = a.alloc(); + break if b { + let s = a.alloc(); + a.alloc() + } else { + a.alloc() + }; }; } -fn run_test(mut f: F) - where F: FnMut(&Allocator) +fn run_test(mut f: F, name: &'static str) +where + F: FnMut(&Allocator), { - let first_alloc = Allocator::new(usize::MAX); + let first_alloc = Allocator::new(usize::MAX, name); f(&first_alloc); - for failing_op in 1..first_alloc.cur_ops.get()+1 { - let alloc = Allocator::new(failing_op); + for failing_op in 1..first_alloc.cur_ops.get() + 1 { + let alloc = Allocator::new(failing_op, name); let alloc = &alloc; let f = panic::AssertUnwindSafe(&mut f); let result = panic::catch_unwind(move || { f.0(alloc); }); match result { - Ok(..) => panic!("test executed {} ops but now {}", - first_alloc.cur_ops.get(), alloc.cur_ops.get()), + Ok(..) => panic!( + "test executed {} ops but now {}", + first_alloc.cur_ops.get(), + alloc.cur_ops.get() + ), Err(e) => { if e.downcast_ref::().is_none() { panic::resume_unwind(e); @@ -424,98 +506,115 @@ fn run_test(mut f: F) } } -fn run_test_nopanic(mut f: F) - where F: FnMut(&Allocator) +fn run_test_nopanic(mut f: F, name: &'static str) +where + F: FnMut(&Allocator), { - let first_alloc = Allocator::new(usize::MAX); + let first_alloc = Allocator::new(usize::MAX, name); f(&first_alloc); } +macro_rules! run_test { + ($e:expr) => { + run_test($e, stringify!($e)); + }; +} + fn main() { - run_test(|a| dynamic_init(a, false)); - run_test(|a| dynamic_init(a, true)); - run_test(|a| dynamic_drop(a, false)); - run_test(|a| dynamic_drop(a, true)); - - run_test(|a| assignment2(a, false, false)); - run_test(|a| assignment2(a, false, true)); - run_test(|a| assignment2(a, true, false)); - run_test(|a| assignment2(a, true, true)); - - run_test(|a| assignment1(a, false)); - run_test(|a| assignment1(a, true)); - - run_test(|a| array_simple(a)); - run_test(|a| vec_simple(a)); - run_test(|a| vec_unreachable(a)); - - run_test(|a| struct_dynamic_drop(a, false, false, false)); - run_test(|a| struct_dynamic_drop(a, false, false, true)); - run_test(|a| struct_dynamic_drop(a, false, true, false)); - run_test(|a| struct_dynamic_drop(a, false, true, true)); - run_test(|a| struct_dynamic_drop(a, true, false, false)); - run_test(|a| struct_dynamic_drop(a, true, false, true)); - run_test(|a| struct_dynamic_drop(a, true, true, false)); - run_test(|a| struct_dynamic_drop(a, true, true, true)); - - run_test(|a| field_assignment(a, false)); - run_test(|a| field_assignment(a, true)); - - run_test(|a| generator(a, 0)); - run_test(|a| generator(a, 1)); - run_test(|a| generator(a, 2)); - run_test(|a| generator(a, 3)); - - run_test(|a| mixed_drop_and_nondrop(a)); - - run_test(|a| slice_pattern_first(a)); - run_test(|a| slice_pattern_middle(a)); - run_test(|a| slice_pattern_two(a)); - run_test(|a| slice_pattern_last(a)); - run_test(|a| slice_pattern_one_of(a, 0)); - run_test(|a| slice_pattern_one_of(a, 1)); - run_test(|a| slice_pattern_one_of(a, 2)); - run_test(|a| slice_pattern_one_of(a, 3)); - - run_test(|a| subslice_pattern_from_end(a, true)); - run_test(|a| subslice_pattern_from_end(a, false)); - run_test(|a| subslice_pattern_from_end_with_drop(a, true, true)); - run_test(|a| subslice_pattern_from_end_with_drop(a, true, false)); - run_test(|a| subslice_pattern_from_end_with_drop(a, false, true)); - run_test(|a| subslice_pattern_from_end_with_drop(a, false, false)); - run_test(|a| slice_pattern_reassign(a)); - run_test(|a| subslice_pattern_reassign(a)); - - run_test(|a| index_field_mixed_ends(a)); - run_test(|a| subslice_mixed_min_lengths(a, 0)); - run_test(|a| subslice_mixed_min_lengths(a, 1)); - run_test(|a| subslice_mixed_min_lengths(a, 2)); - run_test(|a| subslice_mixed_min_lengths(a, 3)); - run_test(|a| subslice_mixed_min_lengths(a, 4)); - run_test(|a| subslice_mixed_min_lengths(a, 5)); - run_test(|a| subslice_mixed_min_lengths(a, 6)); - run_test(|a| subslice_mixed_min_lengths(a, 7)); - - run_test(|a| move_ref_pattern(a)); - - run_test(|a| { + run_test!(|a| dynamic_init(a, false)); + run_test!(|a| dynamic_init(a, true)); + run_test!(|a| dynamic_drop(a, false)); + run_test!(|a| dynamic_drop(a, true)); + + run_test!(|a| assignment2(a, false, false)); + run_test!(|a| assignment2(a, false, true)); + run_test!(|a| assignment2(a, true, false)); + run_test!(|a| assignment2(a, true, true)); + + run_test!(|a| assignment1(a, false)); + run_test!(|a| assignment1(a, true)); + + run_test!(|a| array_simple(a)); + run_test!(|a| vec_simple(a)); + run_test!(|a| vec_unreachable(a)); + + run_test!(|a| struct_dynamic_drop(a, false, false, false)); + run_test!(|a| struct_dynamic_drop(a, false, false, true)); + run_test!(|a| struct_dynamic_drop(a, false, true, false)); + run_test!(|a| struct_dynamic_drop(a, false, true, true)); + run_test!(|a| struct_dynamic_drop(a, true, false, false)); + run_test!(|a| struct_dynamic_drop(a, true, false, true)); + run_test!(|a| struct_dynamic_drop(a, true, true, false)); + run_test!(|a| struct_dynamic_drop(a, true, true, true)); + + run_test!(|a| field_assignment(a, false)); + run_test!(|a| field_assignment(a, true)); + + run_test!(|a| generator(a, 0)); + run_test!(|a| generator(a, 1)); + run_test!(|a| generator(a, 2)); + run_test!(|a| generator(a, 3)); + + run_test!(|a| mixed_drop_and_nondrop(a)); + + run_test!(|a| slice_pattern_first(a)); + run_test!(|a| slice_pattern_middle(a)); + run_test!(|a| slice_pattern_two(a)); + run_test!(|a| slice_pattern_last(a)); + run_test!(|a| slice_pattern_one_of(a, 0)); + run_test!(|a| slice_pattern_one_of(a, 1)); + run_test!(|a| slice_pattern_one_of(a, 2)); + run_test!(|a| slice_pattern_one_of(a, 3)); + + run_test!(|a| subslice_pattern_from_end(a, true)); + run_test!(|a| subslice_pattern_from_end(a, false)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test!(|a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test!(|a| slice_pattern_reassign(a)); + run_test!(|a| subslice_pattern_reassign(a)); + + run_test!(|a| index_field_mixed_ends(a)); + run_test!(|a| subslice_mixed_min_lengths(a, 0)); + run_test!(|a| subslice_mixed_min_lengths(a, 1)); + run_test!(|a| subslice_mixed_min_lengths(a, 2)); + run_test!(|a| subslice_mixed_min_lengths(a, 3)); + run_test!(|a| subslice_mixed_min_lengths(a, 4)); + run_test!(|a| subslice_mixed_min_lengths(a, 5)); + run_test!(|a| subslice_mixed_min_lengths(a, 6)); + run_test!(|a| subslice_mixed_min_lengths(a, 7)); + + run_test!(|a| move_ref_pattern(a)); + + run_test!(|a| { panic_after_return(a); }); - run_test(|a| { + run_test!(|a| { panic_after_return_expr(a); }); - run_test(|a| panic_after_init(a)); - run_test(|a| panic_after_init_temp(a)); - run_test(|a| panic_after_init_by_loop(a)); - - run_test(|a| bindings_after_at_dynamic_init_move(a, true)); - run_test(|a| bindings_after_at_dynamic_init_move(a, false)); - run_test(|a| bindings_after_at_dynamic_init_ref(a, true)); - run_test(|a| bindings_after_at_dynamic_init_ref(a, false)); - run_test(|a| bindings_after_at_dynamic_drop_move(a, true)); - run_test(|a| bindings_after_at_dynamic_drop_move(a, false)); - run_test(|a| bindings_after_at_dynamic_drop_ref(a, true)); - run_test(|a| bindings_after_at_dynamic_drop_ref(a, false)); - - run_test_nopanic(|a| union1(a)); + run_test!(|a| panic_after_init(a)); + run_test!(|a| panic_after_init_temp(a)); + run_test!(|a| panic_after_init_by_loop(a)); + run_test!(|a| panic_after_init_by_match(a, false)); + run_test!(|a| panic_after_init_by_match(a, true)); + run_test!(|a| panic_after_init_by_match_with_guard(a, false)); + run_test!(|a| panic_after_init_by_match_with_guard(a, true)); + run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, false)); + run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, true)); + run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, false)); + run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, true)); + run_test!(|a| panic_after_init_by_break_if(a, false)); + run_test!(|a| panic_after_init_by_break_if(a, true)); + + run_test!(|a| bindings_after_at_dynamic_init_move(a, true)); + run_test!(|a| bindings_after_at_dynamic_init_move(a, false)); + run_test!(|a| bindings_after_at_dynamic_init_ref(a, true)); + run_test!(|a| bindings_after_at_dynamic_init_ref(a, false)); + run_test!(|a| bindings_after_at_dynamic_drop_move(a, true)); + run_test!(|a| bindings_after_at_dynamic_drop_move(a, false)); + run_test!(|a| bindings_after_at_dynamic_drop_ref(a, true)); + run_test!(|a| bindings_after_at_dynamic_drop_ref(a, false)); + + run_test_nopanic(|a| union1(a), "|a| union1(a)"); } From b1d78360f9eb05e93b7f00d7412729ecf0d9f983 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 5 Dec 2020 12:05:03 +0900 Subject: [PATCH 214/274] Ping me when nomicon's toolstate is broken --- src/tools/publish_toolstate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 7586f5aa3b5..0d4a755551a 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -28,7 +28,7 @@ 'rls': {'Xanewok'}, 'rustfmt': {'topecongiro', 'calebcartwright'}, 'book': {'carols10cents', 'steveklabnik'}, - 'nomicon': {'frewsxcv', 'Gankra'}, + 'nomicon': {'frewsxcv', 'Gankra', 'JohnTitor'}, 'reference': {'steveklabnik', 'Havvy', 'matthewjasper', 'ehuss'}, 'rust-by-example': {'steveklabnik', 'marioidival'}, 'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'}, From c2946402ffb5edde461b5047213e56b4e1500ec8 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 4 Dec 2020 18:37:21 -0500 Subject: [PATCH 215/274] Properly re-use def path hash in incremental mode Fixes #79661 In incremental compilation mode, we update a `DefPathHash -> DefId` mapping every time we create a `DepNode` for a foreign `DefId`. This mapping is written out to the on-disk incremental cache, and is read by the next compilation session to allow us to lazily decode `DefId`s. When we decode a `DepNode` from the current incremental cache, we need to ensure that any previously-recorded `DefPathHash -> DefId` mapping gets recorded in the new mapping that we write out. However, PR #74967 didn't do this in all cases, leading to us being unable to decode a `DefPathHash` in certain circumstances. This PR refactors some of the code around `DepNode` deserialization to prevent this kind of mistake from happening again. --- compiler/rustc_middle/src/ty/query/mod.rs | 2 +- .../src/dep_graph/dep_node.rs | 13 ++++++ .../rustc_query_system/src/dep_graph/graph.rs | 23 +++-------- .../rustc_query_system/src/dep_graph/prev.rs | 41 ++++++++++++++++++- src/test/incremental/auxiliary/issue-79661.rs | 6 +++ .../issue-79661-missing-def-path-hash.rs | 14 +++++++ 6 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 src/test/incremental/auxiliary/issue-79661.rs create mode 100644 src/test/incremental/issue-79661-missing-def-path-hash.rs diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index 187f86a52f4..b269dd09b72 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -220,7 +220,7 @@ pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &De .map(|c| c.is_green()) .unwrap_or(false)); - let key = as DepNodeParams>>::recover(tcx, dep_node).unwrap(); + let key = as DepNodeParams>>::recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); if queries::$name::cache_on_disk(tcx, &key, None) { let _ = tcx.$name(key); } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 3d9e739cd28..09e5dc857a7 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -53,6 +53,19 @@ use std::hash::Hash; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] pub struct DepNode { pub kind: K, + // Important - whenever a `DepNode` is constructed, we need to make + // sure to register a `DefPathHash -> DefId` mapping if needed. + // This is currently done in two places: + // + // * When a `DepNode::construct` is called, `arg.to_fingerprint()` + // is responsible for calling `OnDiskCache::store_foreign_def_id_hash` + // if needed + // * When a `DepNode` is loaded from the `PreviousDepGraph`, + // then `PreviousDepGraph::index_to_node` is responsible for calling + // `tcx.register_reused_dep_path_hash` + // + // FIXME: Enforce this by preventing manual construction of `DefNode` + // (e.g. add a `_priv: ()` field) pub hash: PackedFingerprint, } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index ac37b296b53..8bde552e2d4 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -7,7 +7,6 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; use rustc_data_structures::unlikely; use rustc_errors::Diagnostic; use rustc_index::vec::{Idx, IndexVec}; -use rustc_span::def_id::DefPathHash; use parking_lot::{Condvar, Mutex}; use smallvec::{smallvec, SmallVec}; @@ -555,7 +554,7 @@ impl DepGraph { // We never try to mark eval_always nodes as green debug_assert!(!dep_node.kind.is_eval_always()); - debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node); + data.previous.debug_assert_eq(prev_dep_node_index, *dep_node); let prev_deps = data.previous.edge_targets_from(prev_dep_node_index); @@ -573,7 +572,7 @@ impl DepGraph { "try_mark_previous_green({:?}) --- found dependency {:?} to \ be immediately green", dep_node, - data.previous.index_to_node(dep_dep_node_index) + data.previous.debug_dep_node(dep_dep_node_index), ); current_deps.push(node_index); } @@ -586,12 +585,12 @@ impl DepGraph { "try_mark_previous_green({:?}) - END - dependency {:?} was \ immediately red", dep_node, - data.previous.index_to_node(dep_dep_node_index) + data.previous.debug_dep_node(dep_dep_node_index) ); return None; } None => { - let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); + let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index, tcx); // We don't know the state of this dependency. If it isn't // an eval_always node, let's try to mark it green recursively. @@ -700,18 +699,6 @@ impl DepGraph { data.current.intern_node(*dep_node, current_deps, fingerprint) }; - // We have just loaded a deserialized `DepNode` from the previous - // compilation session into the current one. If this was a foreign `DefId`, - // then we stored additional information in the incr comp cache when we - // initially created its fingerprint (see `DepNodeParams::to_fingerprint`) - // We won't be calling `to_fingerprint` again for this `DepNode` (we no longer - // have the original value), so we need to copy over this additional information - // from the old incremental cache into the new cache that we serialize - // and the end of this compilation session. - if dep_node.kind.can_reconstruct_query_key() { - tcx.register_reused_dep_path_hash(DefPathHash(dep_node.hash.into())); - } - // ... emitting any stored diagnostic ... // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere @@ -814,7 +801,7 @@ impl DepGraph { for prev_index in data.colors.values.indices() { match data.colors.get(prev_index) { Some(DepNodeColor::Green(_)) => { - let dep_node = data.previous.index_to_node(prev_index); + let dep_node = data.previous.index_to_node(prev_index, tcx); tcx.try_load_from_on_disk_cache(&dep_node); } None | Some(DepNodeColor::Red) => { diff --git a/compiler/rustc_query_system/src/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs index 29357ce9449..9298b652da2 100644 --- a/compiler/rustc_query_system/src/dep_graph/prev.rs +++ b/compiler/rustc_query_system/src/dep_graph/prev.rs @@ -1,7 +1,9 @@ use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use super::{DepKind, DepNode}; +use crate::dep_graph::DepContext; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; +use rustc_span::def_id::DefPathHash; #[derive(Debug, Encodable, Decodable)] pub struct PreviousDepGraph { @@ -31,7 +33,44 @@ impl PreviousDepGraph { } #[inline] - pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode { + pub fn index_to_node>( + &self, + dep_node_index: SerializedDepNodeIndex, + tcx: CTX, + ) -> DepNode { + let dep_node = self.data.nodes[dep_node_index]; + // We have just loaded a deserialized `DepNode` from the previous + // compilation session into the current one. If this was a foreign `DefId`, + // then we stored additional information in the incr comp cache when we + // initially created its fingerprint (see `DepNodeParams::to_fingerprint`) + // We won't be calling `to_fingerprint` again for this `DepNode` (we no longer + // have the original value), so we need to copy over this additional information + // from the old incremental cache into the new cache that we serialize + // and the end of this compilation session. + if dep_node.kind.can_reconstruct_query_key() { + tcx.register_reused_dep_path_hash(DefPathHash(dep_node.hash.into())); + } + dep_node + } + + /// When debug assertions are enabled, asserts that the dep node at `dep_node_index` is equal to `dep_node`. + /// This method should be preferred over manually calling `index_to_node`. + /// Calls to `index_to_node` may affect global state, so gating a call + /// to `index_to_node` on debug assertions could cause behavior changes when debug assertions + /// are enabled. + #[inline] + pub fn debug_assert_eq(&self, dep_node_index: SerializedDepNodeIndex, dep_node: DepNode) { + debug_assert_eq!(self.data.nodes[dep_node_index], dep_node); + } + + /// Obtains a debug-printable version of the `DepNode`. + /// See `debug_assert_eq` for why this should be preferred over manually + /// calling `dep_node_index` + pub fn debug_dep_node(&self, dep_node_index: SerializedDepNodeIndex) -> impl std::fmt::Debug { + // We're returning the `DepNode` without calling `register_reused_dep_path_hash`, + // but `impl Debug` return type means that it can only be used for debug printing. + // So, there's no risk of calls trying to create new dep nodes that have this + // node as a dependency self.data.nodes[dep_node_index] } diff --git a/src/test/incremental/auxiliary/issue-79661.rs b/src/test/incremental/auxiliary/issue-79661.rs new file mode 100644 index 00000000000..cd32a52ebfd --- /dev/null +++ b/src/test/incremental/auxiliary/issue-79661.rs @@ -0,0 +1,6 @@ +#![feature(rustc_attrs)] + +#[cfg_attr(any(rpass2, rpass3), doc = "Some comment")] +pub struct Foo; + +pub struct Wrapper(Foo); diff --git a/src/test/incremental/issue-79661-missing-def-path-hash.rs b/src/test/incremental/issue-79661-missing-def-path-hash.rs new file mode 100644 index 00000000000..f86fb33fbf6 --- /dev/null +++ b/src/test/incremental/issue-79661-missing-def-path-hash.rs @@ -0,0 +1,14 @@ +// aux-build:issue-79661.rs +// revisions: rpass1 rpass2 rpass3 + +// Regression test for issue #79661 +// We were failing to copy over a DefPathHash->DefId mapping +// from the old incremental cache to the new incremental cache +// when we ended up forcing a query. As a result, a subsequent +// unchanged incremental run would crash due to the missing mapping + +extern crate issue_79661; +use issue_79661::Wrapper; + +pub struct Outer(Wrapper); +fn main() {} From e0e26b4bce7a229cd4f3fefd1d4857325f0542a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Dec 2020 10:02:18 +0100 Subject: [PATCH 216/274] update Miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index 47acece7aa2..e54c5db4f0e 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 47acece7aa25d7b5edfae0bfd4b94e6e55a7b4b0 +Subproject commit e54c5db4f0edbe51db42d2c3e63e9821537ed4f4 From 1734f9c29129b832f499ffdb9a782ff8ccf66187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 5 Dec 2020 12:59:54 +0100 Subject: [PATCH 217/274] remove redundant clones --- compiler/rustc_infer/src/infer/canonical/canonicalizer.rs | 2 +- compiler/rustc_middle/src/ty/fold.rs | 2 +- compiler/rustc_trait_selection/src/traits/query/normalize.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 6781fbc95c0..8a60b196e5e 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -505,7 +505,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { let canon_value = Canonical { max_universe: ty::UniverseIndex::ROOT, variables: List::empty(), - value: value.clone(), + value, }; return canon_value; } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 1883c89a151..13c8d6b2bcc 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -581,7 +581,7 @@ impl<'tcx> TyCtxt<'tcx> { let mut const_map = FxHashMap::default(); if !value.has_escaping_bound_vars() { - (value.clone(), region_map) + (value, region_map) } else { let mut real_fld_r = |br| *region_map.entry(br).or_insert_with(|| fld_r(br)); diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 54743ef9ce9..33cd509cbb8 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -49,7 +49,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { self.param_env, ); if !value.has_projections() { - return Ok(Normalized { value: value.clone(), obligations: vec![] }); + return Ok(Normalized { value, obligations: vec![] }); } let mut normalizer = QueryNormalizer { From 6845e22bbabce5631c388c52eb367168ce9b14ce Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Sat, 5 Dec 2020 14:40:56 +0000 Subject: [PATCH 218/274] Const parameters can not be inferred with `_` Small improvement. Thanks varkor Co-authored-by: varkor Bless --- compiler/rustc_typeck/src/astconv/generics.rs | 7 +++++++ .../ui/const-generics/issues/issue-62878.full.stderr | 2 ++ .../min_const_generics/inferred_const.rs | 8 ++++++++ .../min_const_generics/inferred_const.stderr | 11 +++++++++++ 4 files changed, 28 insertions(+) create mode 100644 src/test/ui/const-generics/min_const_generics/inferred_const.rs create mode 100644 src/test/ui/const-generics/min_const_generics/inferred_const.stderr diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 0db5fda272a..b7e77f389f8 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -44,6 +44,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // the match is non-exhaustive. _ => bug!("invalid generic parameter kind {}", kind), }; + + if let ParamKindOrd::Const { .. } = kind_ord { + if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg { + err.help("const arguments cannot yet be inferred with `_`"); + } + } + let arg_ord = match arg { GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, GenericArg::Type(_) => ParamKindOrd::Type, diff --git a/src/test/ui/const-generics/issues/issue-62878.full.stderr b/src/test/ui/const-generics/issues/issue-62878.full.stderr index fc70be40497..dce2e27c71a 100644 --- a/src/test/ui/const-generics/issues/issue-62878.full.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.full.stderr @@ -9,6 +9,8 @@ error[E0747]: type provided when a constant was expected | LL | foo::<_, {[1]}>(); | ^ + | + = help: const arguments cannot yet be inferred with `_` error[E0308]: mismatched types --> $DIR/issue-62878.rs:11:15 diff --git a/src/test/ui/const-generics/min_const_generics/inferred_const.rs b/src/test/ui/const-generics/min_const_generics/inferred_const.rs new file mode 100644 index 00000000000..dcd069ce3b0 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/inferred_const.rs @@ -0,0 +1,8 @@ +#![feature(min_const_generics)] +fn foo(data: [u32; N]) -> [u32; K] { + [0; K] +} +fn main() { + let a = foo::<_, 2>([0, 1, 2]); + //~^ ERROR type provided when a constant was expected +} diff --git a/src/test/ui/const-generics/min_const_generics/inferred_const.stderr b/src/test/ui/const-generics/min_const_generics/inferred_const.stderr new file mode 100644 index 00000000000..e17105b2aa9 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/inferred_const.stderr @@ -0,0 +1,11 @@ +error[E0747]: type provided when a constant was expected + --> $DIR/inferred_const.rs:6:19 + | +LL | let a = foo::<_, 2>([0, 1, 2]); + | ^ + | + = help: const arguments cannot yet be inferred with `_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0747`. From bd37d7d82769e493a670d5630a82d039e9090c1d Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sat, 5 Dec 2020 16:40:24 +0100 Subject: [PATCH 219/274] Update RLS and Rustfmt --- Cargo.lock | 116 ++++++++++++++++++++++++---------------------- src/tools/rls | 2 +- src/tools/rustfmt | 2 +- 3 files changed, 63 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85be4c392af..c9d6a8eb7a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1924,17 +1924,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -[[package]] -name = "md-5" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "opaque-debug 0.2.3", -] - [[package]] name = "md-5" version = "0.9.1" @@ -2695,9 +2684,9 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.40" +version = "2.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68c5fb83bc092c10e12ca863ab8922b1833382d5d248aaafca779886d3396a44" +checksum = "a2f1a4baaaf5c4a9aa30c708c339ae293d02976d2b7f1575a59f44558d25bfea" dependencies = [ "bitflags", "clap", @@ -3024,18 +3013,18 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_arena" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "477085eefed2f12085c68577cc3827c8c39a31a4a750978aacb9af10f7903174" +checksum = "81f7b9bc5a6f79b1f230833cb4c8f8928d48c129b21df5b372c202fb826c0b5e" dependencies = [ "smallvec 1.4.2", ] [[package]] name = "rustc-ap-rustc_ast" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4ad5ec25f6b3d122354595be0d1b513f37fca3299d9b448b1db28f4a9e4b12" +checksum = "3d77f313e9f30af93f2737f1a99d6552e26b702c5cef3bb65e35f5b4fe5191f1" dependencies = [ "bitflags", "rustc-ap-rustc_data_structures", @@ -3050,9 +3039,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast_passes" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6d8635298d7736decdb3c6e92e784d3eccde557462a9c10ac11a34fec3d756" +checksum = "30408fbf42fa6fbeb383d3fce0f24d2490c3d12527beb2f48e6e728765bc8695" dependencies = [ "itertools 0.9.0", "rustc-ap-rustc_ast", @@ -3069,9 +3058,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast_pretty" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a61bdb5252e1a95b7715038949e10f07ce770a436fcd497cdd9bc7255471de9" +checksum = "d47b8a3adcccc204578b0ee9cd2f9952921fa43977f58343913cca04cce87043" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_span", @@ -3081,9 +3070,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_attr" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84520a16cb61bd31e9c27e87eca5d933a9c94ac84f25649bddcc19989275ab2a" +checksum = "66f5f53ecdbf7d8b47905936f93eb1fdae496137e94b7e4023a0b866b0e1a92d" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", @@ -3100,9 +3089,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_data_structures" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cb2b6a38759cf7c0c1434c8b4cbfcab9cd24970d05f960f2ca01226ddb4d68" +checksum = "3aa913fa40b90157067b17dd7ddfd5df0d8566e339ffa8351a638bdf3fc7ee81" dependencies = [ "arrayvec", "bitflags", @@ -3131,13 +3120,14 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_errors" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46cfb19536426bf9252827a78552d635be207a4be74f4e92832aad82d7f2135c" +checksum = "5d4b4956287d7c4996409b8362aa69c0c9a6853751ff00ee0a6f78223c5ef3ad" dependencies = [ "annotate-snippets 0.8.0", "atty", "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_lint_defs", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", @@ -3150,9 +3140,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_expand" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6273e60042a0ef31f6cfe783c519873993eb426f055be2bc058a48b6ca3934d0" +checksum = "3fa908bb1b67230dd4309e93edefc6a6c2f3d8b6a195f77c47743c882114a22e" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_passes", @@ -3173,9 +3163,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_feature" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2936e8346157e2848305e509f38aa3ed4e97697975ef68027587f5db6a38703f" +checksum = "d9b7a1db115893ed7ed0db80f70d2246c1709de7854238acde76471495930f2a" dependencies = [ "rustc-ap-rustc_data_structures", "rustc-ap-rustc_span", @@ -3183,21 +3173,21 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_fs_util" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4c3ae17776b5a5aa441ca510a650f75805e1f5569edd231caa8378552195a4" +checksum = "55937887cb606cc72193ea3c5feb8bbbb810d812aa233b9a1e7749155c4a3501" [[package]] name = "rustc-ap-rustc_graphviz" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5611bf0ac0ac49c2a22c959c7d8b17f85f69959293f0e8c4f753eca832fe7ad0" +checksum = "e39e179e616356927f0c4eda43e3a35d88476f91e1ac8e4a0a09661dbab44a6e" [[package]] name = "rustc-ap-rustc_index" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca67cf37c427057192e451c7f912e94ae9a8ca5ad69fd481c011fad3f86982cb" +checksum = "572d3962d6999f3b1a71d335308e939e204339d4ad36e6ebe7a591c9d4329f5d" dependencies = [ "arrayvec", "rustc-ap-rustc_macros", @@ -3206,18 +3196,32 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_lexer" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b04cd2159495584d976d501c5394498470c2e94e4f0cebb8186562d407a678" +checksum = "44bc89d9ca7a78fb82e103b389362c55f03800745f8ba14e068b805cfaf783ec" dependencies = [ "unicode-xid", ] +[[package]] +name = "rustc-ap-rustc_lint_defs" +version = "691.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d39bda92aabd77e49ac8ad5e24fccf9d7245b8ff2bf1249ab98733e2e5a2863" +dependencies = [ + "rustc-ap-rustc_ast", + "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_macros", + "rustc-ap-rustc_serialize", + "rustc-ap-rustc_span", + "tracing", +] + [[package]] name = "rustc-ap-rustc_macros" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ec6d623853449acd3c65050d249d3674edab5f6e4d9f074c7bac183269f9c8" +checksum = "a3295fbc9625197494e356e92d8ac08370eddafa60189861c7b2f084b3b5a6b8" dependencies = [ "proc-macro2", "quote", @@ -3227,9 +3231,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_parse" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca524bafce4b04d2b49fee2d40b4b26c3ebab9f1a4f731fdf561f00617862f02" +checksum = "9ff5d0094396844efead43303a6eb25b8a4962e2c80fb0ea4a86e4101fbfd404" dependencies = [ "bitflags", "rustc-ap-rustc_ast", @@ -3247,9 +3251,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_serialize" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c67920561e58f98c4de864407c92b2dd05ace5d5e5301e17444f10f742c005b7" +checksum = "2d5cff6709a8b51a3730288a9ead17cabe8146b1c787db52298447ef7890140a" dependencies = [ "indexmap", "smallvec 1.4.2", @@ -3257,9 +3261,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_session" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0762fd855792e06ef639327237898e4e092ad68150e6a8e19aeb7dc06276ad7a" +checksum = "36bb15ef12174b5ed6419a7e4260a899ce8927e8c8fd1f0cddf178818737dcdf" dependencies = [ "bitflags", "getopts", @@ -3269,6 +3273,7 @@ dependencies = [ "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", "rustc-ap-rustc_fs_util", + "rustc-ap-rustc_lint_defs", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", @@ -3278,28 +3283,29 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_span" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf3db7b4ca5d21c14c45475df155e5e020c9a3760346945a662c9a9053b49c8" +checksum = "104d349a32be9cfd3d39a5a70ad6c5e682ce262fc5cc8717d35a01e980c0d8b2" dependencies = [ "cfg-if 0.1.10", - "md-5 0.8.0", + "md-5", "rustc-ap-rustc_arena", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_index", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "scoped-tls", - "sha-1 0.8.2", + "sha-1 0.9.1", + "sha2", "tracing", "unicode-width", ] [[package]] name = "rustc-ap-rustc_target" -version = "686.0.0" +version = "691.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa6560bb9742b276064d67ab9edb5766ecb303f8ae3854835ad3fad4b432188" +checksum = "9d7ac4ded9a6aecb534744c836a160497985f0d53b272581e95e7890d31b9e17" dependencies = [ "bitflags", "rustc-ap-rustc_data_structures", @@ -4144,7 +4150,7 @@ name = "rustc_span" version = "0.0.0" dependencies = [ "cfg-if 0.1.10", - "md-5 0.9.1", + "md-5", "rustc_arena", "rustc_data_structures", "rustc_index", @@ -4335,7 +4341,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.27" +version = "1.4.28" dependencies = [ "annotate-snippets 0.6.1", "anyhow", diff --git a/src/tools/rls b/src/tools/rls index dab1468d6ae..9b457351f2d 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit dab1468d6aeed0e49f7d0569c1d2128b5a7751e0 +Subproject commit 9b457351f2db8aa436fcf7b46a93e5c2c0e89630 diff --git a/src/tools/rustfmt b/src/tools/rustfmt index 580d826e9b0..29f33eb7d67 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit 580d826e9b0f407a2d4b36696cda2f0fa8d7ddaa +Subproject commit 29f33eb7d67d729c095a7ac9bce702f6351396ba From d366ed2730ed4a11df8a18f440c6874f7fa610f2 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 5 Dec 2020 17:32:19 +0100 Subject: [PATCH 220/274] abort() now takes a msg parameter --- compiler/rustc_mir/src/const_eval/error.rs | 2 ++ compiler/rustc_mir/src/interpret/intrinsics.rs | 4 ++-- compiler/rustc_mir/src/interpret/machine.rs | 6 ++++-- compiler/rustc_mir/src/interpret/terminator.rs | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 39358e03e75..345a3d7e79b 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -20,6 +20,7 @@ pub enum ConstEvalErrKind { ModifiedGlobal, AssertFailure(AssertKind), Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, + Abort(String), } // The errors become `MachineStop` with plain strings when being raised. @@ -46,6 +47,7 @@ impl fmt::Display for ConstEvalErrKind { Panic { msg, line, col, file } => { write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) } + Abort(ref msg) => write!(f, "{}", msg) } } } diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 90018673e1a..18abf4291b1 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -126,7 +126,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { None => match intrinsic_name { sym::transmute => throw_ub_format!("transmuting to uninhabited type"), sym::unreachable => throw_ub!(Unreachable), - sym::abort => M::abort(self)?, + sym::abort => M::abort(self, "aborted execution".to_owned())?, // Unsupported diverging intrinsic. _ => return Ok(false), }, @@ -412,7 +412,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of(ty)?; if layout.abi.is_uninhabited() { - throw_ub_format!("attempted to instantiate uninhabited type `{}`", ty); + M::abort(self, format!("attempted to instantiate uninhabited type `{}`", ty))?; } } sym::simd_insert => { diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 66dbacb2f9d..1c13cdbc6e6 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -176,8 +176,10 @@ pub trait Machine<'mir, 'tcx>: Sized { ) -> InterpResult<'tcx>; /// Called to evaluate `Abort` MIR terminator. - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { - throw_unsup_format!("aborting execution is not supported") + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + use crate::const_eval::ConstEvalErrKind; + + Err(ConstEvalErrKind::Abort(msg).into()) } /// Called for all binary operations where the LHS has pointer type. diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index bb11c2a23bd..18079488c89 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Abort => { - M::abort(self)?; + M::abort(self, "aborted execution".to_owned())?; } // When we encounter Resume, we've finished unwinding From 2fa30ecf77ce6b6da48c606c04484261383e6aae Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sat, 5 Dec 2020 18:08:33 +0100 Subject: [PATCH 221/274] Add libc to rustc-workspace-hack --- Cargo.lock | 1 + src/tools/rustc-workspace-hack/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c9d6a8eb7a2..4fe24f06886 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3392,6 +3392,7 @@ version = "1.0.0" dependencies = [ "byteorder", "crossbeam-utils 0.7.2", + "libc", "proc-macro2", "quote", "serde", diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 337d65e4da4..11b175f9e80 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -64,6 +64,7 @@ features = [ byteorder = { version = "1", features = ['default', 'std'] } curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true } crossbeam-utils = { version = "0.7.2", features = ["nightly"] } +libc = { version = "0.2.79", features = ["align"] } proc-macro2 = { version = "1", features = ["default"] } quote = { version = "1", features = ["default"] } serde = { version = "1.0.82", features = ['derive'] } From 7bd754cf8ca8e4b673f5432c837150b53c8d713d Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 5 Dec 2020 18:39:10 +0100 Subject: [PATCH 222/274] Fix tests (hopefully) --- compiler/rustc_mir/src/const_eval/error.rs | 2 +- library/core/tests/mem.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 345a3d7e79b..0e610e37552 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -47,7 +47,7 @@ impl fmt::Display for ConstEvalErrKind { Panic { msg, line, col, file } => { write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) } - Abort(ref msg) => write!(f, "{}", msg) + Abort(ref msg) => write!(f, "{}", msg), } } } diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 7822c69d10b..f2e441de30b 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -132,7 +132,7 @@ fn test_discriminant_send_sync() { #[test] fn assume_init_good() { - const TRUE: bool = { + const TRUE: bool = unsafe { let mut x = MaybeUninit::::uninit(); x.as_mut_ptr().write(true); x.assume_init() @@ -143,7 +143,7 @@ fn assume_init_good() { #[test] #[should_panic] fn assume_init_bad() { - const BAD: () = { + const BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); }; } From 94762417e8957caa5db219e11be58c4de5def4c6 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 5 Dec 2020 19:37:03 +0100 Subject: [PATCH 223/274] Still unable to get the tests working --- library/core/tests/lib.rs | 2 ++ library/core/tests/mem.rs | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 106c9fe5da3..9e7a8189c81 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -11,6 +11,7 @@ #![feature(cfg_target_has_atomic)] #![feature(const_assume)] #![feature(const_cell_into_inner)] +#![feature(const_maybe_uninit_assume_init)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -53,6 +54,7 @@ #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] +#![feature(const_assert_type)] #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(option_unwrap_none)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index f2e441de30b..4ebcf27e173 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -132,18 +132,17 @@ fn test_discriminant_send_sync() { #[test] fn assume_init_good() { - const TRUE: bool = unsafe { - let mut x = MaybeUninit::::uninit(); - x.as_mut_ptr().write(true); - x.assume_init() - }; + const TRUE: bool = unsafe { MaybeUninit::::new(true).assume_init() }; + assert!(TRUE); } #[test] -#[should_panic] fn assume_init_bad() { - const BAD: () = unsafe { + const _BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); + //~^ ERROR the type `!` does not permit being left uninitialized + //~| ERROR this code causes undefined behavior when executed + //~| ERROR help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done }; } From 898b7c594cfdf1eb56d24a4c6fa02678cf5029a8 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sat, 5 Dec 2020 20:59:53 +0000 Subject: [PATCH 224/274] Renamed the configuraiton to unreadable-literal-lint-fractions --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- tests/ui-toml/lint_decimal_readability/clippy.toml | 2 +- tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 58e91dd32bd..2b99ed570b1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1138,7 +1138,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); - let literal_representation_lint_fraction_readability = conf.lint_fraction_readability; + let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability)); let literal_representation_threshold = conf.literal_representation_threshold; store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index c9d5f781f1b..6403ff6dad1 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -171,7 +171,7 @@ define_Conf! { /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses (disallowed_methods, "disallowed_methods": Vec, Vec::::new()), /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators. - (lint_fraction_readability, "lint_fraction_readability": bool, true), + (unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true), } impl Default for Conf { diff --git a/tests/ui-toml/lint_decimal_readability/clippy.toml b/tests/ui-toml/lint_decimal_readability/clippy.toml index 635e282dc06..6feaf7d5c0c 100644 --- a/tests/ui-toml/lint_decimal_readability/clippy.toml +++ b/tests/ui-toml/lint_decimal_readability/clippy.toml @@ -1 +1 @@ -lint-fraction-readability = false \ No newline at end of file +unreadable-literal-lint-fractions = false \ No newline at end of file diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index eff4da7e658..7b3c476461d 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `lint-fraction-readability`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `third-party` at line 5 column 1 error: aborting due to previous error From c254a15906d6ad64821659b50c4265c96b113159 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sat, 5 Dec 2020 22:23:17 +0000 Subject: [PATCH 225/274] Use true ID for def_id. --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/json/mod.rs | 7 +- src/librustdoc/json/types.rs | 78 +++++----- src/test/rustdoc-json/nested.expected | 196 ++++++++++++++++++++++++++ src/test/rustdoc-json/nested.rs | 7 + 5 files changed, 249 insertions(+), 41 deletions(-) create mode 100644 src/test/rustdoc-json/nested.expected create mode 100644 src/test/rustdoc-json/nested.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8c344338de7..16274430902 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2263,7 +2263,7 @@ impl Clean> for doctree::Import<'_> { name: None, attrs: self.attrs.clean(cx), source: self.span.clean(cx), - def_id: DefId::local(CRATE_DEF_INDEX), + def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: None, const_stability: None, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index c080ad21c0f..5f640bfddf1 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -151,7 +151,12 @@ impl FormatRenderer for JsonRenderer { } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner { e.impls = self.get_impls(id, cache) } - self.index.borrow_mut().insert(id.into(), new_item); + let removed = self.index.borrow_mut().insert(id.into(), new_item.clone()); + // FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check + // to make sure the items are unique. + if let Some(old_item) = removed { + assert_eq!(old_item, new_item); + } } Ok(()) diff --git a/src/librustdoc/json/types.rs b/src/librustdoc/json/types.rs index 10bf2a2acc5..9335fe9be1a 100644 --- a/src/librustdoc/json/types.rs +++ b/src/librustdoc/json/types.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow /// tools to find or link to them. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Crate { /// The id of the root [`Module`] item of the local crate. pub root: Id, @@ -31,7 +31,7 @@ pub struct Crate { pub format_version: u32, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct ExternalCrate { pub name: String, pub html_root_url: Option, @@ -41,7 +41,7 @@ pub struct ExternalCrate { /// information. This struct should contain enough to generate a link/reference to the item in /// question, or can be used by a tool that takes the json output of multiple crates to find /// the actual item definition with all the relevant info. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct ItemSummary { /// Can be used to look up the name and html_root_url of the crate this item came from in the /// `external_crates` map. @@ -53,7 +53,7 @@ pub struct ItemSummary { pub kind: ItemKind, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Item { /// The unique identifier of this item. Can be used to find this item in various mappings. pub id: Id, @@ -79,7 +79,7 @@ pub struct Item { pub inner: ItemEnum, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Span { /// The path to the source file for this span relative to the path `rustdoc` was invoked with. pub filename: PathBuf, @@ -89,14 +89,14 @@ pub struct Span { pub end: (usize, usize), } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Deprecation { pub since: Option, pub note: Option, } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum Visibility { Public, /// For the most part items are private by default. The exceptions are associated items of @@ -112,7 +112,7 @@ pub enum Visibility { } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum GenericArgs { /// <'a, 32, B: Copy, C = u32> AngleBracketed { args: Vec, bindings: Vec }, @@ -121,14 +121,14 @@ pub enum GenericArgs { } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum GenericArg { Lifetime(String), Type(Type), Const(Constant), } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Constant { #[serde(rename = "type")] pub type_: Type, @@ -137,14 +137,14 @@ pub struct Constant { pub is_literal: bool, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct TypeBinding { pub name: String, pub binding: TypeBindingKind, } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum TypeBindingKind { Equality(Type), Constraint(Vec), @@ -154,7 +154,7 @@ pub enum TypeBindingKind { pub struct Id(pub String); #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum ItemKind { Module, ExternCrate, @@ -184,7 +184,7 @@ pub enum ItemKind { } #[serde(untagged)] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum ItemEnum { ModuleItem(Module), ExternCrateItem { @@ -231,13 +231,13 @@ pub enum ItemEnum { }, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Module { pub is_crate: bool, pub items: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Struct { pub struct_type: StructType, pub generics: Generics, @@ -246,7 +246,7 @@ pub struct Struct { pub impls: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Enum { pub generics: Generics, pub variants_stripped: bool, @@ -256,7 +256,7 @@ pub struct Enum { #[serde(rename_all = "snake_case")] #[serde(tag = "variant_kind", content = "variant_inner")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum Variant { Plain, Tuple(Vec), @@ -264,14 +264,14 @@ pub enum Variant { } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum StructType { Plain, Tuple, Unit, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Function { pub decl: FnDecl, pub generics: Generics, @@ -279,7 +279,7 @@ pub struct Function { pub abi: String, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Method { pub decl: FnDecl, pub generics: Generics, @@ -287,20 +287,20 @@ pub struct Method { pub has_body: bool, } -#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] pub struct Generics { pub params: Vec, pub where_predicates: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct GenericParamDef { pub name: String, pub kind: GenericParamDefKind, } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum GenericParamDefKind { Lifetime, Type { bounds: Vec, default: Option }, @@ -308,7 +308,7 @@ pub enum GenericParamDefKind { } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: String, bounds: Vec }, @@ -316,7 +316,7 @@ pub enum WherePredicate { } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum GenericBound { TraitBound { #[serde(rename = "trait")] @@ -329,7 +329,7 @@ pub enum GenericBound { } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum TraitBoundModifier { None, Maybe, @@ -338,7 +338,7 @@ pub enum TraitBoundModifier { #[serde(rename_all = "snake_case")] #[serde(tag = "kind", content = "inner")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum Type { /// Structs, enums, and traits ResolvedPath { @@ -391,7 +391,7 @@ pub enum Type { }, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct FunctionPointer { pub is_unsafe: bool, pub generic_params: Vec, @@ -399,14 +399,14 @@ pub struct FunctionPointer { pub abi: String, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct FnDecl { pub inputs: Vec<(String, Type)>, pub output: Option, pub c_variadic: bool, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Trait { pub is_auto: bool, pub is_unsafe: bool, @@ -416,13 +416,13 @@ pub struct Trait { pub implementors: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct TraitAlias { pub generics: Generics, pub params: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Impl { pub is_unsafe: bool, pub generics: Generics, @@ -438,7 +438,7 @@ pub struct Impl { } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Import { /// The full path being imported. pub span: String, @@ -451,14 +451,14 @@ pub struct Import { pub glob: bool, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct ProcMacro { pub kind: MacroKind, pub helpers: Vec, } #[serde(rename_all = "snake_case")] -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum MacroKind { /// A bang macro `foo!()`. Bang, @@ -468,20 +468,20 @@ pub enum MacroKind { Derive, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Typedef { #[serde(rename = "type")] pub type_: Type, pub generics: Generics, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct OpaqueTy { pub bounds: Vec, pub generics: Generics, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Static { #[serde(rename = "type")] pub type_: Type, diff --git a/src/test/rustdoc-json/nested.expected b/src/test/rustdoc-json/nested.expected new file mode 100644 index 00000000000..65bb0c5fa03 --- /dev/null +++ b/src/test/rustdoc-json/nested.expected @@ -0,0 +1,196 @@ +{ + "crate_version": null, + "external_crates": {}, + "format_version": 1, + "includes_private": false, + "index": { + "0:0": { + "attrs": [], + "crate_id": 0, + "deprecation": null, + "docs": "", + "id": "0:0", + "inner": { + "is_crate": true, + "items": [ + "0:3" + ] + }, + "kind": "module", + "links": {}, + "name": "nested", + "source": { + "begin": [ + 2, + 0 + ], + "end": [ + 7, + 1 + ], + "filename": "$TEST_BASE_DIR/nested.rs" + }, + "visibility": "public" + }, + "0:3": { + "attrs": [], + "crate_id": 0, + "deprecation": null, + "docs": "", + "id": "0:3", + "inner": { + "is_crate": false, + "items": [ + "0:7", + "0:4" + ] + }, + "kind": "module", + "links": {}, + "name": "l1", + "source": { + "begin": [ + 2, + 0 + ], + "end": [ + 7, + 1 + ], + "filename": "$TEST_BASE_DIR/nested.rs" + }, + "visibility": "public" + }, + "0:4": { + "attrs": [], + "crate_id": 0, + "deprecation": null, + "docs": "", + "id": "0:4", + "inner": { + "is_crate": false, + "items": [ + "0:5" + ] + }, + "kind": "module", + "links": {}, + "name": "l3", + "source": { + "begin": [ + 3, + 4 + ], + "end": [ + 5, + 5 + ], + "filename": "$TEST_BASE_DIR/nested.rs" + }, + "visibility": "public" + }, + "0:5": { + "attrs": [], + "crate_id": 0, + "deprecation": null, + "docs": "", + "id": "0:5", + "inner": { + "fields": [], + "fields_stripped": false, + "generics": { + "params": [], + "where_predicates": [] + }, + "impls": [ + "0:10", + "0:11", + "0:12", + "0:14", + "0:15" + ], + "struct_type": "unit" + }, + "kind": "struct", + "links": {}, + "name": "L4", + "source": { + "begin": [ + 4, + 8 + ], + "end": [ + 4, + 22 + ], + "filename": "$TEST_BASE_DIR/nested.rs" + }, + "visibility": "public" + }, + "0:7": { + "attrs": [], + "crate_id": 0, + "deprecation": null, + "docs": "", + "id": "0:7", + "inner": { + "glob": false, + "id": "0:5", + "name": "L4", + "span": "l3::L4" + }, + "kind": "import", + "links": {}, + "name": null, + "source": { + "begin": [ + 6, + 4 + ], + "end": [ + 6, + 19 + ], + "filename": "$TEST_BASE_DIR/nested.rs" + }, + "visibility": "public" + } + }, + "paths": { + "0:0": { + "crate_id": 0, + "kind": "module", + "path": [ + "nested" + ] + }, + "0:3": { + "crate_id": 0, + "kind": "module", + "path": [ + "nested", + "l1" + ] + }, + "0:4": { + "crate_id": 0, + "kind": "module", + "path": [ + "nested", + "l1", + "l3" + ] + }, + "0:5": { + "crate_id": 0, + "kind": "struct", + "path": [ + "nested", + "l1", + "l3", + "L4" + ] + } + }, + "root": "0:0" +} \ No newline at end of file diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs new file mode 100644 index 00000000000..e460b343d37 --- /dev/null +++ b/src/test/rustdoc-json/nested.rs @@ -0,0 +1,7 @@ +// edition:2018 +pub mod l1 { + pub mod l3 { + pub struct L4; + } + pub use l3::L4; +} From bc8317a12aff35c6a85d7727628429f0f3758234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 6 Dec 2020 00:00:00 +0000 Subject: [PATCH 226/274] Compress RWU from at least 32 bits to 4 bits The liveness uses a mixed representation of RWUs based on the observation that most of them have invalid reader and invalid writer. The packed variant uses 32 bits and unpacked 96 bits. Unpacked data contains reader live node and writer live node. Since live nodes are used only to determine their validity, RWUs can always be stored in a packed form with four bits for each: reader bit, writer bit, used bit, and one extra padding bit to simplify packing and unpacking operations. --- compiler/rustc_passes/src/liveness.rs | 305 ++++++++++++-------------- 1 file changed, 146 insertions(+), 159 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index debb873beb9..8c4fe549d12 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -470,96 +470,144 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { #[derive(Clone, Copy)] struct RWU { - reader: Option, - writer: Option, + reader: bool, + writer: bool, used: bool, } -/// Conceptually, this is like a `Vec`. But the number of `RWU`s can get -/// very large, so it uses a more compact representation that takes advantage -/// of the fact that when the number of `RWU`s is large, most of them have an -/// invalid reader and an invalid writer. +/// Conceptually, this is like a `Vec>`. But the number of +/// RWU`s can get very large, so it uses a more compact representation. struct RWUTable { - /// Each entry in `packed_rwus` is either INV_INV_FALSE, INV_INV_TRUE, or - /// an index into `unpacked_rwus`. In the common cases, this compacts the - /// 65 bits of data into 32; in the uncommon cases, it expands the 65 bits - /// in 96. + /// Total number of live nodes. + live_nodes: usize, + /// Total number of variables. + vars: usize, + + /// A compressed representation of `RWU`s. + /// + /// Each word represents 2 different `RWU`s packed together. Each packed RWU + /// is stored in 4 bits: a reader bit, a writer bit, a used bit and a + /// padding bit. /// - /// More compact representations are possible -- e.g., use only 2 bits per - /// packed `RWU` and make the secondary table a HashMap that maps from - /// indices to `RWU`s -- but this one strikes a good balance between size - /// and speed. - packed_rwus: Vec, - unpacked_rwus: Vec, + /// The data for each live node is contiguous and starts at a word boundary, + /// so there might be an unused space left. + words: Vec, + /// Number of words per each live node. + live_node_words: usize, } -// A constant representing `RWU { reader: None; writer: None; used: false }`. -const INV_INV_FALSE: u32 = u32::MAX; - -// A constant representing `RWU { reader: None; writer: None; used: true }`. -const INV_INV_TRUE: u32 = u32::MAX - 1; - impl RWUTable { - fn new(num_rwus: usize) -> RWUTable { - Self { packed_rwus: vec![INV_INV_FALSE; num_rwus], unpacked_rwus: vec![] } + const RWU_READER: u8 = 0b0001; + const RWU_WRITER: u8 = 0b0010; + const RWU_USED: u8 = 0b0100; + const RWU_MASK: u8 = 0b1111; + + /// Size of packed RWU in bits. + const RWU_BITS: usize = 4; + /// Size of a word in bits. + const WORD_BITS: usize = std::mem::size_of::() * 8; + /// Number of packed RWUs that fit into a single word. + const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS; + + fn new(live_nodes: usize, vars: usize) -> RWUTable { + let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT; + Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] } + } + + fn word_and_shift(&self, ln: LiveNode, var: Variable) -> (usize, u32) { + assert!(ln.index() < self.live_nodes); + assert!(var.index() < self.vars); + + let var = var.index(); + let word = var / Self::WORD_RWU_COUNT; + let shift = Self::RWU_BITS * (var % Self::WORD_RWU_COUNT); + (ln.index() * self.live_node_words + word, shift as u32) + } + + fn pick2_rows_mut(&mut self, a: LiveNode, b: LiveNode) -> (&mut [u8], &mut [u8]) { + assert!(a.index() < self.live_nodes); + assert!(b.index() < self.live_nodes); + assert!(a != b); + + let a_start = a.index() * self.live_node_words; + let b_start = b.index() * self.live_node_words; + + unsafe { + let ptr = self.words.as_mut_ptr(); + ( + std::slice::from_raw_parts_mut(ptr.add(a_start), self.live_node_words), + std::slice::from_raw_parts_mut(ptr.add(b_start), self.live_node_words), + ) + } } - fn get(&self, idx: usize) -> RWU { - let packed_rwu = self.packed_rwus[idx]; - match packed_rwu { - INV_INV_FALSE => RWU { reader: None, writer: None, used: false }, - INV_INV_TRUE => RWU { reader: None, writer: None, used: true }, - _ => self.unpacked_rwus[packed_rwu as usize], + fn copy(&mut self, dst: LiveNode, src: LiveNode) { + if dst == src { + return; } + + let (dst_row, src_row) = self.pick2_rows_mut(dst, src); + dst_row.copy_from_slice(src_row); } - fn get_reader(&self, idx: usize) -> Option { - let packed_rwu = self.packed_rwus[idx]; - match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => None, - _ => self.unpacked_rwus[packed_rwu as usize].reader, + /// Sets `dst` to the union of `dst` and `src`, returns true if `dst` was + /// changed. + fn union(&mut self, dst: LiveNode, src: LiveNode) -> bool { + if dst == src { + return false; } - } - fn get_writer(&self, idx: usize) -> Option { - let packed_rwu = self.packed_rwus[idx]; - match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => None, - _ => self.unpacked_rwus[packed_rwu as usize].writer, + let mut changed = false; + let (dst_row, src_row) = self.pick2_rows_mut(dst, src); + for (dst_word, src_word) in dst_row.iter_mut().zip(src_row.iter()) { + let old = *dst_word; + let new = *dst_word | src_word; + *dst_word = new; + changed |= old != new; } + changed } - fn get_used(&self, idx: usize) -> bool { - let packed_rwu = self.packed_rwus[idx]; - match packed_rwu { - INV_INV_FALSE => false, - INV_INV_TRUE => true, - _ => self.unpacked_rwus[packed_rwu as usize].used, - } + fn get_reader(&self, ln: LiveNode, var: Variable) -> bool { + let (word, shift) = self.word_and_shift(ln, var); + (self.words[word] >> shift) & Self::RWU_READER != 0 } - #[inline] - fn copy_packed(&mut self, dst_idx: usize, src_idx: usize) { - self.packed_rwus[dst_idx] = self.packed_rwus[src_idx]; + fn get_writer(&self, ln: LiveNode, var: Variable) -> bool { + let (word, shift) = self.word_and_shift(ln, var); + (self.words[word] >> shift) & Self::RWU_WRITER != 0 } - fn assign_unpacked(&mut self, idx: usize, rwu: RWU) { - if rwu.reader == None && rwu.writer == None { - // When we overwrite an indexing entry in `self.packed_rwus` with - // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry - // from `self.unpacked_rwus`; it's not worth the effort, and we - // can't have entries shifting around anyway. - self.packed_rwus[idx] = if rwu.used { INV_INV_TRUE } else { INV_INV_FALSE } - } else { - // Add a new RWU to `unpacked_rwus` and make `packed_rwus[idx]` - // point to it. - self.packed_rwus[idx] = self.unpacked_rwus.len() as u32; - self.unpacked_rwus.push(rwu); + fn get_used(&self, ln: LiveNode, var: Variable) -> bool { + let (word, shift) = self.word_and_shift(ln, var); + (self.words[word] >> shift) & Self::RWU_USED != 0 + } + + fn get(&self, ln: LiveNode, var: Variable) -> RWU { + let (word, shift) = self.word_and_shift(ln, var); + let rwu_packed = self.words[word] >> shift; + RWU { + reader: rwu_packed & Self::RWU_READER != 0, + writer: rwu_packed & Self::RWU_WRITER != 0, + used: rwu_packed & Self::RWU_USED != 0, } } - fn assign_inv_inv(&mut self, idx: usize) { - self.packed_rwus[idx] = if self.get_used(idx) { INV_INV_TRUE } else { INV_INV_FALSE }; + fn set(&mut self, ln: LiveNode, var: Variable, rwu: RWU) { + let mut packed = 0; + if rwu.reader { + packed |= Self::RWU_READER; + } + if rwu.writer { + packed |= Self::RWU_WRITER; + } + if rwu.used { + packed |= Self::RWU_USED; + } + + let (word, shift) = self.word_and_shift(ln, var); + let word = &mut self.words[word]; + *word = (*word & !(Self::RWU_MASK << shift)) | (packed << shift) } } @@ -613,7 +661,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { upvars, closure_captures, successors: IndexVec::from_elem_n(None, num_live_nodes), - rwu_table: RWUTable::new(num_live_nodes * num_vars), + rwu_table: RWUTable::new(num_live_nodes, num_vars), closure_ln, exit_ln, break_ln: Default::default(), @@ -652,61 +700,37 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { succ } - fn idx(&self, ln: LiveNode, var: Variable) -> usize { - ln.index() * self.ir.var_kinds.len() + var.index() - } - - fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option { - if let Some(reader) = self.rwu_table.get_reader(self.idx(ln, var)) { - Some(self.ir.lnks[reader]) - } else { - None - } + fn live_on_entry(&self, ln: LiveNode, var: Variable) -> bool { + self.rwu_table.get_reader(ln, var) } // Is this variable live on entry to any of its successor nodes? - fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option { + fn live_on_exit(&self, ln: LiveNode, var: Variable) -> bool { let successor = self.successors[ln].unwrap(); self.live_on_entry(successor, var) } fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool { - self.rwu_table.get_used(self.idx(ln, var)) + self.rwu_table.get_used(ln, var) } - fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option { - if let Some(writer) = self.rwu_table.get_writer(self.idx(ln, var)) { - Some(self.ir.lnks[writer]) - } else { - None - } + fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> bool { + self.rwu_table.get_writer(ln, var) } - fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option { + fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> bool { let successor = self.successors[ln].unwrap(); self.assigned_on_entry(successor, var) } - fn indices2(&mut self, ln: LiveNode, succ_ln: LiveNode, mut op: F) + fn write_vars(&self, wr: &mut dyn Write, mut test: F) -> io::Result<()> where - F: FnMut(&mut Liveness<'a, 'tcx>, usize, usize), + F: FnMut(Variable) -> bool, { - let node_base_idx = self.idx(ln, Variable::from(0u32)); - let succ_base_idx = self.idx(succ_ln, Variable::from(0u32)); for var_idx in 0..self.ir.var_kinds.len() { - op(self, node_base_idx + var_idx, succ_base_idx + var_idx); - } - } - - fn write_vars(&self, wr: &mut dyn Write, ln: LiveNode, mut test: F) -> io::Result<()> - where - F: FnMut(usize) -> bool, - { - let node_base_idx = self.idx(ln, Variable::from(0u32)); - for var_idx in 0..self.ir.var_kinds.len() { - let idx = node_base_idx + var_idx; - if test(idx) { - write!(wr, " {:?}", Variable::from(var_idx))?; + let var = Variable::from(var_idx); + if test(var) { + write!(wr, " {:?}", var)?; } } Ok(()) @@ -718,11 +742,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { { let wr = &mut wr as &mut dyn Write; write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]); - self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_some()); + self.write_vars(wr, |var| self.rwu_table.get_reader(ln, var)); write!(wr, " writes"); - self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_some()); + self.write_vars(wr, |var| self.rwu_table.get_writer(ln, var)); write!(wr, " uses"); - self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx)); + self.write_vars(wr, |var| self.rwu_table.get_used(ln, var)); write!(wr, " precedes {:?}]", self.successors[ln]); } @@ -747,17 +771,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.successors[ln] = Some(succ_ln); // It is not necessary to initialize the RWUs here because they are all - // set to INV_INV_FALSE when they are created, and the sets only grow - // during iterations. + // empty when created, and the sets only grow during iterations. } fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) { // more efficient version of init_empty() / merge_from_succ() self.successors[ln] = Some(succ_ln); - - self.indices2(ln, succ_ln, |this, idx, succ_idx| { - this.rwu_table.copy_packed(idx, succ_idx); - }); + self.rwu_table.copy(ln, succ_ln); debug!("init_from_succ(ln={}, succ={})", self.ln_str(ln), self.ln_str(succ_ln)); } @@ -766,81 +786,48 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { return false; } - let mut any_changed = false; - self.indices2(ln, succ_ln, |this, idx, succ_idx| { - // This is a special case, pulled out from the code below, where we - // don't have to do anything. It occurs about 60-70% of the time. - if this.rwu_table.packed_rwus[succ_idx] == INV_INV_FALSE { - return; - } - - let mut changed = false; - let mut rwu = this.rwu_table.get(idx); - let succ_rwu = this.rwu_table.get(succ_idx); - if succ_rwu.reader.is_some() && rwu.reader.is_none() { - rwu.reader = succ_rwu.reader; - changed = true - } - - if succ_rwu.writer.is_some() && rwu.writer.is_none() { - rwu.writer = succ_rwu.writer; - changed = true - } - - if succ_rwu.used && !rwu.used { - rwu.used = true; - changed = true; - } - - if changed { - this.rwu_table.assign_unpacked(idx, rwu); - any_changed = true; - } - }); - + let changed = self.rwu_table.union(ln, succ_ln); debug!( "merge_from_succ(ln={:?}, succ={}, first_merge={}, changed={})", ln, self.ln_str(succ_ln), first_merge, - any_changed + changed ); - any_changed + changed } // Indicates that a local variable was *defined*; we know that no // uses of the variable can precede the definition (resolve checks // this) so we just clear out all the data. fn define(&mut self, writer: LiveNode, var: Variable) { - let idx = self.idx(writer, var); - self.rwu_table.assign_inv_inv(idx); - - debug!("{:?} defines {:?} (idx={}): {}", writer, var, idx, self.ln_str(writer)); + let used = self.rwu_table.get_used(writer, var); + self.rwu_table.set(writer, var, RWU { reader: false, writer: false, used }); + debug!("{:?} defines {:?}: {}", writer, var, self.ln_str(writer)); } // Either read, write, or both depending on the acc bitset fn acc(&mut self, ln: LiveNode, var: Variable, acc: u32) { debug!("{:?} accesses[{:x}] {:?}: {}", ln, acc, var, self.ln_str(ln)); - let idx = self.idx(ln, var); - let mut rwu = self.rwu_table.get(idx); + let mut rwu = self.rwu_table.get(ln, var); if (acc & ACC_WRITE) != 0 { - rwu.reader = None; - rwu.writer = Some(ln); + rwu.reader = false; + rwu.writer = true; } // Important: if we both read/write, must do read second // or else the write will override. if (acc & ACC_READ) != 0 { - rwu.reader = Some(ln); + rwu.reader = true; } if (acc & ACC_USE) != 0 { rwu.used = true; } - self.rwu_table.assign_unpacked(idx, rwu); + self.rwu_table.set(ln, var, rwu); } fn compute(&mut self, body: &hir::Body<'_>, hir_id: HirId) -> LiveNode { @@ -1575,7 +1562,7 @@ impl<'tcx> Liveness<'_, 'tcx> { ty::UpvarCapture::ByRef(..) => continue, }; if self.used_on_entry(entry_ln, var) { - if self.live_on_entry(entry_ln, var).is_none() { + if !self.live_on_entry(entry_ln, var) { if let Some(name) = self.should_warn(var) { self.ir.tcx.struct_span_lint_hir( lint::builtin::UNUSED_ASSIGNMENTS, @@ -1609,7 +1596,7 @@ impl<'tcx> Liveness<'_, 'tcx> { fn warn_about_unused_args(&self, body: &hir::Body<'_>, entry_ln: LiveNode) { for p in body.params { self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| { - if self.live_on_entry(ln, var).is_none() { + if !self.live_on_entry(ln, var) { self.report_unsed_assign(hir_id, spans, var, |name| { format!("value passed to `{}` is never read", name) }); @@ -1658,7 +1645,7 @@ impl<'tcx> Liveness<'_, 'tcx> { // {ret}`, there is only one node, so asking about // assigned_on_exit() is not meaningful. let is_assigned = - if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() }; + if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) }; if is_assigned { self.ir.tcx.struct_span_lint_hir( @@ -1725,7 +1712,7 @@ impl<'tcx> Liveness<'_, 'tcx> { } fn warn_about_dead_assign(&self, spans: Vec, hir_id: HirId, ln: LiveNode, var: Variable) { - if self.live_on_exit(ln, var).is_none() { + if !self.live_on_exit(ln, var) { self.report_unsed_assign(hir_id, spans, var, |name| { format!("value assigned to `{}` is never read", name) }); From 50c6fd6dd52b97334d8b3628cf2f66985b25acc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 6 Dec 2020 00:00:00 +0000 Subject: [PATCH 227/274] Don't ICE on malformed `rustc_args_required_const` attribute --- compiler/rustc_passes/src/check_attr.rs | 98 ++++++++++--------- ...lid-rustc_args_required_const-arguments.rs | 6 ++ ...rustc_args_required_const-arguments.stderr | 14 ++- 3 files changed, 72 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index fc97ca035b9..73fb28e5c9a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -545,60 +545,68 @@ impl CheckAttrVisitor<'tcx> { target: Target, item: Option>, ) -> bool { - if let Target::Fn | Target::Method(..) | Target::ForeignFn = target { - let mut invalid_args = vec![]; - for meta in attr.meta_item_list().expect("no meta item list") { - if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { - if let Some(ItemLike::Item(Item { - kind: ItemKind::Fn(FnSig { decl, .. }, ..), - .. - })) - | Some(ItemLike::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(decl, ..), - .. - })) = item - { - let arg_count = decl.inputs.len() as u128; - if *val >= arg_count { - let span = meta.span(); - self.tcx - .sess - .struct_span_err(span, "index exceeds number of arguments") - .span_label( - span, - format!( - "there {} only {} argument{}", - if arg_count != 1 { "are" } else { "is" }, - arg_count, - pluralize!(arg_count) - ), - ) - .emit(); - return false; - } - } else { - bug!("should be a function item"); + let is_function = matches!(target, Target::Fn | Target::Method(..) | Target::ForeignFn); + if !is_function { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(*span, "not a function") + .emit(); + return false; + } + + let list = match attr.meta_item_list() { + // The attribute form is validated on AST. + None => return false, + Some(it) => it, + }; + + let mut invalid_args = vec![]; + for meta in list { + if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { + if let Some(ItemLike::Item(Item { + kind: ItemKind::Fn(FnSig { decl, .. }, ..), + .. + })) + | Some(ItemLike::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(decl, ..), + .. + })) = item + { + let arg_count = decl.inputs.len() as u128; + if *val >= arg_count { + let span = meta.span(); + self.tcx + .sess + .struct_span_err(span, "index exceeds number of arguments") + .span_label( + span, + format!( + "there {} only {} argument{}", + if arg_count != 1 { "are" } else { "is" }, + arg_count, + pluralize!(arg_count) + ), + ) + .emit(); + return false; } } else { - invalid_args.push(meta.span()); + bug!("should be a function item"); } - } - if !invalid_args.is_empty() { - self.tcx - .sess - .struct_span_err(invalid_args, "arguments should be non-negative integers") - .emit(); - false } else { - true + invalid_args.push(meta.span()); } - } else { + } + + if !invalid_args.is_empty() { self.tcx .sess - .struct_span_err(attr.span, "attribute should be applied to a function") - .span_label(*span, "not a function") + .struct_span_err(invalid_args, "arguments should be non-negative integers") .emit(); false + } else { + true } } diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.rs b/src/test/ui/invalid-rustc_args_required_const-arguments.rs index 76c01c21301..99508baeb00 100644 --- a/src/test/ui/invalid-rustc_args_required_const-arguments.rs +++ b/src/test/ui/invalid-rustc_args_required_const-arguments.rs @@ -23,4 +23,10 @@ extern { fn foo7(_: u8); } +#[rustc_args_required_const] //~ ERROR malformed `rustc_args_required_const` attribute +fn bar1() {} + +#[rustc_args_required_const = 1] //~ ERROR malformed `rustc_args_required_const` attribute +fn bar2() {} + fn main() {} diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.stderr b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr index 39d04626168..932344f0a33 100644 --- a/src/test/ui/invalid-rustc_args_required_const-arguments.stderr +++ b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr @@ -6,6 +6,18 @@ LL | #[rustc_args_required_const(0usize)] | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) +error: malformed `rustc_args_required_const` attribute input + --> $DIR/invalid-rustc_args_required_const-arguments.rs:26:1 + | +LL | #[rustc_args_required_const] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_args_required_const(N)]` + +error: malformed `rustc_args_required_const` attribute input + --> $DIR/invalid-rustc_args_required_const-arguments.rs:29:1 + | +LL | #[rustc_args_required_const = 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_args_required_const(N)]` + error: index exceeds number of arguments --> $DIR/invalid-rustc_args_required_const-arguments.rs:3:29 | @@ -44,5 +56,5 @@ error: index exceeds number of arguments LL | #[rustc_args_required_const(1)] | ^ there is only 1 argument -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors From 7da967ca90d5a68ec2dc655245a26a361c3cbd77 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sun, 6 Dec 2020 02:16:06 +0100 Subject: [PATCH 228/274] Bump Rustfmt to 1.4.29 --- Cargo.lock | 4 ++-- src/tools/rls | 2 +- src/tools/rustfmt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4fe24f06886..1d02e973531 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4342,7 +4342,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.28" +version = "1.4.29" dependencies = [ "annotate-snippets 0.6.1", "anyhow", @@ -5265,7 +5265,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.11.0", + "parking_lot 0.9.0", "regex", "serde", "serde_json", diff --git a/src/tools/rls b/src/tools/rls index 9b457351f2d..2cf84baa5e3 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 9b457351f2db8aa436fcf7b46a93e5c2c0e89630 +Subproject commit 2cf84baa5e3c55ac02f42919e67440acb5417125 diff --git a/src/tools/rustfmt b/src/tools/rustfmt index 29f33eb7d67..70ce18255f4 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit 29f33eb7d67d729c095a7ac9bce702f6351396ba +Subproject commit 70ce18255f429caf0d75ecfed8c1464535ee779b From 898ef0ff874cf99e8b320a3161654c3e289048f6 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 6 Dec 2020 15:07:59 +0100 Subject: [PATCH 229/274] Update Cargo.lock --- Cargo.lock | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 1d02e973531..5c096e9f80c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -569,6 +569,7 @@ dependencies = [ "quine-mc_cluskey", "quote", "regex-syntax", + "rustc-semver", "semver 0.11.0", "serde", "smallvec 1.4.2", @@ -3365,6 +3366,12 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rustc-semver" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84" + [[package]] name = "rustc-std-workspace-alloc" version = "1.99.0" @@ -5265,7 +5272,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.9.0", + "parking_lot 0.11.0", "regex", "serde", "serde_json", From 4255a5afd5d55532fda11f43ded5339ad27ea27e Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 19:01:03 +0100 Subject: [PATCH 230/274] Moved failing test to src/test/ui/ Still have not figured out how to make it work --- library/core/tests/mem.rs | 11 +------ src/test/ui/assume-type-intrinsics.rs | 13 ++++++++ src/test/ui/assume-type-intrinsics.stderr | 37 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/assume-type-intrinsics.rs create mode 100644 src/test/ui/assume-type-intrinsics.stderr diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 4ebcf27e173..268c2ed283f 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -131,18 +131,9 @@ fn test_discriminant_send_sync() { } #[test] +#[cfg(not(bootstrap))] fn assume_init_good() { const TRUE: bool = unsafe { MaybeUninit::::new(true).assume_init() }; assert!(TRUE); } - -#[test] -fn assume_init_bad() { - const _BAD: () = unsafe { - MaybeUninit::::uninit().assume_init(); - //~^ ERROR the type `!` does not permit being left uninitialized - //~| ERROR this code causes undefined behavior when executed - //~| ERROR help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - }; -} diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/assume-type-intrinsics.rs new file mode 100644 index 00000000000..95562f3134f --- /dev/null +++ b/src/test/ui/assume-type-intrinsics.rs @@ -0,0 +1,13 @@ +#![feature(never_type)] +#![feature(const_maybe_uninit_assume_init)] + +fn main() { + use std::mem::MaybeUninit; + + const _BAD: () = unsafe { + MaybeUninit::::uninit().assume_init(); + //~^ ERROR: the type `!` does not permit being left uninitialized + //~| this code causes undefined behavior when executed + //~| WARN: the type `!` does not permit being left uninitialized + }; +} diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/assume-type-intrinsics.stderr new file mode 100644 index 00000000000..be45d1ba384 --- /dev/null +++ b/src/test/ui/assume-type-intrinsics.stderr @@ -0,0 +1,37 @@ +error: any use of this value will cause an error + --> $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL + | +LL | intrinsics::assert_inhabited::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | attempted to instantiate uninhabited type `!` + | inside `MaybeUninit::::assume_init` at $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL + | inside `_BAD` at $DIR/assume-type-intrinsics.rs:8:9 + | + ::: $DIR/assume-type-intrinsics.rs:7:5 + | +LL | / const _BAD: () = unsafe { +LL | | MaybeUninit::::uninit().assume_init(); +LL | | +LL | | +LL | | +LL | | +LL | | }; + | |______- + | + = note: `#[deny(const_err)]` on by default + +warning: the type `!` does not permit being left uninitialized + --> $DIR/assume-type-intrinsics.rs:8:9 + | +LL | MaybeUninit::::uninit().assume_init(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | this code causes undefined behavior when executed + | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + | + = note: `#[warn(invalid_value)]` on by default + = note: the `!` type has no valid value + +error: aborting due to previous error; 1 warning emitted + From 3282b549acbb5922889329cddecd3dec700c54c2 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 19:29:35 +0100 Subject: [PATCH 231/274] Tests finally working --- src/test/ui/assume-type-intrinsics.rs | 4 +--- src/test/ui/assume-type-intrinsics.stderr | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/assume-type-intrinsics.rs index 95562f3134f..8e9cb334527 100644 --- a/src/test/ui/assume-type-intrinsics.rs +++ b/src/test/ui/assume-type-intrinsics.rs @@ -6,8 +6,6 @@ fn main() { const _BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); - //~^ ERROR: the type `!` does not permit being left uninitialized - //~| this code causes undefined behavior when executed - //~| WARN: the type `!` does not permit being left uninitialized + //~^ WARN: the type `!` does not permit being left uninitialized }; } diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/assume-type-intrinsics.stderr index be45d1ba384..b776915affd 100644 --- a/src/test/ui/assume-type-intrinsics.stderr +++ b/src/test/ui/assume-type-intrinsics.stderr @@ -13,9 +13,6 @@ LL | intrinsics::assert_inhabited::(); LL | / const _BAD: () = unsafe { LL | | MaybeUninit::::uninit().assume_init(); LL | | -LL | | -LL | | -LL | | LL | | }; | |______- | From 345f230df98cb695ee092bdec5ce8d4154668c0f Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 20:25:13 +0100 Subject: [PATCH 232/274] Fix comments related to abort() --- compiler/rustc_mir/src/const_eval/machine.rs | 4 ++++ compiler/rustc_mir/src/interpret/intrinsics.rs | 2 +- compiler/rustc_mir/src/interpret/machine.rs | 6 ++---- compiler/rustc_mir/src/interpret/terminator.rs | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index c72089ec55a..03ad2607692 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -333,6 +333,10 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Err(ConstEvalErrKind::AssertFailure(err).into()) } + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + Err(ConstEvalErrKind::Abort(msg).into()) + } + fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> { Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into()) } diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 18abf4291b1..c25a312bb5a 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -126,7 +126,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { None => match intrinsic_name { sym::transmute => throw_ub_format!("transmuting to uninhabited type"), sym::unreachable => throw_ub!(Unreachable), - sym::abort => M::abort(self, "aborted execution".to_owned())?, + sym::abort => M::abort(self, "the program aborted execution".to_owned())?, // Unsupported diverging intrinsic. _ => return Ok(false), }, diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 1c13cdbc6e6..2626afdf033 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -176,10 +176,8 @@ pub trait Machine<'mir, 'tcx>: Sized { ) -> InterpResult<'tcx>; /// Called to evaluate `Abort` MIR terminator. - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { - use crate::const_eval::ConstEvalErrKind; - - Err(ConstEvalErrKind::Abort(msg).into()) + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> { + throw_unsup_format!("aborting execution is not supported") } /// Called for all binary operations where the LHS has pointer type. diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index 18079488c89..a2931325a28 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Abort => { - M::abort(self, "aborted execution".to_owned())?; + M::abort(self, "the program aborted execution".to_owned())?; } // When we encounter Resume, we've finished unwinding From 91fe5488254360732d5116b4ccd136d50d01c25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 27 Nov 2020 00:00:00 +0000 Subject: [PATCH 233/274] Retain assembly operands span when lowering AST to HIR --- compiler/rustc_ast_lowering/src/expr.rs | 10 ++++------ compiler/rustc_hir/src/arena.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- compiler/rustc_passes/src/intrinsicck.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 6 +++--- compiler/rustc_typeck/src/check/expr.rs | 2 +- compiler/rustc_typeck/src/expr_use_visitor.rs | 2 +- src/tools/clippy/clippy_lints/src/loops.rs | 2 +- src/tools/clippy/clippy_lints/src/utils/hir_utils.rs | 2 +- src/tools/clippy/clippy_lints/src/utils/inspector.rs | 2 +- 13 files changed, 18 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e0e78a4d609..6ad6e664316 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1307,7 +1307,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) } } }; - Some(op) + Some((op, *op_sp)) }) .collect(); @@ -1326,7 +1326,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } = *p { let op_sp = asm.operands[operand_idx].1; - match &operands[operand_idx] { + match &operands[operand_idx].0 { hir::InlineAsmOperand::In { reg, .. } | hir::InlineAsmOperand::Out { reg, .. } | hir::InlineAsmOperand::InOut { reg, .. } @@ -1385,8 +1385,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut used_input_regs = FxHashMap::default(); let mut used_output_regs = FxHashMap::default(); let mut required_features: Vec<&str> = vec![]; - for (idx, op) in operands.iter().enumerate() { - let op_sp = asm.operands[idx].1; + for (idx, &(ref op, op_sp)) in operands.iter().enumerate() { if let Some(reg) = op.reg() { // Make sure we don't accidentally carry features from the // previous iteration. @@ -1458,8 +1457,7 @@ impl<'hir> LoweringContext<'_, 'hir> { skip = true; let idx2 = *o.get(); - let op2 = &operands[idx2]; - let op_sp2 = asm.operands[idx2].1; + let &(ref op2, op_sp2) = &operands[idx2]; let reg2 = match op2.reg() { Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r, _ => unreachable!(), diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index 44dfdcfccab..c7dc66b70fe 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -14,7 +14,7 @@ macro_rules! arena_types { // HIR types [few] hir_krate: rustc_hir::Crate<$tcx>, [] arm: rustc_hir::Arm<$tcx>, - [] asm_operand: rustc_hir::InlineAsmOperand<$tcx>, + [] asm_operand: (rustc_hir::InlineAsmOperand<$tcx>, Span), [] asm_template: rustc_ast::InlineAsmTemplatePiece, [] attribute: rustc_ast::Attribute, [] block: rustc_hir::Block<$tcx>, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 44dc6673564..280e863d474 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2143,7 +2143,7 @@ impl<'hir> InlineAsmOperand<'hir> { #[derive(Debug, HashStable_Generic)] pub struct InlineAsm<'hir> { pub template: &'hir [InlineAsmTemplatePiece], - pub operands: &'hir [InlineAsmOperand<'hir>], + pub operands: &'hir [(InlineAsmOperand<'hir>, Span)], pub options: InlineAsmOptions, pub line_spans: &'hir [Span], } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3e8fc689acf..3c330c5d6c5 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1191,7 +1191,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_expr, optional_expression); } ExprKind::InlineAsm(ref asm) => { - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 25b09d76295..597c55b4bd7 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1462,7 +1462,7 @@ impl<'a> State<'a> { let mut args = vec![]; args.push(AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(&a.template))); - args.extend(a.operands.iter().map(|o| AsmArg::Operand(o))); + args.extend(a.operands.iter().map(|(o, _)| AsmArg::Operand(o))); if !a.options.is_empty() { args.push(AsmArg::Options(a.options)); } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e404afeb698..e934d8ed9da 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -408,7 +408,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( operands: asm .operands .iter() - .map(|op| { + .map(|(op, _op_sp)| { match *op { hir::InlineAsmOperand::In { reg, ref expr } => { InlineAsmOperand::In { reg, expr: expr.to_ref() } diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 956be925be8..711e8e87c6c 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -347,7 +347,7 @@ impl ExprVisitor<'tcx> { } fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) { - for (idx, op) in asm.operands.iter().enumerate() { + for (idx, (op, _op_sp)) in asm.operands.iter().enumerate() { match *op { hir::InlineAsmOperand::In { reg, ref expr } => { self.check_asm_operand_type(idx, reg, expr, asm.template, None); diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index debb873beb9..a64c6fa319c 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1174,7 +1174,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }; // Do a first pass for writing outputs only - for op in asm.operands.iter().rev() { + for (op, _op_sp) in asm.operands.iter().rev() { match op { hir::InlineAsmOperand::In { .. } | hir::InlineAsmOperand::Const { .. } @@ -1197,7 +1197,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Then do a second pass for inputs let mut succ = succ; - for op in asm.operands.iter().rev() { + for (op, _op_sp) in asm.operands.iter().rev() { match op { hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::Const { expr, .. } @@ -1454,7 +1454,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { } hir::ExprKind::InlineAsm(ref asm) => { - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::Out { expr, .. } => { if let Some(expr) = expr { diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 26962d2222d..b8a2a4779d9 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1929,7 +1929,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::Const { expr } => { self.check_expr_asm_operand(expr, true); diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 1b51d5e0182..95848ac2c07 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -243,7 +243,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } hir::ExprKind::InlineAsm(ref asm) => { - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::Const { expr, .. } diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 400148ab81d..1bd96b2b4c8 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -768,7 +768,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { ExprKind::InlineAsm(ref asm) => asm .operands .iter() - .map(|o| match o { + .map(|(o, _)| match o { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } | InlineAsmOperand::Const { expr } diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs index d847d22275e..d942d4e12b1 100644 --- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs @@ -517,7 +517,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } asm.options.hash(&mut self.s); - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { InlineAsmOperand::In { reg, expr } => { reg.hash(&mut self.s); diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 8f0ef9150d4..323d8745538 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -293,7 +293,7 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template)); println!("{}options: {:?}", ind, asm.options); println!("{}operands:", ind); - for op in asm.operands { + for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } | hir::InlineAsmOperand::InOut { expr, .. } From 0c13a9c020b1a70ad3d33b4de706567d46955e5d Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Sun, 6 Dec 2020 20:30:07 +0000 Subject: [PATCH 234/274] smarter E0390 --- .../src/error_codes/E0390.md | 5 +- .../src/coherence/inherent_impls.rs | 58 ++++++++++++++++- src/test/ui/error-codes/E0390.stderr | 2 +- src/test/ui/kinds-of-primitive-impl.rs | 23 +++++++ src/test/ui/kinds-of-primitive-impl.stderr | 65 +++++++++++++++++++ .../ui/single-primitive-inherent-impl.stderr | 2 +- 6 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/kinds-of-primitive-impl.rs create mode 100644 src/test/ui/kinds-of-primitive-impl.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0390.md b/compiler/rustc_error_codes/src/error_codes/E0390.md index ecc5b5568ad..7a13160d098 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0390.md +++ b/compiler/rustc_error_codes/src/error_codes/E0390.md @@ -1,4 +1,4 @@ -A method was implemented on a primitive type. +A method or constant was implemented on a primitive type. Erroneous code example: @@ -12,7 +12,8 @@ impl *mut Foo {} // `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive ``` -This isn't allowed, but using a trait to implement a method is a good solution. +This isn't allowed, but using a trait to implement a method or constant +is a good solution. Example: ``` diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index 483ab2f58f2..05f387883f1 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -44,8 +44,8 @@ struct InherentCollect<'tcx> { impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { fn visit_item(&mut self, item: &hir::Item<'_>) { - let ty = match item.kind { - hir::ItemKind::Impl { of_trait: None, ref self_ty, .. } => self_ty, + let (ty, assoc_items) = match item.kind { + hir::ItemKind::Impl { of_trait: None, ref self_ty, items, .. } => (self_ty, items), _ => return, }; @@ -70,6 +70,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "bool", "bool", item.span, + assoc_items, ); } ty::Char => { @@ -80,6 +81,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "char", "char", item.span, + assoc_items, ); } ty::Str => { @@ -90,6 +92,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "str", "str", item.span, + assoc_items, ); } ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => { @@ -100,6 +103,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "slice_u8", "[u8]", item.span, + assoc_items, ); } ty::Slice(_) => { @@ -110,6 +114,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "slice", "[T]", item.span, + assoc_items, ); } ty::Array(_, _) => { @@ -120,6 +125,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "array", "[T; N]", item.span, + assoc_items, ); } ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not }) @@ -132,6 +138,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "const_slice_ptr", "*const [T]", item.span, + assoc_items, ); } ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut }) @@ -144,6 +151,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "mut_slice_ptr", "*mut [T]", item.span, + assoc_items, ); } ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => { @@ -154,6 +162,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "const_ptr", "*const T", item.span, + assoc_items, ); } ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Mut }) => { @@ -164,6 +173,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "mut_ptr", "*mut T", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I8) => { @@ -174,6 +184,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i8", "i8", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I16) => { @@ -184,6 +195,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i16", "i16", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I32) => { @@ -194,6 +206,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i32", "i32", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I64) => { @@ -204,6 +217,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i64", "i64", item.span, + assoc_items, ); } ty::Int(ast::IntTy::I128) => { @@ -214,6 +228,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "i128", "i128", item.span, + assoc_items, ); } ty::Int(ast::IntTy::Isize) => { @@ -224,6 +239,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "isize", "isize", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U8) => { @@ -234,6 +250,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u8", "u8", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U16) => { @@ -244,6 +261,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u16", "u16", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U32) => { @@ -254,6 +272,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u32", "u32", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U64) => { @@ -264,6 +283,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u64", "u64", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::U128) => { @@ -274,6 +294,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "u128", "u128", item.span, + assoc_items, ); } ty::Uint(ast::UintTy::Usize) => { @@ -284,6 +305,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "usize", "usize", item.span, + assoc_items, ); } ty::Float(ast::FloatTy::F32) => { @@ -294,6 +316,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "f32", "f32", item.span, + assoc_items, ); } ty::Float(ast::FloatTy::F64) => { @@ -304,6 +327,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "f64", "f64", item.span, + assoc_items, ); } ty::Error(_) => {} @@ -369,6 +393,7 @@ impl InherentCollect<'tcx> { lang: &str, ty: &str, span: Span, + assoc_items: &[hir::ImplItemRef<'_>], ) { match (lang_def_id, lang_def_id2) { (Some(lang_def_id), _) if lang_def_id == impl_def_id.to_def_id() => { @@ -387,7 +412,34 @@ impl InherentCollect<'tcx> { lang, ty ) - .span_help(span, "consider using a trait to implement these methods") + .span_help( + span, + &format!("consider using a trait{}", { + if assoc_items.len() == 0 { + String::new() + } else { + let plural = assoc_items.len() > 1; + format!( + " to implement {} {}{}", + if plural { "these" } else { "this" }, + { + let item_types = assoc_items.iter().map(|x| x.kind); + if item_types.clone().all(|x| x == hir::AssocItemKind::Const) { + "constant" + } else if item_types + .clone() + .all(|x| matches! {x, hir::AssocItemKind::Fn{ .. } }) + { + "method" + } else { + "associated item" + } + }, + if plural { "s" } else { "" } + ) + } + }), + ) .emit(); } } diff --git a/src/test/ui/error-codes/E0390.stderr b/src/test/ui/error-codes/E0390.stderr index 3ca3a77c74f..414ec20ae80 100644 --- a/src/test/ui/error-codes/E0390.stderr +++ b/src/test/ui/error-codes/E0390.stderr @@ -4,7 +4,7 @@ error[E0390]: only a single inherent implementation marked with `#[lang = "mut_p LL | impl *mut Foo {} | ^^^^^^^^^^^^^^^^ | -help: consider using a trait to implement these methods +help: consider using a trait --> $DIR/E0390.rs:5:1 | LL | impl *mut Foo {} diff --git a/src/test/ui/kinds-of-primitive-impl.rs b/src/test/ui/kinds-of-primitive-impl.rs new file mode 100644 index 00000000000..cbd4d7ae904 --- /dev/null +++ b/src/test/ui/kinds-of-primitive-impl.rs @@ -0,0 +1,23 @@ +// ignore-tidy-linelength + + +impl u8 { +//~^ error: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive + pub const B: u8 = 0; +} + +impl str { +//~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive + fn foo() {} + fn bar(self) {} +} + +impl char { +//~^ error: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive + pub const B: u8 = 0; + pub const C: u8 = 0; + fn foo() {} + fn bar(self) {} +} + +fn main() {} diff --git a/src/test/ui/kinds-of-primitive-impl.stderr b/src/test/ui/kinds-of-primitive-impl.stderr new file mode 100644 index 00000000000..14aed00c005 --- /dev/null +++ b/src/test/ui/kinds-of-primitive-impl.stderr @@ -0,0 +1,65 @@ +error[E0390]: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive + --> $DIR/kinds-of-primitive-impl.rs:4:1 + | +LL | / impl u8 { +LL | | +LL | | pub const B: u8 = 0; +LL | | } + | |_^ + | +help: consider using a trait to implement this constant + --> $DIR/kinds-of-primitive-impl.rs:4:1 + | +LL | / impl u8 { +LL | | +LL | | pub const B: u8 = 0; +LL | | } + | |_^ + +error[E0390]: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive + --> $DIR/kinds-of-primitive-impl.rs:9:1 + | +LL | / impl str { +LL | | +LL | | fn foo() {} +LL | | fn bar(self) {} +LL | | } + | |_^ + | +help: consider using a trait to implement these methods + --> $DIR/kinds-of-primitive-impl.rs:9:1 + | +LL | / impl str { +LL | | +LL | | fn foo() {} +LL | | fn bar(self) {} +LL | | } + | |_^ + +error[E0390]: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive + --> $DIR/kinds-of-primitive-impl.rs:15:1 + | +LL | / impl char { +LL | | +LL | | pub const B: u8 = 0; +LL | | pub const C: u8 = 0; +LL | | fn foo() {} +LL | | fn bar(self) {} +LL | | } + | |_^ + | +help: consider using a trait to implement these associated items + --> $DIR/kinds-of-primitive-impl.rs:15:1 + | +LL | / impl char { +LL | | +LL | | pub const B: u8 = 0; +LL | | pub const C: u8 = 0; +LL | | fn foo() {} +LL | | fn bar(self) {} +LL | | } + | |_^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0390`. diff --git a/src/test/ui/single-primitive-inherent-impl.stderr b/src/test/ui/single-primitive-inherent-impl.stderr index d357afa3b38..0daae91956d 100644 --- a/src/test/ui/single-primitive-inherent-impl.stderr +++ b/src/test/ui/single-primitive-inherent-impl.stderr @@ -6,7 +6,7 @@ LL | | LL | | } | |_^ | -help: consider using a trait to implement these methods +help: consider using a trait --> $DIR/single-primitive-inherent-impl.rs:11:1 | LL | / impl str { From d0a1e40eae2bb02b23b65c33918fce20e9ed4ae4 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 6 Dec 2020 22:29:13 +0100 Subject: [PATCH 235/274] Remove unused feature gate --- library/core/tests/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 9e7a8189c81..2aa3598a0d9 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -54,7 +54,6 @@ #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] -#![feature(const_assert_type)] #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(option_unwrap_none)] From 67db0ea4a7a58abc3687abf8fe55073af3ceff9e Mon Sep 17 00:00:00 2001 From: Ethan Brierley Date: Sun, 6 Dec 2020 21:30:30 +0000 Subject: [PATCH 236/274] suggestions from camelid review --- .../src/coherence/inherent_impls.rs | 55 +++++++++---------- src/test/ui/error-codes/E0390.stderr | 6 +- src/test/ui/kinds-of-primitive-impl.stderr | 31 +---------- .../ui/single-primitive-inherent-impl.stderr | 8 +-- 4 files changed, 32 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index 05f387883f1..0c1578498b8 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -403,6 +403,32 @@ impl InherentCollect<'tcx> { // OK } _ => { + let to_implement = if assoc_items.len() == 0 { + String::new() + } else { + let plural = assoc_items.len() > 1; + let assoc_items_kind = { + let item_types = assoc_items.iter().map(|x| x.kind); + if item_types.clone().all(|x| x == hir::AssocItemKind::Const) { + "constant" + } else if item_types + .clone() + .all(|x| matches! {x, hir::AssocItemKind::Fn{ .. } }) + { + "method" + } else { + "associated item" + } + }; + + format!( + " to implement {} {}{}", + if plural { "these" } else { "this" }, + assoc_items_kind, + if plural { "s" } else { "" } + ) + }; + struct_span_err!( self.tcx.sess, span, @@ -412,34 +438,7 @@ impl InherentCollect<'tcx> { lang, ty ) - .span_help( - span, - &format!("consider using a trait{}", { - if assoc_items.len() == 0 { - String::new() - } else { - let plural = assoc_items.len() > 1; - format!( - " to implement {} {}{}", - if plural { "these" } else { "this" }, - { - let item_types = assoc_items.iter().map(|x| x.kind); - if item_types.clone().all(|x| x == hir::AssocItemKind::Const) { - "constant" - } else if item_types - .clone() - .all(|x| matches! {x, hir::AssocItemKind::Fn{ .. } }) - { - "method" - } else { - "associated item" - } - }, - if plural { "s" } else { "" } - ) - } - }), - ) + .help(&format!("consider using a trait{}", to_implement)) .emit(); } } diff --git a/src/test/ui/error-codes/E0390.stderr b/src/test/ui/error-codes/E0390.stderr index 414ec20ae80..be47e93d19a 100644 --- a/src/test/ui/error-codes/E0390.stderr +++ b/src/test/ui/error-codes/E0390.stderr @@ -4,11 +4,7 @@ error[E0390]: only a single inherent implementation marked with `#[lang = "mut_p LL | impl *mut Foo {} | ^^^^^^^^^^^^^^^^ | -help: consider using a trait - --> $DIR/E0390.rs:5:1 - | -LL | impl *mut Foo {} - | ^^^^^^^^^^^^^^^^ + = help: consider using a trait error: aborting due to previous error diff --git a/src/test/ui/kinds-of-primitive-impl.stderr b/src/test/ui/kinds-of-primitive-impl.stderr index 14aed00c005..d19c85b17f9 100644 --- a/src/test/ui/kinds-of-primitive-impl.stderr +++ b/src/test/ui/kinds-of-primitive-impl.stderr @@ -7,14 +7,7 @@ LL | | pub const B: u8 = 0; LL | | } | |_^ | -help: consider using a trait to implement this constant - --> $DIR/kinds-of-primitive-impl.rs:4:1 - | -LL | / impl u8 { -LL | | -LL | | pub const B: u8 = 0; -LL | | } - | |_^ + = help: consider using a trait to implement this constant error[E0390]: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive --> $DIR/kinds-of-primitive-impl.rs:9:1 @@ -26,15 +19,7 @@ LL | | fn bar(self) {} LL | | } | |_^ | -help: consider using a trait to implement these methods - --> $DIR/kinds-of-primitive-impl.rs:9:1 - | -LL | / impl str { -LL | | -LL | | fn foo() {} -LL | | fn bar(self) {} -LL | | } - | |_^ + = help: consider using a trait to implement these methods error[E0390]: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive --> $DIR/kinds-of-primitive-impl.rs:15:1 @@ -48,17 +33,7 @@ LL | | fn bar(self) {} LL | | } | |_^ | -help: consider using a trait to implement these associated items - --> $DIR/kinds-of-primitive-impl.rs:15:1 - | -LL | / impl char { -LL | | -LL | | pub const B: u8 = 0; -LL | | pub const C: u8 = 0; -LL | | fn foo() {} -LL | | fn bar(self) {} -LL | | } - | |_^ + = help: consider using a trait to implement these associated items error: aborting due to 3 previous errors diff --git a/src/test/ui/single-primitive-inherent-impl.stderr b/src/test/ui/single-primitive-inherent-impl.stderr index 0daae91956d..50a0d5bef86 100644 --- a/src/test/ui/single-primitive-inherent-impl.stderr +++ b/src/test/ui/single-primitive-inherent-impl.stderr @@ -6,13 +6,7 @@ LL | | LL | | } | |_^ | -help: consider using a trait - --> $DIR/single-primitive-inherent-impl.rs:11:1 - | -LL | / impl str { -LL | | -LL | | } - | |_^ + = help: consider using a trait error: aborting due to previous error From b4b66f6e2443cd05e163ac2577620ed06ea265e9 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 6 Dec 2020 14:11:02 -0800 Subject: [PATCH 237/274] Fix trimming of lint docs It was removing all the indentation before. Co-authored-by: Eric Huss --- src/tools/lint-docs/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 326b7948098..ea54a351e03 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -143,8 +143,8 @@ impl<'a> LintExtractor<'a> { Some((lineno, line)) => { let line = line.trim(); if let Some(text) = line.strip_prefix("/// ") { - doc_lines.push(text.trim().to_string()); - } else if line.starts_with("///") { + doc_lines.push(text.to_string()); + } else if line == "///" { doc_lines.push("".to_string()); } else if line.starts_with("// ") { // Ignore comments. From 4eb9da3b17a1e6cdb8517e9f9ee7000f8effaef4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 7 Dec 2020 02:01:35 +0300 Subject: [PATCH 238/274] Move some tests to subdirectories --- .../ui/{issues => derives}/issue-36617.rs | 0 .../ui/{issues => derives}/issue-36617.stderr | 0 src/test/ui/hidden-rt-injection.rs | 8 ------- src/test/ui/hidden-rt-injection.stderr | 9 -------- src/test/ui/hidden-rt-injection2.rs | 8 ------- src/test/ui/hidden-rt-injection2.stderr | 9 -------- src/test/ui/import.rs | 17 -------------- src/test/ui/import2.rs | 10 -------- src/test/ui/import3.rs | 4 ---- src/test/ui/import4.rs | 7 ------ .../auxiliary/issue-36881-aux.rs | 0 .../auxiliary/issue-52891.rs | 0 .../auxiliary/issue-59764.rs | 0 src/test/ui/{ => imports}/double-import.rs | 0 .../ui/{ => imports}/double-import.stderr | 0 .../export-glob-imports-target.rs | 0 src/test/ui/{ => imports}/glob-resolve1.rs | 0 .../ui/{ => imports}/glob-resolve1.stderr | 0 src/test/ui/imports/import-rpass.rs | 12 ++++++++++ src/test/ui/imports/import.rs | 23 +++++++++++-------- src/test/ui/{ => imports}/import.stderr | 0 src/test/ui/imports/import2-rpass.rs | 9 ++++++++ src/test/ui/imports/import2.rs | 13 ++++++----- src/test/ui/{ => imports}/import2.stderr | 0 src/test/ui/imports/import3-rpass.rs | 13 +++++++++++ src/test/ui/imports/import3.rs | 15 +++--------- src/test/ui/{ => imports}/import3.stderr | 0 src/test/ui/imports/import4-rpass.rs | 9 ++++++++ src/test/ui/imports/import4.rs | 10 ++++---- src/test/ui/{ => imports}/import4.stderr | 0 .../ui/{issues => imports}/issue-13404.rs | 0 .../ui/{issues => imports}/issue-13404.stderr | 0 src/test/ui/{issues => imports}/issue-1697.rs | 0 .../ui/{issues => imports}/issue-1697.stderr | 0 .../ui/{issues => imports}/issue-18083.rs | 0 .../ui/{issues => imports}/issue-19498.rs | 0 .../ui/{issues => imports}/issue-19498.stderr | 0 .../ui/{issues => imports}/issue-24081.rs | 0 .../ui/{issues => imports}/issue-24081.stderr | 0 .../ui/{issues => imports}/issue-25396.rs | 0 .../ui/{issues => imports}/issue-25396.stderr | 0 .../ui/{issues => imports}/issue-26886.rs | 0 .../ui/{issues => imports}/issue-26886.stderr | 0 .../ui/{issues => imports}/issue-28134.rs | 0 .../ui/{issues => imports}/issue-28134.stderr | 0 .../ui/{issues => imports}/issue-28388-1.rs | 0 .../{issues => imports}/issue-28388-1.stderr | 0 .../ui/{issues => imports}/issue-28388-2.rs | 0 .../{issues => imports}/issue-28388-2.stderr | 0 src/test/ui/{issues => imports}/issue-2937.rs | 0 .../ui/{issues => imports}/issue-2937.stderr | 0 .../ui/{issues => imports}/issue-30560.rs | 0 .../ui/{issues => imports}/issue-30560.stderr | 0 .../ui/{issues => imports}/issue-31212.rs | 0 .../ui/{issues => imports}/issue-31212.stderr | 0 .../issue-32354-suggest-import-rename.fixed | 0 .../issue-32354-suggest-import-rename.rs | 0 .../issue-32354-suggest-import-rename.stderr | 0 .../ui/{issues => imports}/issue-32833.rs | 0 .../ui/{issues => imports}/issue-32833.stderr | 0 .../ui/{issues => imports}/issue-33464.rs | 0 .../ui/{issues => imports}/issue-33464.stderr | 0 .../ui/{issues => imports}/issue-36881.rs | 0 .../ui/{issues => imports}/issue-36881.stderr | 0 .../ui/{issues => imports}/issue-37887.rs | 0 .../ui/{issues => imports}/issue-37887.stderr | 0 .../ui/{issues => imports}/issue-38293.rs | 0 .../ui/{issues => imports}/issue-38293.stderr | 0 .../ui/{issues => imports}/issue-4366-2.rs | 0 .../{issues => imports}/issue-4366-2.stderr | 0 src/test/ui/{issues => imports}/issue-4366.rs | 0 .../ui/{issues => imports}/issue-4366.stderr | 0 ...n-crate-rename-suggestion-formatting.fixed | 0 ...tern-crate-rename-suggestion-formatting.rs | 0 ...-crate-rename-suggestion-formatting.stderr | 0 .../issue-45829/auxiliary/issue-45829-a.rs | 0 .../issue-45829/auxiliary/issue-45829-b.rs | 0 .../issue-45829/import-self.rs | 0 .../issue-45829/import-self.stderr | 0 .../issue-45829/import-twice.rs | 0 .../issue-45829/import-twice.stderr | 0 .../issue-45829/issue-45829.rs | 0 .../issue-45829/issue-45829.stderr | 0 .../issue-45829/rename-extern-vs-use.rs | 0 .../issue-45829/rename-extern-vs-use.stderr | 0 .../issue-45829/rename-extern-with-tab.rs | 0 .../issue-45829/rename-extern-with-tab.stderr | 0 .../issue-45829/rename-extern.rs | 0 .../issue-45829/rename-extern.stderr | 0 .../issue-45829/rename-use-vs-extern.rs | 0 .../issue-45829/rename-use-vs-extern.stderr | 0 .../issue-45829/rename-use-with-tabs.rs | 0 .../issue-45829/rename-use-with-tabs.stderr | 0 .../issue-45829/rename-with-path.rs | 0 .../issue-45829/rename-with-path.stderr | 0 .../{issues => imports}/issue-45829/rename.rs | 0 .../issue-45829/rename.stderr | 0 .../ui/{issues => imports}/issue-47623.rs | 0 .../ui/{issues => imports}/issue-47623.stderr | 0 .../ui/{issues => imports}/issue-4865-1.rs | 0 .../ui/{issues => imports}/issue-4865-2.rs | 0 .../ui/{issues => imports}/issue-4865-3.rs | 0 .../ui/{issues => imports}/issue-52891.fixed | 0 .../ui/{issues => imports}/issue-52891.rs | 0 .../ui/{issues => imports}/issue-52891.stderr | 0 .../ui/{issues => imports}/issue-53565.rs | 0 .../ui/{issues => imports}/issue-53565.stderr | 0 .../ui/{issues => imports}/issue-59764.rs | 0 .../ui/{issues => imports}/issue-59764.stderr | 0 src/test/ui/{issues => imports}/issue-8208.rs | 0 .../ui/{issues => imports}/issue-8208.stderr | 0 src/test/ui/{issues => imports}/issue-8640.rs | 0 .../ui/{issues => imports}/issue-8640.stderr | 0 .../{ => imports}/resolve_self_super_hint.rs | 0 .../resolve_self_super_hint.stderr | 0 .../ui/{issues => modules}/issue-56411-aux.rs | 0 .../ui/{issues => modules}/issue-56411.rs | 0 .../ui/{issues => modules}/issue-56411.stderr | 0 .../auxiliary/extern-prelude-vec.rs | 0 .../{ => resolve}/auxiliary/extern-prelude.rs | 0 .../ui/{ => resolve}/extern-prelude-fail.rs | 0 .../{ => resolve}/extern-prelude-fail.stderr | 0 src/test/ui/{ => resolve}/extern-prelude.rs | 0 .../ui/{issues => resolve}/issue-49074.rs | 0 .../ui/{issues => resolve}/issue-49074.stderr | 0 .../{ => resolve}/resolve-pseudo-shadowing.rs | 0 .../auxiliary/lint-stability.rs | 0 .../issue-28075.rs | 0 .../issue-28075.stderr | 0 .../issue-28388-3.rs | 0 .../issue-28388-3.stderr | 0 src/test/ui/{issues => unused}/issue-30730.rs | 0 .../ui/{issues => unused}/issue-30730.stderr | 0 src/test/ui/{issues => unused}/issue-46576.rs | 0 .../ui/{issues => unused}/issue-46576.stderr | 0 src/test/ui/{issues => unused}/issue-59896.rs | 0 .../ui/{issues => unused}/issue-59896.stderr | 0 src/test/ui/{issues => unused}/issue-70041.rs | 0 .../ui/{issues => unused}/issue-70041.stderr | 0 139 files changed, 71 insertions(+), 105 deletions(-) rename src/test/ui/{issues => derives}/issue-36617.rs (100%) rename src/test/ui/{issues => derives}/issue-36617.stderr (100%) delete mode 100644 src/test/ui/hidden-rt-injection.rs delete mode 100644 src/test/ui/hidden-rt-injection.stderr delete mode 100644 src/test/ui/hidden-rt-injection2.rs delete mode 100644 src/test/ui/hidden-rt-injection2.stderr delete mode 100644 src/test/ui/import.rs delete mode 100644 src/test/ui/import2.rs delete mode 100644 src/test/ui/import3.rs delete mode 100644 src/test/ui/import4.rs rename src/test/ui/{issues => imports}/auxiliary/issue-36881-aux.rs (100%) rename src/test/ui/{issues => imports}/auxiliary/issue-52891.rs (100%) rename src/test/ui/{issues => imports}/auxiliary/issue-59764.rs (100%) rename src/test/ui/{ => imports}/double-import.rs (100%) rename src/test/ui/{ => imports}/double-import.stderr (100%) rename src/test/ui/{ => imports}/export-glob-imports-target.rs (100%) rename src/test/ui/{ => imports}/glob-resolve1.rs (100%) rename src/test/ui/{ => imports}/glob-resolve1.stderr (100%) create mode 100644 src/test/ui/imports/import-rpass.rs rename src/test/ui/{ => imports}/import.stderr (100%) create mode 100644 src/test/ui/imports/import2-rpass.rs rename src/test/ui/{ => imports}/import2.stderr (100%) create mode 100644 src/test/ui/imports/import3-rpass.rs rename src/test/ui/{ => imports}/import3.stderr (100%) create mode 100644 src/test/ui/imports/import4-rpass.rs rename src/test/ui/{ => imports}/import4.stderr (100%) rename src/test/ui/{issues => imports}/issue-13404.rs (100%) rename src/test/ui/{issues => imports}/issue-13404.stderr (100%) rename src/test/ui/{issues => imports}/issue-1697.rs (100%) rename src/test/ui/{issues => imports}/issue-1697.stderr (100%) rename src/test/ui/{issues => imports}/issue-18083.rs (100%) rename src/test/ui/{issues => imports}/issue-19498.rs (100%) rename src/test/ui/{issues => imports}/issue-19498.stderr (100%) rename src/test/ui/{issues => imports}/issue-24081.rs (100%) rename src/test/ui/{issues => imports}/issue-24081.stderr (100%) rename src/test/ui/{issues => imports}/issue-25396.rs (100%) rename src/test/ui/{issues => imports}/issue-25396.stderr (100%) rename src/test/ui/{issues => imports}/issue-26886.rs (100%) rename src/test/ui/{issues => imports}/issue-26886.stderr (100%) rename src/test/ui/{issues => imports}/issue-28134.rs (100%) rename src/test/ui/{issues => imports}/issue-28134.stderr (100%) rename src/test/ui/{issues => imports}/issue-28388-1.rs (100%) rename src/test/ui/{issues => imports}/issue-28388-1.stderr (100%) rename src/test/ui/{issues => imports}/issue-28388-2.rs (100%) rename src/test/ui/{issues => imports}/issue-28388-2.stderr (100%) rename src/test/ui/{issues => imports}/issue-2937.rs (100%) rename src/test/ui/{issues => imports}/issue-2937.stderr (100%) rename src/test/ui/{issues => imports}/issue-30560.rs (100%) rename src/test/ui/{issues => imports}/issue-30560.stderr (100%) rename src/test/ui/{issues => imports}/issue-31212.rs (100%) rename src/test/ui/{issues => imports}/issue-31212.stderr (100%) rename src/test/ui/{issues => imports}/issue-32354-suggest-import-rename.fixed (100%) rename src/test/ui/{issues => imports}/issue-32354-suggest-import-rename.rs (100%) rename src/test/ui/{issues => imports}/issue-32354-suggest-import-rename.stderr (100%) rename src/test/ui/{issues => imports}/issue-32833.rs (100%) rename src/test/ui/{issues => imports}/issue-32833.stderr (100%) rename src/test/ui/{issues => imports}/issue-33464.rs (100%) rename src/test/ui/{issues => imports}/issue-33464.stderr (100%) rename src/test/ui/{issues => imports}/issue-36881.rs (100%) rename src/test/ui/{issues => imports}/issue-36881.stderr (100%) rename src/test/ui/{issues => imports}/issue-37887.rs (100%) rename src/test/ui/{issues => imports}/issue-37887.stderr (100%) rename src/test/ui/{issues => imports}/issue-38293.rs (100%) rename src/test/ui/{issues => imports}/issue-38293.stderr (100%) rename src/test/ui/{issues => imports}/issue-4366-2.rs (100%) rename src/test/ui/{issues => imports}/issue-4366-2.stderr (100%) rename src/test/ui/{issues => imports}/issue-4366.rs (100%) rename src/test/ui/{issues => imports}/issue-4366.stderr (100%) rename src/test/ui/{issues => imports}/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed (100%) rename src/test/ui/{issues => imports}/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs (100%) rename src/test/ui/{issues => imports}/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/auxiliary/issue-45829-a.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/auxiliary/issue-45829-b.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/import-self.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/import-self.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/import-twice.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/import-twice.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/issue-45829.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/issue-45829.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern-vs-use.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern-vs-use.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern-with-tab.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern-with-tab.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-extern.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-use-vs-extern.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-use-vs-extern.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-use-with-tabs.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-use-with-tabs.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-with-path.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename-with-path.stderr (100%) rename src/test/ui/{issues => imports}/issue-45829/rename.rs (100%) rename src/test/ui/{issues => imports}/issue-45829/rename.stderr (100%) rename src/test/ui/{issues => imports}/issue-47623.rs (100%) rename src/test/ui/{issues => imports}/issue-47623.stderr (100%) rename src/test/ui/{issues => imports}/issue-4865-1.rs (100%) rename src/test/ui/{issues => imports}/issue-4865-2.rs (100%) rename src/test/ui/{issues => imports}/issue-4865-3.rs (100%) rename src/test/ui/{issues => imports}/issue-52891.fixed (100%) rename src/test/ui/{issues => imports}/issue-52891.rs (100%) rename src/test/ui/{issues => imports}/issue-52891.stderr (100%) rename src/test/ui/{issues => imports}/issue-53565.rs (100%) rename src/test/ui/{issues => imports}/issue-53565.stderr (100%) rename src/test/ui/{issues => imports}/issue-59764.rs (100%) rename src/test/ui/{issues => imports}/issue-59764.stderr (100%) rename src/test/ui/{issues => imports}/issue-8208.rs (100%) rename src/test/ui/{issues => imports}/issue-8208.stderr (100%) rename src/test/ui/{issues => imports}/issue-8640.rs (100%) rename src/test/ui/{issues => imports}/issue-8640.stderr (100%) rename src/test/ui/{ => imports}/resolve_self_super_hint.rs (100%) rename src/test/ui/{ => imports}/resolve_self_super_hint.stderr (100%) rename src/test/ui/{issues => modules}/issue-56411-aux.rs (100%) rename src/test/ui/{issues => modules}/issue-56411.rs (100%) rename src/test/ui/{issues => modules}/issue-56411.stderr (100%) rename src/test/ui/{ => resolve}/auxiliary/extern-prelude-vec.rs (100%) rename src/test/ui/{ => resolve}/auxiliary/extern-prelude.rs (100%) rename src/test/ui/{ => resolve}/extern-prelude-fail.rs (100%) rename src/test/ui/{ => resolve}/extern-prelude-fail.stderr (100%) rename src/test/ui/{ => resolve}/extern-prelude.rs (100%) rename src/test/ui/{issues => resolve}/issue-49074.rs (100%) rename src/test/ui/{issues => resolve}/issue-49074.stderr (100%) rename src/test/ui/{ => resolve}/resolve-pseudo-shadowing.rs (100%) rename src/test/ui/{issues => stability-attribute}/auxiliary/lint-stability.rs (100%) rename src/test/ui/{issues => stability-attribute}/issue-28075.rs (100%) rename src/test/ui/{issues => stability-attribute}/issue-28075.stderr (100%) rename src/test/ui/{issues => stability-attribute}/issue-28388-3.rs (100%) rename src/test/ui/{issues => stability-attribute}/issue-28388-3.stderr (100%) rename src/test/ui/{issues => unused}/issue-30730.rs (100%) rename src/test/ui/{issues => unused}/issue-30730.stderr (100%) rename src/test/ui/{issues => unused}/issue-46576.rs (100%) rename src/test/ui/{issues => unused}/issue-46576.stderr (100%) rename src/test/ui/{issues => unused}/issue-59896.rs (100%) rename src/test/ui/{issues => unused}/issue-59896.stderr (100%) rename src/test/ui/{issues => unused}/issue-70041.rs (100%) rename src/test/ui/{issues => unused}/issue-70041.stderr (100%) diff --git a/src/test/ui/issues/issue-36617.rs b/src/test/ui/derives/issue-36617.rs similarity index 100% rename from src/test/ui/issues/issue-36617.rs rename to src/test/ui/derives/issue-36617.rs diff --git a/src/test/ui/issues/issue-36617.stderr b/src/test/ui/derives/issue-36617.stderr similarity index 100% rename from src/test/ui/issues/issue-36617.stderr rename to src/test/ui/derives/issue-36617.stderr diff --git a/src/test/ui/hidden-rt-injection.rs b/src/test/ui/hidden-rt-injection.rs deleted file mode 100644 index 3ca04f93493..00000000000 --- a/src/test/ui/hidden-rt-injection.rs +++ /dev/null @@ -1,8 +0,0 @@ -// This is testing that users can't access the runtime crate. - -mod m { - // The rt has been called both 'native' and 'rt' - use native; //~ ERROR unresolved import -} - -fn main() { } diff --git a/src/test/ui/hidden-rt-injection.stderr b/src/test/ui/hidden-rt-injection.stderr deleted file mode 100644 index 3e288b72ec6..00000000000 --- a/src/test/ui/hidden-rt-injection.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0432]: unresolved import `native` - --> $DIR/hidden-rt-injection.rs:5:9 - | -LL | use native; - | ^^^^^^ no `native` in the root - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/hidden-rt-injection2.rs b/src/test/ui/hidden-rt-injection2.rs deleted file mode 100644 index 2af113c05e0..00000000000 --- a/src/test/ui/hidden-rt-injection2.rs +++ /dev/null @@ -1,8 +0,0 @@ -// This is testing that users can't access the runtime crate. - -mod m { - // The rt has been called both 'native' and 'rt' - use rt; //~ ERROR unresolved import -} - -fn main() { } diff --git a/src/test/ui/hidden-rt-injection2.stderr b/src/test/ui/hidden-rt-injection2.stderr deleted file mode 100644 index 73f89b5856d..00000000000 --- a/src/test/ui/hidden-rt-injection2.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0432]: unresolved import `rt` - --> $DIR/hidden-rt-injection2.rs:5:9 - | -LL | use rt; - | ^^ no `rt` in the root - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/import.rs b/src/test/ui/import.rs deleted file mode 100644 index 3170dd2fae1..00000000000 --- a/src/test/ui/import.rs +++ /dev/null @@ -1,17 +0,0 @@ -use zed::bar; -use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432] - //~| no `baz` in `zed` - //~| HELP a similar name exists in the module - //~| SUGGESTION bar - - -mod zed { - pub fn bar() { println!("bar"); } - use foo; //~ ERROR unresolved import `foo` [E0432] - //~^ no `foo` in the root -} - -fn main() { - zed::foo(); //~ ERROR `foo` is private - bar(); -} diff --git a/src/test/ui/import2.rs b/src/test/ui/import2.rs deleted file mode 100644 index 036d6bc07e2..00000000000 --- a/src/test/ui/import2.rs +++ /dev/null @@ -1,10 +0,0 @@ -use baz::zed::bar; //~ ERROR unresolved import `baz::zed` [E0432] - //~^ could not find `zed` in `baz` - -mod baz {} -mod zed { - pub fn bar() { println!("bar3"); } -} -fn main() { - bar(); -} diff --git a/src/test/ui/import3.rs b/src/test/ui/import3.rs deleted file mode 100644 index 2c6ac9a00e1..00000000000 --- a/src/test/ui/import3.rs +++ /dev/null @@ -1,4 +0,0 @@ -// error-pattern: unresolved -use main::bar; - -fn main() { println!("foo"); } diff --git a/src/test/ui/import4.rs b/src/test/ui/import4.rs deleted file mode 100644 index ba3b7fbf535..00000000000 --- a/src/test/ui/import4.rs +++ /dev/null @@ -1,7 +0,0 @@ -// error-pattern: import - - -mod a { pub use b::foo; } -mod b { pub use a::foo; } - -fn main() { println!("loop"); } diff --git a/src/test/ui/issues/auxiliary/issue-36881-aux.rs b/src/test/ui/imports/auxiliary/issue-36881-aux.rs similarity index 100% rename from src/test/ui/issues/auxiliary/issue-36881-aux.rs rename to src/test/ui/imports/auxiliary/issue-36881-aux.rs diff --git a/src/test/ui/issues/auxiliary/issue-52891.rs b/src/test/ui/imports/auxiliary/issue-52891.rs similarity index 100% rename from src/test/ui/issues/auxiliary/issue-52891.rs rename to src/test/ui/imports/auxiliary/issue-52891.rs diff --git a/src/test/ui/issues/auxiliary/issue-59764.rs b/src/test/ui/imports/auxiliary/issue-59764.rs similarity index 100% rename from src/test/ui/issues/auxiliary/issue-59764.rs rename to src/test/ui/imports/auxiliary/issue-59764.rs diff --git a/src/test/ui/double-import.rs b/src/test/ui/imports/double-import.rs similarity index 100% rename from src/test/ui/double-import.rs rename to src/test/ui/imports/double-import.rs diff --git a/src/test/ui/double-import.stderr b/src/test/ui/imports/double-import.stderr similarity index 100% rename from src/test/ui/double-import.stderr rename to src/test/ui/imports/double-import.stderr diff --git a/src/test/ui/export-glob-imports-target.rs b/src/test/ui/imports/export-glob-imports-target.rs similarity index 100% rename from src/test/ui/export-glob-imports-target.rs rename to src/test/ui/imports/export-glob-imports-target.rs diff --git a/src/test/ui/glob-resolve1.rs b/src/test/ui/imports/glob-resolve1.rs similarity index 100% rename from src/test/ui/glob-resolve1.rs rename to src/test/ui/imports/glob-resolve1.rs diff --git a/src/test/ui/glob-resolve1.stderr b/src/test/ui/imports/glob-resolve1.stderr similarity index 100% rename from src/test/ui/glob-resolve1.stderr rename to src/test/ui/imports/glob-resolve1.stderr diff --git a/src/test/ui/imports/import-rpass.rs b/src/test/ui/imports/import-rpass.rs new file mode 100644 index 00000000000..de8bf626114 --- /dev/null +++ b/src/test/ui/imports/import-rpass.rs @@ -0,0 +1,12 @@ +// run-pass +mod foo { + pub fn x(y: isize) { println!("{}", y); } +} + +mod bar { + use foo::x; + use foo::x as z; + pub fn thing() { x(10); z(10); } +} + +pub fn main() { bar::thing(); } diff --git a/src/test/ui/imports/import.rs b/src/test/ui/imports/import.rs index de8bf626114..3170dd2fae1 100644 --- a/src/test/ui/imports/import.rs +++ b/src/test/ui/imports/import.rs @@ -1,12 +1,17 @@ -// run-pass -mod foo { - pub fn x(y: isize) { println!("{}", y); } -} +use zed::bar; +use zed::baz; //~ ERROR unresolved import `zed::baz` [E0432] + //~| no `baz` in `zed` + //~| HELP a similar name exists in the module + //~| SUGGESTION bar + -mod bar { - use foo::x; - use foo::x as z; - pub fn thing() { x(10); z(10); } +mod zed { + pub fn bar() { println!("bar"); } + use foo; //~ ERROR unresolved import `foo` [E0432] + //~^ no `foo` in the root } -pub fn main() { bar::thing(); } +fn main() { + zed::foo(); //~ ERROR `foo` is private + bar(); +} diff --git a/src/test/ui/import.stderr b/src/test/ui/imports/import.stderr similarity index 100% rename from src/test/ui/import.stderr rename to src/test/ui/imports/import.stderr diff --git a/src/test/ui/imports/import2-rpass.rs b/src/test/ui/imports/import2-rpass.rs new file mode 100644 index 00000000000..7b70f799ebf --- /dev/null +++ b/src/test/ui/imports/import2-rpass.rs @@ -0,0 +1,9 @@ +// run-pass + +use zed::bar; + +mod zed { + pub fn bar() { println!("bar"); } +} + +pub fn main() { bar(); } diff --git a/src/test/ui/imports/import2.rs b/src/test/ui/imports/import2.rs index 7b70f799ebf..036d6bc07e2 100644 --- a/src/test/ui/imports/import2.rs +++ b/src/test/ui/imports/import2.rs @@ -1,9 +1,10 @@ -// run-pass - -use zed::bar; +use baz::zed::bar; //~ ERROR unresolved import `baz::zed` [E0432] + //~^ could not find `zed` in `baz` +mod baz {} mod zed { - pub fn bar() { println!("bar"); } + pub fn bar() { println!("bar3"); } +} +fn main() { + bar(); } - -pub fn main() { bar(); } diff --git a/src/test/ui/import2.stderr b/src/test/ui/imports/import2.stderr similarity index 100% rename from src/test/ui/import2.stderr rename to src/test/ui/imports/import2.stderr diff --git a/src/test/ui/imports/import3-rpass.rs b/src/test/ui/imports/import3-rpass.rs new file mode 100644 index 00000000000..17797aed359 --- /dev/null +++ b/src/test/ui/imports/import3-rpass.rs @@ -0,0 +1,13 @@ +// run-pass +#![allow(unused_imports)] + +use baz::zed; +use baz::zed::bar; + +mod baz { + pub mod zed { + pub fn bar() { println!("bar2"); } + } +} + +pub fn main() { bar(); } diff --git a/src/test/ui/imports/import3.rs b/src/test/ui/imports/import3.rs index 17797aed359..2c6ac9a00e1 100644 --- a/src/test/ui/imports/import3.rs +++ b/src/test/ui/imports/import3.rs @@ -1,13 +1,4 @@ -// run-pass -#![allow(unused_imports)] +// error-pattern: unresolved +use main::bar; -use baz::zed; -use baz::zed::bar; - -mod baz { - pub mod zed { - pub fn bar() { println!("bar2"); } - } -} - -pub fn main() { bar(); } +fn main() { println!("foo"); } diff --git a/src/test/ui/import3.stderr b/src/test/ui/imports/import3.stderr similarity index 100% rename from src/test/ui/import3.stderr rename to src/test/ui/imports/import3.stderr diff --git a/src/test/ui/imports/import4-rpass.rs b/src/test/ui/imports/import4-rpass.rs new file mode 100644 index 00000000000..4fda5386112 --- /dev/null +++ b/src/test/ui/imports/import4-rpass.rs @@ -0,0 +1,9 @@ +// run-pass + +use zed::bar; + +mod zed { + pub fn bar() { println!("bar"); } +} + +pub fn main() { let _zed = 42; bar(); } diff --git a/src/test/ui/imports/import4.rs b/src/test/ui/imports/import4.rs index 4fda5386112..ba3b7fbf535 100644 --- a/src/test/ui/imports/import4.rs +++ b/src/test/ui/imports/import4.rs @@ -1,9 +1,7 @@ -// run-pass +// error-pattern: import -use zed::bar; -mod zed { - pub fn bar() { println!("bar"); } -} +mod a { pub use b::foo; } +mod b { pub use a::foo; } -pub fn main() { let _zed = 42; bar(); } +fn main() { println!("loop"); } diff --git a/src/test/ui/import4.stderr b/src/test/ui/imports/import4.stderr similarity index 100% rename from src/test/ui/import4.stderr rename to src/test/ui/imports/import4.stderr diff --git a/src/test/ui/issues/issue-13404.rs b/src/test/ui/imports/issue-13404.rs similarity index 100% rename from src/test/ui/issues/issue-13404.rs rename to src/test/ui/imports/issue-13404.rs diff --git a/src/test/ui/issues/issue-13404.stderr b/src/test/ui/imports/issue-13404.stderr similarity index 100% rename from src/test/ui/issues/issue-13404.stderr rename to src/test/ui/imports/issue-13404.stderr diff --git a/src/test/ui/issues/issue-1697.rs b/src/test/ui/imports/issue-1697.rs similarity index 100% rename from src/test/ui/issues/issue-1697.rs rename to src/test/ui/imports/issue-1697.rs diff --git a/src/test/ui/issues/issue-1697.stderr b/src/test/ui/imports/issue-1697.stderr similarity index 100% rename from src/test/ui/issues/issue-1697.stderr rename to src/test/ui/imports/issue-1697.stderr diff --git a/src/test/ui/issues/issue-18083.rs b/src/test/ui/imports/issue-18083.rs similarity index 100% rename from src/test/ui/issues/issue-18083.rs rename to src/test/ui/imports/issue-18083.rs diff --git a/src/test/ui/issues/issue-19498.rs b/src/test/ui/imports/issue-19498.rs similarity index 100% rename from src/test/ui/issues/issue-19498.rs rename to src/test/ui/imports/issue-19498.rs diff --git a/src/test/ui/issues/issue-19498.stderr b/src/test/ui/imports/issue-19498.stderr similarity index 100% rename from src/test/ui/issues/issue-19498.stderr rename to src/test/ui/imports/issue-19498.stderr diff --git a/src/test/ui/issues/issue-24081.rs b/src/test/ui/imports/issue-24081.rs similarity index 100% rename from src/test/ui/issues/issue-24081.rs rename to src/test/ui/imports/issue-24081.rs diff --git a/src/test/ui/issues/issue-24081.stderr b/src/test/ui/imports/issue-24081.stderr similarity index 100% rename from src/test/ui/issues/issue-24081.stderr rename to src/test/ui/imports/issue-24081.stderr diff --git a/src/test/ui/issues/issue-25396.rs b/src/test/ui/imports/issue-25396.rs similarity index 100% rename from src/test/ui/issues/issue-25396.rs rename to src/test/ui/imports/issue-25396.rs diff --git a/src/test/ui/issues/issue-25396.stderr b/src/test/ui/imports/issue-25396.stderr similarity index 100% rename from src/test/ui/issues/issue-25396.stderr rename to src/test/ui/imports/issue-25396.stderr diff --git a/src/test/ui/issues/issue-26886.rs b/src/test/ui/imports/issue-26886.rs similarity index 100% rename from src/test/ui/issues/issue-26886.rs rename to src/test/ui/imports/issue-26886.rs diff --git a/src/test/ui/issues/issue-26886.stderr b/src/test/ui/imports/issue-26886.stderr similarity index 100% rename from src/test/ui/issues/issue-26886.stderr rename to src/test/ui/imports/issue-26886.stderr diff --git a/src/test/ui/issues/issue-28134.rs b/src/test/ui/imports/issue-28134.rs similarity index 100% rename from src/test/ui/issues/issue-28134.rs rename to src/test/ui/imports/issue-28134.rs diff --git a/src/test/ui/issues/issue-28134.stderr b/src/test/ui/imports/issue-28134.stderr similarity index 100% rename from src/test/ui/issues/issue-28134.stderr rename to src/test/ui/imports/issue-28134.stderr diff --git a/src/test/ui/issues/issue-28388-1.rs b/src/test/ui/imports/issue-28388-1.rs similarity index 100% rename from src/test/ui/issues/issue-28388-1.rs rename to src/test/ui/imports/issue-28388-1.rs diff --git a/src/test/ui/issues/issue-28388-1.stderr b/src/test/ui/imports/issue-28388-1.stderr similarity index 100% rename from src/test/ui/issues/issue-28388-1.stderr rename to src/test/ui/imports/issue-28388-1.stderr diff --git a/src/test/ui/issues/issue-28388-2.rs b/src/test/ui/imports/issue-28388-2.rs similarity index 100% rename from src/test/ui/issues/issue-28388-2.rs rename to src/test/ui/imports/issue-28388-2.rs diff --git a/src/test/ui/issues/issue-28388-2.stderr b/src/test/ui/imports/issue-28388-2.stderr similarity index 100% rename from src/test/ui/issues/issue-28388-2.stderr rename to src/test/ui/imports/issue-28388-2.stderr diff --git a/src/test/ui/issues/issue-2937.rs b/src/test/ui/imports/issue-2937.rs similarity index 100% rename from src/test/ui/issues/issue-2937.rs rename to src/test/ui/imports/issue-2937.rs diff --git a/src/test/ui/issues/issue-2937.stderr b/src/test/ui/imports/issue-2937.stderr similarity index 100% rename from src/test/ui/issues/issue-2937.stderr rename to src/test/ui/imports/issue-2937.stderr diff --git a/src/test/ui/issues/issue-30560.rs b/src/test/ui/imports/issue-30560.rs similarity index 100% rename from src/test/ui/issues/issue-30560.rs rename to src/test/ui/imports/issue-30560.rs diff --git a/src/test/ui/issues/issue-30560.stderr b/src/test/ui/imports/issue-30560.stderr similarity index 100% rename from src/test/ui/issues/issue-30560.stderr rename to src/test/ui/imports/issue-30560.stderr diff --git a/src/test/ui/issues/issue-31212.rs b/src/test/ui/imports/issue-31212.rs similarity index 100% rename from src/test/ui/issues/issue-31212.rs rename to src/test/ui/imports/issue-31212.rs diff --git a/src/test/ui/issues/issue-31212.stderr b/src/test/ui/imports/issue-31212.stderr similarity index 100% rename from src/test/ui/issues/issue-31212.stderr rename to src/test/ui/imports/issue-31212.stderr diff --git a/src/test/ui/issues/issue-32354-suggest-import-rename.fixed b/src/test/ui/imports/issue-32354-suggest-import-rename.fixed similarity index 100% rename from src/test/ui/issues/issue-32354-suggest-import-rename.fixed rename to src/test/ui/imports/issue-32354-suggest-import-rename.fixed diff --git a/src/test/ui/issues/issue-32354-suggest-import-rename.rs b/src/test/ui/imports/issue-32354-suggest-import-rename.rs similarity index 100% rename from src/test/ui/issues/issue-32354-suggest-import-rename.rs rename to src/test/ui/imports/issue-32354-suggest-import-rename.rs diff --git a/src/test/ui/issues/issue-32354-suggest-import-rename.stderr b/src/test/ui/imports/issue-32354-suggest-import-rename.stderr similarity index 100% rename from src/test/ui/issues/issue-32354-suggest-import-rename.stderr rename to src/test/ui/imports/issue-32354-suggest-import-rename.stderr diff --git a/src/test/ui/issues/issue-32833.rs b/src/test/ui/imports/issue-32833.rs similarity index 100% rename from src/test/ui/issues/issue-32833.rs rename to src/test/ui/imports/issue-32833.rs diff --git a/src/test/ui/issues/issue-32833.stderr b/src/test/ui/imports/issue-32833.stderr similarity index 100% rename from src/test/ui/issues/issue-32833.stderr rename to src/test/ui/imports/issue-32833.stderr diff --git a/src/test/ui/issues/issue-33464.rs b/src/test/ui/imports/issue-33464.rs similarity index 100% rename from src/test/ui/issues/issue-33464.rs rename to src/test/ui/imports/issue-33464.rs diff --git a/src/test/ui/issues/issue-33464.stderr b/src/test/ui/imports/issue-33464.stderr similarity index 100% rename from src/test/ui/issues/issue-33464.stderr rename to src/test/ui/imports/issue-33464.stderr diff --git a/src/test/ui/issues/issue-36881.rs b/src/test/ui/imports/issue-36881.rs similarity index 100% rename from src/test/ui/issues/issue-36881.rs rename to src/test/ui/imports/issue-36881.rs diff --git a/src/test/ui/issues/issue-36881.stderr b/src/test/ui/imports/issue-36881.stderr similarity index 100% rename from src/test/ui/issues/issue-36881.stderr rename to src/test/ui/imports/issue-36881.stderr diff --git a/src/test/ui/issues/issue-37887.rs b/src/test/ui/imports/issue-37887.rs similarity index 100% rename from src/test/ui/issues/issue-37887.rs rename to src/test/ui/imports/issue-37887.rs diff --git a/src/test/ui/issues/issue-37887.stderr b/src/test/ui/imports/issue-37887.stderr similarity index 100% rename from src/test/ui/issues/issue-37887.stderr rename to src/test/ui/imports/issue-37887.stderr diff --git a/src/test/ui/issues/issue-38293.rs b/src/test/ui/imports/issue-38293.rs similarity index 100% rename from src/test/ui/issues/issue-38293.rs rename to src/test/ui/imports/issue-38293.rs diff --git a/src/test/ui/issues/issue-38293.stderr b/src/test/ui/imports/issue-38293.stderr similarity index 100% rename from src/test/ui/issues/issue-38293.stderr rename to src/test/ui/imports/issue-38293.stderr diff --git a/src/test/ui/issues/issue-4366-2.rs b/src/test/ui/imports/issue-4366-2.rs similarity index 100% rename from src/test/ui/issues/issue-4366-2.rs rename to src/test/ui/imports/issue-4366-2.rs diff --git a/src/test/ui/issues/issue-4366-2.stderr b/src/test/ui/imports/issue-4366-2.stderr similarity index 100% rename from src/test/ui/issues/issue-4366-2.stderr rename to src/test/ui/imports/issue-4366-2.stderr diff --git a/src/test/ui/issues/issue-4366.rs b/src/test/ui/imports/issue-4366.rs similarity index 100% rename from src/test/ui/issues/issue-4366.rs rename to src/test/ui/imports/issue-4366.rs diff --git a/src/test/ui/issues/issue-4366.stderr b/src/test/ui/imports/issue-4366.stderr similarity index 100% rename from src/test/ui/issues/issue-4366.stderr rename to src/test/ui/imports/issue-4366.stderr diff --git a/src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed b/src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed similarity index 100% rename from src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed rename to src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.fixed diff --git a/src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs b/src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs similarity index 100% rename from src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs rename to src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs diff --git a/src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr b/src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr similarity index 100% rename from src/test/ui/issues/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr rename to src/test/ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr diff --git a/src/test/ui/issues/issue-45829/auxiliary/issue-45829-a.rs b/src/test/ui/imports/issue-45829/auxiliary/issue-45829-a.rs similarity index 100% rename from src/test/ui/issues/issue-45829/auxiliary/issue-45829-a.rs rename to src/test/ui/imports/issue-45829/auxiliary/issue-45829-a.rs diff --git a/src/test/ui/issues/issue-45829/auxiliary/issue-45829-b.rs b/src/test/ui/imports/issue-45829/auxiliary/issue-45829-b.rs similarity index 100% rename from src/test/ui/issues/issue-45829/auxiliary/issue-45829-b.rs rename to src/test/ui/imports/issue-45829/auxiliary/issue-45829-b.rs diff --git a/src/test/ui/issues/issue-45829/import-self.rs b/src/test/ui/imports/issue-45829/import-self.rs similarity index 100% rename from src/test/ui/issues/issue-45829/import-self.rs rename to src/test/ui/imports/issue-45829/import-self.rs diff --git a/src/test/ui/issues/issue-45829/import-self.stderr b/src/test/ui/imports/issue-45829/import-self.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/import-self.stderr rename to src/test/ui/imports/issue-45829/import-self.stderr diff --git a/src/test/ui/issues/issue-45829/import-twice.rs b/src/test/ui/imports/issue-45829/import-twice.rs similarity index 100% rename from src/test/ui/issues/issue-45829/import-twice.rs rename to src/test/ui/imports/issue-45829/import-twice.rs diff --git a/src/test/ui/issues/issue-45829/import-twice.stderr b/src/test/ui/imports/issue-45829/import-twice.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/import-twice.stderr rename to src/test/ui/imports/issue-45829/import-twice.stderr diff --git a/src/test/ui/issues/issue-45829/issue-45829.rs b/src/test/ui/imports/issue-45829/issue-45829.rs similarity index 100% rename from src/test/ui/issues/issue-45829/issue-45829.rs rename to src/test/ui/imports/issue-45829/issue-45829.rs diff --git a/src/test/ui/issues/issue-45829/issue-45829.stderr b/src/test/ui/imports/issue-45829/issue-45829.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/issue-45829.stderr rename to src/test/ui/imports/issue-45829/issue-45829.stderr diff --git a/src/test/ui/issues/issue-45829/rename-extern-vs-use.rs b/src/test/ui/imports/issue-45829/rename-extern-vs-use.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern-vs-use.rs rename to src/test/ui/imports/issue-45829/rename-extern-vs-use.rs diff --git a/src/test/ui/issues/issue-45829/rename-extern-vs-use.stderr b/src/test/ui/imports/issue-45829/rename-extern-vs-use.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern-vs-use.stderr rename to src/test/ui/imports/issue-45829/rename-extern-vs-use.stderr diff --git a/src/test/ui/issues/issue-45829/rename-extern-with-tab.rs b/src/test/ui/imports/issue-45829/rename-extern-with-tab.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern-with-tab.rs rename to src/test/ui/imports/issue-45829/rename-extern-with-tab.rs diff --git a/src/test/ui/issues/issue-45829/rename-extern-with-tab.stderr b/src/test/ui/imports/issue-45829/rename-extern-with-tab.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern-with-tab.stderr rename to src/test/ui/imports/issue-45829/rename-extern-with-tab.stderr diff --git a/src/test/ui/issues/issue-45829/rename-extern.rs b/src/test/ui/imports/issue-45829/rename-extern.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern.rs rename to src/test/ui/imports/issue-45829/rename-extern.rs diff --git a/src/test/ui/issues/issue-45829/rename-extern.stderr b/src/test/ui/imports/issue-45829/rename-extern.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-extern.stderr rename to src/test/ui/imports/issue-45829/rename-extern.stderr diff --git a/src/test/ui/issues/issue-45829/rename-use-vs-extern.rs b/src/test/ui/imports/issue-45829/rename-use-vs-extern.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-use-vs-extern.rs rename to src/test/ui/imports/issue-45829/rename-use-vs-extern.rs diff --git a/src/test/ui/issues/issue-45829/rename-use-vs-extern.stderr b/src/test/ui/imports/issue-45829/rename-use-vs-extern.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-use-vs-extern.stderr rename to src/test/ui/imports/issue-45829/rename-use-vs-extern.stderr diff --git a/src/test/ui/issues/issue-45829/rename-use-with-tabs.rs b/src/test/ui/imports/issue-45829/rename-use-with-tabs.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-use-with-tabs.rs rename to src/test/ui/imports/issue-45829/rename-use-with-tabs.rs diff --git a/src/test/ui/issues/issue-45829/rename-use-with-tabs.stderr b/src/test/ui/imports/issue-45829/rename-use-with-tabs.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-use-with-tabs.stderr rename to src/test/ui/imports/issue-45829/rename-use-with-tabs.stderr diff --git a/src/test/ui/issues/issue-45829/rename-with-path.rs b/src/test/ui/imports/issue-45829/rename-with-path.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename-with-path.rs rename to src/test/ui/imports/issue-45829/rename-with-path.rs diff --git a/src/test/ui/issues/issue-45829/rename-with-path.stderr b/src/test/ui/imports/issue-45829/rename-with-path.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename-with-path.stderr rename to src/test/ui/imports/issue-45829/rename-with-path.stderr diff --git a/src/test/ui/issues/issue-45829/rename.rs b/src/test/ui/imports/issue-45829/rename.rs similarity index 100% rename from src/test/ui/issues/issue-45829/rename.rs rename to src/test/ui/imports/issue-45829/rename.rs diff --git a/src/test/ui/issues/issue-45829/rename.stderr b/src/test/ui/imports/issue-45829/rename.stderr similarity index 100% rename from src/test/ui/issues/issue-45829/rename.stderr rename to src/test/ui/imports/issue-45829/rename.stderr diff --git a/src/test/ui/issues/issue-47623.rs b/src/test/ui/imports/issue-47623.rs similarity index 100% rename from src/test/ui/issues/issue-47623.rs rename to src/test/ui/imports/issue-47623.rs diff --git a/src/test/ui/issues/issue-47623.stderr b/src/test/ui/imports/issue-47623.stderr similarity index 100% rename from src/test/ui/issues/issue-47623.stderr rename to src/test/ui/imports/issue-47623.stderr diff --git a/src/test/ui/issues/issue-4865-1.rs b/src/test/ui/imports/issue-4865-1.rs similarity index 100% rename from src/test/ui/issues/issue-4865-1.rs rename to src/test/ui/imports/issue-4865-1.rs diff --git a/src/test/ui/issues/issue-4865-2.rs b/src/test/ui/imports/issue-4865-2.rs similarity index 100% rename from src/test/ui/issues/issue-4865-2.rs rename to src/test/ui/imports/issue-4865-2.rs diff --git a/src/test/ui/issues/issue-4865-3.rs b/src/test/ui/imports/issue-4865-3.rs similarity index 100% rename from src/test/ui/issues/issue-4865-3.rs rename to src/test/ui/imports/issue-4865-3.rs diff --git a/src/test/ui/issues/issue-52891.fixed b/src/test/ui/imports/issue-52891.fixed similarity index 100% rename from src/test/ui/issues/issue-52891.fixed rename to src/test/ui/imports/issue-52891.fixed diff --git a/src/test/ui/issues/issue-52891.rs b/src/test/ui/imports/issue-52891.rs similarity index 100% rename from src/test/ui/issues/issue-52891.rs rename to src/test/ui/imports/issue-52891.rs diff --git a/src/test/ui/issues/issue-52891.stderr b/src/test/ui/imports/issue-52891.stderr similarity index 100% rename from src/test/ui/issues/issue-52891.stderr rename to src/test/ui/imports/issue-52891.stderr diff --git a/src/test/ui/issues/issue-53565.rs b/src/test/ui/imports/issue-53565.rs similarity index 100% rename from src/test/ui/issues/issue-53565.rs rename to src/test/ui/imports/issue-53565.rs diff --git a/src/test/ui/issues/issue-53565.stderr b/src/test/ui/imports/issue-53565.stderr similarity index 100% rename from src/test/ui/issues/issue-53565.stderr rename to src/test/ui/imports/issue-53565.stderr diff --git a/src/test/ui/issues/issue-59764.rs b/src/test/ui/imports/issue-59764.rs similarity index 100% rename from src/test/ui/issues/issue-59764.rs rename to src/test/ui/imports/issue-59764.rs diff --git a/src/test/ui/issues/issue-59764.stderr b/src/test/ui/imports/issue-59764.stderr similarity index 100% rename from src/test/ui/issues/issue-59764.stderr rename to src/test/ui/imports/issue-59764.stderr diff --git a/src/test/ui/issues/issue-8208.rs b/src/test/ui/imports/issue-8208.rs similarity index 100% rename from src/test/ui/issues/issue-8208.rs rename to src/test/ui/imports/issue-8208.rs diff --git a/src/test/ui/issues/issue-8208.stderr b/src/test/ui/imports/issue-8208.stderr similarity index 100% rename from src/test/ui/issues/issue-8208.stderr rename to src/test/ui/imports/issue-8208.stderr diff --git a/src/test/ui/issues/issue-8640.rs b/src/test/ui/imports/issue-8640.rs similarity index 100% rename from src/test/ui/issues/issue-8640.rs rename to src/test/ui/imports/issue-8640.rs diff --git a/src/test/ui/issues/issue-8640.stderr b/src/test/ui/imports/issue-8640.stderr similarity index 100% rename from src/test/ui/issues/issue-8640.stderr rename to src/test/ui/imports/issue-8640.stderr diff --git a/src/test/ui/resolve_self_super_hint.rs b/src/test/ui/imports/resolve_self_super_hint.rs similarity index 100% rename from src/test/ui/resolve_self_super_hint.rs rename to src/test/ui/imports/resolve_self_super_hint.rs diff --git a/src/test/ui/resolve_self_super_hint.stderr b/src/test/ui/imports/resolve_self_super_hint.stderr similarity index 100% rename from src/test/ui/resolve_self_super_hint.stderr rename to src/test/ui/imports/resolve_self_super_hint.stderr diff --git a/src/test/ui/issues/issue-56411-aux.rs b/src/test/ui/modules/issue-56411-aux.rs similarity index 100% rename from src/test/ui/issues/issue-56411-aux.rs rename to src/test/ui/modules/issue-56411-aux.rs diff --git a/src/test/ui/issues/issue-56411.rs b/src/test/ui/modules/issue-56411.rs similarity index 100% rename from src/test/ui/issues/issue-56411.rs rename to src/test/ui/modules/issue-56411.rs diff --git a/src/test/ui/issues/issue-56411.stderr b/src/test/ui/modules/issue-56411.stderr similarity index 100% rename from src/test/ui/issues/issue-56411.stderr rename to src/test/ui/modules/issue-56411.stderr diff --git a/src/test/ui/auxiliary/extern-prelude-vec.rs b/src/test/ui/resolve/auxiliary/extern-prelude-vec.rs similarity index 100% rename from src/test/ui/auxiliary/extern-prelude-vec.rs rename to src/test/ui/resolve/auxiliary/extern-prelude-vec.rs diff --git a/src/test/ui/auxiliary/extern-prelude.rs b/src/test/ui/resolve/auxiliary/extern-prelude.rs similarity index 100% rename from src/test/ui/auxiliary/extern-prelude.rs rename to src/test/ui/resolve/auxiliary/extern-prelude.rs diff --git a/src/test/ui/extern-prelude-fail.rs b/src/test/ui/resolve/extern-prelude-fail.rs similarity index 100% rename from src/test/ui/extern-prelude-fail.rs rename to src/test/ui/resolve/extern-prelude-fail.rs diff --git a/src/test/ui/extern-prelude-fail.stderr b/src/test/ui/resolve/extern-prelude-fail.stderr similarity index 100% rename from src/test/ui/extern-prelude-fail.stderr rename to src/test/ui/resolve/extern-prelude-fail.stderr diff --git a/src/test/ui/extern-prelude.rs b/src/test/ui/resolve/extern-prelude.rs similarity index 100% rename from src/test/ui/extern-prelude.rs rename to src/test/ui/resolve/extern-prelude.rs diff --git a/src/test/ui/issues/issue-49074.rs b/src/test/ui/resolve/issue-49074.rs similarity index 100% rename from src/test/ui/issues/issue-49074.rs rename to src/test/ui/resolve/issue-49074.rs diff --git a/src/test/ui/issues/issue-49074.stderr b/src/test/ui/resolve/issue-49074.stderr similarity index 100% rename from src/test/ui/issues/issue-49074.stderr rename to src/test/ui/resolve/issue-49074.stderr diff --git a/src/test/ui/resolve-pseudo-shadowing.rs b/src/test/ui/resolve/resolve-pseudo-shadowing.rs similarity index 100% rename from src/test/ui/resolve-pseudo-shadowing.rs rename to src/test/ui/resolve/resolve-pseudo-shadowing.rs diff --git a/src/test/ui/issues/auxiliary/lint-stability.rs b/src/test/ui/stability-attribute/auxiliary/lint-stability.rs similarity index 100% rename from src/test/ui/issues/auxiliary/lint-stability.rs rename to src/test/ui/stability-attribute/auxiliary/lint-stability.rs diff --git a/src/test/ui/issues/issue-28075.rs b/src/test/ui/stability-attribute/issue-28075.rs similarity index 100% rename from src/test/ui/issues/issue-28075.rs rename to src/test/ui/stability-attribute/issue-28075.rs diff --git a/src/test/ui/issues/issue-28075.stderr b/src/test/ui/stability-attribute/issue-28075.stderr similarity index 100% rename from src/test/ui/issues/issue-28075.stderr rename to src/test/ui/stability-attribute/issue-28075.stderr diff --git a/src/test/ui/issues/issue-28388-3.rs b/src/test/ui/stability-attribute/issue-28388-3.rs similarity index 100% rename from src/test/ui/issues/issue-28388-3.rs rename to src/test/ui/stability-attribute/issue-28388-3.rs diff --git a/src/test/ui/issues/issue-28388-3.stderr b/src/test/ui/stability-attribute/issue-28388-3.stderr similarity index 100% rename from src/test/ui/issues/issue-28388-3.stderr rename to src/test/ui/stability-attribute/issue-28388-3.stderr diff --git a/src/test/ui/issues/issue-30730.rs b/src/test/ui/unused/issue-30730.rs similarity index 100% rename from src/test/ui/issues/issue-30730.rs rename to src/test/ui/unused/issue-30730.rs diff --git a/src/test/ui/issues/issue-30730.stderr b/src/test/ui/unused/issue-30730.stderr similarity index 100% rename from src/test/ui/issues/issue-30730.stderr rename to src/test/ui/unused/issue-30730.stderr diff --git a/src/test/ui/issues/issue-46576.rs b/src/test/ui/unused/issue-46576.rs similarity index 100% rename from src/test/ui/issues/issue-46576.rs rename to src/test/ui/unused/issue-46576.rs diff --git a/src/test/ui/issues/issue-46576.stderr b/src/test/ui/unused/issue-46576.stderr similarity index 100% rename from src/test/ui/issues/issue-46576.stderr rename to src/test/ui/unused/issue-46576.stderr diff --git a/src/test/ui/issues/issue-59896.rs b/src/test/ui/unused/issue-59896.rs similarity index 100% rename from src/test/ui/issues/issue-59896.rs rename to src/test/ui/unused/issue-59896.rs diff --git a/src/test/ui/issues/issue-59896.stderr b/src/test/ui/unused/issue-59896.stderr similarity index 100% rename from src/test/ui/issues/issue-59896.stderr rename to src/test/ui/unused/issue-59896.stderr diff --git a/src/test/ui/issues/issue-70041.rs b/src/test/ui/unused/issue-70041.rs similarity index 100% rename from src/test/ui/issues/issue-70041.rs rename to src/test/ui/unused/issue-70041.rs diff --git a/src/test/ui/issues/issue-70041.stderr b/src/test/ui/unused/issue-70041.stderr similarity index 100% rename from src/test/ui/issues/issue-70041.stderr rename to src/test/ui/unused/issue-70041.stderr From 8065dabd171f7807b47a461b17f443df47a0cad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 7 Dec 2020 00:00:00 +0000 Subject: [PATCH 239/274] Validate naked functions definitions --- compiler/rustc_lint_defs/src/builtin.rs | 45 +++ compiler/rustc_passes/src/naked_functions.rs | 239 +++++++++++++- src/test/ui/asm/naked-functions.rs | 169 ++++++++++ src/test/ui/asm/naked-functions.stderr | 300 ++++++++++++++++++ src/test/ui/asm/naked-params.rs | 51 --- src/test/ui/asm/naked-params.stderr | 44 --- .../feature-gate-naked_functions.rs | 10 +- .../feature-gate-naked_functions.stderr | 4 +- .../rfc-2091-track-caller/error-with-naked.rs | 10 +- .../error-with-naked.stderr | 2 +- 10 files changed, 755 insertions(+), 119 deletions(-) create mode 100644 src/test/ui/asm/naked-functions.rs create mode 100644 src/test/ui/asm/naked-functions.stderr delete mode 100644 src/test/ui/asm/naked-params.rs delete mode 100644 src/test/ui/asm/naked-params.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index fa82dce0ae2..a9358c9610a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2742,6 +2742,50 @@ declare_lint! { "detects deprecation attributes with no effect", } +declare_lint! { + /// The `unsupported_naked_functions` lint detects naked function + /// definitions that are unsupported but were previously accepted. + /// + /// ### Example + /// + /// ```rust + /// #![feature(naked_functions)] + /// + /// #[naked] + /// pub fn f() -> u32 { + /// 42 + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The naked functions must be defined using a single inline assembly + /// block. + /// + /// The execution must never fall through past the end of the assembly + /// code so the block must use `noreturn` option. The asm block can also + /// use `att_syntax` option, but other options are not allowed. + /// + /// The asm block must not contain any operands other than `const` and + /// `sym`. Additionally, naked function should specify a non-Rust ABI. + /// + /// While other definitions of naked functions were previously accepted, + /// they are unsupported and might not work reliably. This is a + /// [future-incompatible] lint that will transition into hard error in + /// the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub UNSUPPORTED_NAKED_FUNCTIONS, + Warn, + "unsupported naked function definitions", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #32408 ", + edition: None, + }; +} + declare_tool_lint! { pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL, Deny, @@ -2832,6 +2876,7 @@ declare_lint_pass! { UNINHABITED_STATIC, FUNCTION_ITEM_REFERENCES, USELESS_DEPRECATED, + UNSUPPORTED_NAKED_FUNCTIONS, ] } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 6ef45cdd391..5b50ef8627b 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,10 +1,16 @@ +//! Checks validity of naked functions. + +use rustc_ast::InlineAsmOptions; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_target::spec::abi::Abi; fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { tcx.hir().visit_item_likes_in_module( @@ -33,27 +39,52 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> { fk: FnKind<'v>, _fd: &'tcx hir::FnDecl<'tcx>, body_id: hir::BodyId, - _span: Span, - _hir_id: hir::HirId, + span: Span, + hir_id: HirId, ) { + let ident_span; + let fn_header; + match fk { - // Rejected during attribute check. Do not validate further. - FnKind::Closure(..) => return, - FnKind::ItemFn(..) | FnKind::Method(..) => {} + FnKind::Closure(..) => { + // Closures with a naked attribute are rejected during attribute + // check. Don't validate them any further. + return; + } + FnKind::ItemFn(ident, _, ref header, ..) => { + ident_span = ident.span; + fn_header = header; + } + + FnKind::Method(ident, ref sig, ..) => { + ident_span = ident.span; + fn_header = &sig.header; + } } let naked = fk.attrs().iter().any(|attr| attr.has_name(sym::naked)); if naked { let body = self.tcx.hir().body(body_id); - check_params(self.tcx, body); - check_body(self.tcx, body); + check_abi(self.tcx, hir_id, fn_header.abi, ident_span); + check_no_patterns(self.tcx, body.params); + check_no_parameters_use(self.tcx, body); + check_asm(self.tcx, hir_id, body, span); } } } +/// Checks that function uses non-Rust ABI. +fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) { + if abi == Abi::Rust { + tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_ident_span, |lint| { + lint.build("Rust ABI is unsupported in naked functions").emit(); + }); + } +} + /// Checks that parameters don't use patterns. Mirrors the checks for function declarations. -fn check_params(tcx: TyCtxt<'_>, body: &hir::Body<'_>) { - for param in body.params { +fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { + for param in params { match param.pat.kind { hir::PatKind::Wild | hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, None) => {} @@ -69,23 +100,23 @@ fn check_params(tcx: TyCtxt<'_>, body: &hir::Body<'_>) { } } -/// Checks that function parameters aren't referenced in the function body. -fn check_body<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) { +/// Checks that function parameters aren't used in the function body. +fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) { let mut params = hir::HirIdSet::default(); for param in body.params { param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| { params.insert(hir_id); }); } - CheckBody { tcx, params }.visit_body(body); + CheckParameters { tcx, params }.visit_body(body); } -struct CheckBody<'tcx> { +struct CheckParameters<'tcx> { tcx: TyCtxt<'tcx>, params: hir::HirIdSet, } -impl<'tcx> Visitor<'tcx> for CheckBody<'tcx> { +impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { type Map = ErasedMap<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { @@ -103,11 +134,189 @@ impl<'tcx> Visitor<'tcx> for CheckBody<'tcx> { .sess .struct_span_err( expr.span, - "use of parameters not allowed inside naked functions", + "referencing function parameters is not allowed in naked functions", ) + .help("follow the calling convention in asm block to use parameters") .emit(); + return; } } hir::intravisit::walk_expr(self, expr); } } + +/// Checks that function body contains a single inline assembly block. +fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) { + let mut this = CheckInlineAssembly { tcx, items: Vec::new() }; + this.visit_body(body); + if let &[(ItemKind::Asm, _)] = &this.items[..] { + // Ok. + } else { + tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| { + let mut diag = lint.build("naked functions must contain a single asm block"); + let mut has_asm = false; + for &(kind, span) in &this.items { + match kind { + ItemKind::Asm if has_asm => { + diag.span_label( + span, + "multiple asm blocks are unsupported in naked functions", + ); + } + ItemKind::Asm => has_asm = true, + ItemKind::NonAsm => { + diag.span_label(span, "non-asm is unsupported in naked functions"); + } + } + } + diag.emit(); + }); + } +} + +struct CheckInlineAssembly<'tcx> { + tcx: TyCtxt<'tcx>, + items: Vec<(ItemKind, Span)>, +} + +#[derive(Copy, Clone)] +enum ItemKind { + Asm, + NonAsm, +} + +impl<'tcx> CheckInlineAssembly<'tcx> { + fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { + match expr.kind { + ExprKind::Box(..) + | ExprKind::ConstBlock(..) + | ExprKind::Array(..) + | ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Tup(..) + | ExprKind::Binary(..) + | ExprKind::Unary(..) + | ExprKind::Lit(..) + | ExprKind::Cast(..) + | ExprKind::Type(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::Closure(..) + | ExprKind::Assign(..) + | ExprKind::AssignOp(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Path(..) + | ExprKind::AddrOf(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::Struct(..) + | ExprKind::Repeat(..) + | ExprKind::Yield(..) => { + self.items.push((ItemKind::NonAsm, span)); + } + + ExprKind::InlineAsm(ref asm) => { + self.items.push((ItemKind::Asm, span)); + self.check_inline_asm(expr.hir_id, asm, span); + } + + ExprKind::LlvmInlineAsm(..) => { + self.items.push((ItemKind::Asm, span)); + self.tcx.struct_span_lint_hir( + UNSUPPORTED_NAKED_FUNCTIONS, + expr.hir_id, + span, + |lint| { + lint.build( + "the LLVM-style inline assembly is unsupported in naked functions", + ) + .help("use the new asm! syntax specified in RFC 2873") + .emit(); + }, + ); + } + + ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => { + hir::intravisit::walk_expr(self, expr); + } + } + } + + fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) { + let unsupported_operands: Vec = asm + .operands + .iter() + .filter_map(|&(ref op, op_sp)| match op { + InlineAsmOperand::Const { .. } | InlineAsmOperand::Sym { .. } => None, + InlineAsmOperand::In { .. } + | InlineAsmOperand::Out { .. } + | InlineAsmOperand::InOut { .. } + | InlineAsmOperand::SplitInOut { .. } => Some(op_sp), + }) + .collect(); + if !unsupported_operands.is_empty() { + self.tcx.struct_span_lint_hir( + UNSUPPORTED_NAKED_FUNCTIONS, + hir_id, + unsupported_operands, + |lint| { + lint.build("only `const` and `sym` operands are supported in naked functions") + .emit(); + }, + ); + } + + let unsupported_options: Vec<&'static str> = [ + (InlineAsmOptions::NOMEM, "`nomem`"), + (InlineAsmOptions::NOSTACK, "`nostack`"), + (InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"), + (InlineAsmOptions::PURE, "`pure`"), + (InlineAsmOptions::READONLY, "`readonly`"), + ] + .iter() + .filter_map(|&(option, name)| if asm.options.contains(option) { Some(name) } else { None }) + .collect(); + + if !unsupported_options.is_empty() { + self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| { + lint.build(&format!( + "asm options unsupported in naked functions: {}", + unsupported_options.join(", ") + )) + .emit(); + }); + } + + if !asm.options.contains(InlineAsmOptions::NORETURN) { + self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| { + lint.build("asm in naked functions must use `noreturn` option").emit(); + }); + } + } +} + +impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> { + type Map = ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { + match stmt.kind { + StmtKind::Item(..) => {} + StmtKind::Local(..) => { + self.items.push((ItemKind::NonAsm, stmt.span)); + } + StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => { + self.check_expr(expr, stmt.span); + } + } + } + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + self.check_expr(&expr, expr.span); + } +} diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs new file mode 100644 index 00000000000..a46ca4544a6 --- /dev/null +++ b/src/test/ui/asm/naked-functions.rs @@ -0,0 +1,169 @@ +// only-x86_64 +#![feature(asm)] +#![feature(llvm_asm)] +#![feature(naked_functions)] +#![feature(or_patterns)] +#![crate_type = "lib"] + +#[repr(C)] +pub struct P { x: u8, y: u16 } + +#[naked] +pub unsafe extern "C" fn patterns( + mut a: u32, + //~^ ERROR patterns not allowed in naked function parameters + &b: &i32, + //~^ ERROR patterns not allowed in naked function parameters + (None | Some(_)): Option>, + //~^ ERROR patterns not allowed in naked function parameters + P { x, y }: P, + //~^ ERROR patterns not allowed in naked function parameters +) { + asm!("", options(noreturn)) +} + +#[naked] +pub unsafe extern "C" fn inc(a: u32) -> u32 { + //~^ WARN naked functions must contain a single asm block + //~| WARN this was previously accepted + a + 1 + //~^ ERROR referencing function parameters is not allowed in naked functions +} + +#[naked] +pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { + asm!("/* {0} */", in(reg) a, options(noreturn)); + //~^ ERROR referencing function parameters is not allowed in naked functions + //~| WARN only `const` and `sym` operands are supported in naked functions + //~| WARN this was previously accepted +} + +#[naked] +pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { + //~^ WARN naked functions must contain a single asm block + //~| WARN this was previously accepted + (|| a + 1)() +} + +#[naked] +pub unsafe extern "C" fn unsupported_operands() { + //~^ WARN naked functions must contain a single asm block + //~| WARN this was previously accepted + let mut a = 0usize; + let mut b = 0usize; + let mut c = 0usize; + let mut d = 0usize; + let mut e = 0usize; + const F: usize = 0usize; + static G: usize = 0usize; + asm!("/* {0} {1} {2} {3} {4} {5} {6} */", + //~^ WARN asm in naked functions must use `noreturn` option + //~| WARN this was previously accepted + in(reg) a, + //~^ WARN only `const` and `sym` operands are supported in naked functions + //~| WARN this was previously accepted + inlateout(reg) b, + inout(reg) c, + lateout(reg) d, + out(reg) e, + const F, + sym G, + ); +} + +#[naked] +pub extern "C" fn missing_assembly() { + //~^ WARN naked functions must contain a single asm block + //~| WARN this was previously accepted +} + +#[naked] +pub extern "C" fn too_many_asm_blocks() { + //~^ WARN naked functions must contain a single asm block + //~| WARN this was previously accepted + asm!(""); + //~^ WARN asm in naked functions must use `noreturn` option + //~| WARN this was previously accepted + asm!(""); + //~^ WARN asm in naked functions must use `noreturn` option + //~| WARN this was previously accepted + asm!(""); + //~^ WARN asm in naked functions must use `noreturn` option + //~| WARN this was previously accepted + asm!("", options(noreturn)); +} + +pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { + #[naked] + pub extern "C" fn inner(y: usize) -> usize { + //~^ WARN naked functions must contain a single asm block + //~| WARN this was previously accepted + *&y + //~^ ERROR referencing function parameters is not allowed in naked functions + } + inner +} + +#[naked] +unsafe extern "C" fn llvm() -> ! { + //~^ WARN naked functions must contain a single asm block + //~| WARN this was previously accepted + llvm_asm!(""); + //~^ WARN LLVM-style inline assembly is unsupported in naked functions + //~| WARN this was previously accepted + core::hint::unreachable_unchecked(); +} + +#[naked] +unsafe extern "C" fn invalid_options() { + asm!("", options(nomem, preserves_flags, noreturn)); + //~^ WARN asm options unsupported in naked functions: `nomem`, `preserves_flags` + //~| WARN this was previously accepted +} + +#[naked] +unsafe extern "C" fn invalid_options_continued() { + asm!("", options(readonly, nostack), options(pure)); + //~^ ERROR asm with `pure` option must have at least one output + //~| WARN asm options unsupported in naked functions: `nostack`, `pure`, `readonly` + //~| WARN this was previously accepted + //~| WARN asm in naked functions must use `noreturn` option + //~| WARN this was previously accepted +} + +#[naked] +pub unsafe fn default_abi() { + //~^ WARN Rust ABI is unsupported in naked functions + //~| WARN this was previously accepted + asm!("", options(noreturn)); +} + +#[naked] +pub unsafe extern "Rust" fn rust_abi() { + //~^ WARN Rust ABI is unsupported in naked functions + //~| WARN this was previously accepted + asm!("", options(noreturn)); +} + +#[naked] +pub extern "C" fn valid_a() -> T { + unsafe { asm!("", options(noreturn)); } +} + +#[naked] +pub extern "C" fn valid_b() { + unsafe { { { + asm!("", options(noreturn)); ; ; ; + } ; } ; } +} + +#[naked] +pub unsafe extern "C" fn valid_c() { + asm!("", options(noreturn)); +} + +#[cfg(target_arch = "x86_64")] +#[naked] +pub unsafe extern "C" fn valid_att_syntax() { + asm!("", options(noreturn, att_syntax)); +} diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr new file mode 100644 index 00000000000..076289427b5 --- /dev/null +++ b/src/test/ui/asm/naked-functions.stderr @@ -0,0 +1,300 @@ +error: asm with `pure` option must have at least one output + --> $DIR/naked-functions.rs:126:14 + | +LL | asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ + +error: patterns not allowed in naked function parameters + --> $DIR/naked-functions.rs:13:5 + | +LL | mut a: u32, + | ^^^^^ + +error: patterns not allowed in naked function parameters + --> $DIR/naked-functions.rs:15:5 + | +LL | &b: &i32, + | ^^ + +error: patterns not allowed in naked function parameters + --> $DIR/naked-functions.rs:17:6 + | +LL | (None | Some(_)): Option>, + | ^^^^^^^^^^^^^^ + +error: patterns not allowed in naked function parameters + --> $DIR/naked-functions.rs:19:5 + | +LL | P { x, y }: P, + | ^^^^^^^^^^ + +error: referencing function parameters is not allowed in naked functions + --> $DIR/naked-functions.rs:29:5 + | +LL | a + 1 + | ^ + | + = help: follow the calling convention in asm block to use parameters + +warning: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:26:1 + | +LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 { +LL | | +LL | | +LL | | a + 1 + | | ----- non-asm is unsupported in naked functions +LL | | +LL | | } + | |_^ + | + = note: `#[warn(unsupported_naked_functions)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +error: referencing function parameters is not allowed in naked functions + --> $DIR/naked-functions.rs:35:31 + | +LL | asm!("/* {0} */", in(reg) a, options(noreturn)); + | ^ + | + = help: follow the calling convention in asm block to use parameters + +warning: only `const` and `sym` operands are supported in naked functions + --> $DIR/naked-functions.rs:35:23 + | +LL | asm!("/* {0} */", in(reg) a, options(noreturn)); + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:42:1 + | +LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { +LL | | +LL | | +LL | | (|| a + 1)() + | | ------------ non-asm is unsupported in naked functions +LL | | } + | |_^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: only `const` and `sym` operands are supported in naked functions + --> $DIR/naked-functions.rs:62:10 + | +LL | in(reg) a, + | ^^^^^^^^^ +... +LL | inlateout(reg) b, + | ^^^^^^^^^^^^^^^^ +LL | inout(reg) c, + | ^^^^^^^^^^^^ +LL | lateout(reg) d, + | ^^^^^^^^^^^^^^ +LL | out(reg) e, + | ^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:59:5 + | +LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */", +LL | | +LL | | +LL | | in(reg) a, +... | +LL | | sym G, +LL | | ); + | |______^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:49:1 + | +LL | / pub unsafe extern "C" fn unsupported_operands() { +LL | | +LL | | +LL | | let mut a = 0usize; + | | ------------------- non-asm is unsupported in naked functions +LL | | let mut b = 0usize; + | | ------------------- non-asm is unsupported in naked functions +LL | | let mut c = 0usize; + | | ------------------- non-asm is unsupported in naked functions +LL | | let mut d = 0usize; + | | ------------------- non-asm is unsupported in naked functions +LL | | let mut e = 0usize; + | | ------------------- non-asm is unsupported in naked functions +... | +LL | | ); +LL | | } + | |_^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:75:1 + | +LL | / pub extern "C" fn missing_assembly() { +LL | | +LL | | +LL | | } + | |_^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:84:5 + | +LL | asm!(""); + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:87:5 + | +LL | asm!(""); + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:90:5 + | +LL | asm!(""); + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:81:1 + | +LL | / pub extern "C" fn too_many_asm_blocks() { +LL | | +LL | | +LL | | asm!(""); +... | +LL | | asm!(""); + | | --------- multiple asm blocks are unsupported in naked functions +... | +LL | | asm!(""); + | | --------- multiple asm blocks are unsupported in naked functions +... | +LL | | asm!("", options(noreturn)); + | | ---------------------------- multiple asm blocks are unsupported in naked functions +LL | | } + | |_^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +error: referencing function parameters is not allowed in naked functions + --> $DIR/naked-functions.rs:101:11 + | +LL | *&y + | ^ + | + = help: follow the calling convention in asm block to use parameters + +warning: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:98:5 + | +LL | / pub extern "C" fn inner(y: usize) -> usize { +LL | | +LL | | +LL | | *&y + | | --- non-asm is unsupported in naked functions +LL | | +LL | | } + | |_____^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: the LLVM-style inline assembly is unsupported in naked functions + --> $DIR/naked-functions.rs:111:5 + | +LL | llvm_asm!(""); + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + = help: use the new asm! syntax specified in RFC 2873 + = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: naked functions must contain a single asm block + --> $DIR/naked-functions.rs:108:1 + | +LL | / unsafe extern "C" fn llvm() -> ! { +LL | | +LL | | +LL | | llvm_asm!(""); +... | +LL | | core::hint::unreachable_unchecked(); + | | ------------------------------------ non-asm is unsupported in naked functions +LL | | } + | |_^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: asm options unsupported in naked functions: `nomem`, `preserves_flags` + --> $DIR/naked-functions.rs:119:5 + | +LL | asm!("", options(nomem, preserves_flags, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly` + --> $DIR/naked-functions.rs:126:5 + | +LL | asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: asm in naked functions must use `noreturn` option + --> $DIR/naked-functions.rs:126:5 + | +LL | asm!("", options(readonly, nostack), options(pure)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: Rust ABI is unsupported in naked functions + --> $DIR/naked-functions.rs:135:15 + | +LL | pub unsafe fn default_abi() { + | ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +warning: Rust ABI is unsupported in naked functions + --> $DIR/naked-functions.rs:142:29 + | +LL | pub unsafe extern "Rust" fn rust_abi() { + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #32408 + +error: aborting due to 8 previous errors; 19 warnings emitted + diff --git a/src/test/ui/asm/naked-params.rs b/src/test/ui/asm/naked-params.rs deleted file mode 100644 index 46a4fc11e5a..00000000000 --- a/src/test/ui/asm/naked-params.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Check that use of function parameters is validate in naked functions. -// -// ignore-wasm32 asm unsupported -#![feature(asm)] -#![feature(naked_functions)] -#![feature(or_patterns)] -#![crate_type = "lib"] - -#[repr(C)] -pub struct P { x: u8, y: u16 } - -#[naked] -pub unsafe extern "C" fn f( - mut a: u32, - //~^ ERROR patterns not allowed in naked function parameters - &b: &i32, - //~^ ERROR patterns not allowed in naked function parameters - (None | Some(_)): Option>, - //~^ ERROR patterns not allowed in naked function parameters - P { x, y }: P, - //~^ ERROR patterns not allowed in naked function parameters -) { - asm!("", options(noreturn)) -} - -#[naked] -pub unsafe extern "C" fn inc(a: u32) -> u32 { - a + 1 - //~^ ERROR use of parameters not allowed inside naked functions -} - -#[naked] -pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { - asm!("/* {0} */", in(reg) a, options(noreturn)); - //~^ ERROR use of parameters not allowed inside naked functions -} - -#[naked] -pub unsafe extern "C" fn sum(x: u32, y: u32) -> u32 { - // FIXME: Should be detected by asm-only check. - (|| { x + y})() -} - -pub fn outer(x: u32) -> extern "C" fn(usize) -> usize { - #[naked] - pub extern "C" fn inner(y: usize) -> usize { - *&y - //~^ ERROR use of parameters not allowed inside naked functions - } - inner -} diff --git a/src/test/ui/asm/naked-params.stderr b/src/test/ui/asm/naked-params.stderr deleted file mode 100644 index 1a99e5109fc..00000000000 --- a/src/test/ui/asm/naked-params.stderr +++ /dev/null @@ -1,44 +0,0 @@ -error: patterns not allowed in naked function parameters - --> $DIR/naked-params.rs:14:5 - | -LL | mut a: u32, - | ^^^^^ - -error: patterns not allowed in naked function parameters - --> $DIR/naked-params.rs:16:5 - | -LL | &b: &i32, - | ^^ - -error: patterns not allowed in naked function parameters - --> $DIR/naked-params.rs:18:6 - | -LL | (None | Some(_)): Option>, - | ^^^^^^^^^^^^^^ - -error: patterns not allowed in naked function parameters - --> $DIR/naked-params.rs:20:5 - | -LL | P { x, y }: P, - | ^^^^^^^^^^ - -error: use of parameters not allowed inside naked functions - --> $DIR/naked-params.rs:28:5 - | -LL | a + 1 - | ^ - -error: use of parameters not allowed inside naked functions - --> $DIR/naked-params.rs:34:31 - | -LL | asm!("/* {0} */", in(reg) a, options(noreturn)); - | ^ - -error: use of parameters not allowed inside naked functions - --> $DIR/naked-params.rs:47:11 - | -LL | *&y - | ^ - -error: aborting due to 7 previous errors - diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.rs b/src/test/ui/feature-gates/feature-gate-naked_functions.rs index 16a51a1e82f..06bddc422cf 100644 --- a/src/test/ui/feature-gates/feature-gate-naked_functions.rs +++ b/src/test/ui/feature-gates/feature-gate-naked_functions.rs @@ -1,11 +1,15 @@ +#![feature(asm)] + #[naked] //~^ the `#[naked]` attribute is an experimental feature -fn naked() {} +extern "C" fn naked() { + asm!("", options(noreturn)) +} #[naked] //~^ the `#[naked]` attribute is an experimental feature -fn naked_2() -> isize { - 0 +extern "C" fn naked_2() -> isize { + asm!("", options(noreturn)) } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr index e24dde5429d..d95561d2013 100644 --- a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr +++ b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr @@ -1,5 +1,5 @@ error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:1:1 + --> $DIR/feature-gate-naked_functions.rs:3:1 | LL | #[naked] | ^^^^^^^^ @@ -8,7 +8,7 @@ LL | #[naked] = help: add `#![feature(naked_functions)]` to the crate attributes to enable error[E0658]: the `#[naked]` attribute is an experimental feature - --> $DIR/feature-gate-naked_functions.rs:5:1 + --> $DIR/feature-gate-naked_functions.rs:9:1 | LL | #[naked] | ^^^^^^^^ diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs index c60ff7dc934..70ec0e3033c 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs @@ -1,15 +1,19 @@ -#![feature(naked_functions)] +#![feature(asm, naked_functions)] #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` #[naked] -fn f() {} +extern "C" fn f() { + asm!("", options(noreturn)); +} struct S; impl S { #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` #[naked] - fn g() {} + extern "C" fn g() { + asm!("", options(noreturn)); + } } fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr index 211cd3f16ba..1b49148d629 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr @@ -5,7 +5,7 @@ LL | #[track_caller] | ^^^^^^^^^^^^^^^ error[E0736]: cannot use `#[track_caller]` with `#[naked]` - --> $DIR/error-with-naked.rs:10:5 + --> $DIR/error-with-naked.rs:12:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ From 2ee34a0923643f277775c874beb8990be4b1385c Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 6 Dec 2020 18:52:36 -0800 Subject: [PATCH 240/274] Use `summary_opts()` in another spot I added `summary_opts()` before I cut the branch for #77686 (2 months ago!), so this "slipped through the cracks". --- src/librustdoc/html/markdown.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 0e4c5410abe..fb17eb462e1 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1057,7 +1057,7 @@ fn markdown_summary_with_limit(md: &str, length_limit: usize) -> (String, bool) *text_length += text.len(); }; - 'outer: for event in Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH) { + 'outer: for event in Parser::new_ext(md, summary_opts()) { match &event { Event::Text(text) => { for word in text.split_inclusive(char::is_whitespace) { From 88da5682c364c9c89c2e7c54a4f2c94999cdc644 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 7 Dec 2020 16:16:42 +0300 Subject: [PATCH 241/274] Privatize some of libcore unicode_internals My understanding is that these API are perma unstable, so it doesn't make sense to pollute docs & IDE completion[1] with them. [1]: https://github.com/rust-analyzer/rust-analyzer/issues/6738 --- library/alloc/src/str.rs | 2 +- library/core/src/unicode/mod.rs | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 339592728ac..578eca7d893 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -388,7 +388,7 @@ impl str { } fn case_ignoreable_then_cased>(iter: I) -> bool { - use core::unicode::derived_property::{Case_Ignorable, Cased}; + use core::unicode::{Case_Ignorable, Cased}; match iter.skip_while(|&c| Case_Ignorable(c)).next() { Some(c) => Cased(c), None => false, diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs index 28c07f77170..37ca0a0779b 100644 --- a/library/core/src/unicode/mod.rs +++ b/library/core/src/unicode/mod.rs @@ -18,17 +18,14 @@ mod unicode_data; pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION; // For use in liballoc, not re-exported in libstd. -pub mod derived_property { - pub use super::{Case_Ignorable, Cased}; -} +pub use unicode_data::{ + case_ignorable::lookup as Case_Ignorable, cased::lookup as Cased, conversions, +}; -pub use unicode_data::alphabetic::lookup as Alphabetic; -pub use unicode_data::case_ignorable::lookup as Case_Ignorable; -pub use unicode_data::cased::lookup as Cased; -pub use unicode_data::cc::lookup as Cc; -pub use unicode_data::conversions; -pub use unicode_data::grapheme_extend::lookup as Grapheme_Extend; -pub use unicode_data::lowercase::lookup as Lowercase; -pub use unicode_data::n::lookup as N; -pub use unicode_data::uppercase::lookup as Uppercase; -pub use unicode_data::white_space::lookup as White_Space; +pub(crate) use unicode_data::alphabetic::lookup as Alphabetic; +pub(crate) use unicode_data::cc::lookup as Cc; +pub(crate) use unicode_data::grapheme_extend::lookup as Grapheme_Extend; +pub(crate) use unicode_data::lowercase::lookup as Lowercase; +pub(crate) use unicode_data::n::lookup as N; +pub(crate) use unicode_data::uppercase::lookup as Uppercase; +pub(crate) use unicode_data::white_space::lookup as White_Space; From 9703bb81923d23acf064543c17acac7ee071a1e5 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 7 Dec 2020 15:14:56 +0100 Subject: [PATCH 242/274] Fix SGX CI, take 3 Broken in #79038 --- library/std/tests/env.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs index 76056637a4c..b095c2dde62 100644 --- a/library/std/tests/env.rs +++ b/library/std/tests/env.rs @@ -78,9 +78,11 @@ fn test_env_set_var() { } #[test] -#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] +#[cfg_attr(not(any(unix, windows)), ignore, allow(unused))] #[allow(deprecated)] fn env_home_dir() { + use std::path::PathBuf; + fn var_to_os_string(var: Result) -> Option { match var { Ok(var) => Some(OsString::from(var)), @@ -91,8 +93,6 @@ fn env_home_dir() { cfg_if::cfg_if! { if #[cfg(unix)] { - use std::path::PathBuf; - let oldhome = var_to_os_string(var("HOME")); set_var("HOME", "/home/MountainView"); @@ -110,8 +110,6 @@ fn env_home_dir() { if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } } else if #[cfg(windows)] { - use std::path::PathBuf; - let oldhome = var_to_os_string(var("HOME")); let olduserprofile = var_to_os_string(var("USERPROFILE")); From e3e4870bcec6820d60771052760a26891c4f8e45 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 6 Dec 2020 21:31:42 +0100 Subject: [PATCH 243/274] small `TypeVisitor` refactor --- compiler/rustc_mir/src/interpret/util.rs | 9 ++-- compiler/rustc_typeck/src/check/check.rs | 68 +++++++++++++----------- library/core/src/ops/control_flow.rs | 14 +++++ 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index ec90f063a55..c2165db278f 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -13,12 +13,13 @@ where return Ok(()); } + struct FoundParam; struct UsedParamsNeedSubstVisitor<'tcx> { tcx: TyCtxt<'tcx>, } impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { - type BreakTy = (); + type BreakTy = FoundParam; fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if !c.needs_subst() { @@ -26,7 +27,7 @@ where } match c.val { - ty::ConstKind::Param(..) => ControlFlow::BREAK, + ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), _ => c.super_visit_with(self), } } @@ -37,7 +38,7 @@ where } match *ty.kind() { - ty::Param(_) => ControlFlow::BREAK, + ty::Param(_) => ControlFlow::Break(FoundParam), ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) | ty::FnDef(def_id, substs) => { @@ -76,7 +77,7 @@ where } let mut vis = UsedParamsNeedSubstVisitor { tcx }; - if ty.visit_with(&mut vis).is_break() { + if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { throw_inval!(TooGeneric); } else { Ok(()) diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 489d836298f..ec7369fd3e8 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -462,39 +462,25 @@ pub(super) fn check_opaque<'tcx>( /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result /// in "inheriting lifetimes". +#[instrument(skip(tcx, span))] pub(super) fn check_opaque_for_inheriting_lifetimes( tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span, ) { let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id)); - debug!( - "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}", - def_id, span, item - ); - - #[derive(Debug)] - struct ProhibitOpaqueVisitor<'tcx> { - opaque_identity_ty: Ty<'tcx>, - generics: &'tcx ty::Generics, - } + debug!(?item, ?span); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { - type BreakTy = Option>; - - fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); - if t != self.opaque_identity_ty && t.super_visit_with(self).is_break() { - return ControlFlow::Break(Some(t)); - } - ControlFlow::CONTINUE - } + struct FoundParentLifetime; + struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { + type BreakTy = FoundParentLifetime; fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); + debug!("FindParentLifetimeVisitor: r={:?}", r); if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - if *index < self.generics.parent_count as u32 { - return ControlFlow::Break(None); + if *index < self.0.parent_count as u32 { + return ControlFlow::Break(FoundParentLifetime); } else { return ControlFlow::CONTINUE; } @@ -505,7 +491,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { if let ty::ConstKind::Unevaluated(..) = c.val { - // FIXME(#72219) We currenctly don't detect lifetimes within substs + // FIXME(#72219) We currently don't detect lifetimes within substs // which would violate this check. Even though the particular substitution is not used // within the const, this should still be fixed. return ControlFlow::CONTINUE; @@ -514,6 +500,26 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( } } + #[derive(Debug)] + struct ProhibitOpaqueVisitor<'tcx> { + opaque_identity_ty: Ty<'tcx>, + generics: &'tcx ty::Generics, + } + + impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { + type BreakTy = Ty<'tcx>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); + if t == self.opaque_identity_ty { + ControlFlow::CONTINUE + } else { + t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics)) + .map_break(|FoundParentLifetime| t) + } + } + } + if let ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, .. @@ -555,14 +561,12 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { if snippet == "Self" { - if let Some(ty) = ty { - err.span_suggestion( - span, - "consider spelling out the type instead", - format!("{:?}", ty), - Applicability::MaybeIncorrect, - ); - } + err.span_suggestion( + span, + "consider spelling out the type instead", + format!("{:?}", ty), + Applicability::MaybeIncorrect, + ); } } err.emit(); diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 5ede1ba8e2c..4834ca74b82 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -56,6 +56,20 @@ impl ControlFlow { ControlFlow::Break(x) => Some(x), } } + + /// Maps `ControlFlow` to `ControlFlow` by applying a function + /// to the break value in case it exists. + #[inline] + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub fn map_break(self, f: F) -> ControlFlow + where + F: FnOnce(B) -> T, + { + match self { + ControlFlow::Continue(x) => ControlFlow::Continue(x), + ControlFlow::Break(x) => ControlFlow::Break(f(x)), + } + } } impl ControlFlow { From 97c7022d08fac94c09f671322c0696d65a75cca0 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 7 Dec 2020 17:33:43 +0200 Subject: [PATCH 244/274] rustc_codegen_ssa: use bitcasts instead of type punning for scalar transmutes. --- compiler/rustc_codegen_ssa/src/mir/block.rs | 19 +++++++++++ src/test/codegen/transmute-scalar.rs | 35 +++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/test/codegen/transmute-scalar.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e59832a8eed..ce56f163549 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1395,6 +1395,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dst: PlaceRef<'tcx, Bx::Value>, ) { let src = self.codegen_operand(bx, src); + + // Special-case transmutes between scalars as simple bitcasts. + match (&src.layout.abi, &dst.layout.abi) { + (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => { + // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers. + if (src_scalar.value == abi::Pointer) == (dst_scalar.value == abi::Pointer) { + assert_eq!(src.layout.size, dst.layout.size); + + // NOTE(eddyb) the `from_immediate` and `to_immediate_scalar` + // conversions allow handling `bool`s the same as `u8`s. + let src = bx.from_immediate(src.immediate()); + let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout)); + Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst); + return; + } + } + _ => {} + } + let llty = bx.backend_type(src.layout); let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty)); let align = src.layout.align.abi.min(dst.align); diff --git a/src/test/codegen/transmute-scalar.rs b/src/test/codegen/transmute-scalar.rs new file mode 100644 index 00000000000..48aea4a2f08 --- /dev/null +++ b/src/test/codegen/transmute-scalar.rs @@ -0,0 +1,35 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// CHECK: define i32 @f32_to_bits(float %x) +// CHECK: %2 = bitcast float %x to i32 +// CHECK-NEXT: store i32 %2, i32* %0 +// CHECK-NEXT: %3 = load i32, i32* %0 +// CHECK: ret i32 %3 +#[no_mangle] +pub fn f32_to_bits(x: f32) -> u32 { + unsafe { std::mem::transmute(x) } +} + +// CHECK: define i8 @bool_to_byte(i1 zeroext %b) +// CHECK: %1 = zext i1 %b to i8 +// CHECK-NEXT: store i8 %1, i8* %0 +// CHECK-NEXT: %2 = load i8, i8* %0 +// CHECK: ret i8 %2 +#[no_mangle] +pub fn bool_to_byte(b: bool) -> u8 { + unsafe { std::mem::transmute(b) } +} + +// CHECK: define zeroext i1 @byte_to_bool(i8 %byte) +// CHECK: %1 = trunc i8 %byte to i1 +// CHECK-NEXT: %2 = zext i1 %1 to i8 +// CHECK-NEXT: store i8 %2, i8* %0 +// CHECK-NEXT: %3 = load i8, i8* %0 +// CHECK-NEXT: %4 = trunc i8 %3 to i1 +// CHECK: ret i1 %4 +#[no_mangle] +pub unsafe fn byte_to_bool(byte: u8) -> bool { + std::mem::transmute(byte) +} From 0ee3f6d7efda309a867b83a9ec7705b600376ed8 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 7 Dec 2020 12:51:28 -0500 Subject: [PATCH 245/274] Update xsv to prevent random CI failures This fixes occasional proptest failures due to a bug in xsv, which aren't related to bugs in the rust compiler. --- src/tools/cargotest/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 8aabe077cf1..0a6bac48ebb 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -36,7 +36,7 @@ const TEST_REPOS: &[Test] = &[ Test { name: "xsv", repo: "https://github.com/BurntSushi/xsv", - sha: "66956b6bfd62d6ac767a6b6499c982eae20a2c9f", + sha: "3de6c04269a7d315f7e9864b9013451cd9580a08", lock: None, packages: &[], }, From bdda98aaba493be28569083c5ac57629caf3504d Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Mon, 7 Dec 2020 18:59:10 +0100 Subject: [PATCH 246/274] Add comment for assert_inhabited in compiler/rustc_mir/src/interpret/intrinsics.rs Co-authored-by: Ralf Jung --- compiler/rustc_mir/src/interpret/intrinsics.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index c25a312bb5a..2ffb7a05f25 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -412,6 +412,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of(ty)?; if layout.abi.is_uninhabited() { + // The run-time intrinsic panics just to get a good backtrace; here we abort + // since there is no problem showing a backtrace even for aborts. M::abort(self, format!("attempted to instantiate uninhabited type `{}`", ty))?; } } From 69ab0bcabff34b97cd8fe9f0c741748a9ffc8928 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Mon, 7 Dec 2020 21:26:09 +0100 Subject: [PATCH 247/274] Use 'error-pattern' in ui test --- src/test/ui/assume-type-intrinsics.rs | 4 +++- src/test/ui/assume-type-intrinsics.stderr | 19 +++---------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/test/ui/assume-type-intrinsics.rs b/src/test/ui/assume-type-intrinsics.rs index 8e9cb334527..77370e1ccc5 100644 --- a/src/test/ui/assume-type-intrinsics.rs +++ b/src/test/ui/assume-type-intrinsics.rs @@ -1,11 +1,13 @@ +// error-pattern: any use of this value will cause an error + #![feature(never_type)] #![feature(const_maybe_uninit_assume_init)] +#[allow(invalid_value)] fn main() { use std::mem::MaybeUninit; const _BAD: () = unsafe { MaybeUninit::::uninit().assume_init(); - //~^ WARN: the type `!` does not permit being left uninitialized }; } diff --git a/src/test/ui/assume-type-intrinsics.stderr b/src/test/ui/assume-type-intrinsics.stderr index b776915affd..6f400086a54 100644 --- a/src/test/ui/assume-type-intrinsics.stderr +++ b/src/test/ui/assume-type-intrinsics.stderr @@ -6,29 +6,16 @@ LL | intrinsics::assert_inhabited::(); | | | attempted to instantiate uninhabited type `!` | inside `MaybeUninit::::assume_init` at $SRC_DIR/core/src/mem/maybe_uninit.rs:LL:COL - | inside `_BAD` at $DIR/assume-type-intrinsics.rs:8:9 + | inside `_BAD` at $DIR/assume-type-intrinsics.rs:11:9 | - ::: $DIR/assume-type-intrinsics.rs:7:5 + ::: $DIR/assume-type-intrinsics.rs:10:5 | LL | / const _BAD: () = unsafe { LL | | MaybeUninit::::uninit().assume_init(); -LL | | LL | | }; | |______- | = note: `#[deny(const_err)]` on by default -warning: the type `!` does not permit being left uninitialized - --> $DIR/assume-type-intrinsics.rs:8:9 - | -LL | MaybeUninit::::uninit().assume_init(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | this code causes undefined behavior when executed - | help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done - | - = note: `#[warn(invalid_value)]` on by default - = note: the `!` type has no valid value - -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error From 9cc563b70b1e99c26404b059c36f2c66cc91e5f8 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Mon, 7 Dec 2020 21:40:20 +0100 Subject: [PATCH 248/274] Fixup: `filter().is_none()` -> `!any()` --- compiler/rustc_typeck/src/check/pat.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index bcb73e1b4e7..5fc573a57ad 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1174,7 +1174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let mut unmentioned_err = None; - // Report an error if incorrect number of the fields were specified. + // Report an error if an incorrect number of fields was specified. if adt.is_union() { if fields.len() != 1 { tcx.sess @@ -1185,12 +1185,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !etc && !unmentioned_fields.is_empty() { - let no_accessible_unmentioned_fields = unmentioned_fields - .iter() - .find(|(field, _)| { - field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) - }) - .is_none(); + let no_accessible_unmentioned_fields = !unmentioned_fields.iter().any(|(field, _)| { + field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) + }); if no_accessible_unmentioned_fields { unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields)); From 174935988f131efcbce3c63924ee056940c36fb5 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 8 Dec 2020 00:05:26 +0100 Subject: [PATCH 249/274] Make assume_init_{ref,mut} const --- library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index fc44a5a55fb..06195ac6285 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -103,6 +103,7 @@ #![feature(const_likely)] #![feature(const_unreachable_unchecked)] #![feature(const_maybe_uninit_assume_init)] +#![feature(const_maybe_uninit_as_ptr)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index eddfff6f513..57ebab33188 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -668,13 +668,14 @@ impl MaybeUninit { /// } /// ``` #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn assume_init_ref(&self) -> &T { + pub const unsafe fn assume_init_ref(&self) -> &T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::(); - &*self.value + &*self.as_ptr() } } @@ -790,13 +791,14 @@ impl MaybeUninit { // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make // a final decision about the rules before stabilization. #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] - pub unsafe fn assume_init_mut(&mut self) -> &mut T { + pub const unsafe fn assume_init_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { intrinsics::assert_inhabited::(); - &mut *self.value + &mut *self.as_mut_ptr() } } From 077527170bd112d97bdbb288ae8771930bcaa5b7 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 8 Dec 2020 00:07:34 +0100 Subject: [PATCH 250/274] Make write and slice_as_[mut_]_ptr const --- library/core/src/mem/maybe_uninit.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 57ebab33188..8800d7714cf 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -373,8 +373,9 @@ impl MaybeUninit { /// skip running the destructor. For your convenience, this also returns a mutable /// reference to the (now safely initialized) contents of `self`. #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub fn write(&mut self, val: T) -> &mut T { + pub const fn write(&mut self, val: T) -> &mut T { *self = MaybeUninit::new(val); // SAFETY: We just initialized this value. unsafe { self.assume_init_mut() } @@ -846,15 +847,17 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { + pub const fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this.as_ptr() as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] + #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { + pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this.as_mut_ptr() as *mut T } } From af9402af0f57607638294419b000f06a77da3014 Mon Sep 17 00:00:00 2001 From: LingMan Date: Tue, 8 Dec 2020 02:40:14 +0100 Subject: [PATCH 251/274] Replace simple `if let` constructs with Option::map Replaces a few constructs of the form if let Some(x) = var { Some(...) } else { None } with calls to Option::map. --- compiler/rustc_typeck/src/check/demand.rs | 54 ++++++----------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index d12d2cb59a5..763e4d651a2 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -361,11 +361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn replace_prefix(&self, s: &str, old: &str, new: &str) -> Option { - if let Some(stripped) = s.strip_prefix(old) { - Some(new.to_string() + stripped) - } else { - None - } + s.strip_prefix(old).map(|stripped| new.to_string() + stripped) } /// This function is used to determine potential "simple" improvements or users' errors and @@ -587,47 +583,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Mutability::Mut => { let new_prefix = "&mut ".to_owned() + derefs; match mutbl_a { - hir::Mutability::Mut => { - if let Some(s) = - self.replace_prefix(&src, "&mut ", &new_prefix) - { - Some((s, Applicability::MachineApplicable)) - } else { - None - } - } - hir::Mutability::Not => { - if let Some(s) = - self.replace_prefix(&src, "&", &new_prefix) - { - Some((s, Applicability::Unspecified)) - } else { - None - } - } + hir::Mutability::Mut => self + .replace_prefix(&src, "&mut ", &new_prefix) + .map(|s| (s, Applicability::MachineApplicable)), + hir::Mutability::Not => self + .replace_prefix(&src, "&", &new_prefix) + .map(|s| (s, Applicability::Unspecified)), } } hir::Mutability::Not => { let new_prefix = "&".to_owned() + derefs; match mutbl_a { - hir::Mutability::Mut => { - if let Some(s) = - self.replace_prefix(&src, "&mut ", &new_prefix) - { - Some((s, Applicability::MachineApplicable)) - } else { - None - } - } - hir::Mutability::Not => { - if let Some(s) = - self.replace_prefix(&src, "&", &new_prefix) - { - Some((s, Applicability::MachineApplicable)) - } else { - None - } - } + hir::Mutability::Mut => self + .replace_prefix(&src, "&mut ", &new_prefix) + .map(|s| (s, Applicability::MachineApplicable)), + hir::Mutability::Not => self + .replace_prefix(&src, "&", &new_prefix) + .map(|s| (s, Applicability::MachineApplicable)), } } } { From 95c268f64d71427b00b46fde8fbf499d380e9409 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Mon, 7 Dec 2020 17:41:53 -0800 Subject: [PATCH 252/274] Fixes to Rust coverage Fixes: #79725 Some macros can create a situation where `fn_sig_span` and `body_span` map to different files. New documentation on coverage tests incorrectly assumed multiple test binaries could just be listed at the end of the `llvm-cov` command, but it turns out each binary needs a `--object` prefix. This PR fixes the bug and updates the documentation to correct that issue. It also fixes a few other minor issues in internal implementation comments, and adds documentation on getting coverage results for doc tests. --- .../src/coverageinfo/mapgen.rs | 2 +- .../rustc_mir/src/transform/coverage/graph.rs | 6 +- .../rustc_mir/src/transform/coverage/mod.rs | 22 ++++- .../rustc_mir/src/transform/coverage/spans.rs | 42 ++++----- .../source-based-code-coverage.md | 91 ++++++++++++++++++- .../coverage-reports/Makefile | 22 +++-- .../expected_show_coverage.uses_crate.txt | 4 +- .../expected_show_coverage_counters.async.txt | 10 +- ...pected_show_coverage_counters.generics.txt | 4 +- ...cted_show_coverage_counters.uses_crate.txt | 10 +- 10 files changed, 157 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 1c7e727f9b0..72ba5bbd5f2 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -241,7 +241,7 @@ fn save_function_record( /// (functions referenced by other "used" or public items). Any other functions considered unused, /// or "Unreachable" were still parsed and processed through the MIR stage. /// -/// We can find the unreachable functions by the set different of all MIR `DefId`s (`tcx` query +/// We can find the unreachable functions by the set difference of all MIR `DefId`s (`tcx` query /// `mir_keys`) minus the codegenned `DefId`s (`tcx` query `collect_and_partition_mono_items`). /// /// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs index f79f0d32538..2408a999c05 100644 --- a/compiler/rustc_mir/src/transform/coverage/graph.rs +++ b/compiler/rustc_mir/src/transform/coverage/graph.rs @@ -33,7 +33,7 @@ impl CoverageGraph { // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock // equivalents. Note that since the BasicCoverageBlock graph has been fully simplified, the // each predecessor of a BCB leader_bb should be in a unique BCB, and each successor of a - // BCB last_bb should bin in its own unique BCB. Therefore, collecting the BCBs using + // BCB last_bb should be in its own unique BCB. Therefore, collecting the BCBs using // `bb_to_bcb` should work without requiring a deduplication step. let successors = IndexVec::from_fn_n( @@ -283,7 +283,9 @@ rustc_index::newtype_index! { } } -/// A BasicCoverageBlockData (BCB) represents the maximal-length sequence of MIR BasicBlocks without +/// `BasicCoverageBlockData` holds the data indexed by a `BasicCoverageBlock`. +/// +/// A `BasicCoverageBlock` (BCB) represents the maximal-length sequence of MIR `BasicBlock`s without /// conditional branches, and form a new, simplified, coverage-specific Control Flow Graph, without /// altering the original MIR CFG. /// diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 10f522d6746..f69748db238 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -88,6 +88,7 @@ struct Instrumentor<'a, 'tcx> { pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>, + source_file: Lrc, fn_sig_span: Span, body_span: Span, basic_coverage_blocks: CoverageGraph, @@ -96,9 +97,13 @@ struct Instrumentor<'a, 'tcx> { impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { + let source_map = tcx.sess.source_map(); let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, mir_body.source.def_id()); let body_span = hir_body.value.span; - let fn_sig_span = match some_fn_sig { + let source_file = source_map.lookup_source_file(body_span.lo()); + let fn_sig_span = match some_fn_sig.filter(|fn_sig| { + Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.hi())) + }) { Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()), None => body_span.shrink_to_lo(), }; @@ -108,6 +113,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { pass_name, tcx, mir_body, + source_file, fn_sig_span, body_span, basic_coverage_blocks, @@ -268,8 +274,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let tcx = self.tcx; let source_map = tcx.sess.source_map(); let body_span = self.body_span; - let source_file = source_map.lookup_source_file(body_span.lo()); - let file_name = Symbol::intern(&source_file.name.to_string()); + let file_name = Symbol::intern(&self.source_file.name.to_string()); let mut bcb_counters = IndexVec::from_elem_n(None, self.basic_coverage_blocks.num_nodes()); for covspan in coverage_spans { @@ -285,11 +290,20 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { bug!("Every BasicCoverageBlock should have a Counter or Expression"); }; graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind); + + debug!( + "Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})", + file_name, + self.source_file, + source_map.span_to_string(span), + source_map.span_to_string(body_span) + ); + inject_statement( self.mir_body, counter_kind, self.bcb_last_bb(bcb), - Some(make_code_region(file_name, &source_file, span, body_span)), + Some(make_code_region(file_name, &self.source_file, span, body_span)), ); } } diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs index 6eb89754ee6..fd3e782f6df 100644 --- a/compiler/rustc_mir/src/transform/coverage/spans.rs +++ b/compiler/rustc_mir/src/transform/coverage/spans.rs @@ -217,6 +217,27 @@ pub struct CoverageSpans<'a, 'tcx> { } impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { + /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be + /// counted. + /// + /// The basic steps are: + /// + /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each + /// `BasicCoverageBlockData`. + /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position + /// are sorted with longer spans before shorter spans; and equal spans are sorted + /// (deterministically) based on "dominator" relationship (if any). + /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance, + /// if another span or spans are already counting the same code region), or should be merged + /// into a broader combined span (because it represents a contiguous, non-branching, and + /// uninterrupted region of source code). + /// + /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since + /// closures have their own MIR, their `Span` in their enclosing function should be left + /// "uncovered". + /// + /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need + /// to be). pub(super) fn generate_coverage_spans( mir_body: &'a mir::Body<'tcx>, fn_sig_span: Span, @@ -247,27 +268,6 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { coverage_spans.to_refined_spans() } - /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be - /// counted. - /// - /// The basic steps are: - /// - /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each - /// `BasicCoverageBlockData`. - /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position - /// are sorted with longer spans before shorter spans; and equal spans are sorted - /// (deterministically) based on "dominator" relationship (if any). - /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance, - /// if another span or spans are already counting the same code region), or should be merged - /// into a broader combined span (because it represents a contiguous, non-branching, and - /// uninterrupted region of source code). - /// - /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since - /// closures have their own MIR, their `Span` in their enclosing function should be left - /// "uncovered". - /// - /// Note the resulting vector of `CoverageSpan`s does may not be fully sorted (and does not need - /// to be). fn mir_to_initial_sorted_coverage_spans(&self) -> Vec { let mut initial_spans = Vec::::with_capacity(self.mir_body.num_nodes() * 2); for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() { diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md index 9930bc67cd5..6ca5ae40707 100644 --- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md @@ -213,19 +213,102 @@ Then run the `cov` tool, with the `profdata` file and all test binaries: $ cargo cov -- report \ --use-color --ignore-filename-regex='/.cargo/registry' \ --instr-profile=json5format.profdata \ - target/debug/deps/lib-30768f9c53506dc5 \ - target/debug/deps/json5format-fececd4653271682 + --object target/debug/deps/lib-30768f9c53506dc5 \ + --object target/debug/deps/json5format-fececd4653271682 $ cargo cov -- show \ --use-color --ignore-filename-regex='/.cargo/registry' \ --instr-profile=json5format.profdata \ - target/debug/deps/lib-30768f9c53506dc5 \ - target/debug/deps/json5format-fececd4653271682 \ + --object target/debug/deps/lib-30768f9c53506dc5 \ + --object target/debug/deps/json5format-fececd4653271682 \ --show-instantiations --show-line-counts-or-regions \ --Xdemangler=rustfilt | less -R ``` _Note the command line option `--ignore-filename-regex=/.cargo/registry`, which excludes the sources for dependencies from the coverage results._ +### Tips for listing the binaries automatically + +For `bash` users, one suggested way to automatically complete the `cov` command with the list of binaries is with a command like: + +```bash +$ cargo cov -- report \ + $( \ + for file in \ + $( \ + RUSTFLAGS="-Zinstrument-coverage" \ + cargo test --tests --no-run --message-format=json \ + | jq -r "select(.profile.test == true) | .filenames[]" \ + | grep -v dSYM - \ + ); \ + do \ + printf "%s %s " -object $file; \ + done \ + ) \ + --instr-profile=json5format.profdata --summary-only # and/or other options +``` + +Adding `--no-run --message-format=json` to the _same_ `cargo test` command used to run +the tests (including the same environment variables and flags) generates output in a JSON +format that `jq` can easily query. + +The `printf` command takes this list and generates the `--object ` arguments +for each listed test binary. + +### Including doc tests + +The previous examples run `cargo test` with `--tests`, which excludes doc tests.[^79417] + +To include doc tests in the coverage results, drop the `--tests` flag, and apply the +`-Zinstrument-coverage` flag, and some doc-test-specific options in the +`RUSTDOCFLAGS` environment variable. (The `cargo profdata` command does not change.) + +```bash +$ RUSTFLAGS="-Zinstrument-coverage" \ + RUSTDOCFLAGS="-Zinstrument-coverage -Zunstable-options --persist-doctests target/debug/doctestbins" \ + LLVM_PROFILE_FILE="json5format-%m.profraw" \ + cargo test +$ cargo profdata -- merge \ + -sparse json5format-*.profraw -o json5format.profdata +``` + +The `-Zunstable-options --persist-doctests` flag is required, to save the test binaries +(with their coverage maps) for `llvm-cov`. + +```bash +$ cargo cov -- report \ + $( \ + for file in \ + $( \ + RUSTFLAGS="-Zinstrument-coverage" \ + RUSTDOCFLAGS="-Zinstrument-coverage -Zunstable-options --persist-doctests target/debug/doctestbins" \ + cargo test --no-run --message-format=json \ + | jq -r "select(.profile.test == true) | .filenames[]" \ + | grep -v dSYM - \ + ) \ + target/debug/doctestbins/*/rust_out; \ + do \ + [[ -x $file ]] && printf "%s %s " -object $file; \ + done \ + ) \ + --instr-profile=json5format.profdata --summary-only # and/or other options +``` + +Note, the differences in this `cargo cov` command, compared with the version without +doc tests, include: + +* The `cargo test ... --no-run` command is updated with the same environment variables + and flags used to _build_ the tests, _including_ the doc tests. (`LLVM_PROFILE_FILE` + is only used when _running_ the tests.) +* The file glob pattern `target/debug/doctestbins/*/rust_out` adds the `rust_out` + binaries generated for doc tests (note, however, that some `rust_out` files may not + be executable binaries). +* `[[ -x $file ]] &&` filters the files passed on to the `printf`, to include only + executable binaries. + +[^79417]: There is ongoing work to resolve a known issue +[(#79417)](https://github.com/rust-lang/rust/issues/79417) that doc test coverage +generates incorrect source line numbers in `llvm-cov show` results. + ## Other references Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.) diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 302f09ae422..a5d6970009a 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -147,13 +147,19 @@ else # Note `llvm-cov show` output for some programs can vary, but can be ignored # by inserting `// ignore-llvm-cov-show-diffs` at the top of the source file. # - # FIXME(richkadel): It looks like most past variations seem to have been mitigated. None of the - # Rust test source samples have the `// ignore-llvm-cov-show-diffs` anymore. The main variation - # I had seen (and is still present in the new `coverage/lib/used_crate.rs`) is the `llvm-cov show` - # reporting of multiple instantiations of a generic function with different type substitutions. - # For some reason, `llvm-cov show` can report these in a non-deterministic order, breaking the - # `diff` comparision. I was able to work around the problem with `diff --ignore-matching-lines=RE` + # FIXME(richkadel): None of the Rust test source samples have the + # `// ignore-llvm-cov-show-diffs` anymore. This directive exists to work around a limitation + # with `llvm-cov show`. When reporting coverage for multiple instantiations of a generic function, + # with different type substitutions, `llvm-cov show` prints these in a non-deterministic order, + # breaking the `diff` comparision. + # + # A partial workaround is implemented below, with `diff --ignore-matching-lines=RE` # to ignore each line prefixing each generic instantiation coverage code region. + # + # This workaround only works if the coverage counts are identical across all reported + # instantiations. If there is no way to ensure this, you may need to apply the + # `// ignore-llvm-cov-show-diffs` directive, and rely on the `.json` and counter + # files for validating results have not changed. $(DIFF) --ignore-matching-lines='::<.*>.*:$$' \ expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ @@ -190,10 +196,6 @@ endif $(call BIN,"$(TMPDIR)"/$@) \ | "$(PYTHON)" $(BASEDIR)/prettify_json.py \ > "$(TMPDIR)"/actual_export_coverage.$@.json - # FIXME(richkadel): With the addition of `--ignore-matching-lines=RE` to ignore the - # non-deterministically-ordered coverage results for multiple instantiations of generics with - # differing type substitutions, I probably don't need the `.json` files anymore (and may not - # need `prettify_json.py` either). ifdef RUSTC_BLESS_TEST cp "$(TMPDIR)"/actual_export_coverage.$@.json expected_export_coverage.$@.json diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index 4c03e950af0..e14e733fff6 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -19,12 +19,12 @@ 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 19| 2|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_crate::used_only_from_bin_crate_generic_function::<&str>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt index abc2d32a897..ed91e8898ee 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt @@ -35,9 +35,6 @@ Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) Counter in file 0 21:1 -> 21:23, #1 Counter in file 0 67:5 -> 67:23, #1 Counter in file 0 38:1 -> 38:19, #1 -Counter in file 0 29:1 -> 29:22, #1 -Counter in file 0 93:1 -> 101:2, #1 -Counter in file 0 91:1 -> 91:25, #1 Counter in file 0 38:19 -> 42:12, #1 Counter in file 0 43:9 -> 43:10, #3 Counter in file 0 43:14 -> 43:18, (#1 + 0) @@ -49,11 +46,14 @@ Counter in file 0 44:27 -> 44:32, #8 Counter in file 0 44:36 -> 44:38, (#6 + 0) Counter in file 0 45:14 -> 45:16, #7 Counter in file 0 47:1 -> 47:2, (#5 + (#6 + #7)) +Counter in file 0 29:1 -> 29:22, #1 +Counter in file 0 93:1 -> 101:2, #1 +Counter in file 0 91:1 -> 91:25, #1 Counter in file 0 51:5 -> 52:18, #1 Counter in file 0 53:13 -> 53:14, #2 Counter in file 0 63:13 -> 63:14, (#1 - #2) Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2)) -Counter in file 0 13:20 -> 13:21, #1 +Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 49:1 -> 68:12, #1 Counter in file 0 69:9 -> 69:10, #2 Counter in file 0 69:14 -> 69:27, (#1 + 0) @@ -69,8 +69,8 @@ Counter in file 0 86:14 -> 86:16, #2 Counter in file 0 87:14 -> 87:16, #3 Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2)))) Counter in file 0 17:1 -> 17:20, #1 -Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 66:5 -> 66:23, #1 +Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 117:17 -> 117:19, #1 diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt index b41f482173b..e2cbf6f709e 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.generics.txt @@ -32,12 +32,12 @@ Combined regions: 10:5 -> 12:6 (count=1) Segment at 10:5 (count = 1), RegionEntry Segment at 12:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworklENtNtNtCs6HRHKMTmAen_4core3ops4drop4Drop4dropB4_ +Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworklENtNtNtCs3rFBWs28XFJ_4core3ops4drop4Drop4dropB4_ Combined regions: 17:5 -> 19:6 (count=1) Segment at 17:5 (count = 1), RegionEntry Segment at 19:6 (count = 0), Skipped -Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworkdENtNtNtCs6HRHKMTmAen_4core3ops4drop4Drop4dropB4_ +Emitting segments for function: _RNvXs_Cs4fqI2P2rA04_8genericsINtB4_8FireworkdENtNtNtCs3rFBWs28XFJ_4core3ops4drop4Drop4dropB4_ Combined regions: 17:5 -> 19:6 (count=1) Segment at 17:5 (count = 1), RegionEntry diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt index 42cc4904e5f..b0319cd9e18 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt @@ -1,5 +1,5 @@ -Counter in file 0 25:1 -> 27:2, #1 Counter in file 0 17:1 -> 19:2, #1 +Counter in file 0 25:1 -> 27:2, #1 Counter in file 0 17:1 -> 19:2, #1 Counter in file 0 5:1 -> 12:2, #1 Counter in file 0 17:1 -> 19:2, 0 @@ -78,17 +78,17 @@ Segment at 51:1 (count = 0), RegionEntry Segment at 51:2 (count = 0), Skipped Segment at 53:1 (count = 1), RegionEntry Segment at 61:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionRINtNtCsFAjihUSTht_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionReECs4fqI2P2rA04_10uses_crate Combined regions: 17:1 -> 19:2 (count=1) Segment at 17:1 (count = 1), RegionEntry Segment at 19:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionReECs4fqI2P2rA04_10uses_crate +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate41used_only_from_bin_crate_generic_functionRINtNtCs3QflaznQylx_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate Combined regions: 17:1 -> 19:2 (count=1) Segment at 17:1 (count = 1), RegionEntry Segment at 19:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionINtNtCsFAjihUSTht_5alloc3vec3VeclEEB2_ +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate46used_only_from_this_lib_crate_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEEB2_ Combined regions: 21:1 -> 23:2 (count=1) Segment at 21:1 (count = 1), RegionEntry @@ -98,7 +98,7 @@ Combined regions: 21:1 -> 23:2 (count=1) Segment at 21:1 (count = 1), RegionEntry Segment at 23:2 (count = 0), Skipped -Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionINtNtCsFAjihUSTht_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate +Emitting segments for function: _RINvCsbDqzXfLQacH_10used_crate50used_from_bin_crate_and_lib_crate_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEECs4fqI2P2rA04_10uses_crate Combined regions: 25:1 -> 27:2 (count=1) Segment at 25:1 (count = 1), RegionEntry From 9eacdb5a777a8ec3aa6bf92f24fd39ef24a31ada Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 7 Dec 2020 18:35:06 -0800 Subject: [PATCH 253/274] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 63d0fe43449..d274fcf862b 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 63d0fe43449adcb316d34d98a982b597faca4178 +Subproject commit d274fcf862b89264fa2c6b917b15230705257317 From 37853f925f115eae8b2a3750d071de6af32309e7 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 26 Nov 2020 21:00:35 +0100 Subject: [PATCH 254/274] Visit ForeignItems when marking dead code. --- compiler/rustc_passes/src/dead.rs | 46 ++++++++++--------- src/test/ui/lint/dead-code/type-in-foreign.rs | 19 ++++++++ 2 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/lint/dead-code/type-in-foreign.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index b87b13cff80..bbd6b9b505f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -396,24 +396,6 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } } - hir::ItemKind::Trait(.., trait_item_refs) => { - for trait_item_ref in trait_item_refs { - let trait_item = self.krate.trait_item(trait_item_ref.id); - match trait_item.kind { - hir::TraitItemKind::Const(_, Some(_)) - | hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => { - if has_allow_dead_code_or_lang_attr( - self.tcx, - trait_item.hir_id, - &trait_item.attrs, - ) { - self.worklist.push(trait_item.hir_id); - } - } - _ => {} - } - } - } hir::ItemKind::Impl { ref of_trait, items, .. } => { if of_trait.is_some() { self.worklist.push(item.hir_id); @@ -440,15 +422,37 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } - fn visit_trait_item(&mut self, _item: &hir::TraitItem<'_>) { - // ignore: we are handling this in `visit_item` above + fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { + match trait_item.kind { + hir::TraitItemKind::Const(_, Some(_)) + | hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => { + if has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id, &trait_item.attrs) + { + self.worklist.push(trait_item.hir_id); + } + } + _ => {} + } } fn visit_impl_item(&mut self, _item: &hir::ImplItem<'_>) { // ignore: we are handling this in `visit_item` above } - fn visit_foreign_item(&mut self, _item: &'v hir::ForeignItem<'v>) {} + fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) { + match foreign_item.kind { + hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Fn(..) => { + if has_allow_dead_code_or_lang_attr( + self.tcx, + foreign_item.hir_id, + &foreign_item.attrs, + ) { + self.worklist.push(foreign_item.hir_id); + } + } + _ => {} + } + } } fn create_and_seed_worklist<'tcx>( diff --git a/src/test/ui/lint/dead-code/type-in-foreign.rs b/src/test/ui/lint/dead-code/type-in-foreign.rs new file mode 100644 index 00000000000..b6c593f316f --- /dev/null +++ b/src/test/ui/lint/dead-code/type-in-foreign.rs @@ -0,0 +1,19 @@ +// Verify that we do not warn on types that are used by foreign functions. +// check-pass +#![deny(dead_code)] + +#[repr(C)] +struct Type(u8); + +#[repr(C)] +struct Param(u8); + +extern "C" { + #[allow(dead_code)] + fn hey(t: Param); + + #[allow(dead_code)] + static much: Type; +} + +fn main() {} From 06aa7a7601fe53bb095543bd633da3e165df2738 Mon Sep 17 00:00:00 2001 From: LingMan Date: Tue, 8 Dec 2020 14:46:19 +0100 Subject: [PATCH 255/274] Strip prefix instead of replacing it with empty string --- compiler/rustc_typeck/src/check/demand.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index d12d2cb59a5..e1ff1925a14 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -552,11 +552,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(&src, "&", "") { + if let Some(src) = src.strip_prefix('&') { return Some(( sp, "consider removing the borrow", - src, + src.to_string(), Applicability::MachineApplicable, )); } From 7654b12112664f4e21e519c0c0d7d0aff1f70221 Mon Sep 17 00:00:00 2001 From: LingMan Date: Tue, 8 Dec 2020 15:37:39 +0100 Subject: [PATCH 256/274] Simplify visit_{foreign,trait}_item Using an `if` seems like a better semantic fit and saves a few lines. --- compiler/rustc_passes/src/dead.rs | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index bbd6b9b505f..00152878d6d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -423,15 +423,11 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { - match trait_item.kind { - hir::TraitItemKind::Const(_, Some(_)) - | hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => { - if has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id, &trait_item.attrs) - { - self.worklist.push(trait_item.hir_id); - } - } - _ => {} + use hir::TraitItemKind::{Const, Fn}; + if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) + && has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id, &trait_item.attrs) + { + self.worklist.push(trait_item.hir_id); } } @@ -440,17 +436,11 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) { - match foreign_item.kind { - hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Fn(..) => { - if has_allow_dead_code_or_lang_attr( - self.tcx, - foreign_item.hir_id, - &foreign_item.attrs, - ) { - self.worklist.push(foreign_item.hir_id); - } - } - _ => {} + use hir::ForeignItemKind::{Fn, Static}; + if matches!(foreign_item.kind, Static(..) | Fn(..)) + && has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id, &foreign_item.attrs) + { + self.worklist.push(foreign_item.hir_id); } } } From a332e2b38fb3c374d751edadfc2c21594f2e7611 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 7 Dec 2020 17:05:28 -0500 Subject: [PATCH 257/274] Account for gaps in def path table during decoding When encoding a proc-macro crate, there may be gaps in the table (since we only encode the crate root and proc-macro items). Account for this by checking if the entry is present, rather than using `unwrap()` --- compiler/rustc_metadata/src/rmeta/decoder.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index c571ed7b612..43f7b2a9928 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1553,6 +1553,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { return Some(DefId { krate, index: def_index_guess }); } + let is_proc_macro = self.is_proc_macro_crate(); + // Slow path: We need to find out the new `DefIndex` of the provided // `DefPathHash`, if its still exists. This requires decoding every `DefPathHash` // stored in this crate. @@ -1561,9 +1563,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let mut map = FxHashMap::with_capacity_and_hasher(end_id as usize, Default::default()); for i in 0..end_id { let def_index = DefIndex::from_u32(i); - let hash = - self.root.tables.def_path_hashes.get(self, def_index).unwrap().decode(self); - map.insert(hash, def_index); + // There may be gaps in the encoded table if we're decoding a proc-macro crate + if let Some(hash) = self.root.tables.def_path_hashes.get(self, def_index) { + map.insert(hash.decode(self), def_index); + } else if !is_proc_macro { + panic!("Missing def_path_hashes entry for {:?}", def_index); + } } map }); From dbe3acfaebf258da43a7ca9e03c43df508b44132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 5 Dec 2020 13:12:07 +0100 Subject: [PATCH 258/274] don't wrap code block in Ok() (clipppy::unit_arg) --- src/bootstrap/setup.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 55d2445fc49..2d4484c562c 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -198,7 +198,7 @@ simply delete the `pre-commit` file from .git/hooks." }; }; - Ok(if should_install { + if should_install { let src = src_path.join("src").join("etc").join("pre-commit.sh"); let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map( |output| { @@ -217,5 +217,6 @@ simply delete the `pre-commit` file from .git/hooks." }; } else { println!("Ok, skipping installation!"); - }) + } + Ok(()) } From 0fa461558c85202281b1d33b7b77f27a32459be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 5 Dec 2020 13:16:34 +0100 Subject: [PATCH 259/274] use .contains() or .any() instead of find(x).is_some() (clippy::search_is_some) --- compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs | 2 +- src/librustdoc/html/markdown.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index 2a90fb042dd..6211cf8a9da 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -445,7 +445,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", type_name, needle_fr ); - if type_name.find(&format!("'{}", counter)).is_some() { + if type_name.contains(&format!("'{}", counter)) { // Only add a label if we can confirm that a region was labelled. RegionNameHighlight::CannotMatchHirTy(span, type_name) } else { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index fb17eb462e1..bdbb90837c7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -391,7 +391,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { _, ))) => { debug!("saw end of shortcut link to {}", dest); - if self.links.iter().find(|&link| *link.href == **dest).is_some() { + if self.links.iter().any(|link| *link.href == **dest) { assert!(self.shortcut_link.is_some(), "saw closing link without opening tag"); self.shortcut_link = None; } From c37e19843aefbe098bb0d511a877a3831d755704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 5 Dec 2020 13:32:08 +0100 Subject: [PATCH 260/274] don't create owned values for comparison (clippy::cmp_owned) --- compiler/rustc_lint/src/nonstandard_style.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 2720c376774..6d61b86f32e 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -131,7 +131,7 @@ impl NonCamelCaseTypes { let cc = to_camel_case(name); // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". - if name.to_string() != cc { + if *name != cc { err.span_suggestion( ident.span, "convert the identifier to upper camel case", @@ -271,7 +271,7 @@ impl NonSnakeCase { let mut err = lint.build(&msg); // We cannot provide meaningful suggestions // if the characters are in the category of "Uppercase Letter". - if name.to_string() != sc { + if *name != sc { // We have a valid span in almost all cases, but we don't have one when linting a crate // name provided via the command line. if !ident.span.is_dummy() { @@ -455,7 +455,7 @@ impl NonUpperCaseGlobals { lint.build(&format!("{} `{}` should have an upper case name", sort, name)); // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". - if name.to_string() != uc { + if *name != uc { err.span_suggestion( ident.span, "convert the identifier to upper case", From 20f8538d1fb52a7e92e1bd7c731d213ad393eec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 5 Dec 2020 13:35:05 +0100 Subject: [PATCH 261/274] simplify if let Some(_) = x to if x.is_some() (clippy::redundant_pattern_matching) --- .../error_reporting/nice_region_error/different_lifetimes.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 59786059fae..cdd68d83f22 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -121,7 +121,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { (Some(ret_span), _) => { let sup_future = self.future_return_type(scope_def_id_sup); - let (return_type, action) = if let Some(_) = sup_future { + let (return_type, action) = if sup_future.is_some() { ("returned future", "held across an await point") } else { ("return type", "returned") @@ -140,7 +140,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } (_, Some(ret_span)) => { let sub_future = self.future_return_type(scope_def_id_sub); - let (return_type, action) = if let Some(_) = sub_future { + let (return_type, action) = if sub_future.is_some() { ("returned future", "held across an await point") } else { ("return type", "returned") From d711c3006bae35588899cd0d823c79122de40a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 9 Dec 2020 00:00:00 +0000 Subject: [PATCH 262/274] Remove `first_merge` from liveness debug logs --- compiler/rustc_passes/src/liveness.rs | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index ad059c05a76..0b464f25efb 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -781,19 +781,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!("init_from_succ(ln={}, succ={})", self.ln_str(ln), self.ln_str(succ_ln)); } - fn merge_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode, first_merge: bool) -> bool { + fn merge_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) -> bool { if ln == succ_ln { return false; } let changed = self.rwu_table.union(ln, succ_ln); - debug!( - "merge_from_succ(ln={:?}, succ={}, first_merge={}, changed={})", - ln, - self.ln_str(succ_ln), - first_merge, - changed - ); + debug!("merge_from_succ(ln={:?}, succ={}, changed={})", ln, self.ln_str(succ_ln), changed); changed } @@ -893,7 +887,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }; // Propagate through calls to the closure. - let mut first_merge = true; loop { self.init_from_succ(self.closure_ln, succ); for param in body.params { @@ -903,10 +896,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }) } - if !self.merge_from_succ(self.exit_ln, self.closure_ln, first_merge) { + if !self.merge_from_succ(self.exit_ln, self.closure_ln) { break; } - first_merge = false; assert_eq!(succ, self.propagate_through_expr(&body.value, self.exit_ln)); } @@ -1012,7 +1004,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // let ln = self.live_node(expr.hir_id, expr.span); self.init_empty(ln, succ); - let mut first_merge = true; for arm in arms { let body_succ = self.propagate_through_expr(&arm.body, succ); @@ -1021,8 +1012,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { body_succ, ); let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ); - self.merge_from_succ(ln, arm_succ, first_merge); - first_merge = false; + self.merge_from_succ(ln, arm_succ); } self.propagate_through_expr(&e, ln) } @@ -1133,7 +1123,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let ln = self.live_node(expr.hir_id, expr.span); self.init_from_succ(ln, succ); - self.merge_from_succ(ln, r_succ, false); + self.merge_from_succ(ln, r_succ); self.propagate_through_expr(&l, ln) } @@ -1377,7 +1367,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { */ // first iteration: - let mut first_merge = true; let ln = self.live_node(expr.hir_id, expr.span); self.init_empty(ln, succ); debug!("propagate_through_loop: using id for loop body {} {:?}", expr.hir_id, body); @@ -1389,8 +1378,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let body_ln = self.propagate_through_block(body, ln); // repeat until fixed point is reached: - while self.merge_from_succ(ln, body_ln, first_merge) { - first_merge = false; + while self.merge_from_succ(ln, body_ln) { assert_eq!(body_ln, self.propagate_through_block(body, ln)); } From c7d7bc917d94f185f18209906162bc453ae874ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 9 Dec 2020 00:00:00 +0000 Subject: [PATCH 263/274] Move RWUTable to a separate module --- compiler/rustc_passes/src/liveness.rs | 151 +----------------- .../rustc_passes/src/liveness/rwu_table.rs | 144 +++++++++++++++++ 2 files changed, 149 insertions(+), 146 deletions(-) create mode 100644 compiler/rustc_passes/src/liveness/rwu_table.rs diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index ad059c05a76..a449bddbaae 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -105,6 +105,8 @@ use std::io; use std::io::prelude::*; use std::rc::Rc; +mod rwu_table; + rustc_index::newtype_index! { pub struct Variable { DEBUG_FORMAT = "v({})", @@ -468,149 +470,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { // Actually we compute just a bit more than just liveness, but we use // the same basic propagation framework in all cases. -#[derive(Clone, Copy)] -struct RWU { - reader: bool, - writer: bool, - used: bool, -} - -/// Conceptually, this is like a `Vec>`. But the number of -/// RWU`s can get very large, so it uses a more compact representation. -struct RWUTable { - /// Total number of live nodes. - live_nodes: usize, - /// Total number of variables. - vars: usize, - - /// A compressed representation of `RWU`s. - /// - /// Each word represents 2 different `RWU`s packed together. Each packed RWU - /// is stored in 4 bits: a reader bit, a writer bit, a used bit and a - /// padding bit. - /// - /// The data for each live node is contiguous and starts at a word boundary, - /// so there might be an unused space left. - words: Vec, - /// Number of words per each live node. - live_node_words: usize, -} - -impl RWUTable { - const RWU_READER: u8 = 0b0001; - const RWU_WRITER: u8 = 0b0010; - const RWU_USED: u8 = 0b0100; - const RWU_MASK: u8 = 0b1111; - - /// Size of packed RWU in bits. - const RWU_BITS: usize = 4; - /// Size of a word in bits. - const WORD_BITS: usize = std::mem::size_of::() * 8; - /// Number of packed RWUs that fit into a single word. - const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS; - - fn new(live_nodes: usize, vars: usize) -> RWUTable { - let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT; - Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] } - } - - fn word_and_shift(&self, ln: LiveNode, var: Variable) -> (usize, u32) { - assert!(ln.index() < self.live_nodes); - assert!(var.index() < self.vars); - - let var = var.index(); - let word = var / Self::WORD_RWU_COUNT; - let shift = Self::RWU_BITS * (var % Self::WORD_RWU_COUNT); - (ln.index() * self.live_node_words + word, shift as u32) - } - - fn pick2_rows_mut(&mut self, a: LiveNode, b: LiveNode) -> (&mut [u8], &mut [u8]) { - assert!(a.index() < self.live_nodes); - assert!(b.index() < self.live_nodes); - assert!(a != b); - - let a_start = a.index() * self.live_node_words; - let b_start = b.index() * self.live_node_words; - - unsafe { - let ptr = self.words.as_mut_ptr(); - ( - std::slice::from_raw_parts_mut(ptr.add(a_start), self.live_node_words), - std::slice::from_raw_parts_mut(ptr.add(b_start), self.live_node_words), - ) - } - } - - fn copy(&mut self, dst: LiveNode, src: LiveNode) { - if dst == src { - return; - } - - let (dst_row, src_row) = self.pick2_rows_mut(dst, src); - dst_row.copy_from_slice(src_row); - } - - /// Sets `dst` to the union of `dst` and `src`, returns true if `dst` was - /// changed. - fn union(&mut self, dst: LiveNode, src: LiveNode) -> bool { - if dst == src { - return false; - } - - let mut changed = false; - let (dst_row, src_row) = self.pick2_rows_mut(dst, src); - for (dst_word, src_word) in dst_row.iter_mut().zip(src_row.iter()) { - let old = *dst_word; - let new = *dst_word | src_word; - *dst_word = new; - changed |= old != new; - } - changed - } - - fn get_reader(&self, ln: LiveNode, var: Variable) -> bool { - let (word, shift) = self.word_and_shift(ln, var); - (self.words[word] >> shift) & Self::RWU_READER != 0 - } - - fn get_writer(&self, ln: LiveNode, var: Variable) -> bool { - let (word, shift) = self.word_and_shift(ln, var); - (self.words[word] >> shift) & Self::RWU_WRITER != 0 - } - - fn get_used(&self, ln: LiveNode, var: Variable) -> bool { - let (word, shift) = self.word_and_shift(ln, var); - (self.words[word] >> shift) & Self::RWU_USED != 0 - } - - fn get(&self, ln: LiveNode, var: Variable) -> RWU { - let (word, shift) = self.word_and_shift(ln, var); - let rwu_packed = self.words[word] >> shift; - RWU { - reader: rwu_packed & Self::RWU_READER != 0, - writer: rwu_packed & Self::RWU_WRITER != 0, - used: rwu_packed & Self::RWU_USED != 0, - } - } - - fn set(&mut self, ln: LiveNode, var: Variable, rwu: RWU) { - let mut packed = 0; - if rwu.reader { - packed |= Self::RWU_READER; - } - if rwu.writer { - packed |= Self::RWU_WRITER; - } - if rwu.used { - packed |= Self::RWU_USED; - } - - let (word, shift) = self.word_and_shift(ln, var); - let word = &mut self.words[word]; - *word = (*word & !(Self::RWU_MASK << shift)) | (packed << shift) - } -} - const ACC_READ: u32 = 1; const ACC_WRITE: u32 = 2; const ACC_USE: u32 = 4; @@ -623,7 +482,7 @@ struct Liveness<'a, 'tcx> { upvars: Option<&'tcx FxIndexMap>, closure_captures: Option<&'tcx FxIndexMap>, successors: IndexVec>, - rwu_table: RWUTable, + rwu_table: rwu_table::RWUTable, /// A live node representing a point of execution before closure entry & /// after closure exit. Used to calculate liveness of captured variables @@ -661,7 +520,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { upvars, closure_captures, successors: IndexVec::from_elem_n(None, num_live_nodes), - rwu_table: RWUTable::new(num_live_nodes, num_vars), + rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars), closure_ln, exit_ln, break_ln: Default::default(), @@ -802,7 +661,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // this) so we just clear out all the data. fn define(&mut self, writer: LiveNode, var: Variable) { let used = self.rwu_table.get_used(writer, var); - self.rwu_table.set(writer, var, RWU { reader: false, writer: false, used }); + self.rwu_table.set(writer, var, rwu_table::RWU { reader: false, writer: false, used }); debug!("{:?} defines {:?}: {}", writer, var, self.ln_str(writer)); } diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs new file mode 100644 index 00000000000..a1a6f27398e --- /dev/null +++ b/compiler/rustc_passes/src/liveness/rwu_table.rs @@ -0,0 +1,144 @@ +use crate::liveness::{LiveNode, Variable}; + +#[derive(Clone, Copy)] +pub(super) struct RWU { + pub(super) reader: bool, + pub(super) writer: bool, + pub(super) used: bool, +} + +/// Conceptually, this is like a `Vec>`. But the number of +/// RWU`s can get very large, so it uses a more compact representation. +pub(super) struct RWUTable { + /// Total number of live nodes. + live_nodes: usize, + /// Total number of variables. + vars: usize, + + /// A compressed representation of `RWU`s. + /// + /// Each word represents 2 different `RWU`s packed together. Each packed RWU + /// is stored in 4 bits: a reader bit, a writer bit, a used bit and a + /// padding bit. + /// + /// The data for each live node is contiguous and starts at a word boundary, + /// so there might be an unused space left. + words: Vec, + /// Number of words per each live node. + live_node_words: usize, +} + +impl RWUTable { + const RWU_READER: u8 = 0b0001; + const RWU_WRITER: u8 = 0b0010; + const RWU_USED: u8 = 0b0100; + const RWU_MASK: u8 = 0b1111; + + /// Size of packed RWU in bits. + const RWU_BITS: usize = 4; + /// Size of a word in bits. + const WORD_BITS: usize = std::mem::size_of::() * 8; + /// Number of packed RWUs that fit into a single word. + const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS; + + pub(super) fn new(live_nodes: usize, vars: usize) -> RWUTable { + let live_node_words = (vars + Self::WORD_RWU_COUNT - 1) / Self::WORD_RWU_COUNT; + Self { live_nodes, vars, live_node_words, words: vec![0u8; live_node_words * live_nodes] } + } + + fn word_and_shift(&self, ln: LiveNode, var: Variable) -> (usize, u32) { + assert!(ln.index() < self.live_nodes); + assert!(var.index() < self.vars); + + let var = var.index(); + let word = var / Self::WORD_RWU_COUNT; + let shift = Self::RWU_BITS * (var % Self::WORD_RWU_COUNT); + (ln.index() * self.live_node_words + word, shift as u32) + } + + fn pick2_rows_mut(&mut self, a: LiveNode, b: LiveNode) -> (&mut [u8], &mut [u8]) { + assert!(a.index() < self.live_nodes); + assert!(b.index() < self.live_nodes); + assert!(a != b); + + let a_start = a.index() * self.live_node_words; + let b_start = b.index() * self.live_node_words; + + unsafe { + let ptr = self.words.as_mut_ptr(); + ( + std::slice::from_raw_parts_mut(ptr.add(a_start), self.live_node_words), + std::slice::from_raw_parts_mut(ptr.add(b_start), self.live_node_words), + ) + } + } + + pub(super) fn copy(&mut self, dst: LiveNode, src: LiveNode) { + if dst == src { + return; + } + + let (dst_row, src_row) = self.pick2_rows_mut(dst, src); + dst_row.copy_from_slice(src_row); + } + + /// Sets `dst` to the union of `dst` and `src`, returns true if `dst` was + /// changed. + pub(super) fn union(&mut self, dst: LiveNode, src: LiveNode) -> bool { + if dst == src { + return false; + } + + let mut changed = false; + let (dst_row, src_row) = self.pick2_rows_mut(dst, src); + for (dst_word, src_word) in dst_row.iter_mut().zip(src_row.iter()) { + let old = *dst_word; + let new = *dst_word | src_word; + *dst_word = new; + changed |= old != new; + } + changed + } + + pub(super) fn get_reader(&self, ln: LiveNode, var: Variable) -> bool { + let (word, shift) = self.word_and_shift(ln, var); + (self.words[word] >> shift) & Self::RWU_READER != 0 + } + + pub(super) fn get_writer(&self, ln: LiveNode, var: Variable) -> bool { + let (word, shift) = self.word_and_shift(ln, var); + (self.words[word] >> shift) & Self::RWU_WRITER != 0 + } + + pub(super) fn get_used(&self, ln: LiveNode, var: Variable) -> bool { + let (word, shift) = self.word_and_shift(ln, var); + (self.words[word] >> shift) & Self::RWU_USED != 0 + } + + pub(super) fn get(&self, ln: LiveNode, var: Variable) -> RWU { + let (word, shift) = self.word_and_shift(ln, var); + let rwu_packed = self.words[word] >> shift; + RWU { + reader: rwu_packed & Self::RWU_READER != 0, + writer: rwu_packed & Self::RWU_WRITER != 0, + used: rwu_packed & Self::RWU_USED != 0, + } + } + + pub(super) fn set(&mut self, ln: LiveNode, var: Variable, rwu: RWU) { + let mut packed = 0; + if rwu.reader { + packed |= Self::RWU_READER; + } + if rwu.writer { + packed |= Self::RWU_WRITER; + } + if rwu.used { + packed |= Self::RWU_USED; + } + + let (word, shift) = self.word_and_shift(ln, var); + let word = &mut self.words[word]; + *word = (*word & !(Self::RWU_MASK << shift)) | (packed << shift) + } +} From 4a7f2ec49227e51a213b980cb1866133b3d555e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 9 Dec 2020 00:00:00 +0000 Subject: [PATCH 264/274] Update LLVM submodule --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 7ade8dc4b84..8d78ad13896 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 7ade8dc4b84142abd3e6d1fb8a0f4111b0bbd571 +Subproject commit 8d78ad13896b955f630714f386a95ed91b237e3d From bd837e899bdb13a6207a0494556380fc4491f2eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Oct 2020 17:46:01 +0100 Subject: [PATCH 265/274] make sure we do not promote things with interior mutability --- src/test/ui/consts/promote-not.rs | 7 ++++++- src/test/ui/consts/promote-not.stderr | 22 ++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs index 30bb9917bf7..a7938fabad5 100644 --- a/src/test/ui/consts/promote-not.rs +++ b/src/test/ui/consts/promote-not.rs @@ -3,6 +3,8 @@ #![allow(unconditional_panic, const_err)] #![feature(const_fn, const_fn_union)] +use std::cell::Cell; + // We do not promote mutable references. static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed @@ -32,4 +34,7 @@ const TEST_UNION: () = { let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed }; -fn main() {} +fn main() { + // We must not promote things with interior mutability. + let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed +} diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr index 6ca7a4c273e..2698424c165 100644 --- a/src/test/ui/consts/promote-not.stderr +++ b/src/test/ui/consts/promote-not.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:7:50 + --> $DIR/promote-not.rs:9:50 | LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); | ----------^^^^^^^^^- @@ -9,7 +9,7 @@ LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); | using this value as a static requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:10:18 + --> $DIR/promote-not.rs:12:18 | LL | let x = &mut [1,2,3]; | ^^^^^^^ creates a temporary which is freed while still in use @@ -19,7 +19,7 @@ LL | }; | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:19:32 + --> $DIR/promote-not.rs:21:32 | LL | let _x: &'static () = &foo(); | ----------- ^^^^^ creates a temporary which is freed while still in use @@ -29,7 +29,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:27:29 + --> $DIR/promote-not.rs:29:29 | LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use @@ -39,7 +39,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:32:29 + --> $DIR/promote-not.rs:34:29 | LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use @@ -48,6 +48,16 @@ LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; LL | }; | - temporary value is freed at the end of this statement -error: aborting due to 5 previous errors +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:39:29 + | +LL | let _val: &'static _ = &(Cell::new(1), 2).0; + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0716`. From 99a44ed086978339d531aa40f84efdaa1bacbb45 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Oct 2020 18:06:41 +0100 Subject: [PATCH 266/274] remove a hack that seems to only benefit a few very special cases --- .../rustc_mir/src/transform/promote_consts.rs | 58 ++----------------- src/test/ui/consts/promote-not.rs | 9 ++- src/test/ui/consts/promote-not.stderr | 25 +++++++- 3 files changed, 37 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 927aae82a36..8d5ed747c3f 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable}; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_index::vec::{Idx, IndexVec}; use rustc_target::spec::abi::Abi; @@ -326,41 +326,16 @@ impl<'tcx> Validator<'_, 'tcx> { if place.projection.contains(&ProjectionElem::Deref) { return Err(Unpromotable); } - - let mut has_mut_interior = - self.qualif_local::(place.local); - // HACK(eddyb) this should compute the same thing as - // `::in_projection` from - // `check_consts::qualifs` but without recursion. - if has_mut_interior { - // This allows borrowing fields which don't have - // `HasMutInterior`, from a type that does, e.g.: - // `let _: &'static _ = &(Cell::new(1), 2).1;` - let mut place_projection = &place.projection[..]; - // FIXME(eddyb) use a forward loop instead of a reverse one. - while let &[ref proj_base @ .., elem] = place_projection { - // FIXME(eddyb) this is probably excessive, with - // the exception of `union` member accesses. - let ty = - Place::ty_from(place.local, proj_base, self.body, self.tcx) - .projection_ty(self.tcx, elem) - .ty; - if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) { - has_mut_interior = false; - break; - } - - place_projection = proj_base; - } + if self.qualif_local::(place.local) { + return Err(Unpromotable); } // FIXME(eddyb) this duplicates part of `validate_rvalue`. + let has_mut_interior = + self.qualif_local::(place.local); if has_mut_interior { return Err(Unpromotable); } - if self.qualif_local::(place.local) { - return Err(Unpromotable); - } if let BorrowKind::Mut { .. } = kind { let ty = place.ty(self.body, self.tcx).ty; @@ -692,28 +667,7 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_place(place)?; - // HACK(eddyb) this should compute the same thing as - // `::in_projection` from - // `check_consts::qualifs` but without recursion. - let mut has_mut_interior = - self.qualif_local::(place.local); - if has_mut_interior { - let mut place_projection = place.projection; - // FIXME(eddyb) use a forward loop instead of a reverse one. - while let &[ref proj_base @ .., elem] = place_projection { - // FIXME(eddyb) this is probably excessive, with - // the exception of `union` member accesses. - let ty = Place::ty_from(place.local, proj_base, self.body, self.tcx) - .projection_ty(self.tcx, elem) - .ty; - if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) { - has_mut_interior = false; - break; - } - - place_projection = proj_base; - } - } + let has_mut_interior = self.qualif_local::(place.local); if has_mut_interior { return Err(Unpromotable); } diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs index a7938fabad5..1e4d8586b87 100644 --- a/src/test/ui/consts/promote-not.rs +++ b/src/test/ui/consts/promote-not.rs @@ -34,7 +34,14 @@ const TEST_UNION: () = { let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed }; +// In a `const`, we do not promote things with interior mutability. Not even if we "project it away". +const TEST_INTERIOR_MUT: () = { + // The "0." case is already ruled out by not permitting any interior mutability in `const`. + let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed +}; + fn main() { - // We must not promote things with interior mutability. + // We must not promote things with interior mutability. Not even if we "project it away". let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr index 2698424c165..6e76d9ee6c1 100644 --- a/src/test/ui/consts/promote-not.stderr +++ b/src/test/ui/consts/promote-not.stderr @@ -49,15 +49,36 @@ LL | }; | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:39:29 + --> $DIR/promote-not.rs:40:29 + | +LL | let _val: &'static _ = &(Cell::new(1), 2).1; + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:45:29 | LL | let _val: &'static _ = &(Cell::new(1), 2).0; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use | | | type annotation requires that borrow lasts for `'static` +LL | let _val: &'static _ = &(Cell::new(1), 2).1; +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:46:29 + | +LL | let _val: &'static _ = &(Cell::new(1), 2).1; + | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` LL | } | - temporary value is freed at the end of this statement -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0716`. From d057a93e6f43eb410b9c348a8fe590bdc4452ae6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Nov 2020 15:22:38 +0100 Subject: [PATCH 267/274] remove a test that does not work any more --- src/test/ui/issues/issue-49955-2.rs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 src/test/ui/issues/issue-49955-2.rs diff --git a/src/test/ui/issues/issue-49955-2.rs b/src/test/ui/issues/issue-49955-2.rs deleted file mode 100644 index 267ed746322..00000000000 --- a/src/test/ui/issues/issue-49955-2.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-pass -// compile-flags: -Z borrowck=mir - -use std::cell::Cell; - -const FIVE: Cell = Cell::new(5); - -#[inline(never)] -fn tuple_field() -> &'static u32 { - // This test is MIR-borrowck-only because the old borrowck - // doesn't agree that borrows of "frozen" (i.e., without any - // interior mutability) fields of non-frozen temporaries, - // should be promoted, while MIR promotion does promote them. - &(FIVE, 42).1 -} - -fn main() { - assert_eq!(tuple_field().to_string(), "42"); -} From 84fe7cf24eb801348c120218cafe80efda597f04 Mon Sep 17 00:00:00 2001 From: oli Date: Wed, 9 Dec 2020 10:50:34 +0000 Subject: [PATCH 268/274] Also generate `StorageDead` in constants --- .../rustc_mir/src/interpret/eval_context.rs | 22 +++------- .../src/build/expr/as_operand.rs | 4 +- .../src/build/expr/as_rvalue.rs | 7 ++- .../rustc_mir_build/src/build/expr/into.rs | 6 +-- compiler/rustc_mir_build/src/build/scope.rs | 40 ++++------------- .../mir-opt/const-promotion-extern-static.rs | 3 ++ ...motion_extern_static.BAR.PromoteTemps.diff | 3 ++ ..._promotion_extern_static.BOP.mir_map.0.mir | 17 +++++++ ...motion_extern_static.FOO.PromoteTemps.diff | 3 ++ ...age_live_dead_in_statics.XXX.mir_map.0.mir | 44 +++++++++++++++++++ 10 files changed, 92 insertions(+), 57 deletions(-) create mode 100644 src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 05b4d1c410d..d48b7fb3b92 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -4,7 +4,7 @@ use std::mem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::{self as hir, def::DefKind, def_id::DefId, definitions::DefPathData}; +use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_middle::ich::StableHashingContext; @@ -700,21 +700,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let mut locals = IndexVec::from_elem(dummy, &body.local_decls); // Now mark those locals as dead that we do not want to initialize - match self.tcx.def_kind(instance.def_id()) { - // statics and constants don't have `Storage*` statements, no need to look for them - // - // FIXME: The above is likely untrue. See - // . Is it - // okay to ignore `StorageDead`/`StorageLive` annotations during CTFE? - DefKind::Static | DefKind::Const | DefKind::AssocConst => {} - _ => { - // Mark locals that use `Storage*` annotations as dead on function entry. - let always_live = AlwaysLiveLocals::new(self.body()); - for local in locals.indices() { - if !always_live.contains(local) { - locals[local].value = LocalValue::Dead; - } - } + // Mark locals that use `Storage*` annotations as dead on function entry. + let always_live = AlwaysLiveLocals::new(self.body()); + for local in locals.indices() { + if !always_live.contains(local) { + locals[local].value = LocalValue::Dead; } } // done diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index cf075abc94b..60f8d8c8a9f 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -19,7 +19,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let local_scope = self.local_scope(); - self.as_operand(block, local_scope, expr) + self.as_operand(block, Some(local_scope), expr) } /// Returns an operand suitable for use until the end of the current scope expression and @@ -79,7 +79,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let local_scope = self.local_scope(); - self.as_call_operand(block, local_scope, expr) + self.as_call_operand(block, Some(local_scope), expr) } /// Compile `expr` into a value that can be used as an operand. diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c0e4141a558..6537ba745c1 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let local_scope = self.local_scope(); - self.as_rvalue(block, local_scope, expr) + self.as_rvalue(block, Some(local_scope), expr) } /// Compile `expr`, yielding an rvalue. @@ -445,9 +445,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place), ); - // In constants, temp_lifetime is None. We should not need to drop - // anything because no values with a destructor can be created in - // a constant at this time, even if the type may need dropping. + // See the comment in `expr_as_temp` and on the `rvalue_scopes` field for why + // this can be `None`. if let Some(temp_lifetime) = temp_lifetime { this.schedule_drop_storage_and_value(upvar_span, temp_lifetime, temp); } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 5f9743b7f59..1f70fdb5ae3 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // (#66975) Source could be a const of type `!`, so has to // exist in the generated MIR. - unpack!(block = this.as_temp(block, this.local_scope(), source, Mutability::Mut,)); + unpack!(block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,)); // This is an optimization. If the expression was a call then we already have an // unreachable block. Don't bother to terminate it and create a new one. @@ -300,7 +300,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // (evaluating them in order given by user) let fields_map: FxHashMap<_, _> = fields .into_iter() - .map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr)))) + .map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr)))) .collect(); let field_names = this.hir.all_fields(adt_def, variant_index); @@ -468,7 +468,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Yield { value } => { let scope = this.local_scope(); - let value = unpack!(block = this.as_operand(block, scope, value)); + let value = unpack!(block = this.as_operand(block, Some(scope), value)); let resume = this.cfg.start_new_block(); this.record_operands_moved(slice::from_ref(&value)); this.cfg.terminate( diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 468b3484ca5..e137f77ffbb 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -85,7 +85,6 @@ use crate::build::matches::{ArmHasGuard, Candidate}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; use crate::thir::{Arm, Expr, ExprRef, LintLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir as hir; use rustc_index::vec::IndexVec; use rustc_middle::middle::region; use rustc_middle::mir::*; @@ -740,18 +739,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// We would allocate the box but then free it on the unwinding /// path; we would also emit a free on the 'success' path from /// panic, but that will turn out to be removed as dead-code. - /// - /// When building statics/constants, returns `None` since - /// intermediate values do not have to be dropped in that case. - crate fn local_scope(&self) -> Option { - match self.hir.body_owner_kind { - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => - // No need to free storage in this context. - { - None - } - hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => Some(self.scopes.topmost()), - } + crate fn local_scope(&self) -> region::Scope { + self.scopes.topmost() } // Scheduling drops @@ -938,23 +927,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// not the `DROP(_X)` itself, but the (spurious) unwind pathways /// that it creates. See #64391 for an example. crate fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) { - let scope = match self.local_scope() { - None => { - // if there is no local scope, operands won't be dropped anyway - return; - } + let local_scope = self.local_scope(); + let scope = self.scopes.scopes.last_mut().unwrap(); - Some(local_scope) => { - let top_scope = self.scopes.scopes.last_mut().unwrap(); - assert!( - top_scope.region_scope == local_scope, - "local scope ({:?}) is not the topmost scope!", - local_scope - ); - - top_scope - } - }; + assert_eq!( + scope.region_scope, local_scope, + "local scope is not the topmost scope!", + ); // look for moves of a local variable, like `MOVE(_X)` let locals_moved = operands @@ -993,9 +972,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match cond { // Don't try to drop a constant Operand::Constant(_) => (), - // If constants and statics, we don't generate StorageLive for this - // temporary, so don't try to generate StorageDead for it either. - _ if self.local_scope().is_none() => (), Operand::Copy(place) | Operand::Move(place) => { if let Some(cond_temp) = place.as_local() { // Manually drop the condition on both branches. diff --git a/src/test/mir-opt/const-promotion-extern-static.rs b/src/test/mir-opt/const-promotion-extern-static.rs index 9c30e040031..0f13fe1b48c 100644 --- a/src/test/mir-opt/const-promotion-extern-static.rs +++ b/src/test/mir-opt/const-promotion-extern-static.rs @@ -12,4 +12,7 @@ static mut BAR: *const &i32 = [&Y].as_ptr(); // EMIT_MIR const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir static mut FOO: *const &i32 = [unsafe { &X }].as_ptr(); +// EMIT_MIR const_promotion_extern_static.BOP.mir_map.0.mir +static BOP: &i32 = &13; + fn main() {} diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index bbce9c288ef..5ba76c4f0bd 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -33,6 +33,8 @@ + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 +- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 + StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:9:36: 9:42 @@ -42,6 +44,7 @@ bb1: { - StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44 - StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44 + StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44 return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:45 } diff --git a/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir b/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir new file mode 100644 index 00000000000..4d24387afc7 --- /dev/null +++ b/src/test/mir-opt/const_promotion_extern_static.BOP.mir_map.0.mir @@ -0,0 +1,17 @@ +// MIR for `BOP` 0 mir_map + +static BOP: &i32 = { + let mut _0: &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:16:13: 16:17 + let _1: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 + let _2: i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:16:21: 16:23 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 + StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:16:21: 16:23 + _2 = const 13_i32; // scope 0 at $DIR/const-promotion-extern-static.rs:16:21: 16:23 + _1 = &_2; // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 + _0 = &(*_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23 + StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:22: 16:23 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:16:1: 16:24 + } +} diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 82277b2a21c..1565cc7d5e7 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -35,6 +35,8 @@ + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 +- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 + StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:13:47: 13:53 @@ -44,6 +46,7 @@ bb1: { - StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55 - StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55 + StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55 return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:56 } diff --git a/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir b/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir index 6d05e8278ba..6c22af787d3 100644 --- a/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir +++ b/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir @@ -143,9 +143,52 @@ static XXX: &Foo = { StorageLive(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31 _48 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31 _6 = [move _7, move _8, move _9, move _10, move _11, move _12, move _13, move _14, move _15, move _16, move _17, move _18, move _19, move _20, move _21, move _22, move _23, move _24, move _25, move _26, move _27, move _28, move _29, move _30, move _31, move _32, move _33, move _34, move _35, move _36, move _37, move _38, move _39, move _40, move _41, move _42, move _43, move _44, move _45, move _46, move _47, move _48]; // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:12: 22:6 + StorageDead(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 + StorageDead(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 _5 = &_6; // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 _4 = &(*_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 _3 = move _4 as &[(u32, u32)] (Pointer(Unsize)); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6 + StorageDead(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6 _2 = Foo { tup: const "hi", data: move _3 }; // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:29: 23:2 // ty::Const // + ty: &str @@ -153,6 +196,7 @@ static XXX: &Foo = { // mir::Constant // + span: $DIR/storage_live_dead_in_statics.rs:6:10: 6:14 // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [104, 105], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 2 }) } + StorageDead(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2 _1 = &_2; // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:28: 23:2 _0 = &(*_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:28: 23:2 StorageDead(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2 From 31d72c2658e3ca3c51bb08ff5152c815d595e7ac Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 7 Nov 2020 16:09:40 +0300 Subject: [PATCH 269/274] Accept arbitrary expressions in key-value attributes at parse time --- compiler/rustc_ast/src/ast.rs | 17 +-- compiler/rustc_ast/src/mut_visit.rs | 21 ++-- compiler/rustc_ast/src/visit.rs | 1 - compiler/rustc_ast_passes/src/feature_gate.rs | 4 + compiler/rustc_feature/src/active.rs | 3 + compiler/rustc_parse/src/parser/mod.rs | 27 ++-- compiler/rustc_span/src/symbol.rs | 1 + src/test/rustdoc/external-doc.rs | 16 +++ .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- src/test/ui/attr-eq-token-tree.rs | 2 +- src/test/ui/attr-eq-token-tree.stderr | 6 +- src/test/ui/attributes/key-value-expansion.rs | 10 +- .../ui/attributes/key-value-expansion.stderr | 21 ++-- ...ture-gate-extended_key_value_attributes.rs | 8 ++ ...-gate-extended_key_value_attributes.stderr | 39 ++++++ src/test/ui/macros/macro-attribute.rs | 2 +- src/test/ui/macros/macro-attribute.stderr | 4 +- .../ui/malformed/malformed-interpolated.rs | 7 +- .../malformed/malformed-interpolated.stderr | 24 ++-- src/test/ui/parser/attr-bad-meta-2.rs | 2 +- src/test/ui/parser/attr-bad-meta-2.stderr | 4 +- src/test/ui/suffixed-literal-meta.rs | 14 +-- src/test/ui/suffixed-literal-meta.stderr | 118 ++---------------- 24 files changed, 145 insertions(+), 210 deletions(-) create mode 100644 src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs create mode 100644 src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9d6ee65049a..220bbed7e78 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -24,7 +24,7 @@ pub use UnsafeSource::*; use crate::ptr::P; use crate::token::{self, CommentKind, DelimToken}; -use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree}; +use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -39,7 +39,6 @@ use rustc_span::{Span, DUMMY_SP}; use std::cmp::Ordering; use std::convert::TryFrom; use std::fmt; -use std::iter; #[cfg(test)] mod tests; @@ -1514,20 +1513,6 @@ impl MacArgs { } } - /// Tokens together with the delimiters or `=`. - /// Use of this method generally means that something suboptimal or hacky is happening. - pub fn outer_tokens(&self) -> TokenStream { - match *self { - MacArgs::Empty => TokenStream::default(), - MacArgs::Delimited(dspan, delim, ref tokens) => { - TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into() - } - MacArgs::Eq(eq_span, ref tokens) => { - iter::once(TokenTree::token(token::Eq, eq_span)).chain(tokens.trees()).collect() - } - } - } - /// Whether a macro with these arguments needs a semicolon /// when used as a standalone item or statement. pub fn need_semicolon(&self) -> bool { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c4e92a9f6d1..3889ede7f4c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -371,20 +371,15 @@ pub fn visit_mac_args(args: &mut MacArgs, vis: &mut T) { // The value in `#[key = VALUE]` must be visited as an expression for backward // compatibility, so that macros can be expanded in that position. if !vis.token_visiting_enabled() { - if let Some(TokenTree::Token(token)) = tokens.trees_ref().next() { - if let token::Interpolated(..) = token.kind { - // ^^ Do not `make_mut` unless we have to. - match Lrc::make_mut(&mut tokens.0).get_mut(0) { - Some((TokenTree::Token(token), _spacing)) => match &mut token.kind { - token::Interpolated(nt) => match Lrc::make_mut(nt) { - token::NtExpr(expr) => vis.visit_expr(expr), - t => panic!("unexpected token in key-value attribute: {:?}", t), - }, - t => panic!("unexpected token in key-value attribute: {:?}", t), - }, + match Lrc::make_mut(&mut tokens.0).get_mut(0) { + Some((TokenTree::Token(token), _spacing)) => match &mut token.kind { + token::Interpolated(nt) => match Lrc::make_mut(nt) { + token::NtExpr(expr) => vis.visit_expr(expr), t => panic!("unexpected token in key-value attribute: {:?}", t), - } - } + }, + t => panic!("unexpected token in key-value attribute: {:?}", t), + }, + t => panic!("unexpected token in key-value attribute: {:?}", t), } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 61426a838de..a420bb56350 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -906,7 +906,6 @@ pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) { token::NtExpr(expr) => visitor.visit_expr(expr), t => panic!("unexpected token in key-value attribute: {:?}", t), }, - token::Literal(..) | token::Ident(..) => {} t => panic!("unexpected token in key-value attribute: {:?}", t), }, t => panic!("unexpected token in key-value attribute: {:?}", t), diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5b75fbf339b..9d54d89e080 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -630,6 +630,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(const_trait_impl, "const trait impls are experimental"); gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); gate_all!(inline_const, "inline-const is experimental"); + gate_all!( + extended_key_value_attributes, + "arbitrary expressions in key-value attributes are unstable" + ); if sess.parse_sess.span_diagnostic.err_count() == 0 { // Errors for `destructuring_assignment` can get quite noisy, especially where `_` is // involved, so we only emit errors where there are no other parsing errors. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 75337634d3f..845e03150d7 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -620,6 +620,9 @@ declare_features! ( /// Allows capturing disjoint fields in a closure/generator (RFC 2229). (active, capture_disjoint_fields, "1.49.0", Some(53488), None), + /// Allows arbitrary expressions in key-value attributes at parse time. + (active, extended_key_value_attributes, "1.50.0", Some(78835), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 22f308ff36d..df4695b18e7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -23,6 +23,7 @@ use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, E use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit}; use rustc_ast::{Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; +use rustc_data_structures::sync::Lrc; use rustc_errors::PResult; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError}; use rustc_session::parse::ParseSess; @@ -935,16 +936,24 @@ impl<'a> Parser<'a> { is_interpolated_expr = true; } } - let token_tree = if is_interpolated_expr { - // We need to accept arbitrary interpolated expressions to continue - // supporting things like `doc = $expr` that work on stable. - // Non-literal interpolated expressions are rejected after expansion. - self.parse_token_tree() - } else { - self.parse_unsuffixed_lit()?.token_tree() - }; - MacArgs::Eq(eq_span, token_tree.into()) + // The value here is never passed to macros as tokens by itself (not as a part + // of the whole attribute), so we don't collect tokens here. If this changes, + // then token will need to be collected. One catch here is that we are using + // a nonterminal for keeping the expression, but this nonterminal should not + // be wrapped into a group when converting to token stream. + let expr = self.parse_expr()?; + let span = expr.span; + + match &expr.kind { + // Not gated to supporte things like `doc = $expr` that work on stable. + _ if is_interpolated_expr => {} + ExprKind::Lit(lit) if lit.kind.is_unsuffixed() => {} + _ => self.sess.gated_spans.gate(sym::extended_key_value_attributes, span), + } + + let token = token::Interpolated(Lrc::new(token::NtExpr(expr))); + MacArgs::Eq(eq_span, TokenTree::token(token, span).into()) } else { MacArgs::Empty } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e75ddb36ff8..b9c942d61a9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -496,6 +496,7 @@ symbols! { expf64, export_name, expr, + extended_key_value_attributes, extern_absolute_paths, extern_crate_item_prelude, extern_crate_self, diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs index 4a13f4069c4..befd31a5492 100644 --- a/src/test/rustdoc/external-doc.rs +++ b/src/test/rustdoc/external-doc.rs @@ -1,4 +1,5 @@ #![feature(external_doc)] +#![feature(extended_key_value_attributes)] // @has external_doc/struct.CanHasDocs.html // @has - '//h1' 'External Docs' @@ -6,3 +7,18 @@ #[doc(include = "auxiliary/external-doc.md")] /// ## Inline Docs pub struct CanHasDocs; + +// @has external_doc/struct.IncludeStrDocs.html +// @has - '//h1' 'External Docs' +// @has - '//h2' 'Inline Docs' +#[doc = include_str!("auxiliary/external-doc.md")] +/// ## Inline Docs +pub struct IncludeStrDocs; + +macro_rules! dir { () => { "auxiliary" } } + +// @has external_doc/struct.EagerExpansion.html +// @has - '//h1' 'External Docs' +#[doc = include_str!(concat!(dir!(), "/external-doc.md"))] +/// ## Inline Docs +pub struct EagerExpansion; diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index b19cfc4d5c3..deb2a1af204 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":null}]}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 65d6cd475cc..71336f452fc 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":null}]}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/attr-eq-token-tree.rs b/src/test/ui/attr-eq-token-tree.rs index c301492b9e2..330b119772a 100644 --- a/src/test/ui/attr-eq-token-tree.rs +++ b/src/test/ui/attr-eq-token-tree.rs @@ -1,2 +1,2 @@ -#[my_attr = !] //~ ERROR unexpected token: `!` +#[my_attr = !] //~ ERROR expected expression, found `]` fn main() {} diff --git a/src/test/ui/attr-eq-token-tree.stderr b/src/test/ui/attr-eq-token-tree.stderr index bb37c2e0cc4..1846444b668 100644 --- a/src/test/ui/attr-eq-token-tree.stderr +++ b/src/test/ui/attr-eq-token-tree.stderr @@ -1,8 +1,8 @@ -error: unexpected token: `!` - --> $DIR/attr-eq-token-tree.rs:1:13 +error: expected expression, found `]` + --> $DIR/attr-eq-token-tree.rs:1:14 | LL | #[my_attr = !] - | ^ + | ^ expected expression error: aborting due to previous error diff --git a/src/test/ui/attributes/key-value-expansion.rs b/src/test/ui/attributes/key-value-expansion.rs index 831c8091f32..08121413ee9 100644 --- a/src/test/ui/attributes/key-value-expansion.rs +++ b/src/test/ui/attributes/key-value-expansion.rs @@ -12,23 +12,22 @@ extern crate key_value_expansion; macro_rules! bug { ($expr:expr) => { #[rustc_dummy = $expr] // Any key-value attribute, not necessarily `doc` - //~^ ERROR unexpected token: `(7u32)` struct S; }; } // Any expressions containing macro call `X` that's more complex than `X` itself. // Parentheses will work. -bug!((column!())); +bug!((column!())); //~ ERROR unexpected token: `(7u32)` // Original test case. macro_rules! bug { () => { - bug!("bug" + stringify!(found)); + bug!("bug" + stringify!(found)); //~ ERROR unexpected token: `"bug" + "found"` }; ($test:expr) => { - #[doc = $test] //~ ERROR unexpected token: `"bug" + "found"` + #[doc = $test] struct Test {} }; } @@ -39,7 +38,7 @@ bug!(); macro_rules! doc_comment { ($x:expr) => { - #[doc = $x] //~ ERROR unexpected token: `{ + #[doc = $x] extern {} }; } @@ -47,6 +46,7 @@ macro_rules! doc_comment { macro_rules! some_macro { ($t1: ty) => { doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()} + //~^ ERROR unexpected token: `{ }; } diff --git a/src/test/ui/attributes/key-value-expansion.stderr b/src/test/ui/attributes/key-value-expansion.stderr index 5da4557f0ae..4b14b88a74f 100644 --- a/src/test/ui/attributes/key-value-expansion.stderr +++ b/src/test/ui/attributes/key-value-expansion.stderr @@ -1,19 +1,14 @@ error: unexpected token: `(7u32)` - --> $DIR/key-value-expansion.rs:14:25 + --> $DIR/key-value-expansion.rs:21:6 | -LL | #[rustc_dummy = $expr] // Any key-value attribute, not necessarily `doc` - | ^^^^^ -... LL | bug!((column!())); - | ------------------ in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^ error: unexpected token: `"bug" + "found"` - --> $DIR/key-value-expansion.rs:31:17 + --> $DIR/key-value-expansion.rs:27:14 | -LL | #[doc = $test] - | ^^^^^ +LL | bug!("bug" + stringify!(found)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | bug!(); | ------- in this macro invocation @@ -30,10 +25,10 @@ error: unexpected token: `{ })); res }.as_str()` - --> $DIR/key-value-expansion.rs:42:17 + --> $DIR/key-value-expansion.rs:48:23 | -LL | #[doc = $x] - | ^^ +LL | doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | some_macro!(u8); | ---------------- in this macro invocation diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs new file mode 100644 index 00000000000..f19fdb45f1f --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs @@ -0,0 +1,8 @@ +#[cfg(FALSE)] +#[attr = multi::segment::path] //~ ERROR arbitrary expressions in key-value attributes are unstable +#[attr = macro_call!()] //~ ERROR arbitrary expressions in key-value attributes are unstable +#[attr = 1 + 2] //~ ERROR arbitrary expressions in key-value attributes are unstable +#[attr = what?] //~ ERROR arbitrary expressions in key-value attributes are unstable +struct S; + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr new file mode 100644 index 00000000000..9887814b907 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr @@ -0,0 +1,39 @@ +error[E0658]: arbitrary expressions in key-value attributes are unstable + --> $DIR/feature-gate-extended_key_value_attributes.rs:2:10 + | +LL | #[attr = multi::segment::path] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #78835 for more information + = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable + +error[E0658]: arbitrary expressions in key-value attributes are unstable + --> $DIR/feature-gate-extended_key_value_attributes.rs:3:10 + | +LL | #[attr = macro_call!()] + | ^^^^^^^^^^^^^ + | + = note: see issue #78835 for more information + = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable + +error[E0658]: arbitrary expressions in key-value attributes are unstable + --> $DIR/feature-gate-extended_key_value_attributes.rs:4:10 + | +LL | #[attr = 1 + 2] + | ^^^^^ + | + = note: see issue #78835 for more information + = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable + +error[E0658]: arbitrary expressions in key-value attributes are unstable + --> $DIR/feature-gate-extended_key_value_attributes.rs:5:10 + | +LL | #[attr = what?] + | ^^^^^ + | + = note: see issue #78835 for more information + = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/macros/macro-attribute.rs b/src/test/ui/macros/macro-attribute.rs index f580dfa8e34..88834a96721 100644 --- a/src/test/ui/macros/macro-attribute.rs +++ b/src/test/ui/macros/macro-attribute.rs @@ -1,2 +1,2 @@ -#[doc = $not_there] //~ ERROR unexpected token: `$` +#[doc = $not_there] //~ ERROR expected expression, found `$` fn main() { } diff --git a/src/test/ui/macros/macro-attribute.stderr b/src/test/ui/macros/macro-attribute.stderr index d28ce25341d..3316d387264 100644 --- a/src/test/ui/macros/macro-attribute.stderr +++ b/src/test/ui/macros/macro-attribute.stderr @@ -1,8 +1,8 @@ -error: unexpected token: `$` +error: expected expression, found `$` --> $DIR/macro-attribute.rs:1:9 | LL | #[doc = $not_there] - | ^ + | ^ expected expression error: aborting due to previous error diff --git a/src/test/ui/malformed/malformed-interpolated.rs b/src/test/ui/malformed/malformed-interpolated.rs index 5101b5caeea..b962447e7ed 100644 --- a/src/test/ui/malformed/malformed-interpolated.rs +++ b/src/test/ui/malformed/malformed-interpolated.rs @@ -2,8 +2,7 @@ macro_rules! check { ($expr: expr) => ( - #[rustc_dummy = $expr] //~ ERROR unexpected token: `-0` - //~| ERROR unexpected token: `0 + 0` + #[rustc_dummy = $expr] use main as _; ); } @@ -11,7 +10,7 @@ macro_rules! check { check!("0"); // OK check!(0); // OK check!(0u8); //~ ERROR suffixed literals are not allowed in attributes -check!(-0); // ERROR, see above -check!(0 + 0); // ERROR, see above +check!(-0); //~ ERROR unexpected token: `-0` +check!(0 + 0); //~ ERROR unexpected token: `0 + 0` fn main() {} diff --git a/src/test/ui/malformed/malformed-interpolated.stderr b/src/test/ui/malformed/malformed-interpolated.stderr index d1be82cf7b7..4b9332ddd01 100644 --- a/src/test/ui/malformed/malformed-interpolated.stderr +++ b/src/test/ui/malformed/malformed-interpolated.stderr @@ -1,5 +1,5 @@ error: suffixed literals are not allowed in attributes - --> $DIR/malformed-interpolated.rs:13:8 + --> $DIR/malformed-interpolated.rs:12:8 | LL | check!(0u8); | ^^^ @@ -7,26 +7,16 @@ LL | check!(0u8); = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: unexpected token: `-0` - --> $DIR/malformed-interpolated.rs:5:25 - | -LL | #[rustc_dummy = $expr] - | ^^^^^ -... -LL | check!(-0); // ERROR, see above - | ----------- in this macro invocation + --> $DIR/malformed-interpolated.rs:13:8 | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | check!(-0); + | ^^ error: unexpected token: `0 + 0` - --> $DIR/malformed-interpolated.rs:5:25 - | -LL | #[rustc_dummy = $expr] - | ^^^^^ -... -LL | check!(0 + 0); // ERROR, see above - | -------------- in this macro invocation + --> $DIR/malformed-interpolated.rs:14:8 | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | check!(0 + 0); + | ^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/attr-bad-meta-2.rs b/src/test/ui/parser/attr-bad-meta-2.rs index cefd3369742..db612ed883d 100644 --- a/src/test/ui/parser/attr-bad-meta-2.rs +++ b/src/test/ui/parser/attr-bad-meta-2.rs @@ -1,2 +1,2 @@ -#[path =] //~ ERROR unexpected token: `]` +#[path =] //~ ERROR expected expression, found `]` mod m {} diff --git a/src/test/ui/parser/attr-bad-meta-2.stderr b/src/test/ui/parser/attr-bad-meta-2.stderr index 2d772dae691..6fc6fb665a8 100644 --- a/src/test/ui/parser/attr-bad-meta-2.stderr +++ b/src/test/ui/parser/attr-bad-meta-2.stderr @@ -1,8 +1,8 @@ -error: unexpected token: `]` +error: expected expression, found `]` --> $DIR/attr-bad-meta-2.rs:1:9 | LL | #[path =] - | ^ + | ^ expected expression error: aborting due to previous error diff --git a/src/test/ui/suffixed-literal-meta.rs b/src/test/ui/suffixed-literal-meta.rs index c3a4eabad70..319264aec9c 100644 --- a/src/test/ui/suffixed-literal-meta.rs +++ b/src/test/ui/suffixed-literal-meta.rs @@ -1,27 +1,15 @@ -#![feature(rustc_attrs)] +#![feature(rustc_attrs, extended_key_value_attributes)] #[rustc_dummy = 1usize] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1u8] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1u16] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1u32] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1u64] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1isize] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1i8] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1i16] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1i32] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1i64] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes - //~| ERROR: suffixed literals are not allowed in attributes fn main() {} diff --git a/src/test/ui/suffixed-literal-meta.stderr b/src/test/ui/suffixed-literal-meta.stderr index 84fe91d662a..5245ffead71 100644 --- a/src/test/ui/suffixed-literal-meta.stderr +++ b/src/test/ui/suffixed-literal-meta.stderr @@ -7,119 +7,23 @@ LL | #[rustc_dummy = 1usize] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:5:17 + --> $DIR/suffixed-literal-meta.rs:4:17 | LL | #[rustc_dummy = 1u8] | ^^^ | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:7:17 - | -LL | #[rustc_dummy = 1u16] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:9:17 - | -LL | #[rustc_dummy = 1u32] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:11:17 - | -LL | #[rustc_dummy = 1u64] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:13:17 - | -LL | #[rustc_dummy = 1isize] - | ^^^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:15:17 - | -LL | #[rustc_dummy = 1i8] - | ^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:17:17 - | -LL | #[rustc_dummy = 1i16] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:19:17 - | -LL | #[rustc_dummy = 1i32] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:21:17 - | -LL | #[rustc_dummy = 1i64] - | ^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:23:17 - | -LL | #[rustc_dummy = 1.0f32] - | ^^^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:25:17 - | -LL | #[rustc_dummy = 1.0f64] - | ^^^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:3:17 - | -LL | #[rustc_dummy = 1usize] - | ^^^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - error: suffixed literals are not allowed in attributes --> $DIR/suffixed-literal-meta.rs:5:17 | -LL | #[rustc_dummy = 1u8] - | ^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - -error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:7:17 - | LL | #[rustc_dummy = 1u16] | ^^^^ | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:9:17 + --> $DIR/suffixed-literal-meta.rs:6:17 | LL | #[rustc_dummy = 1u32] | ^^^^ @@ -127,7 +31,7 @@ LL | #[rustc_dummy = 1u32] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:11:17 + --> $DIR/suffixed-literal-meta.rs:7:17 | LL | #[rustc_dummy = 1u64] | ^^^^ @@ -135,7 +39,7 @@ LL | #[rustc_dummy = 1u64] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:13:17 + --> $DIR/suffixed-literal-meta.rs:8:17 | LL | #[rustc_dummy = 1isize] | ^^^^^^ @@ -143,7 +47,7 @@ LL | #[rustc_dummy = 1isize] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:15:17 + --> $DIR/suffixed-literal-meta.rs:9:17 | LL | #[rustc_dummy = 1i8] | ^^^ @@ -151,7 +55,7 @@ LL | #[rustc_dummy = 1i8] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:17:17 + --> $DIR/suffixed-literal-meta.rs:10:17 | LL | #[rustc_dummy = 1i16] | ^^^^ @@ -159,7 +63,7 @@ LL | #[rustc_dummy = 1i16] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:19:17 + --> $DIR/suffixed-literal-meta.rs:11:17 | LL | #[rustc_dummy = 1i32] | ^^^^ @@ -167,7 +71,7 @@ LL | #[rustc_dummy = 1i32] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:21:17 + --> $DIR/suffixed-literal-meta.rs:12:17 | LL | #[rustc_dummy = 1i64] | ^^^^ @@ -175,7 +79,7 @@ LL | #[rustc_dummy = 1i64] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:23:17 + --> $DIR/suffixed-literal-meta.rs:13:17 | LL | #[rustc_dummy = 1.0f32] | ^^^^^^ @@ -183,12 +87,12 @@ LL | #[rustc_dummy = 1.0f32] = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) error: suffixed literals are not allowed in attributes - --> $DIR/suffixed-literal-meta.rs:25:17 + --> $DIR/suffixed-literal-meta.rs:14:17 | LL | #[rustc_dummy = 1.0f64] | ^^^^^^ | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -error: aborting due to 24 previous errors +error: aborting due to 12 previous errors From 570de0a3be6e92840776dcb0b1706716f173c7ad Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 9 Dec 2020 20:47:55 +0100 Subject: [PATCH 270/274] Remove tab-lock and replace it with ctrl+up/down arrows to switch between search result tabs --- src/librustdoc/html/static/main.js | 33 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 69984be5eb6..054abd9656d 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1469,16 +1469,21 @@ function defocusSearchBar() { }); if (e.which === 38) { // up - if (!actives[currentTab].length || - !actives[currentTab][0].previousElementSibling) { - return; + if (e.ctrlKey) { // Going through result tabs. + printTab(currentTab > 0 ? currentTab - 1 : 2); + } else { + if (!actives[currentTab].length || + !actives[currentTab][0].previousElementSibling) { + return; + } + addClass(actives[currentTab][0].previousElementSibling, "highlighted"); + removeClass(actives[currentTab][0], "highlighted"); } - - addClass(actives[currentTab][0].previousElementSibling, "highlighted"); - removeClass(actives[currentTab][0], "highlighted"); e.preventDefault(); } else if (e.which === 40) { // down - if (!actives[currentTab].length) { + if (e.ctrlKey) { // Going through result tabs. + printTab(currentTab > 1 ? 0 : currentTab + 1); + } else if (!actives[currentTab].length) { var results = document.getElementById("results").childNodes; if (results.length > 0) { var res = results[currentTab].getElementsByClassName("result"); @@ -1496,13 +1501,6 @@ function defocusSearchBar() { document.location.href = actives[currentTab][0].getElementsByTagName("a")[0].href; } - } else if (e.which === 9) { // tab - if (e.shiftKey) { - printTab(currentTab > 0 ? currentTab - 1 : 2); - } else { - printTab(currentTab > 1 ? 0 : currentTab + 1); - } - e.preventDefault(); } else if (e.which === 16) { // shift // Does nothing, it's just to avoid losing "focus" on the highlighted element. } else if (actives[currentTab].length > 0) { @@ -2879,11 +2877,14 @@ function defocusSearchBar() { ["T", "Focus the theme picker menu"], ["↑", "Move up in search results"], ["↓", "Move down in search results"], - ["↹", "Switch tab"], + ["ctrl + ↑ / ↓", "Switch result tab"], ["⏎", "Go to active search result"], ["+", "Expand all sections"], ["-", "Collapse all sections"], - ].map(x => "
" + x[0] + "
" + x[1] + "
").join(""); + ].map(x => "
" + + x[0].split(" ") + .map((y, index) => (index & 1) === 0 ? "" + y + "" : y) + .join("") + "
" + x[1] + "
").join(""); var div_shortcuts = document.createElement("div"); addClass(div_shortcuts, "shortcuts"); div_shortcuts.innerHTML = "

Keyboard Shortcuts

" + shortcuts + "
"; From 5c1d2ced03fe8ce62deaf23abf62213d959ec4cb Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 9 Dec 2020 21:54:24 +0200 Subject: [PATCH 271/274] tests: add 3 cases involving pointers to codegen/transmute-scalar. --- src/test/codegen/transmute-scalar.rs | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/test/codegen/transmute-scalar.rs b/src/test/codegen/transmute-scalar.rs index 48aea4a2f08..f16335fdc74 100644 --- a/src/test/codegen/transmute-scalar.rs +++ b/src/test/codegen/transmute-scalar.rs @@ -2,6 +2,9 @@ #![crate_type = "lib"] +// FIXME(eddyb) all of these tests show memory stores and loads, even after a +// scalar `bitcast`, more special-casing is required to remove `alloca` usage. + // CHECK: define i32 @f32_to_bits(float %x) // CHECK: %2 = bitcast float %x to i32 // CHECK-NEXT: store i32 %2, i32* %0 @@ -33,3 +36,50 @@ pub fn bool_to_byte(b: bool) -> u8 { pub unsafe fn byte_to_bool(byte: u8) -> bool { std::mem::transmute(byte) } + +// CHECK: define i8* @ptr_to_ptr(i16* %p) +// CHECK: %2 = bitcast i16* %p to i8* +// CHECK-NEXT: store i8* %2, i8** %0 +// CHECK-NEXT: %3 = load i8*, i8** %0 +// CHECK: ret i8* %3 +#[no_mangle] +pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { + unsafe { std::mem::transmute(p) } +} + +// HACK(eddyb) scalar `transmute`s between pointers and non-pointers are +// currently not special-cased like other scalar `transmute`s, because +// LLVM requires specifically `ptrtoint`/`inttoptr` instead of `bitcast`. +// +// Tests below show the non-special-cased behavior (with the possible +// future special-cased instructions in the "NOTE(eddyb)" comments). + +// CHECK: define [[USIZE:i[0-9]+]] @ptr_to_int(i16* %p) + +// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: +// %2 = ptrtoint i16* %p to [[USIZE]] +// store [[USIZE]] %2, [[USIZE]]* %0 +// CHECK: %2 = bitcast [[USIZE]]* %0 to i16** +// CHECK-NEXT: store i16* %p, i16** %2 + +// CHECK-NEXT: %3 = load [[USIZE]], [[USIZE]]* %0 +// CHECK: ret [[USIZE]] %3 +#[no_mangle] +pub fn ptr_to_int(p: *mut u16) -> usize { + unsafe { std::mem::transmute(p) } +} + +// CHECK: define i16* @int_to_ptr([[USIZE]] %i) + +// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: +// %2 = inttoptr [[USIZE]] %i to i16* +// store i16* %2, i16** %0 +// CHECK: %2 = bitcast i16** %0 to [[USIZE]]* +// CHECK-NEXT: store [[USIZE]] %i, [[USIZE]]* %2 + +// CHECK-NEXT: %3 = load i16*, i16** %0 +// CHECK: ret i16* %3 +#[no_mangle] +pub fn int_to_ptr(i: usize) -> *mut u16 { + unsafe { std::mem::transmute(i) } +} From 028754a2f7f62ed1e4df889fadfa74eb2d007109 Mon Sep 17 00:00:00 2001 From: The8472 Date: Sat, 21 Nov 2020 19:34:45 +0100 Subject: [PATCH 272/274] implement better availability probing for copy_file_range previously any attempt to copy to an immutable file (EPERM) would disable copy_file_range support for the whole process. --- library/std/src/sys/unix/kernel_copy.rs | 82 +++++++++++++++---------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 5bfac803153..56efc93a1e2 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -59,7 +59,7 @@ use crate::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use crate::os::unix::net::UnixStream; use crate::process::{ChildStderr, ChildStdin, ChildStdout}; use crate::ptr; -use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use crate::sys::cvt; #[cfg(test)] @@ -491,6 +491,13 @@ impl CopyResult { } } +/// Invalid file descriptor. +/// +/// Valid file descriptors are guaranteed to be positive numbers (see `open()` manpage) +/// while negative values are used to indicate errors. +/// Thus -1 will never be overlap with a valid open file. +const INVALID_FD: RawFd = -1; + /// linux-specific implementation that will attempt to use copy_file_range for copy offloading /// as the name says, it only works on regular files /// @@ -500,9 +507,13 @@ impl CopyResult { pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> CopyResult { use crate::cmp; + const NOT_PROBED: u8 = 0; + const UNAVAILABLE: u8 = 1; + const AVAILABLE: u8 = 2; + // Kernel prior to 4.5 don't have copy_file_range // We store the availability in a global to avoid unnecessary syscalls - static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true); + static HAS_COPY_FILE_RANGE: AtomicU8 = AtomicU8::new(NOT_PROBED); syscall! { fn copy_file_range( @@ -515,39 +526,39 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> ) -> libc::ssize_t } - let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); - let mut written = 0u64; - while written < max_len { - let copy_result = if has_copy_file_range { - let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64); - // cap to 1GB chunks in case u64::MAX is passed as max_len and the file has a non-zero seek position - // this allows us to copy large chunks without hitting EOVERFLOW, - // unless someone sets a file offset close to u64::MAX - 1GB, in which case a fallback would be required - let bytes_to_copy = cmp::min(bytes_to_copy as usize, 0x4000_0000usize); - let copy_result = unsafe { - // We actually don't have to adjust the offsets, - // because copy_file_range adjusts the file offset automatically - cvt(copy_file_range( - reader, - ptr::null_mut(), - writer, - ptr::null_mut(), - bytes_to_copy, - 0, - )) + match HAS_COPY_FILE_RANGE.load(Ordering::Relaxed) { + NOT_PROBED => { + // EPERM can indicate seccomp filters or an immutable file. + // To distinguish these cases we probe with invalid file descriptors which should result in EBADF if the syscall is supported + // and some other error (ENOSYS or EPERM) if it's not available + let result = unsafe { + cvt(copy_file_range(INVALID_FD, ptr::null_mut(), INVALID_FD, ptr::null_mut(), 1, 0)) }; - if let Err(ref copy_err) = copy_result { - match copy_err.raw_os_error() { - Some(libc::ENOSYS | libc::EPERM | libc::EOPNOTSUPP) => { - HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); - } - _ => {} - } + + if matches!(result.map_err(|e| e.raw_os_error()), Err(Some(libc::EBADF))) { + HAS_COPY_FILE_RANGE.store(AVAILABLE, Ordering::Relaxed); + } else { + HAS_COPY_FILE_RANGE.store(UNAVAILABLE, Ordering::Relaxed); + return CopyResult::Fallback(0); } - copy_result - } else { - Err(Error::from_raw_os_error(libc::ENOSYS)) + } + UNAVAILABLE => return CopyResult::Fallback(0), + _ => {} + }; + + let mut written = 0u64; + while written < max_len { + let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64); + // cap to 1GB chunks in case u64::MAX is passed as max_len and the file has a non-zero seek position + // this allows us to copy large chunks without hitting EOVERFLOW, + // unless someone sets a file offset close to u64::MAX - 1GB, in which case a fallback would be required + let bytes_to_copy = cmp::min(bytes_to_copy as usize, 0x4000_0000usize); + let copy_result = unsafe { + // We actually don't have to adjust the offsets, + // because copy_file_range adjusts the file offset automatically + cvt(copy_file_range(reader, ptr::null_mut(), writer, ptr::null_mut(), bytes_to_copy, 0)) }; + match copy_result { Ok(0) if written == 0 => { // fallback to work around several kernel bugs where copy_file_range will fail to @@ -567,11 +578,14 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> libc::ENOSYS | libc::EXDEV | libc::EINVAL | libc::EPERM | libc::EOPNOTSUPP, ) => { // Try fallback io::copy if either: - // - Kernel version is < 4.5 (ENOSYS) + // - Kernel version is < 4.5 (ENOSYS¹) // - Files are mounted on different fs (EXDEV) // - copy_file_range is broken in various ways on RHEL/CentOS 7 (EOPNOTSUPP) - // - copy_file_range is disallowed, for example by seccomp (EPERM) + // - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM) // - copy_file_range cannot be used with pipes or device nodes (EINVAL) + // + // ¹ these cases should be detected by the initial probe but we handle them here + // anyway in case syscall interception changes during runtime assert_eq!(written, 0); CopyResult::Fallback(0) } From 7647d03c33339bd85a1665047b22ae7e800fee98 Mon Sep 17 00:00:00 2001 From: The8472 Date: Wed, 9 Dec 2020 21:12:39 +0100 Subject: [PATCH 273/274] Improve comment grammar --- library/std/src/sys/unix/kernel_copy.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs index 56efc93a1e2..200dbf06ff8 100644 --- a/library/std/src/sys/unix/kernel_copy.rs +++ b/library/std/src/sys/unix/kernel_copy.rs @@ -498,8 +498,8 @@ impl CopyResult { /// Thus -1 will never be overlap with a valid open file. const INVALID_FD: RawFd = -1; -/// linux-specific implementation that will attempt to use copy_file_range for copy offloading -/// as the name says, it only works on regular files +/// Linux-specific implementation that will attempt to use copy_file_range for copy offloading. +/// As the name says, it only works on regular files. /// /// Callers must handle fallback to a generic copy loop. /// `Fallback` may indicate non-zero number of bytes already written From 718fba92b0f319a271265df53fd0221447897311 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 10 Dec 2020 13:24:47 +0200 Subject: [PATCH 274/274] tests: codegen/transmute-scalar needs optimizations enabled. --- src/test/codegen/transmute-scalar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/codegen/transmute-scalar.rs b/src/test/codegen/transmute-scalar.rs index f16335fdc74..78b4aa3fb88 100644 --- a/src/test/codegen/transmute-scalar.rs +++ b/src/test/codegen/transmute-scalar.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes +// compile-flags: -O -C no-prepopulate-passes #![crate_type = "lib"]